added -y/--side-by-side option
[dfdiff.git] / sbin / hammer / hammer.c
blob49db592421046a8628f83d8aba93c3e6ab8a837f
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:
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.
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.
34 * $DragonFly: src/sbin/hammer/hammer.c,v 1.14 2008/05/04 19:18:17 dillon Exp $
37 #include "hammer.h"
38 #include <signal.h>
39 #include <math.h>
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);
47 int RecurseOpt;
48 int VerboseOpt;
49 int NoSyncOpt;
50 const char *LinkPath;
52 int
53 main(int ac, char **av)
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;
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 */
90 ac -= optind;
91 av += optind;
92 if (ac < 1) {
93 usage(1);
94 /* not reached */
97 if (timeout > 0) {
98 signal(SIGALRM, sigalrm);
99 alarm(timeout);
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);
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);
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);
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);
130 if (strcmp(av[0], "namekey") == 0) {
131 int64_t key;
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);
141 if (strcmp(av[0], "namekey32") == 0) {
142 int32_t key;
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);
152 if (strcmp(av[0], "prune") == 0) {
153 hammer_cmd_prune(av + 1, ac - 1);
154 exit(0);
157 if (strncmp(av[0], "history", 7) == 0) {
158 hammer_cmd_history(av[0] + 7, av + 1, ac - 1);
159 exit(0);
161 if (strcmp(av[0], "reblock") == 0) {
162 hammer_cmd_reblock(av + 1, ac - 1);
163 exit(0);
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");
172 if (strcmp(av[0], "show") == 0) {
173 hammer_off_t node_offset = (hammer_off_t)-1;
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);
181 if (strcmp(av[0], "blockmap") == 0) {
182 hammer_parsedevs(blkdevs);
183 hammer_cmd_blockmap();
184 exit(0);
186 usage(1);
187 /* not reached */
188 return(0);
192 * Parse a timestamp for the mount point
194 * yyyymmddhhmmss
195 * -N[s/h/d/m/y]
197 static
198 void
199 hammer_parsetime(u_int64_t *tidp, const char *timestr)
201 struct timeval tv;
202 struct tm tm;
203 int32_t n;
204 char c;
206 gettimeofday(&tv, NULL);
208 if (*timestr == 0)
209 usage(1);
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);
237 } else {
238 double seconds = 0;
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);
257 *tidp = (u_int64_t)tv.tv_sec * 1000000000LLU +
258 tv.tv_usec * 1000LLU;
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.
266 * The NoSyncOpt prevents both the sync() call and any sleeps from occuring.
268 static
269 void
270 hammer_waitsync(int dosleep)
272 time_t t1, t2;
274 if (NoSyncOpt == 0) {
275 sync();
276 t1 = t2 = time(NULL);
277 while (dosleep && t1 == t2) {
278 usleep(100000);
279 t2 = time(NULL);
284 static
285 void
286 hammer_parsedevs(const char *blkdevs)
288 char *copy;
289 char *volname;
291 if (blkdevs == NULL) {
292 errx(1, "A -f blkdevs specification is required "
293 "for this command");
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);
304 static
305 void
306 sigalrm(int signo __unused)
308 /* do nothing (interrupts HAMMER ioctl) */
311 static
312 void
313 usage(int exit_code)
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"
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);