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 36 #include "hammer.h" 37 38 #include <libutil.h> 39 #include <libhammer.h> 40 41 void show_info(char *path); 42 static double percent(int64_t value, int64_t total); 43 44 void 45 hammer_cmd_info(char **av, int ac) 46 { 47 struct statfs *stfsbuf; 48 int mntsize, i, first = 1; 49 char *fstype, *path; 50 51 tzset(); 52 53 if (ac > 0) { 54 while (ac) { 55 show_info(*av); 56 --ac; 57 ++av; 58 if (ac) 59 printf("\n"); 60 } 61 } else { 62 mntsize = getmntinfo(&stfsbuf, MNT_NOWAIT); 63 if (mntsize > 0) { 64 for (i = 0; i < mntsize; i++) { 65 fstype = stfsbuf[i].f_fstypename; 66 path = stfsbuf[i].f_mntonname; 67 if ((strcmp(fstype, "hammer")) == 0) { 68 if (first) 69 first = 0; 70 else 71 printf("\n"); 72 show_info(path); 73 } 74 } 75 if (first) 76 printf("No mounted HAMMER filesystems found\n"); 77 } else { 78 printf("No mounted filesystems found\n"); 79 } 80 } 81 } 82 83 /* 84 * This is an adhoc function which exists only because libhammer can't 85 * properly handle variety of errors. 86 */ 87 static 88 void 89 __test_if_hammer_or_abort(const char *path) 90 { 91 struct hammer_ioc_info info; 92 int fd; 93 94 fd = open(path, O_RDONLY); 95 if (fd < 0) { 96 err(1, "Failed to open %s", path); 97 /* not reached */ 98 } 99 100 /* 101 * This ioctl never fails as long as fd is for HAMMER filesystem, 102 * thus we can assume path isn't in HAMMER if this fails. 103 */ 104 if (ioctl(fd, HAMMERIOC_GET_INFO, &info) < 0) { 105 err(1, "%s is probably not a HAMMER filesystem", path); 106 /* not reached */ 107 } 108 109 close(fd); 110 } 111 112 void 113 show_info(char *path) 114 { 115 libhammer_fsinfo_t fip; 116 libhammer_pfsinfo_t pi, pi_first; 117 struct hammer_ioc_volume_list ioc; 118 int64_t usedbigblocks; 119 int64_t usedbytes, rsvbytes; 120 int64_t totalbytes, freebytes; 121 char *fsid; 122 char buf[6]; 123 char rootvol[MAXPATHLEN]; 124 int i; 125 126 fsid = NULL; 127 usedbigblocks = 0; 128 129 usedbytes = totalbytes = rsvbytes = freebytes = 0; 130 131 /* Need to do this before libhammer gets involved */ 132 __test_if_hammer_or_abort(path); 133 134 fip = libhammer_get_fsinfo(path); 135 if (fip == NULL) { 136 errx(1, "Failed to get filesystem info"); 137 /* not reached */ 138 } 139 140 /* Find out the UUID strings */ 141 hammer_uuid_to_string(&fip->vol_fsid, &fsid); 142 143 /* Get the volume paths */ 144 if (hammer_fs_to_vol(path, &ioc) == -1) { 145 errx(1, "Failed to get volume paths"); 146 /* not reached */ 147 } 148 149 /* Get the root volume path */ 150 if (hammer_fs_to_rootvol(path, rootvol, sizeof(rootvol)) == -1) { 151 errx(1, "Failed to get root volume path"); 152 /* not reached */ 153 } 154 155 /* Volume information */ 156 printf("Volume identification\n"); 157 printf("\tLabel %s\n", fip->vol_name); 158 printf("\tNo. Volumes %d\n", fip->nvolumes); 159 printf("\tHAMMER Volumes "); 160 for (i = 0; i < ioc.nvols; i++) { 161 printf("%s", ioc.vols[i].device_name); 162 if (i != ioc.nvols - 1) 163 printf(":"); 164 } 165 printf("\n"); 166 printf("\tRoot Volume %s\n", rootvol); 167 printf("\tFSID %s\n", fsid); 168 printf("\tHAMMER Version %d\n", fip->version); 169 170 /* Big-blocks information */ 171 usedbigblocks = fip->bigblocks - fip->freebigblocks; 172 173 printf("Big-block information\n"); 174 printf("\tTotal %10jd\n", (intmax_t)fip->bigblocks); 175 printf("\tUsed %10jd (%.2lf%%)\n" 176 "\tReserved %10jd (%.2lf%%)\n" 177 "\tFree %10jd (%.2lf%%)\n", 178 (intmax_t)usedbigblocks, 179 percent(usedbigblocks, fip->bigblocks), 180 (intmax_t)fip->rsvbigblocks, 181 percent(fip->rsvbigblocks, fip->bigblocks), 182 (intmax_t)(fip->freebigblocks - fip->rsvbigblocks), 183 percent(fip->freebigblocks - fip->rsvbigblocks, fip->bigblocks)); 184 printf("Space information\n"); 185 186 /* Space information */ 187 totalbytes = (fip->bigblocks << HAMMER_BIGBLOCK_BITS); 188 usedbytes = (usedbigblocks << HAMMER_BIGBLOCK_BITS); 189 rsvbytes = (fip->rsvbigblocks << HAMMER_BIGBLOCK_BITS); 190 freebytes = ((fip->freebigblocks - fip->rsvbigblocks) 191 << HAMMER_BIGBLOCK_BITS); 192 193 printf("\tNo. Inodes %10jd\n", (intmax_t)fip->inodes); 194 humanize_number(buf, sizeof(buf) - (totalbytes < 0 ? 0 : 1), 195 totalbytes, "", HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B); 196 printf("\tTotal size %6s (%jd bytes)\n", 197 buf, (intmax_t)totalbytes); 198 199 humanize_number(buf, sizeof(buf) - (usedbytes < 0 ? 0 : 1), 200 usedbytes, "", HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B); 201 printf("\tUsed %6s (%.2lf%%)\n", buf, 202 percent(usedbytes, totalbytes)); 203 204 humanize_number(buf, sizeof(buf) - (rsvbytes < 0 ? 0 : 1), 205 rsvbytes, "", HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B); 206 printf("\tReserved %6s (%.2lf%%)\n", buf, 207 percent(rsvbytes, totalbytes)); 208 209 humanize_number(buf, sizeof(buf) - (freebytes < 0 ? 0 : 1), 210 freebytes, "", HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B); 211 printf("\tFree %6s (%.2lf%%)\n", buf, 212 percent(freebytes, totalbytes)); 213 214 /* Pseudo-filesystem information */ 215 printf("PFS information\n"); 216 printf("\t PFS# Mode Snaps\n"); 217 218 /* Iterate all the PFSs found */ 219 pi_first = libhammer_get_first_pfs(fip); 220 for (pi = pi_first; pi != NULL; pi = libhammer_get_next_pfs(pi)) { 221 printf("\t%6d %-6s", 222 pi->pfs_id, (pi->ismaster ? "MASTER" : "SLAVE")); 223 224 snprintf(buf, 6, "%d", pi->snapcount); 225 printf(" %6s", (pi->head.error && pi->snapcount == 0) ? "-" : buf); 226 if (pi->pfs_id == HAMMER_ROOT_PFSID) 227 printf(" (root PFS)"); 228 printf("\n"); 229 } 230 231 free(fsid); 232 233 libhammer_free_fsinfo(fip); 234 235 } 236 237 static 238 double 239 percent(int64_t value, int64_t total) 240 { 241 /* Avoid divide-by-zero */ 242 if (total == 0) 243 return 100.0; 244 245 return ((value * 100.0) / (double)total); 246 } 247