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