| Commit | Line | Data |
|---|---|---|
| b66b9421 AH |
1 | /* |
| 2 | * Copyright (c) 2009 The DragonFly Project. All rights reserved. | |
| 3 | * | |
| eac446c5 MD |
4 | * This code is derived from software contributed to The DragonFly Project |
| 5 | * by Antonio Huete <tuxillo@quantumachine.net> | |
| 6 | * | |
| b66b9421 AH |
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); | |
| 7bb56fa9 | 39 | char *find_pfs_mount(int pfsid, uuid_t parentuuid, int ismaster); |
| eac446c5 | 40 | double percent(int64_t value, int64_t total); |
| 095ad2eb | 41 | u_int32_t count_snapshots(int fd, u_int32_t version, char *pfs_snapshots, char *mountedon); |
| b66b9421 AH |
42 | |
| 43 | void | |
| eac446c5 | 44 | hammer_cmd_info(void) |
| b66b9421 | 45 | { |
| eac446c5 | 46 | struct statfs *stfsbuf; |
| 095ad2eb | 47 | int mntsize, i, first = 1; |
| eac446c5 | 48 | char *fstype, *path; |
| b66b9421 AH |
49 | |
| 50 | tzset(); | |
| eac446c5 MD |
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; | |
| 095ad2eb TN |
56 | if ((strcmp(fstype, "hammer")) == 0) { |
| 57 | if (first) | |
| 58 | first = 0; | |
| 59 | else | |
| 60 | fprintf(stdout, "\n"); | |
| b66b9421 | 61 | show_info(path); |
| 095ad2eb | 62 | } |
| b66b9421 | 63 | } |
| 7bb56fa9 | 64 | } else { |
| eac446c5 | 65 | fprintf(stdout, "No mounted filesystems found\n"); |
| 7bb56fa9 | 66 | } |
| eac446c5 | 67 | |
| b66b9421 AH |
68 | } |
| 69 | ||
| 7bb56fa9 MD |
70 | void |
| 71 | show_info(char *path) | |
| 72 | { | |
| 7bb56fa9 MD |
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; | |
| 095ad2eb | 78 | char *fsid; |
| 7bb56fa9 MD |
79 | char *mountedon; |
| 80 | char buf[6]; | |
| 81 | u_int32_t sc; | |
| b66b9421 | 82 | |
| 095ad2eb | 83 | fsid = mountedon = NULL; |
| eac446c5 | 84 | usedbigblocks = 0; |
| 095ad2eb | 85 | pfs_id = 0; /* Include PFS#0 */ |
| eac446c5 | 86 | bytes = 0; |
| 7bb56fa9 | 87 | sc = 0; |
| b66b9421 AH |
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"); | |
| 095ad2eb TN |
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); | |
| b66b9421 AH |
112 | |
| 113 | /* Big blocks information */ | |
| 114 | usedbigblocks = info.bigblocks - info.freebigblocks; | |
| 115 | ||
| 116 | fprintf(stdout, "Big block information\n"); | |
| 095ad2eb TN |
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", | |
| a276dc6b MD |
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)); | |
| b66b9421 AH |
128 | fprintf(stdout, "Space information\n"); |
| 129 | ||
| 130 | /* Space information */ | |
| 095ad2eb | 131 | fprintf(stdout, "\tNo. Inodes %10jd\n", (intmax_t)info.inodes); |
| b66b9421 | 132 | bytes = (info.bigblocks << HAMMER_LARGEBLOCK_BITS); |
| 7bb56fa9 MD |
133 | humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), bytes, "", |
| 134 | HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B); | |
| a276dc6b MD |
135 | fprintf(stdout, "\tTotal size %6s (%jd bytes)\n", |
| 136 | buf, (intmax_t)bytes); | |
| b66b9421 AH |
137 | |
| 138 | bytes = (usedbigblocks << HAMMER_LARGEBLOCK_BITS); | |
| 7bb56fa9 MD |
139 | humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), bytes, "", |
| 140 | HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B); | |
| b66b9421 AH |
141 | fprintf(stdout, "\tUsed space %6s\n", buf); |
| 142 | ||
| 143 | bytes = (info.rsvbigblocks << HAMMER_LARGEBLOCK_BITS); | |
| 7bb56fa9 MD |
144 | humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), bytes, "", |
| 145 | HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE | HN_B); | |
| b66b9421 AH |
146 | fprintf(stdout, "\tReserved space %6s\n", buf); |
| 147 | ||
| 148 | bytes = ((info.freebigblocks - info.rsvbigblocks) << HAMMER_LARGEBLOCK_BITS); | |
| 7bb56fa9 MD |
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"); | |
| 095ad2eb | 155 | fprintf(stdout, "\tPFS-Id Mode Snaps Mounted-on\n"); |
| 7bb56fa9 MD |
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) { | |
| 7bb56fa9 | 165 | ismaster = (pfs_od.mirror_flags & HAMMER_PFSD_SLAVE) ? 0 : 1; |
| 095ad2eb TN |
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); | |
| 7bb56fa9 | 172 | |
| 095ad2eb | 173 | fprintf(stdout, "\t%6d %-6s %6d ", |
| 7bb56fa9 MD |
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++; | |
| 095ad2eb | 182 | } |
| 7bb56fa9 MD |
183 | |
| 184 | free(fsid); | |
| 185 | free(mountedon); | |
| b66b9421 AH |
186 | } |
| 187 | ||
| 7bb56fa9 MD |
188 | char * |
| 189 | find_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; | |
| d14ecbb6 | 197 | char *trailstr; |
| 7bb56fa9 MD |
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; | |
| b66b9421 | 206 | |
| 7bb56fa9 MD |
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 | ||
| 260 | double | |
| 261 | percent(int64_t value, int64_t total) | |
| 262 | { | |
| b66b9421 | 263 | /* Avoid divide-by-zero */ |
| 095ad2eb TN |
264 | if (total == 0) |
| 265 | return 100.0; | |
| b66b9421 | 266 | |
| eac446c5 | 267 | return ((value * 100.0) / (double)total); |
| b66b9421 | 268 | } |
| 095ad2eb TN |
269 | |
| 270 | u_int32_t | |
| 271 | count_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 | } |