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