]> git.wh0rd.org - dump.git/blob - restore/main.c
8911d2069475a9366848a7644d17324f7db88d88
[dump.git] / restore / main.c
1 /*
2 * Ported to Linux's Second Extended File System as part of the
3 * dump and restore backup suit
4 * Remy Card <card@Linux.EU.Org>, 1994-1997
5 * Stelian Pop <pop@noos.fr>, 1999-2000
6 * Stelian Pop <pop@noos.fr> - AlcĂ´ve <www.alcove.fr>, 2000
7 */
8
9 /*
10 * Copyright (c) 1983, 1993
11 * The Regents of the University of California. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 */
41
42 #ifndef lint
43 static const char rcsid[] =
44 "$Id: main.c,v 1.20 2001/04/10 12:46:53 stelian Exp $";
45 #endif /* not lint */
46
47 #include <config.h>
48 #include <sys/param.h>
49 #include <sys/stat.h>
50 #include <errno.h>
51
52 #ifdef __linux__
53 #ifdef HAVE_EXT2FS_EXT2_FS_H
54 #include <ext2fs/ext2_fs.h>
55 #else
56 #include <linux/ext2_fs.h>
57 #endif
58 #include <bsdcompat.h>
59 #include <signal.h>
60 #include <string.h>
61 #else /* __linux__ */
62 #include <ufs/ufs/dinode.h>
63 #endif /* __linux__ */
64 #include <protocols/dumprestore.h>
65
66 #include <compaterr.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <unistd.h>
70
71 #ifdef __linux__
72 #include <ext2fs/ext2fs.h>
73 #include <getopt.h>
74 #endif
75
76 #include "pathnames.h"
77 #include "restore.h"
78 #include "extern.h"
79
80 int bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0;
81 int hflag = 1, mflag = 1, Nflag = 0, zflag = 0;
82 int uflag = 0;
83 int dokerberos = 0;
84 char command = '\0';
85 long dumpnum = 1;
86 long volno = 0;
87 long ntrec;
88 char *dumpmap;
89 char *usedinomap;
90 dump_ino_t maxino;
91 time_t dumptime;
92 time_t dumpdate;
93 FILE *terminal;
94 char *tmpdir;
95 int compare_ignore_not_found;
96 int compare_errors;
97 char filesys[NAMELEN];
98 static const char *stdin_opt = NULL;
99
100 #ifdef __linux__
101 char *__progname;
102 #endif
103
104 static void obsolete __P((int *, char **[]));
105 static void usage __P((void));
106 static void use_stdin __P((const char *));
107
108 int
109 main(int argc, char *argv[])
110 {
111 int ch;
112 dump_ino_t ino;
113 char *inputdev = _PATH_DEFTAPE;
114 char *symtbl = "./restoresymtable";
115 char *p, name[MAXPATHLEN];
116 FILE *filelist = NULL;
117 char fname[MAXPATHLEN];
118 #ifdef USE_QFA
119 time_t tistart, tiend, titaken;
120 tapeposflag = 0;
121 #endif
122
123 /* Temp files should *not* be readable. We set permissions later. */
124 (void) umask(077);
125 filesys[0] = '\0';
126 #ifdef __linux__
127 __progname = argv[0];
128 #endif
129
130 if (argc < 2)
131 usage();
132
133 if ((inputdev = getenv("TAPE")) == NULL)
134 inputdev = _PATH_DEFTAPE;
135 if ((tmpdir = getenv("TMPDIR")) == NULL)
136 tmpdir = _PATH_TMP;
137 if ((tmpdir = strdup(tmpdir)) == NULL)
138 err(1, "malloc tmpdir");
139 for (p = tmpdir + strlen(tmpdir) - 1; p >= tmpdir && *p == '/'; p--)
140 ;
141 obsolete(&argc, &argv);
142 while ((ch = getopt(argc, argv,
143 "b:CcdD:f:hi"
144 #ifdef KERBEROS
145 "k"
146 #endif
147 "mMN"
148 #ifdef USE_QFA
149 "Q:"
150 #endif
151 "Rrs:tT:uvxX:y")) != -1)
152 switch(ch) {
153 case 'b':
154 /* Change default tape blocksize. */
155 bflag = 1;
156 ntrec = strtol(optarg, &p, 10);
157 if (*p)
158 errx(1, "illegal blocksize -- %s", optarg);
159 if (ntrec <= 0)
160 errx(1, "block size must be greater than 0");
161 break;
162 case 'c':
163 cvtflag = 1;
164 break;
165 case 'D':
166 strncpy(filesys, optarg, NAMELEN);
167 filesys[NAMELEN - 1] = '\0';
168 break;
169 case 'T':
170 tmpdir = optarg;
171 break;
172 case 'd':
173 dflag = 1;
174 break;
175 case 'f':
176 if( !strcmp(optarg,"-") )
177 use_stdin("-f");
178 inputdev = optarg;
179 break;
180 case 'h':
181 hflag = 0;
182 break;
183 #ifdef KERBEROS
184 case 'k':
185 dokerberos = 1;
186 break;
187 #endif
188 case 'C':
189 case 'i':
190 case 'R':
191 case 'r':
192 case 't':
193 case 'x':
194 if (command != '\0')
195 errx(1,
196 "%c and %c options are mutually exclusive",
197 ch, command);
198 command = ch;
199 break;
200 case 'm':
201 mflag = 0;
202 break;
203 case 'M':
204 Mflag = 1;
205 break;
206 case 'N':
207 Nflag = 1;
208 break;
209 #ifdef USE_QFA
210 case 'Q':
211 gTapeposfile = optarg;
212 tapeposflag = 1;
213 break;
214 #endif
215 case 's':
216 /* Dumpnum (skip to) for multifile dump tapes. */
217 dumpnum = strtol(optarg, &p, 10);
218 if (*p)
219 errx(1, "illegal dump number -- %s", optarg);
220 if (dumpnum <= 0)
221 errx(1, "dump number must be greater than 0");
222 break;
223 case 'u':
224 uflag = 1;
225 break;
226 case 'v':
227 vflag = 1;
228 break;
229 case 'X':
230 if( !strcmp(optarg,"-") ) {
231 use_stdin("-X");
232 filelist = stdin;
233 }
234 else
235 if ( !(filelist = fopen(optarg,"r")) )
236 errx(1, "can't open file for reading -- %s", optarg);
237 break;
238 case 'y':
239 yflag = 1;
240 break;
241 default:
242 usage();
243 }
244 argc -= optind;
245 argv += optind;
246
247 if (command == '\0')
248 errx(1, "none of C, i, R, r, t or x options specified");
249
250 if (signal(SIGINT, onintr) == SIG_IGN)
251 (void) signal(SIGINT, SIG_IGN);
252 if (signal(SIGTERM, onintr) == SIG_IGN)
253 (void) signal(SIGTERM, SIG_IGN);
254 setlinebuf(stderr);
255
256 atexit(cleanup);
257
258 setinput(inputdev);
259
260 if (argc == 0 && !filelist) {
261 argc = 1;
262 *--argv = ".";
263 }
264
265 #ifdef USE_QFA
266 if (tapeposflag) {
267 msg("reading QFA positions from %s\n", gTapeposfile);
268 if ((gTapeposfp = fopen(gTapeposfile, "r")) == NULL)
269 errx(1, "can't open file for reading -- %s",
270 gTapeposfile);
271 /* start reading header info */
272 if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
273 errx(1, "not requested format of -- %s", gTapeposfile);
274 gTps[strlen(gTps) - 1] = 0; /* delete end of line */
275 if (strcmp(gTps, QFA_MAGIC) != 0)
276 errx(1, "not requested format of -- %s", gTapeposfile);
277 if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
278 errx(1, "not requested format of -- %s", gTapeposfile);
279 gTps[strlen(gTps) - 1] = 0;
280 if (strcmp(gTps, QFA_VERSION) != 0)
281 errx(1, "not requested format of -- %s", gTapeposfile);
282 /* read dumpdate */
283 if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
284 errx(1, "not requested format of -- %s", gTapeposfile);
285 gTps[strlen(gTps) - 1] = 0;
286 /* TODO: check dumpdate from QFA file with current dump file's
287 * dump date */
288 /* if not equal either output warning and continue without QFA
289 * or abort */
290 /* read empty line */
291 if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
292 errx(1, "not requested format of -- %s", gTapeposfile);
293 gTps[strlen(gTps) - 1] = 0;
294 /* read table header line */
295 if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
296 errx(1, "not requested format of -- %s", gTapeposfile);
297 gTps[strlen(gTps) - 1] = 0;
298 /* end reading header info */
299 /* tape position table starts here */
300 gSeekstart = ftell(gTapeposfp); /* remember for later use */
301 }
302 #endif /* USE_QFA */
303
304 switch (command) {
305 /*
306 * Compare contents of tape.
307 */
308 case 'C': {
309 struct stat stbuf;
310
311 Vprintf(stdout, "Begin compare restore\n");
312 compare_ignore_not_found = 0;
313 compare_errors = 0;
314 setup();
315 printf("filesys = %s\n", filesys);
316 if (stat(filesys, &stbuf) < 0)
317 err(1, "cannot stat directory %s", filesys);
318 if (chdir(filesys) < 0)
319 err(1, "cannot cd to %s", filesys);
320 compare_ignore_not_found = dumptime > 0;
321 initsymtable((char *)0);
322 extractdirs(0);
323 treescan(".", ROOTINO, nodeupdates);
324 compareleaves();
325 checkrestore();
326 if (compare_errors) {
327 printf("Some files were modified!\n");
328 exit(2);
329 }
330 break;
331 }
332
333 /*
334 * Interactive mode.
335 */
336 case 'i':
337 setup();
338 extractdirs(1);
339 initsymtable(NULL);
340 runcmdshell();
341 break;
342 /*
343 * Incremental restoration of a file system.
344 */
345 case 'r':
346 setup();
347 if (dumptime > 0) {
348 /*
349 * This is an incremental dump tape.
350 */
351 Vprintf(stdout, "Begin incremental restore\n");
352 initsymtable(symtbl);
353 extractdirs(1);
354 removeoldleaves();
355 Vprintf(stdout, "Calculate node updates.\n");
356 treescan(".", ROOTINO, nodeupdates);
357 findunreflinks();
358 removeoldnodes();
359 } else {
360 /*
361 * This is a level zero dump tape.
362 */
363 Vprintf(stdout, "Begin level 0 restore\n");
364 initsymtable((char *)0);
365 extractdirs(1);
366 Vprintf(stdout, "Calculate extraction list.\n");
367 treescan(".", ROOTINO, nodeupdates);
368 }
369 createleaves(symtbl);
370 createlinks();
371 setdirmodes(FORCE);
372 checkrestore();
373 if (dflag) {
374 Vprintf(stdout, "Verify the directory structure\n");
375 treescan(".", ROOTINO, verifyfile);
376 }
377 dumpsymtable(symtbl, (long)1);
378 break;
379 /*
380 * Resume an incremental file system restoration.
381 */
382 case 'R':
383 initsymtable(symtbl);
384 skipmaps();
385 skipdirs();
386 createleaves(symtbl);
387 createlinks();
388 setdirmodes(FORCE);
389 checkrestore();
390 dumpsymtable(symtbl, (long)1);
391 break;
392
393 /* handle file names from either text file (-X) or the command line */
394 #define NEXTFILE(p) \
395 p = NULL; \
396 if (argc) { \
397 --argc; \
398 p = *argv++; \
399 } \
400 else if (filelist) { \
401 if ((p = fgets(fname, MAXPATHLEN, filelist))) { \
402 if ( *p && *(p + strlen(p) - 1) == '\n' ) /* possible null string */ \
403 *(p + strlen(p) - 1) = '\0'; \
404 if ( !*p ) /* skip empty lines */ \
405 continue; \
406 } \
407 }
408
409 /*
410 * List contents of tape.
411 */
412 case 't':
413 setup();
414 extractdirs(0);
415 initsymtable((char *)0);
416 for (;;) {
417 NEXTFILE(p);
418 if (!p)
419 break;
420 canon(p, name, sizeof(name));
421 ino = dirlookup(name);
422 if (ino == 0)
423 continue;
424 treescan(name, ino, listfile);
425 }
426 break;
427 /*
428 * Batch extraction of tape contents.
429 */
430 case 'x':
431 #ifdef USE_QFA
432 tistart = time(NULL);
433 #endif
434 setup();
435 extractdirs(1);
436 initsymtable((char *)0);
437 for (;;) {
438 NEXTFILE(p);
439 if (!p)
440 break;
441 canon(p, name, sizeof(name));
442 ino = dirlookup(name);
443 if (ino == 0)
444 continue;
445 if (mflag)
446 pathcheck(name);
447 treescan(name, ino, addfile);
448 }
449 createfiles();
450 createlinks();
451 setdirmodes(0);
452 if (dflag)
453 checkrestore();
454 #ifdef USE_QFA
455 tiend = time(NULL);
456 titaken = tiend - tistart;
457 #ifdef USE_QFA
458 msg("restore took %d:%02d:%02d\n", titaken / 3600,
459 (titaken % 3600) / 60, titaken % 60);
460 #endif
461 #endif
462 break;
463 }
464 exit(0);
465 /* NOTREACHED */
466 return 0; /* gcc shut up */
467 }
468
469 static void
470 usage(void)
471 {
472 #ifdef __linux__
473 const char *ext2ver, *ext2date;
474
475 ext2fs_get_library_version(&ext2ver, &ext2date);
476 (void)fprintf(stderr, "%s %s (using libext2fs %s of %s)\n",
477 __progname, _DUMP_VERSION, ext2ver, ext2date);
478 #else
479 (void)fprintf(stderr, "%s %s\n", __progname, _DUMP_VERSION);
480 #endif
481
482 #ifdef KERBEROS
483 #define kerbflag "k"
484 #else
485 #define kerbflag
486 #endif
487 (void)fprintf(stderr,
488 "usage:\t%s%s\n\t%s%s\n\t%s%s\n\t%s%s\n\t%s%s\n\t%s%s\n",
489 __progname, " -C [-c" kerbflag "Mvy] [-b blocksize] [-D filesystem] [-f file] [-s fileno]",
490 __progname, " -i [-ch" kerbflag "mMuvy] [-b blocksize] [-f file] [-s fileno]",
491 __progname, " -r [-c" kerbflag "Muvy] [-b blocksize] [-f file] [-s fileno] [-T directory]",
492 __progname, " -R [-c" kerbflag "Muvy] [-b blocksize] [-f file] [-s fileno] [-T directory]",
493 __progname, " -t [-ch" kerbflag "Muvy] [-b blocksize] [-f file] [-s fileno] [-X filelist] [file ...]",
494 __progname, " -x [-ch" kerbflag "mMuvy] [-b blocksize] [-f file] [-s fileno] [-X filelist] [file ...]");
495 exit(1);
496 }
497
498 /*
499 * obsolete --
500 * Change set of key letters and ordered arguments into something
501 * getopt(3) will like.
502 */
503 static void
504 obsolete(int *argcp, char **argvp[])
505 {
506 int argc, flags;
507 char *ap, **argv, *flagsp = NULL, **nargv, *p = NULL;
508
509 /* Setup. */
510 argv = *argvp;
511 argc = *argcp;
512
513 /* Return if no arguments or first argument has leading dash. */
514 ap = argv[1];
515 if (argc == 1 || *ap == '-')
516 return;
517
518 /* Allocate space for new arguments. */
519 if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
520 (p = flagsp = malloc(strlen(ap) + 2)) == NULL)
521 err(1, "malloc args");
522
523 *nargv++ = *argv;
524 argv += 2, argc -= 2;
525
526 for (flags = 0; *ap; ++ap) {
527 switch (*ap) {
528 case 'b':
529 case 'D':
530 case 'f':
531 case 'Q':
532 case 's':
533 case 'T':
534 case 'X':
535 if (*argv == NULL) {
536 warnx("option requires an argument -- %c", *ap);
537 usage();
538 }
539 if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
540 err(1, "malloc arg");
541 nargv[0][0] = '-';
542 nargv[0][1] = *ap;
543 (void)strcpy(&nargv[0][2], *argv);
544 ++argv;
545 ++nargv;
546 break;
547 default:
548 if (!flags) {
549 *p++ = '-';
550 flags = 1;
551 }
552 *p++ = *ap;
553 break;
554 }
555 }
556
557 /* Terminate flags. */
558 if (flags) {
559 *p = '\0';
560 *nargv++ = flagsp;
561 }
562
563 /* Copy remaining arguments. */
564 while ((*nargv++ = *argv++));
565
566 /* Update argument count. */
567 *argcp = nargv - *argvp - 1;
568 }
569
570 /*
571 * use_stdin --
572 * reserve stdin for opt (avoid conflicts)
573 */
574 void
575 use_stdin(const char *opt)
576 {
577 if (stdin_opt)
578 errx(1, "can't handle standard input for both %s and %s",
579 stdin_opt, opt);
580 stdin_opt = opt;
581 }