Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / tools / dumpscan / 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 <afsconfig.h>
31 #include <afs/param.h>
32
33 #include <roken.h>
34
35 #include "dumpscan.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 dt_uint64 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 }