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