1 /* 2 * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 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 * $DragonFly: src/sbin/hammer/hammer.c,v 1.14 2008/05/04 19:18:17 dillon Exp $ 35 */ 36 37 #include "hammer.h" 38 #include <signal.h> 39 #include <math.h> 40 41 static void hammer_parsetime(u_int64_t *tidp, const char *timestr); 42 static void hammer_waitsync(int dosleep); 43 static void hammer_parsedevs(const char *blkdevs); 44 static void sigalrm(int signo); 45 static void usage(int exit_code); 46 47 int RecurseOpt; 48 int VerboseOpt; 49 int NoSyncOpt; 50 const char *LinkPath; 51 52 int 53 main(int ac, char **av) 54 { 55 struct timeval tv; 56 u_int64_t tid; 57 int ch; 58 int timeout = 0; 59 u_int32_t status; 60 char *blkdevs = NULL; 61 62 while ((ch = getopt(ac, av, "hf:rs:t:vx")) != -1) { 63 switch(ch) { 64 case 'h': 65 usage(0); 66 /* not reached */ 67 case 'r': 68 RecurseOpt = 1; 69 break; 70 case 'f': 71 blkdevs = optarg; 72 break; 73 case 's': 74 LinkPath = optarg; 75 break; 76 case 't': 77 timeout = strtol(optarg, NULL, 0); 78 break; 79 case 'v': 80 ++VerboseOpt; 81 break; 82 case 'x': 83 ++NoSyncOpt; 84 break; 85 default: 86 usage(1); 87 /* not reached */ 88 } 89 } 90 ac -= optind; 91 av += optind; 92 if (ac < 1) { 93 usage(1); 94 /* not reached */ 95 } 96 97 if (timeout > 0) { 98 signal(SIGALRM, sigalrm); 99 alarm(timeout); 100 } 101 102 if (strcmp(av[0], "now") == 0) { 103 hammer_waitsync(1); 104 tid = (hammer_tid_t)time(NULL) * 1000000000LLU; 105 printf("0x%08x\n", (int)(tid / 1000000000LL)); 106 exit(0); 107 } 108 if (strcmp(av[0], "now64") == 0) { 109 hammer_waitsync(0); 110 gettimeofday(&tv, NULL); 111 tid = (hammer_tid_t)tv.tv_sec * 1000000000LLU + 112 tv.tv_usec * 1000LLU; 113 printf("0x%016llx\n", tid); 114 exit(0); 115 } 116 if (strcmp(av[0], "stamp") == 0) { 117 if (av[1] == NULL) 118 usage(1); 119 hammer_parsetime(&tid, av[1]); 120 printf("0x%08x\n", (int)(tid / 1000000000LL)); 121 exit(0); 122 } 123 if (strcmp(av[0], "stamp64") == 0) { 124 if (av[1] == NULL) 125 usage(1); 126 hammer_parsetime(&tid, av[1]); 127 printf("0x%016llx\n", tid); 128 exit(0); 129 } 130 if (strcmp(av[0], "namekey") == 0) { 131 int64_t key; 132 133 if (av[1] == NULL) 134 usage(1); 135 key = (int64_t)(crc32(av[1], strlen(av[1])) & 0x7FFFFFFF) << 32; 136 if (key == 0) 137 key |= 0x100000000LL; 138 printf("0x%016llx\n", key); 139 exit(0); 140 } 141 if (strcmp(av[0], "namekey32") == 0) { 142 int32_t key; 143 144 if (av[1] == NULL) 145 usage(1); 146 key = crc32(av[1], strlen(av[1])) & 0x7FFFFFFF; 147 if (key == 0) 148 ++key; 149 printf("0x%08x\n", key); 150 exit(0); 151 } 152 if (strcmp(av[0], "prune") == 0) { 153 hammer_cmd_prune(av + 1, ac - 1); 154 exit(0); 155 } 156 157 if (strncmp(av[0], "history", 7) == 0) { 158 hammer_cmd_history(av[0] + 7, av + 1, ac - 1); 159 exit(0); 160 } 161 if (strcmp(av[0], "reblock") == 0) { 162 hammer_cmd_reblock(av + 1, ac - 1); 163 exit(0); 164 } 165 166 uuid_name_lookup(&Hammer_FSType, "DragonFly HAMMER", &status); 167 if (status != uuid_s_ok) { 168 errx(1, "uuids file does not have the DragonFly " 169 "HAMMER filesystem type"); 170 } 171 172 if (strcmp(av[0], "show") == 0) { 173 hammer_off_t node_offset = (hammer_off_t)-1; 174 175 hammer_parsedevs(blkdevs); 176 if (ac > 1) 177 sscanf(av[1], "%llx", &node_offset); 178 hammer_cmd_show(node_offset, 0, NULL, NULL); 179 exit(0); 180 } 181 if (strcmp(av[0], "blockmap") == 0) { 182 hammer_parsedevs(blkdevs); 183 hammer_cmd_blockmap(); 184 exit(0); 185 } 186 usage(1); 187 /* not reached */ 188 return(0); 189 } 190 191 /* 192 * Parse a timestamp for the mount point 193 * 194 * yyyymmddhhmmss 195 * -N[s/h/d/m/y] 196 */ 197 static 198 void 199 hammer_parsetime(u_int64_t *tidp, const char *timestr) 200 { 201 struct timeval tv; 202 struct tm tm; 203 int32_t n; 204 char c; 205 206 gettimeofday(&tv, NULL); 207 208 if (*timestr == 0) 209 usage(1); 210 211 if (isalpha(timestr[strlen(timestr)-1])) { 212 if (sscanf(timestr, "%d%c", &n, &c) != 2) 213 usage(1); 214 switch(c) { 215 case 'Y': 216 n *= 365; 217 goto days; 218 case 'M': 219 n *= 30; 220 /* fall through */ 221 case 'D': 222 days: 223 n *= 24; 224 /* fall through */ 225 case 'h': 226 n *= 60; 227 /* fall through */ 228 case 'm': 229 n *= 60; 230 /* fall through */ 231 case 's': 232 tv.tv_sec -= n; 233 break; 234 default: 235 usage(1); 236 } 237 } else { 238 double seconds = 0; 239 240 localtime_r(&tv.tv_sec, &tm); 241 seconds = (double)tm.tm_sec; 242 tm.tm_year += 1900; 243 tm.tm_mon += 1; 244 n = sscanf(timestr, "%4d%2d%2d:%2d%2d%lf", 245 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 246 &tm.tm_hour, &tm.tm_min, &seconds); 247 tm.tm_mon -= 1; 248 tm.tm_year -= 1900; 249 /* if [:hhmmss] is omitted, assume :000000.0 */ 250 if (n < 4) 251 tm.tm_hour = tm.tm_min = tm.tm_sec = 0; 252 else 253 tm.tm_sec = (int)seconds; 254 tv.tv_sec = mktime(&tm); 255 tv.tv_usec = (int)((seconds - floor(seconds)) * 1000000.0); 256 } 257 *tidp = (u_int64_t)tv.tv_sec * 1000000000LLU + 258 tv.tv_usec * 1000LLU; 259 } 260 261 /* 262 * If the TID is within 60 seconds of the current time we sync(). If 263 * dosleep is non-zero and the TID is within 1 second of the current time 264 * we wait for the second-hand to turn over. 265 * 266 * The NoSyncOpt prevents both the sync() call and any sleeps from occuring. 267 */ 268 static 269 void 270 hammer_waitsync(int dosleep) 271 { 272 time_t t1, t2; 273 274 if (NoSyncOpt == 0) { 275 sync(); 276 t1 = t2 = time(NULL); 277 while (dosleep && t1 == t2) { 278 usleep(100000); 279 t2 = time(NULL); 280 } 281 } 282 } 283 284 static 285 void 286 hammer_parsedevs(const char *blkdevs) 287 { 288 char *copy; 289 char *volname; 290 291 if (blkdevs == NULL) { 292 errx(1, "A -f blkdevs specification is required " 293 "for this command"); 294 } 295 296 copy = strdup(blkdevs); 297 while ((volname = copy) != NULL) { 298 if ((copy = strchr(copy, ':')) != NULL) 299 *copy++ = 0; 300 setup_volume(-1, volname, 0, O_RDONLY); 301 } 302 } 303 304 static 305 void 306 sigalrm(int signo __unused) 307 { 308 /* do nothing (interrupts HAMMER ioctl) */ 309 } 310 311 static 312 void 313 usage(int exit_code) 314 { 315 fprintf(stderr, 316 "hammer -h\n" 317 "hammer [-x] now[64]\n" 318 "hammer stamp[64] <time>\n" 319 "hammer [-s linkpath] prune <filesystem> [using <configfile>]\n" 320 "hammer [-s linkpath] prune <filesystem> from <modulo_time> to " 321 "<modulo_time> every <modulo_time>\n" 322 "hammer prune <filesystem> everything\n" 323 "hammer reblock <filesystem> [compact%%] (default 90%%)\n" 324 "hammer history[@offset[,len]] <file-1>...<file-N>\n" 325 "hammer -f blkdevs [-r] show\n" 326 "hammer -f blkdevs blockmap\n" 327 ); 328 fprintf(stderr, "time: +n[s/m/h/D/M/Y]\n" 329 "time: yyyymmdd[:hhmmss]\n" 330 "modulo_time: n{s,m,h,d,M,y}\n"); 331 exit(exit_code); 332 } 333 334