]> git.wh0rd.org - dump.git/blob - restore/main.c
Fixed the remote tape/file detection in restore.
[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.32 2001/11/16 14:09:07 stelian Exp $";
45 #endif /* not lint */
46
47 #include <config.h>
48 #include <compatlfs.h>
49 #include <sys/param.h>
50 #include <sys/stat.h>
51 #include <errno.h>
52
53 #ifdef __linux__
54 #include <sys/time.h>
55 #include <time.h>
56 #ifdef HAVE_EXT2FS_EXT2_FS_H
57 #include <ext2fs/ext2_fs.h>
58 #else
59 #include <linux/ext2_fs.h>
60 #endif
61 #include <bsdcompat.h>
62 #include <signal.h>
63 #include <string.h>
64 #else /* __linux__ */
65 #include <ufs/ufs/dinode.h>
66 #endif /* __linux__ */
67 #include <protocols/dumprestore.h>
68
69 #include <compaterr.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <unistd.h>
73
74 #ifdef __linux__
75 #include <ext2fs/ext2fs.h>
76 #include <getopt.h>
77 #endif
78
79 #include "pathnames.h"
80 #include "restore.h"
81 #include "extern.h"
82
83 int bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0;
84 int hflag = 1, mflag = 1, Mflag = 0, Nflag = 0, Vflag = 0, zflag = 0;
85 int uflag = 0, lflag = 0;
86 int dokerberos = 0;
87 char command = '\0';
88 long dumpnum = 1;
89 long volno = 0;
90 long ntrec;
91 char *dumpmap;
92 char *usedinomap;
93 dump_ino_t maxino;
94 time_t dumptime;
95 time_t dumpdate;
96 FILE *terminal;
97 char *tmpdir;
98 int compare_ignore_not_found;
99 int compare_errors;
100 char filesys[NAMELEN];
101 static const char *stdin_opt = NULL;
102 char *bot_script = NULL;
103
104 #ifdef USE_QFA
105 FILE *gTapeposfp;
106 char *gTapeposfile;
107 char gTps[255];
108 long gSeekstart;
109 int tapeposflag;
110 #endif /* USE_QFA */
111
112 #ifdef __linux__
113 char *__progname;
114 #endif
115
116 static void obsolete __P((int *, char **[]));
117 static void usage __P((void));
118 static void use_stdin __P((const char *));
119
120 int
121 main(int argc, char *argv[])
122 {
123 int ch;
124 dump_ino_t ino;
125 char *inputdev = _PATH_DEFTAPE;
126 char *symtbl = "./restoresymtable";
127 char *p, name[MAXPATHLEN];
128 FILE *filelist = NULL;
129 char fname[MAXPATHLEN];
130 #ifdef USE_QFA
131 tapeposflag = 0;
132 #endif
133 #ifdef USE_QFADEBUG
134 time_t tistart, tiend, titaken;
135 #endif
136
137 /* Temp files should *not* be readable. We set permissions later. */
138 (void) umask(077);
139 filesys[0] = '\0';
140 #ifdef __linux__
141 __progname = argv[0];
142 #endif
143
144 if (argc < 2)
145 usage();
146
147 if ((inputdev = getenv("TAPE")) == NULL)
148 inputdev = _PATH_DEFTAPE;
149 if ((tmpdir = getenv("TMPDIR")) == NULL)
150 tmpdir = _PATH_TMP;
151 if ((tmpdir = strdup(tmpdir)) == NULL)
152 err(1, "malloc tmpdir");
153 for (p = tmpdir + strlen(tmpdir) - 1; p >= tmpdir && *p == '/'; p--)
154 ;
155 obsolete(&argc, &argv);
156 while ((ch = getopt(argc, argv,
157 "b:CcdD:f:F:hi"
158 #ifdef KERBEROS
159 "k"
160 #endif
161 "lmMN"
162 #ifdef USE_QFA
163 "Q:"
164 #endif
165 "Rrs:tT:uvVxX:y")) != -1)
166 switch(ch) {
167 case 'b':
168 /* Change default tape blocksize. */
169 bflag = 1;
170 ntrec = strtol(optarg, &p, 10);
171 if (*p)
172 errx(1, "illegal blocksize -- %s", optarg);
173 if (ntrec <= 0)
174 errx(1, "block size must be greater than 0");
175 break;
176 case 'c':
177 cvtflag = 1;
178 break;
179 case 'D':
180 strncpy(filesys, optarg, NAMELEN);
181 filesys[NAMELEN - 1] = '\0';
182 break;
183 case 'T':
184 tmpdir = optarg;
185 break;
186 case 'd':
187 dflag = 1;
188 break;
189 case 'f':
190 if( !strcmp(optarg,"-") )
191 use_stdin("-f");
192 inputdev = optarg;
193 break;
194 case 'F':
195 bot_script = optarg;
196 break;
197 case 'h':
198 hflag = 0;
199 break;
200 #ifdef KERBEROS
201 case 'k':
202 dokerberos = 1;
203 break;
204 #endif
205 case 'C':
206 case 'i':
207 case 'R':
208 case 'r':
209 case 't':
210 case 'x':
211 if (command != '\0')
212 errx(1,
213 "%c and %c options are mutually exclusive",
214 ch, command);
215 command = ch;
216 break;
217 case 'l':
218 lflag = 1;
219 break;
220 case 'm':
221 mflag = 0;
222 break;
223 case 'M':
224 Mflag = 1;
225 break;
226 case 'N':
227 Nflag = 1;
228 break;
229 #ifdef USE_QFA
230 case 'Q':
231 gTapeposfile = optarg;
232 tapeposflag = 1;
233 break;
234 #endif
235 case 's':
236 /* Dumpnum (skip to) for multifile dump tapes. */
237 dumpnum = strtol(optarg, &p, 10);
238 if (*p)
239 errx(1, "illegal dump number -- %s", optarg);
240 if (dumpnum <= 0)
241 errx(1, "dump number must be greater than 0");
242 break;
243 case 'u':
244 uflag = 1;
245 break;
246 case 'v':
247 vflag = 1;
248 break;
249 case 'V':
250 Vflag = 1;
251 break;
252 case 'X':
253 if( !strcmp(optarg,"-") ) {
254 use_stdin("-X");
255 filelist = stdin;
256 }
257 else
258 if ( !(filelist = fopen(optarg,"r")) )
259 errx(1, "can't open file for reading -- %s", optarg);
260 break;
261 case 'y':
262 yflag = 1;
263 break;
264 default:
265 usage();
266 }
267 argc -= optind;
268 argv += optind;
269
270 if (command == '\0')
271 errx(1, "none of C, i, R, r, t or x options specified");
272
273 #ifdef USE_QFA
274 if (!mflag && tapeposflag)
275 errx(1, "m and Q options are mutually exclusive");
276 #endif
277
278 if (signal(SIGINT, onintr) == SIG_IGN)
279 (void) signal(SIGINT, SIG_IGN);
280 if (signal(SIGTERM, onintr) == SIG_IGN)
281 (void) signal(SIGTERM, SIG_IGN);
282 setlinebuf(stderr);
283
284 atexit(cleanup);
285
286 if (command == 'C' && inputdev[0] != '/' && strcmp(inputdev, "-")
287 #ifdef RRESTORE
288 && !strchr(inputdev, ':')
289 #endif
290 ) {
291 /* since we chdir into the directory we are comparing
292 * to, we must retain the full tape path */
293 char wd[MAXPATHLEN], fullpathinput[MAXPATHLEN];
294 if (!getcwd(wd, MAXPATHLEN))
295 err(1, "can't get current directory");
296 snprintf(fullpathinput, MAXPATHLEN, "%s/%s", wd, inputdev);
297 fullpathinput[MAXPATHLEN - 1] = '\0';
298 setinput(fullpathinput);
299 }
300 else
301 setinput(inputdev);
302
303 if (argc == 0 && !filelist) {
304 argc = 1;
305 *--argv = ".";
306 }
307
308 #ifdef USE_QFA
309 if (tapeposflag) {
310 msg("reading QFA positions from %s\n", gTapeposfile);
311 if ((gTapeposfp = fopen(gTapeposfile, "r")) == NULL)
312 errx(1, "can't open file for reading -- %s",
313 gTapeposfile);
314 /* start reading header info */
315 if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
316 errx(1, "not requested format of -- %s", gTapeposfile);
317 gTps[strlen(gTps) - 1] = 0; /* delete end of line */
318 if (strcmp(gTps, QFA_MAGIC) != 0)
319 errx(1, "not requested format of -- %s", gTapeposfile);
320 if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
321 errx(1, "not requested format of -- %s", gTapeposfile);
322 gTps[strlen(gTps) - 1] = 0;
323 if (strcmp(gTps, QFA_VERSION) != 0)
324 errx(1, "not requested format of -- %s", gTapeposfile);
325 /* read dumpdate */
326 if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
327 errx(1, "not requested format of -- %s", gTapeposfile);
328 gTps[strlen(gTps) - 1] = 0;
329 /* TODO: check dumpdate from QFA file with current dump file's
330 * dump date */
331 /* if not equal either output warning and continue without QFA
332 * or abort */
333 /* read empty line */
334 if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
335 errx(1, "not requested format of -- %s", gTapeposfile);
336 gTps[strlen(gTps) - 1] = 0;
337 /* read table header line */
338 if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
339 errx(1, "not requested format of -- %s", gTapeposfile);
340 gTps[strlen(gTps) - 1] = 0;
341 /* end reading header info */
342 /* tape position table starts here */
343 gSeekstart = ftell(gTapeposfp); /* remember for later use */
344 }
345 #endif /* USE_QFA */
346
347 switch (command) {
348 /*
349 * Compare contents of tape.
350 */
351 case 'C': {
352 struct STAT stbuf;
353
354 Vprintf(stdout, "Begin compare restore\n");
355 compare_ignore_not_found = 0;
356 compare_errors = 0;
357 setup();
358 printf("filesys = %s\n", filesys);
359 if (STAT(filesys, &stbuf) < 0)
360 err(1, "cannot stat directory %s", filesys);
361 if (chdir(filesys) < 0)
362 err(1, "cannot cd to %s", filesys);
363 compare_ignore_not_found = dumptime > 0;
364 initsymtable((char *)0);
365 extractdirs(0);
366 treescan(".", ROOTINO, nodeupdates);
367 compareleaves();
368 checkrestore();
369 if (compare_errors) {
370 printf("Some files were modified!\n");
371 exit(2);
372 }
373 break;
374 }
375
376 /*
377 * Interactive mode.
378 */
379 case 'i':
380 setup();
381 extractdirs(1);
382 initsymtable(NULL);
383 runcmdshell();
384 break;
385 /*
386 * Incremental restoration of a file system.
387 */
388 case 'r':
389 setup();
390 if (dumptime > 0) {
391 /*
392 * This is an incremental dump tape.
393 */
394 Vprintf(stdout, "Begin incremental restore\n");
395 initsymtable(symtbl);
396 extractdirs(1);
397 removeoldleaves();
398 Vprintf(stdout, "Calculate node updates.\n");
399 treescan(".", ROOTINO, nodeupdates);
400 findunreflinks();
401 removeoldnodes();
402 } else {
403 /*
404 * This is a level zero dump tape.
405 */
406 Vprintf(stdout, "Begin level 0 restore\n");
407 initsymtable((char *)0);
408 extractdirs(1);
409 Vprintf(stdout, "Calculate extraction list.\n");
410 treescan(".", ROOTINO, nodeupdates);
411 }
412 createleaves(symtbl);
413 createlinks();
414 setdirmodes(FORCE);
415 checkrestore();
416 if (dflag) {
417 Vprintf(stdout, "Verify the directory structure\n");
418 treescan(".", ROOTINO, verifyfile);
419 }
420 dumpsymtable(symtbl, (long)1);
421 break;
422 /*
423 * Resume an incremental file system restoration.
424 */
425 case 'R':
426 initsymtable(symtbl);
427 skipmaps();
428 skipdirs();
429 createleaves(symtbl);
430 createlinks();
431 setdirmodes(FORCE);
432 checkrestore();
433 dumpsymtable(symtbl, (long)1);
434 break;
435
436 /* handle file names from either text file (-X) or the command line */
437 #define NEXTFILE(p) \
438 p = NULL; \
439 if (argc) { \
440 --argc; \
441 p = *argv++; \
442 } \
443 else if (filelist) { \
444 if ((p = fgets(fname, MAXPATHLEN, filelist))) { \
445 if ( *p && *(p + strlen(p) - 1) == '\n' ) /* possible null string */ \
446 *(p + strlen(p) - 1) = '\0'; \
447 if ( !*p ) /* skip empty lines */ \
448 continue; \
449 } \
450 }
451
452 /*
453 * List contents of tape.
454 */
455 case 't':
456 setup();
457 extractdirs(0);
458 initsymtable((char *)0);
459 for (;;) {
460 NEXTFILE(p);
461 if (!p)
462 break;
463 canon(p, name, sizeof(name));
464 ino = dirlookup(name);
465 if (ino == 0)
466 continue;
467 treescan(name, ino, listfile);
468 }
469 break;
470 /*
471 * Batch extraction of tape contents.
472 */
473 case 'x':
474 #ifdef USE_QFADEBUG
475 tistart = time(NULL);
476 #endif
477 setup();
478 extractdirs(1);
479 initsymtable((char *)0);
480 for (;;) {
481 NEXTFILE(p);
482 if (!p)
483 break;
484 canon(p, name, sizeof(name));
485 ino = dirlookup(name);
486 if (ino == 0)
487 continue;
488 if (mflag)
489 pathcheck(name);
490 treescan(name, ino, addfile);
491 }
492 createfiles();
493 createlinks();
494 setdirmodes(0);
495 if (dflag)
496 checkrestore();
497 #ifdef USE_QFADEBUG
498 tiend = time(NULL);
499 titaken = tiend - tistart;
500 msg("restore took %d:%02d:%02d\n", titaken / 3600,
501 (titaken % 3600) / 60, titaken % 60);
502 #endif /* USE_QFADEBUG */
503 break;
504 }
505 exit(0);
506 /* NOTREACHED */
507 return 0; /* gcc shut up */
508 }
509
510 static void
511 usage(void)
512 {
513 #ifdef __linux__
514 const char *ext2ver, *ext2date;
515
516 ext2fs_get_library_version(&ext2ver, &ext2date);
517 (void)fprintf(stderr, "%s %s (using libext2fs %s of %s)\n",
518 __progname, _DUMP_VERSION, ext2ver, ext2date);
519 #else
520 (void)fprintf(stderr, "%s %s\n", __progname, _DUMP_VERSION);
521 #endif
522
523 #ifdef KERBEROS
524 #define kerbflag "k"
525 #else
526 #define kerbflag
527 #endif
528
529 #ifdef USE_QFA
530 #define qfaflag "[-Q file] "
531 #else
532 #define qfaflag
533 #endif
534
535 (void)fprintf(stderr,
536 "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",
537 __progname, " -C [-c" kerbflag "lMvVy] [-b blocksize] [-D filesystem] [-f file] [-F script] [-s fileno]",
538 __progname, " -i [-ch" kerbflag "lmMuvVy] [-b blocksize] [-f file] [-F script] " qfaflag "[-s fileno]",
539 __progname, " -r [-c" kerbflag "lMuvVy] [-b blocksize] [-f file] [-F script] [-s fileno] [-T directory]",
540 __progname, " -R [-c" kerbflag "lMuvVy] [-b blocksize] [-f file] [-F script] [-s fileno] [-T directory]",
541 __progname, " -t [-ch" kerbflag "lMuvVy] [-b blocksize] [-f file] [-F script] " qfaflag "[-s fileno] [-X filelist] [file ...]",
542 __progname, " -x [-ch" kerbflag "lmMuvVy] [-b blocksize] [-f file] [-F script] " qfaflag "[-s fileno] [-X filelist] [file ...]");
543 exit(1);
544 }
545
546 /*
547 * obsolete --
548 * Change set of key letters and ordered arguments into something
549 * getopt(3) will like.
550 */
551 static void
552 obsolete(int *argcp, char **argvp[])
553 {
554 int argc, flags;
555 char *ap, **argv, *flagsp = NULL, **nargv, *p = NULL;
556
557 /* Setup. */
558 argv = *argvp;
559 argc = *argcp;
560
561 /* Return if no arguments or first argument has leading dash. */
562 ap = argv[1];
563 if (argc == 1 || *ap == '-')
564 return;
565
566 /* Allocate space for new arguments. */
567 if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
568 (p = flagsp = malloc(strlen(ap) + 2)) == NULL)
569 err(1, "malloc args");
570
571 *nargv++ = *argv;
572 argv += 2, argc -= 2;
573
574 for (flags = 0; *ap; ++ap) {
575 switch (*ap) {
576 case 'b':
577 case 'D':
578 case 'f':
579 case 'F':
580 case 'Q':
581 case 's':
582 case 'T':
583 case 'X':
584 if (*argv == NULL) {
585 warnx("option requires an argument -- %c", *ap);
586 usage();
587 }
588 if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
589 err(1, "malloc arg");
590 nargv[0][0] = '-';
591 nargv[0][1] = *ap;
592 (void)strcpy(&nargv[0][2], *argv);
593 ++argv;
594 ++nargv;
595 break;
596 default:
597 if (!flags) {
598 *p++ = '-';
599 flags = 1;
600 }
601 *p++ = *ap;
602 break;
603 }
604 }
605
606 /* Terminate flags. */
607 if (flags) {
608 *p = '\0';
609 *nargv++ = flagsp;
610 }
611
612 /* Copy remaining arguments. */
613 while ((*nargv++ = *argv++));
614
615 /* Update argument count. */
616 *argcp = nargv - *argvp - 1;
617 }
618
619 /*
620 * use_stdin --
621 * reserve stdin for opt (avoid conflicts)
622 */
623 void
624 use_stdin(const char *opt)
625 {
626 if (stdin_opt)
627 errx(1, "can't handle standard input for both %s and %s",
628 stdin_opt, opt);
629 stdin_opt = opt;
630 }