8589abe4681361db3fad577c52e2bc5974fc502d
[openafs.git] / src / tests / afsdump_scan.c
1 /*
2  * CMUCS AFStools
3  * dumpscan - routines for scanning and manipulating AFS volume dumps
4  *
5  * Copyright (c) 1998 Carnegie Mellon University
6  * All Rights Reserved.
7  * 
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie Mellon
26  * the rights to redistribute these changes.
27  */
28
29 /* afsdump_scan.c - General-purpose dump scanner */
30
31 #include <sys/fcntl.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <string.h>
35
36 #include <afs/param.h>
37 #include <afs/com_err.h>
38
39 #include "dumpscan.h"
40 #include "dumpscan_errs.h"
41 #include "xf_errs.h"
42 extern int optind;
43 extern char *optarg;
44
45 extern XFILE repair_output;
46 extern afs_uint32 repair_dumphdr_cb(afs_dump_header *, XFILE *, void *);
47 extern afs_uint32 repair_volhdr_cb(afs_vol_header *, XFILE *, void *);
48 extern afs_uint32 repair_vnode_cb(afs_vnode *, XFILE *, void *);
49
50 char *argv0;
51 static char *input_path, *gendump_path;
52 static afs_uint32 printflags, repairflags;
53 static int quiet, verbose, error_count;
54
55 static path_hashinfo phi;
56 static dump_parser dp;
57
58
59 /* Print a usage message and exit */
60 static void
61 usage(int status, char *msg)
62 {
63     if (msg)
64         fprintf(stderr, "%s: %s\n", argv0, msg);
65     fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
66     fprintf(stderr, "  -Pxxx  Set print options:\n");
67     fprintf(stderr, "          B = Print backup system header (if any)\n");
68     fprintf(stderr, "          H = Print AFS dump header\n");
69     fprintf(stderr, "          V = Print AFS volume header\n");
70     fprintf(stderr, "          v = List vnodes\n");
71     fprintf(stderr, "          p = Include path to each vnode\n");
72     fprintf(stderr, "          i = Include info for each vnode\n");
73     fprintf(stderr, "          d = List directory contents\n");
74     fprintf(stderr, "          a = List access control lists\n");
75     fprintf(stderr, "          g = Print debugging info\n");
76     fprintf(stderr, "  -Rxxx  Set repair options:\n");
77     fprintf(stderr, "          0 = Skip null tags\n");
78     fprintf(stderr, "          b = Seek backward to find skipped tags\n");
79     fprintf(stderr, "          d = Resync after vnode data\n");
80     fprintf(stderr, "          v = Resync after corrupted vnodes\n");
81     fprintf(stderr, "  -h     Print this help message\n");
82     fprintf(stderr, "  -gxxx  Generate a new dump in file xxx\n");
83     fprintf(stderr, "  -q     Quiet mode (don't print errors)\n");
84     fprintf(stderr, "  -v     Verbose mode\n");
85     exit(status);
86 }
87
88
89 /* Parse the argument given to the -P option.
90  * Returns the resulting * dumpscan print flags (DSPRINT_*).
91  * If an unrecognized flag is used, prints an error message and exits.
92  */
93 static afs_uint32
94 parse_printflags(char *flags)
95 {
96     afs_uint32 result = 0;
97     char *x;
98
99     for (x = flags; *x; x++)
100         switch (*x) {
101         case 'B':
102             result |= DSPRINT_BCKHDR;
103             continue;
104         case 'H':
105             result |= DSPRINT_DUMPHDR;
106             continue;
107         case 'V':
108             result |= DSPRINT_VOLHDR;
109             continue;
110         case 'v':
111             result |= DSPRINT_ITEM;
112             continue;
113         case 'p':
114             result |= DSPRINT_PATH;
115             continue;
116         case 'i':
117             result |= DSPRINT_VNODE;
118             continue;
119         case 'd':
120             result |= DSPRINT_DIR;
121             continue;
122         case 'a':
123             result |= DSPRINT_ACL;
124             continue;
125         case 'g':
126             result |= DSPRINT_DEBUG;
127             continue;
128         default:
129             usage(1, "Invalid print options!");
130         }
131     return result;
132 }
133
134
135 /* Parse the argument given to the -R option.
136  * Returns the resulting * dumpscan repair flags (DSFIX_*).
137  * If an unrecognized flag is used, prints an error message and exits.
138  */
139 static afs_uint32
140 parse_repairflags(char *flags)
141 {
142     afs_uint32 result = 0;
143     char *x;
144
145     for (x = flags; *x; x++)
146         switch (*x) {
147         case '0':
148             result |= DSFIX_SKIP;
149             continue;
150         case 'b':
151             result |= DSFIX_RSKIP;
152             continue;
153         case 'd':
154             result |= DSFIX_VDSYNC;
155             continue;
156         case 'v':
157             result |= DSFIX_VFSYNC;
158             continue;
159         default:
160             usage(1, "Invalid repair options!");
161         }
162     return result;
163 }
164
165
166 /* Parse the command-line options */
167 static void
168 parse_options(int argc, char **argv)
169 {
170     int c;
171
172     /* Set the program name */
173     if ((argv0 = strrchr(argv[0], '/')))
174         argv0++;
175     else
176         argv0 = argv[0];
177
178     /* Initialize options */
179     input_path = gendump_path = 0;
180     printflags = repairflags = 0;
181     quiet = verbose = 0;
182
183     /* Initialize other stuff */
184     error_count = 0;
185
186     /* Parse the options */
187     while ((c = getopt(argc, argv, "P:R:g:hqv")) != EOF) {
188         switch (c) {
189         case 'P':
190             printflags = parse_printflags(optarg);
191             continue;
192         case 'R':
193             repairflags = parse_repairflags(optarg);
194             continue;
195         case 'g':
196             gendump_path = optarg;
197             continue;
198         case 'q':
199             quiet = 1;
200             continue;
201         case 'v':
202             verbose = 1;
203             continue;
204         case 'h':
205             usage(0, 0);
206         default:
207             usage(1, "Invalid option!");
208         }
209     }
210
211     if (quiet && verbose)
212         usage(1, "Can't specify both -q and -v");
213
214     /* Parse non-option arguments */
215     if (argc - optind > 1)
216         usage(1, "Too many arguments!");
217     input_path = (argc == optind) ? "-" : argv[optind];
218 }
219
220
221 /* A callback to count and print errors */
222 static afs_uint32
223 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
224 {
225     va_list alist;
226
227     error_count++;
228     if (!quiet) {
229         va_start(alist, msg);
230         afs_com_err_va(argv0, code, msg, alist);
231         va_end(alist);
232     }
233     return 0;
234 }
235
236
237 /* A callback to print the path of a vnode. */
238 static afs_uint32
239 print_vnode_path(afs_vnode * v, XFILE * X, void *refcon)
240 {
241     afs_uint32 r;
242     char *name = 0;
243
244     /* Do repair, but only for known vnode types */
245     if (gendump_path && (!(v->field_mask & F_VNODE_TYPE)
246                          || ((v->type != vFile) && (v->type != vDirectory)
247                              && (v->type != vSymlink)))) {
248         r = repair_vnode_cb(v, X, refcon);
249         if (r)
250             return r;
251     }
252     r = Path_Build(X, &phi, v->vnode, &name, 0);
253     if (!r && name)
254         printf(" Path: %s\n", name);
255     if (name)
256         free(name);
257     return r;
258 }
259
260
261 /* Setup for generating a repaired dump */
262 static afs_uint32
263 setup_repair(void)
264 {
265     afs_uint32 r;
266
267     r = xfopen(&repair_output, O_RDWR | O_CREAT | O_TRUNC, gendump_path);
268     if (r)
269         return r;
270
271     dp.cb_dumphdr = repair_dumphdr_cb;
272     dp.cb_volhdr = repair_volhdr_cb;
273     dp.cb_vnode_dir = repair_vnode_cb;
274     dp.cb_vnode_file = repair_vnode_cb;
275     dp.cb_vnode_link = repair_vnode_cb;
276     dp.cb_vnode_empty = repair_vnode_cb;
277     return 0;
278 }
279
280 extern afs_uint32 DumpDumpEnd(XFILE * OX);
281
282 /* Main program */
283 int
284 main(int argc, char **argv)
285 {
286     XFILE input_file;
287     afs_uint32 r;
288
289     parse_options(argc, argv);
290     initialize_acfg_error_table();
291     initialize_AVds_error_table();
292     initialize_rxk_error_table();
293     initialize_u_error_table();
294     initialize_vl_error_table();
295     initialize_vols_error_table();
296     initialize_xFil_error_table();
297     r = xfopen(&input_file, O_RDONLY, input_path);
298     if (r) {
299         afs_com_err(argv0, r, "opening %s", input_path);
300         exit(2);
301     }
302
303     memset(&dp, 0, sizeof(dp));
304     dp.cb_error = my_error_cb;
305     dp.repair_flags = repairflags;
306     if (input_file.is_seekable)
307         dp.flags |= DSFLAG_SEEK;
308     else {
309         if (repairflags)
310             fprintf(stderr,
311                     "Repair modes available only for seekable dumps\n");
312         if (printflags & DSPRINT_PATH)
313             fprintf(stderr,
314                     "Path-printing available only for seekable dumps\n");
315         if (repairflags || (printflags & DSPRINT_PATH))
316             exit(1);
317     }
318
319     if (gendump_path && (r = setup_repair())) {
320         afs_com_err(argv0, r, "setting up repair output");
321         xfclose(&input_file);
322         exit(2);
323     }
324
325     if (printflags & DSPRINT_PATH) {
326         u_int64 where;
327
328         dp.print_flags = printflags & DSPRINT_DEBUG;
329         memset(&phi, 0, sizeof(phi));
330         phi.p = &dp;
331
332         if ((r = xftell(&input_file, &where))
333             || (r = Path_PreScan(&input_file, &phi, 0))
334             || (r = xfseek(&input_file, &where))) {
335             afs_com_err(argv0, r, "- path initialization failed");
336             xfclose(&input_file);
337             exit(2);
338         }
339
340         dp.cb_vnode_dir = print_vnode_path;
341         dp.cb_vnode_file = print_vnode_path;
342         dp.cb_vnode_link = print_vnode_path;
343         dp.cb_vnode_empty = print_vnode_path;
344         dp.cb_vnode_wierd = print_vnode_path;
345     }
346
347     dp.print_flags = printflags;
348     r = ParseDumpFile(&input_file, &dp);
349     xfclose(&input_file);
350     if (gendump_path) {
351         if (!r)
352             r = DumpDumpEnd(&repair_output);
353         if (!r)
354             r = xfclose(&repair_output);
355         else
356             xfclose(&repair_output);
357     }
358
359     if (verbose && error_count)
360         fprintf(stderr, "*** %d errors\n", error_count);
361     if (r && !quiet)
362         fprintf(stderr, "*** FAILED: %s\n", afs_error_message(r));
363     exit(0);
364 }