57df4e289678bf74d75ea37df3fe705ebb39ea56
[dragonfly.git] / sbin / hammer / cmd_info.c
1 /*
2  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Antonio Huete <tuxillo@quantumachine.net>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  */
35 #include "hammer.h"
36 #include <libutil.h>
37
38 void    show_info(char *path);
39 char    *find_pfs_mount(int pfsid, uuid_t parentuuid, int ismaster);
40 double  percent(int64_t value, int64_t total);
41
42 void
43 hammer_cmd_info(void)
44 {
45         struct statfs *stfsbuf;
46         int mntsize, i;
47         char *fstype, *path;
48
49         tzset();
50         mntsize = getmntinfo(&stfsbuf, MNT_NOWAIT);
51         if (mntsize > 0) {
52                 for (i=0; i < mntsize; i++) {
53                         fstype = stfsbuf[i].f_fstypename;
54                         path = stfsbuf[i].f_mntonname;
55                         if ((strcmp(fstype, "hammer")) == 0)
56                                 show_info(path);
57                 }
58         } else {
59                 fprintf(stdout, "No mounted filesystems found\n");
60         }
61
62 }
63
64 void
65 show_info(char *path)
66 {
67         struct      hammer_ioc_snapshot snapinfo;
68         struct      hammer_pseudofs_data pfs_od;
69         struct      hammer_ioc_pseudofs_rw pfs;
70         int64_t     usedbigblocks, bytes;
71         struct      hammer_ioc_info info;
72         int         fd, pfs_id, ismaster;
73         char        *fsid, *fstype;
74         char        *mountedon;
75         char        buf[6];
76         u_int32_t   sc;
77
78         fsid = fstype = mountedon = NULL;
79         usedbigblocks = 0;
80         pfs_id = 1;           /* Do not include PFS#0 */
81         bytes = 0;
82         sc = 0;
83
84         bzero(&info, sizeof(struct hammer_ioc_info));
85         bzero(&snapinfo, sizeof(struct hammer_ioc_snapshot));
86
87         /* Try to get a file descriptor based on the path given */
88         fd = open(path, O_RDONLY);
89         if (fd < 0) {
90                 perror("show_info");
91                 exit(EXIT_FAILURE);
92         }
93
94         if ((ioctl(fd, HAMMERIOC_GET_INFO, &info)) < 0) {
95                 perror("show_info");
96                 exit(EXIT_FAILURE);
97         }
98
99         /* Find out the UUID strings */
100         uuid_to_string(&info.vol_fsid, &fsid, NULL);
101
102         /* Volume information */
103         fprintf(stdout, "Volume identification\n");
104         fprintf(stdout, "\tLabel          %s\n", info.vol_name);
105         fprintf(stdout, "\tNo. Volumes    %d\n", info.nvolumes);
106         fprintf(stdout, "\tFSID           %s\n", fsid);
107
108         /* Big blocks information */
109         usedbigblocks = info.bigblocks - info.freebigblocks;
110
111         fprintf(stdout, "Big block information\n");
112         fprintf(stdout, "\tTotal\t       %jd\n", (intmax_t)info.bigblocks);
113         fprintf(stdout, "\tUsed\t       %jd (%.2lf%%)\n\tReserved       "
114                                        "%jd (%.2lf%%)\n\tFree\t       "
115                                        "%jd (%.2lf%%)\n",
116                         (intmax_t)usedbigblocks,
117                         percent(usedbigblocks, info.bigblocks),
118                         (intmax_t)info.rsvbigblocks,
119                         percent(info.rsvbigblocks, info.bigblocks),
120                         (intmax_t)(info.freebigblocks - info.rsvbigblocks),
121                         percent(info.freebigblocks - info.rsvbigblocks,
122                                 info.bigblocks));
123         fprintf(stdout, "Space information\n");
124
125         /* Space information */
126         bytes = (info.bigblocks << HAMMER_LARGEBLOCK_BITS);
127         humanize_number(buf, sizeof(buf)  - (bytes < 0 ? 0 : 1), bytes, "",
128                         HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B);
129         fprintf(stdout, "\tTotal size     %6s (%jd bytes)\n",
130                 buf, (intmax_t)bytes);
131
132         bytes = (usedbigblocks << HAMMER_LARGEBLOCK_BITS);
133         humanize_number(buf, sizeof(buf)  - (bytes < 0 ? 0 : 1), bytes, "",
134                         HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B);
135         fprintf(stdout, "\tUsed space     %6s\n", buf);
136
137         bytes = (info.rsvbigblocks << HAMMER_LARGEBLOCK_BITS);
138         humanize_number(buf, sizeof(buf)  - (bytes < 0 ? 0 : 1), bytes, "",
139                         HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B);
140         fprintf(stdout, "\tReserved space %6s\n", buf);
141
142         bytes = ((info.freebigblocks - info.rsvbigblocks) << HAMMER_LARGEBLOCK_BITS);
143         humanize_number(buf, sizeof(buf)  - (bytes < 0 ? 0 : 1), bytes, "",
144                         HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B);
145         fprintf(stdout, "\tFree space     %6s\n", buf);
146
147         /* Pseudo-filesystem information */
148         fprintf(stdout, "PFS information\n");
149         fprintf(stdout, "\tPFS-Id\tMode\tSnaps\tMounted-on\n");
150
151         while(pfs_id < HAMMER_MAX_PFS) {
152                 bzero(&pfs, sizeof(pfs));
153                 bzero(&pfs_od, sizeof(pfs_od));
154                 pfs.pfs_id = pfs_id;
155                 pfs.ondisk = &pfs_od;
156                 pfs.bytes = sizeof(pfs_od);
157                 pfs.version = HAMMER_IOC_PSEUDOFS_VERSION;
158                 if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) >= 0) {
159                         if (ioctl(fd, HAMMERIOC_GET_SNAPSHOT, &snapinfo) >= 0)
160                                 sc = snapinfo.count;
161
162                         ismaster = (pfs_od.mirror_flags & HAMMER_PFSD_SLAVE) ? 0 : 1;
163                         mountedon = find_pfs_mount(pfs_id, info.vol_fsid, ismaster);
164
165                         fprintf(stdout, "\t%05d\t%6s\t%5u\t",
166                                 pfs_id, (ismaster ? "MASTER" : "SLAVE"), sc);
167                         if (mountedon)
168                                 fprintf(stdout, "%s", mountedon);
169                         else
170                                 fprintf(stdout, "not-mounted");
171                         fprintf(stdout, "\n");
172                 }
173                 pfs_id++;
174         }
175
176         fprintf(stdout, "\n\n");        /* In the case multiple volumes, two new-line separation */
177
178         free(fsid);
179         free(mountedon);
180 }
181
182 char *
183 find_pfs_mount(int pfsid, uuid_t parentuuid, int ismaster)
184 {
185         struct hammer_ioc_info hi;
186         struct statfs *mntbuf;
187         int mntsize;
188         int curmount;
189         int fd;
190         size_t  mntbufsize;
191         char **trailstr;
192         char *retval;
193
194         retval = NULL;
195
196         /* Do not continue if there are no mounted filesystems */
197         mntsize = getfsstat(NULL, 0, MNT_NOWAIT);
198         if (mntsize <= 0)
199                 return retval;
200
201         mntbufsize = (mntsize) * sizeof(struct statfs);
202         mntbuf = malloc(mntbufsize);
203         if (mntbuf == NULL) {
204                 perror("show_info");
205                 exit(EXIT_FAILURE);
206         }
207
208         mntsize = getfsstat(mntbuf, (long)mntbufsize, MNT_NOWAIT);
209         curmount = mntsize - 1;
210
211         asprintf(&trailstr, ":%05d", pfsid);
212
213         /*
214          * Iterate all the mounted points looking for the PFS passed to
215          * this function.
216          */
217         while(curmount >= 0) {
218                 /*
219                  * We need to avoid that PFS belonging to other HAMMER
220                  * filesystems are showed as mounted, so we compare
221                  * against the FSID, which is presumable to be unique.
222                  */
223                 bzero(&hi, sizeof(hi));
224                 if ((fd = open(mntbuf[curmount].f_mntfromname, O_RDONLY)) < 0) {
225                         curmount--;
226                         continue;
227                 }
228
229                 if ((ioctl(fd, HAMMERIOC_GET_INFO, &hi)) < 0) {
230                         curmount--;
231                         continue;
232                 }
233
234                 if (strstr(mntbuf[curmount].f_mntfromname, trailstr) != NULL &&
235                     (uuid_compare(&hi.vol_fsid, &parentuuid, NULL)) == 0) {
236                         if (ismaster) {
237                                 if (strstr(mntbuf[curmount].f_mntfromname, "@@-1") != NULL) {
238                                         retval = strdup(mntbuf[curmount].f_mntonname);
239                                         break;
240                                 }
241                         } else {
242                                 if (strstr(mntbuf[curmount].f_mntfromname, "@@0x") != NULL ) {
243                                         retval = strdup(mntbuf[curmount].f_mntonname);
244                                         break;
245                                 }
246                         }
247                 }
248                 curmount--;
249         }
250         free(trailstr);
251         return retval;
252 }
253
254 double
255 percent(int64_t value, int64_t total)
256 {
257         /* Avoid divide-by-zero */
258         if (value == 0)
259                 value = 1;
260
261         return ((value * 100.0) / (double)total);
262 }