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