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