0127a5e4e8466c67d6b7b14462362584354b35f4
[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 "dumpscan.h"
37
38 extern int optind;
39 extern char *optarg;
40
41 extern XFILE repair_output;
42 extern afs_uint32 repair_dumphdr_cb(afs_dump_header *, XFILE *, void *);
43 extern afs_uint32 repair_volhdr_cb(afs_vol_header *, XFILE *, void *);
44 extern afs_uint32 repair_vnode_cb(afs_vnode *, XFILE *, void *);
45
46 char *argv0;
47 static char *input_path, *gendump_path;
48 static afs_uint32 printflags, repairflags;
49 static int quiet, verbose, error_count;
50
51 static path_hashinfo phi;
52 static dump_parser dp;
53
54
55 /* Print a usage message and exit */
56 static void
57 usage(int status, char *msg)
58 {
59     if (msg)
60         fprintf(stderr, "%s: %s\n", argv0, msg);
61     fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
62     fprintf(stderr, "  -Pxxx  Set print options:\n");
63     fprintf(stderr, "          B = Print backup system header (if any)\n");
64     fprintf(stderr, "          H = Print AFS dump header\n");
65     fprintf(stderr, "          V = Print AFS volume header\n");
66     fprintf(stderr, "          v = List vnodes\n");
67     fprintf(stderr, "          p = Include path to each vnode\n");
68     fprintf(stderr, "          i = Include info for each vnode\n");
69     fprintf(stderr, "          d = List directory contents\n");
70     fprintf(stderr, "          a = List access control lists\n");
71     fprintf(stderr, "          g = Print debugging info\n");
72     fprintf(stderr, "  -Rxxx  Set repair options:\n");
73     fprintf(stderr, "          0 = Skip null tags\n");
74     fprintf(stderr, "          b = Seek backward to find skipped tags\n");
75     fprintf(stderr, "          d = Resync after vnode data\n");
76     fprintf(stderr, "          v = Resync after corrupted vnodes\n");
77     fprintf(stderr, "  -h     Print this help message\n");
78     fprintf(stderr, "  -gxxx  Generate a new dump in file xxx\n");
79     fprintf(stderr, "  -q     Quiet mode (don't print errors)\n");
80     fprintf(stderr, "  -v     Verbose mode\n");
81     exit(status);
82 }
83
84
85 /* Parse the argument given to the -P option.
86  * Returns the resulting * dumpscan print flags (DSPRINT_*).
87  * If an unrecognized flag is used, prints an error message and exits.
88  */
89 static afs_uint32
90 parse_printflags(char *flags)
91 {
92     afs_uint32 result = 0;
93     char *x;
94
95     for (x = flags; *x; x++)
96         switch (*x) {
97         case 'B':
98             result |= DSPRINT_BCKHDR;
99             continue;
100         case 'H':
101             result |= DSPRINT_DUMPHDR;
102             continue;
103         case 'V':
104             result |= DSPRINT_VOLHDR;
105             continue;
106         case 'v':
107             result |= DSPRINT_ITEM;
108             continue;
109         case 'p':
110             result |= DSPRINT_PATH;
111             continue;
112         case 'i':
113             result |= DSPRINT_VNODE;
114             continue;
115         case 'd':
116             result |= DSPRINT_DIR;
117             continue;
118         case 'a':
119             result |= DSPRINT_ACL;
120             continue;
121         case 'g':
122             result |= DSPRINT_DEBUG;
123             continue;
124         default:
125             usage(1, "Invalid print options!");
126         }
127     return result;
128 }
129
130
131 /* Parse the argument given to the -R option.
132  * Returns the resulting * dumpscan repair flags (DSFIX_*).
133  * If an unrecognized flag is used, prints an error message and exits.
134  */
135 static afs_uint32
136 parse_repairflags(char *flags)
137 {
138     afs_uint32 result = 0;
139     char *x;
140
141     for (x = flags; *x; x++)
142         switch (*x) {
143         case '0':
144             result |= DSFIX_SKIP;
145             continue;
146         case 'b':
147             result |= DSFIX_RSKIP;
148             continue;
149         case 'd':
150             result |= DSFIX_VDSYNC;
151             continue;
152         case 'v':
153             result |= DSFIX_VFSYNC;
154             continue;
155         default:
156             usage(1, "Invalid repair options!");
157         }
158     return result;
159 }
160
161
162 /* Parse the command-line options */
163 static void
164 parse_options(int argc, char **argv)
165 {
166     int c;
167
168     /* Set the program name */
169     if (argv0 = strrchr(argv[0], '/'))
170         argv0++;
171     else
172         argv0 = argv[0];
173
174     /* Initialize options */
175     input_path = gendump_path = 0;
176     printflags = repairflags = 0;
177     quiet = verbose = 0;
178
179     /* Initialize other stuff */
180     error_count = 0;
181
182     /* Parse the options */
183     while ((c = getopt(argc, argv, "P:R:g:hqv")) != EOF) {
184         switch (c) {
185         case 'P':
186             printflags = parse_printflags(optarg);
187             continue;
188         case 'R':
189             repairflags = parse_repairflags(optarg);
190             continue;
191         case 'g':
192             gendump_path = optarg;
193             continue;
194         case 'q':
195             quiet = 1;
196             continue;
197         case 'v':
198             verbose = 1;
199             continue;
200         case 'h':
201             usage(0, 0);
202         default:
203             usage(1, "Invalid option!");
204         }
205     }
206
207     if (quiet && verbose)
208         usage(1, "Can't specify both -q and -v");
209
210     /* Parse non-option arguments */
211     if (argc - optind > 1)
212         usage(1, "Too many arguments!");
213     input_path = (argc == optind) ? "-" : argv[optind];
214 }
215
216
217 /* A callback to count and print errors */
218 static afs_uint32
219 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
220 {
221     va_list alist;
222
223     error_count++;
224     if (!quiet) {
225         va_start(alist, msg);
226         afs_com_err_va(argv0, code, msg, alist);
227         va_end(alist);
228     }
229 }
230
231
232 /* A callback to print the path of a vnode. */
233 static afs_uint32
234 print_vnode_path(afs_vnode * v, XFILE * X, void *refcon)
235 {
236     afs_uint32 r;
237     char *name = 0;
238
239     /* Do repair, but only for known vnode types */
240     if (gendump_path && (!(v->field_mask & F_VNODE_TYPE)
241                          || v->type != vFile || v->type != vDirectory
242                          || v->type != vSymlink)) {
243         r = repair_vnode_cb(v, X, refcon);
244         if (r)
245             return r;
246     }
247     r = Path_Build(X, &phi, v->vnode, &name, 0);
248     if (!r && name)
249         printf(" Path: %s\n", name);
250     if (name)
251         free(name);
252     return r;
253 }
254
255
256 /* Setup for generating a repaired dump */
257 static afs_uint32
258 setup_repair(void)
259 {
260     afs_uint32 r;
261
262     r = xfopen(&repair_output, O_RDWR | O_CREAT | O_TRUNC, gendump_path);
263     if (r)
264         return r;
265
266     dp.cb_dumphdr = repair_dumphdr_cb;
267     dp.cb_volhdr = repair_volhdr_cb;
268     dp.cb_vnode_dir = repair_vnode_cb;
269     dp.cb_vnode_file = repair_vnode_cb;
270     dp.cb_vnode_link = repair_vnode_cb;
271     dp.cb_vnode_empty = repair_vnode_cb;
272     return 0;
273 }
274
275
276 /* Main program */
277 void
278 main(int argc, char **argv)
279 {
280     XFILE input_file;
281     afs_uint32 r;
282
283     parse_options(argc, argv);
284     initialize_acfg_error_table();
285     initialize_AVds_error_table();
286     initialize_rxk_error_table();
287     initialize_u_error_table();
288     initialize_vl_error_table();
289     initialize_vols_error_table();
290     initialize_xFil_error_table();
291     r = xfopen(&input_file, O_RDONLY, input_path);
292     if (r) {
293         afs_com_err(argv0, r, "opening %s", input_path);
294         exit(2);
295     }
296
297     memset(&dp, 0, sizeof(dp));
298     dp.cb_error = my_error_cb;
299     dp.repair_flags = repairflags;
300     if (input_file.is_seekable)
301         dp.flags |= DSFLAG_SEEK;
302     else {
303         if (repairflags)
304             fprintf(stderr,
305                     "Repair modes available only for seekable dumps\n");
306         if (printflags & DSPRINT_PATH)
307             fprintf(stderr,
308                     "Path-printing available only for seekable dumps\n");
309         if (repairflags || (printflags & DSPRINT_PATH))
310             exit(1);
311     }
312
313     if (gendump_path && (r = setup_repair())) {
314         afs_com_err(argv0, r, "setting up repair output");
315         xfclose(&input_file);
316         exit(2);
317     }
318
319     if (printflags & DSPRINT_PATH) {
320         u_int64 where;
321
322         dp.print_flags = printflags & DSPRINT_DEBUG;
323         memset(&phi, 0, sizeof(phi));
324         phi.p = &dp;
325
326         if ((r = xftell(&input_file, &where))
327             || (r = Path_PreScan(&input_file, &phi, 0))
328             || (r = xfseek(&input_file, &where))) {
329             afs_com_err(argv0, r, "- path initialization failed");
330             xfclose(&input_file);
331             exit(2);
332         }
333
334         dp.cb_vnode_dir = print_vnode_path;
335         dp.cb_vnode_file = print_vnode_path;
336         dp.cb_vnode_link = print_vnode_path;
337         dp.cb_vnode_empty = print_vnode_path;
338         dp.cb_vnode_wierd = print_vnode_path;
339     }
340
341     dp.print_flags = printflags;
342     r = ParseDumpFile(&input_file, &dp);
343     xfclose(&input_file);
344     if (gendump_path) {
345         if (!r)
346             r = DumpDumpEnd(&repair_output);
347         if (!r)
348             r = xfclose(&repair_output);
349         else
350             xfclose(&repair_output);
351     }
352
353     if (verbose && error_count)
354         fprintf(stderr, "*** %d errors\n", error_count);
355     if (r && !quiet)
356         fprintf(stderr, "*** FAILED: %s\n", afs_error_message(r));
357     exit(0);
358 }