Merge branch 'vendor/ZLIB'
[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 u_int32_t count_snapshots(int fd, u_int32_t version,
42     char *pfs_snapshots, char *mountedon);
43
44 void
45 hammer_cmd_info(void)
46 {
47         struct statfs *stfsbuf;
48         int mntsize, i, first = 1;
49         char *fstype, *path;
50
51         tzset();
52         mntsize = getmntinfo(&stfsbuf, MNT_NOWAIT);
53         if (mntsize > 0) {
54                 for (i = 0; i < mntsize; i++) {
55                         fstype = stfsbuf[i].f_fstypename;
56                         path = stfsbuf[i].f_mntonname;
57                         if ((strcmp(fstype, "hammer")) == 0) {
58                                 if (first)
59                                         first = 0;
60                                 else
61                                         fprintf(stdout, "\n");
62                                 show_info(path);
63                         }
64                 }
65         } else {
66                 fprintf(stdout, "No mounted filesystems found\n");
67         }
68
69 }
70
71 void
72 show_info(char *path)
73 {
74         struct      hammer_pseudofs_data pfs_od;
75         struct      hammer_ioc_pseudofs_rw pfs;
76         int64_t     usedbigblocks;
77         int64_t     usedbytes, rsvbytes;
78         int64_t     totalbytes, freebytes;
79         struct      hammer_ioc_info info;
80         int         fd, pfs_id, ismaster;
81         char        *fsid;
82         char        *mountedon;
83         char        buf[6];
84         u_int32_t   sc;
85
86         fsid = mountedon = NULL;
87         usedbigblocks = 0;
88         pfs_id = 0;           /* Include PFS#0 */
89         usedbytes = totalbytes = rsvbytes = freebytes = 0;
90         sc = 0;
91
92         bzero(&info, sizeof(struct hammer_ioc_info));
93
94         /* Try to get a file descriptor based on the path given */
95         fd = open(path, O_RDONLY);
96         if (fd < 0) {
97                 perror("show_info");
98                 exit(EXIT_FAILURE);
99         }
100
101         if ((ioctl(fd, HAMMERIOC_GET_INFO, &info)) < 0) {
102                 perror("show_info");
103                 exit(EXIT_FAILURE);
104         }
105
106         /* Find out the UUID strings */
107         uuid_to_string(&info.vol_fsid, &fsid, NULL);
108
109         /* Volume information */
110         fprintf(stdout, "Volume identification\n");
111         fprintf(stdout, "\tLabel               %s\n", info.vol_name);
112         fprintf(stdout, "\tNo. Volumes         %d\n", info.nvolumes);
113         fprintf(stdout, "\tFSID                %s\n", fsid);
114         fprintf(stdout, "\tHAMMER Version      %d\n", info.version);
115
116         /* Big blocks information */
117         usedbigblocks = info.bigblocks - info.freebigblocks;
118
119         fprintf(stdout, "Big block information\n");
120         fprintf(stdout, "\tTotal      %10jd\n", (intmax_t)info.bigblocks);
121         fprintf(stdout, "\tUsed       %10jd (%.2lf%%)\n"
122                         "\tReserved   %10jd (%.2lf%%)\n"
123                         "\tFree       %10jd (%.2lf%%)\n",
124                         (intmax_t)usedbigblocks,
125                         percent(usedbigblocks, info.bigblocks),
126                         (intmax_t)info.rsvbigblocks,
127                         percent(info.rsvbigblocks, info.bigblocks),
128                         (intmax_t)(info.freebigblocks - info.rsvbigblocks),
129                         percent(info.freebigblocks - info.rsvbigblocks,
130                                 info.bigblocks));
131         fprintf(stdout, "Space information\n");
132
133         /* Space information */
134         totalbytes = (info.bigblocks << HAMMER_LARGEBLOCK_BITS);
135         usedbytes = (usedbigblocks << HAMMER_LARGEBLOCK_BITS);
136         rsvbytes = (info.rsvbigblocks << HAMMER_LARGEBLOCK_BITS);
137         freebytes = ((info.freebigblocks - info.rsvbigblocks)
138             << HAMMER_LARGEBLOCK_BITS);
139
140         fprintf(stdout, "\tNo. Inodes %10jd\n", (intmax_t)info.inodes);
141         humanize_number(buf, sizeof(buf)  - (totalbytes < 0 ? 0 : 1),
142             totalbytes, "", HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B);
143         fprintf(stdout, "\tTotal size     %6s (%jd bytes)\n",
144             buf, (intmax_t)totalbytes);
145
146         humanize_number(buf, sizeof(buf)  - (usedbytes < 0 ? 0 : 1),
147             usedbytes, "", HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B);
148         fprintf(stdout, "\tUsed           %6s (%.2lf%%)\n", buf,
149             percent(usedbytes, totalbytes));
150
151         humanize_number(buf, sizeof(buf)  - (rsvbytes < 0 ? 0 : 1),
152             rsvbytes, "", HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B);
153         fprintf(stdout, "\tReserved       %6s (%.2lf%%)\n", buf,
154             percent(rsvbytes, totalbytes));
155
156         humanize_number(buf, sizeof(buf)  - (freebytes < 0 ? 0 : 1),
157             freebytes, "", HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B);
158         fprintf(stdout, "\tFree           %6s (%.2lf%%)\n", buf,
159             percent(freebytes, totalbytes));
160
161         /* Pseudo-filesystem information */
162         fprintf(stdout, "PFS information\n");
163         fprintf(stdout, "\tPFS ID  Mode    Snaps  Mounted on\n");
164
165         while(pfs_id < HAMMER_MAX_PFS) {
166                 bzero(&pfs, sizeof(pfs));
167                 bzero(&pfs_od, sizeof(pfs_od));
168                 pfs.pfs_id = pfs_id;
169                 pfs.ondisk = &pfs_od;
170                 pfs.bytes = sizeof(pfs_od);
171                 pfs.version = HAMMER_IOC_PSEUDOFS_VERSION;
172                 if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) >= 0) {
173                         ismaster = (pfs_od.mirror_flags & HAMMER_PFSD_SLAVE)
174                             ? 0 : 1;
175                         if (pfs_id == 0)
176                                 mountedon = strdup(path);
177                         else
178                                 mountedon = find_pfs_mount(pfs_id,
179                                     info.vol_fsid, ismaster);
180
181                         sc = count_snapshots(fd, info.version, pfs_od.snapshots,
182                             mountedon);
183
184                         fprintf(stdout, "\t%6d  %-6s %6d  ",
185                             pfs_id, (ismaster ? "MASTER" : "SLAVE"), sc);
186                         if (mountedon)
187                                 fprintf(stdout, "%s", mountedon);
188                         else
189                                 fprintf(stdout, "not mounted");
190                         fprintf(stdout, "\n");
191                 }
192                 pfs_id++;
193         }
194
195         free(fsid);
196         free(mountedon);
197 }
198
199 char *
200 find_pfs_mount(int pfsid, uuid_t parentuuid, int ismaster)
201 {
202         struct hammer_ioc_info hi;
203         struct statfs *mntbuf;
204         int mntsize;
205         int curmount;
206         int fd;
207         size_t  mntbufsize;
208         char *trailstr;
209         char *retval;
210
211         retval = NULL;
212
213         /* Do not continue if there are no mounted filesystems */
214         mntsize = getfsstat(NULL, 0, MNT_NOWAIT);
215         if (mntsize <= 0)
216                 return retval;
217
218         mntbufsize = (mntsize) * sizeof(struct statfs);
219         mntbuf = malloc(mntbufsize);
220         if (mntbuf == NULL) {
221                 perror("show_info");
222                 exit(EXIT_FAILURE);
223         }
224
225         mntsize = getfsstat(mntbuf, (long)mntbufsize, MNT_NOWAIT);
226         curmount = mntsize - 1;
227
228         asprintf(&trailstr, ":%05d", pfsid);
229
230         /*
231          * Iterate all the mounted points looking for the PFS passed to
232          * this function.
233          */
234         while(curmount >= 0) {
235                 /*
236                  * We need to avoid that PFS belonging to other HAMMER
237                  * filesystems are showed as mounted, so we compare
238                  * against the FSID, which is presumable to be unique.
239                  */
240                 bzero(&hi, sizeof(hi));
241                 if ((fd = open(mntbuf[curmount].f_mntfromname, O_RDONLY)) < 0) {
242                         curmount--;
243                         continue;
244                 }
245
246                 if ((ioctl(fd, HAMMERIOC_GET_INFO, &hi)) < 0) {
247                         curmount--;
248                         continue;
249                 }
250
251                 if (strstr(mntbuf[curmount].f_mntfromname, trailstr) != NULL &&
252                     (uuid_compare(&hi.vol_fsid, &parentuuid, NULL)) == 0) {
253                         if (ismaster) {
254                                 if (strstr(mntbuf[curmount].f_mntfromname,
255                                     "@@-1") != NULL) {
256                                         retval =
257                                             strdup(mntbuf[curmount].f_mntonname);
258                                         break;
259                                 }
260                         } else {
261                                 if (strstr(mntbuf[curmount].f_mntfromname,
262                                     "@@0x") != NULL ) {
263                                         retval =
264                                             strdup(mntbuf[curmount].f_mntonname);
265                                         break;
266                                 }
267                         }
268                 }
269                 curmount--;
270         }
271         free(trailstr);
272         return retval;
273 }
274
275 double
276 percent(int64_t value, int64_t total)
277 {
278         /* Avoid divide-by-zero */
279         if (total == 0)
280                 return 100.0;
281
282         return ((value * 100.0) / (double)total);
283 }
284
285 u_int32_t
286 count_snapshots(int fd, u_int32_t version, char *pfs_snapshots, char *mountedon)
287 {
288         struct hammer_ioc_snapshot snapinfo;
289         char *snapshots_path, *fpath;
290         struct dirent *den;
291         struct stat st;
292         DIR *dir;
293         u_int32_t snapshot_count = 0;
294
295         bzero(&snapinfo, sizeof(struct hammer_ioc_snapshot));
296         if (version < 3) {
297                 /*
298                  * old style: count the number of softlinks in the snapshots dir
299                  */
300                 if (pfs_snapshots[0])
301                         snapshots_path = pfs_snapshots;
302                 else
303                         asprintf(&snapshots_path, "%s/snapshots", mountedon);
304                 if ((dir = opendir(snapshots_path)) != NULL) {
305                         while ((den = readdir(dir)) != NULL) {
306                                 if (den->d_name[0] == '.')
307                                         continue;
308                                 asprintf(&fpath, "%s/%s", snapshots_path,
309                                     den->d_name);
310                                 if (lstat(fpath, &st) == 0 &&
311                                     S_ISLNK(st.st_mode))
312                                         snapshot_count++;
313                                 free(fpath);
314                         }
315                         closedir(dir);
316                 }
317         } else {
318                 /*
319                  * new style: file system meta-data
320                  */
321                 do {
322                         if (ioctl(fd, HAMMERIOC_GET_SNAPSHOT, &snapinfo) < 0) {
323                                 perror("count_snapshots");
324                                 exit(EXIT_FAILURE);
325                         }
326                         snapshot_count += snapinfo.count;
327                 } while (snapinfo.head.error == 0 && snapinfo.count);
328         }
329         return snapshot_count;
330 }