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