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