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