xref: /dragonfly/sbin/hammer/cmd_info.c (revision 10cbe914)
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 }
331