Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sbin / restore / main.c
1 /*
2  * Copyright (c) 1983, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1983, 1993\n\
37         The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)main.c      8.6 (Berkeley) 5/4/95";
43 #endif
44 static const char rcsid[] =
45   "$FreeBSD: src/sbin/restore/main.c,v 1.10.2.3 2001/10/02 08:30:17 cjc Exp $";
46 #endif /* not lint */
47
48 #include <sys/param.h>
49 #include <sys/stat.h>
50
51 #include <ufs/ufs/dinode.h>
52 #include <protocols/dumprestore.h>
53
54 #include <err.h>
55 #include <paths.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <unistd.h>
60
61 #include "restore.h"
62 #include "extern.h"
63
64 int     bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0;
65 int     hflag = 1, mflag = 1, Nflag = 0;
66 int     uflag = 0;
67 int     dokerberos = 0;
68 char    command = '\0';
69 long    dumpnum = 1;
70 long    volno = 0;
71 long    ntrec;
72 char    *dumpmap;
73 char    *usedinomap;
74 ino_t   maxino;
75 time_t  dumptime;
76 time_t  dumpdate;
77 FILE    *terminal;
78
79 static void obsolete __P((int *, char **[]));
80 static void usage __P((void));
81
82 int
83 main(argc, argv)
84         int argc;
85         char *argv[];
86 {
87         int ch;
88         ino_t ino;
89         char *inputdev;
90         char *symtbl = "./restoresymtable";
91         char *p, name[MAXPATHLEN];
92
93         /* Temp files should *not* be readable.  We set permissions later. */
94         (void) umask(077);
95
96         if (argc < 2)
97                 usage();
98
99         if ((inputdev = getenv("TAPE")) == NULL)
100                 inputdev = _PATH_DEFTAPE;
101         obsolete(&argc, &argv);
102 #ifdef KERBEROS
103 #define optlist "b:cdf:hikmNRrs:tuvxy"
104 #else
105 #define optlist "b:cdf:himNRrs:tuvxy"
106 #endif
107         while ((ch = getopt(argc, argv, optlist)) != -1)
108                 switch(ch) {
109                 case 'b':
110                         /* Change default tape blocksize. */
111                         bflag = 1;
112                         ntrec = strtol(optarg, &p, 10);
113                         if (*p)
114                                 errx(1, "illegal blocksize -- %s", optarg);
115                         if (ntrec <= 0)
116                                 errx(1, "block size must be greater than 0");
117                         break;
118                 case 'c':
119                         cvtflag = 1;
120                         break;
121                 case 'd':
122                         dflag = 1;
123                         break;
124                 case 'f':
125                         inputdev = optarg;
126                         break;
127                 case 'h':
128                         hflag = 0;
129                         break;
130 #ifdef KERBEROS
131                 case 'k':
132                         dokerberos = 1;
133                         break;
134 #endif
135                 case 'i':
136                 case 'R':
137                 case 'r':
138                 case 't':
139                 case 'x':
140                         if (command != '\0')
141                                 errx(1,
142                                     "%c and %c options are mutually exclusive",
143                                     ch, command);
144                         command = ch;
145                         break;
146                 case 'm':
147                         mflag = 0;
148                         break;
149                 case 'N':
150                         Nflag = 1;
151                         break;
152                 case 's':
153                         /* Dumpnum (skip to) for multifile dump tapes. */
154                         dumpnum = strtol(optarg, &p, 10);
155                         if (*p)
156                                 errx(1, "illegal dump number -- %s", optarg);
157                         if (dumpnum <= 0)
158                                 errx(1, "dump number must be greater than 0");
159                         break;
160                 case 'u':
161                         uflag = 1;
162                         break;
163                 case 'v':
164                         vflag = 1;
165                         break;
166                 case 'y':
167                         yflag = 1;
168                         break;
169                 default:
170                         usage();
171                 }
172         argc -= optind;
173         argv += optind;
174
175         if (command == '\0')
176                 errx(1, "none of i, R, r, t or x options specified");
177
178         if (signal(SIGINT, onintr) == SIG_IGN)
179                 (void) signal(SIGINT, SIG_IGN);
180         if (signal(SIGTERM, onintr) == SIG_IGN)
181                 (void) signal(SIGTERM, SIG_IGN);
182         setlinebuf(stderr);
183
184         setinput(inputdev);
185
186         if (argc == 0) {
187                 argc = 1;
188                 *--argv = ".";
189         }
190
191         switch (command) {
192         /*
193          * Interactive mode.
194          */
195         case 'i':
196                 setup();
197                 extractdirs(1);
198                 initsymtable(NULL);
199                 runcmdshell();
200                 break;
201         /*
202          * Incremental restoration of a file system.
203          */
204         case 'r':
205                 setup();
206                 if (dumptime > 0) {
207                         /*
208                          * This is an incremental dump tape.
209                          */
210                         vprintf(stdout, "Begin incremental restore\n");
211                         initsymtable(symtbl);
212                         extractdirs(1);
213                         removeoldleaves();
214                         vprintf(stdout, "Calculate node updates.\n");
215                         treescan(".", ROOTINO, nodeupdates);
216                         findunreflinks();
217                         removeoldnodes();
218                 } else {
219                         /*
220                          * This is a level zero dump tape.
221                          */
222                         vprintf(stdout, "Begin level 0 restore\n");
223                         initsymtable((char *)0);
224                         extractdirs(1);
225                         vprintf(stdout, "Calculate extraction list.\n");
226                         treescan(".", ROOTINO, nodeupdates);
227                 }
228                 createleaves(symtbl);
229                 createlinks();
230                 setdirmodes(FORCE);
231                 checkrestore();
232                 if (dflag) {
233                         vprintf(stdout, "Verify the directory structure\n");
234                         treescan(".", ROOTINO, verifyfile);
235                 }
236                 dumpsymtable(symtbl, (long)1);
237                 break;
238         /*
239          * Resume an incremental file system restoration.
240          */
241         case 'R':
242                 initsymtable(symtbl);
243                 skipmaps();
244                 skipdirs();
245                 createleaves(symtbl);
246                 createlinks();
247                 setdirmodes(FORCE);
248                 checkrestore();
249                 dumpsymtable(symtbl, (long)1);
250                 break;
251         /*
252          * List contents of tape.
253          */
254         case 't':
255                 setup();
256                 extractdirs(0);
257                 initsymtable((char *)0);
258                 while (argc--) {
259                         canon(*argv++, name, sizeof(name));
260                         ino = dirlookup(name);
261                         if (ino == 0)
262                                 continue;
263                         treescan(name, ino, listfile);
264                 }
265                 break;
266         /*
267          * Batch extraction of tape contents.
268          */
269         case 'x':
270                 setup();
271                 extractdirs(1);
272                 initsymtable((char *)0);
273                 while (argc--) {
274                         canon(*argv++, name, sizeof(name));
275                         ino = dirlookup(name);
276                         if (ino == 0)
277                                 continue;
278                         if (mflag)
279                                 pathcheck(name);
280                         treescan(name, ino, addfile);
281                 }
282                 createfiles();
283                 createlinks();
284                 setdirmodes(0);
285                 if (dflag)
286                         checkrestore();
287                 break;
288         }
289         done(0);
290         /* NOTREACHED */
291 }
292
293 static void
294 usage()
295 {
296         (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n",
297           "restore -i [-cdhkmNuvy] [-b blocksize] [-f file] [-s fileno]",
298           "restore -r [-cdkNuvy] [-b blocksize] [-f file] [-s fileno]",
299           "restore -R [-cdkNuvy] [-b blocksize] [-f file] [-s fileno]",
300           "restore -x [-cdhkmNuvy] [-b blocksize] [-f file] [-s fileno] [file ...]",
301           "restore -t [-cdhkNuvy] [-b blocksize] [-f file] [-s fileno] [file ...]");
302         done(1);
303 }
304
305 /*
306  * obsolete --
307  *      Change set of key letters and ordered arguments into something
308  *      getopt(3) will like.
309  */
310 static void
311 obsolete(argcp, argvp)
312         int *argcp;
313         char **argvp[];
314 {
315         int argc, flags;
316         char *ap, **argv, *flagsp, **nargv, *p;
317
318         /* Setup. */
319         argv = *argvp;
320         argc = *argcp;
321
322         /* Return if no arguments or first argument has leading dash. */
323         ap = argv[1];
324         if (argc == 1 || *ap == '-')
325                 return;
326
327         /* Allocate space for new arguments. */
328         if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
329             (p = flagsp = malloc(strlen(ap) + 2)) == NULL)
330                 err(1, NULL);
331
332         *nargv++ = *argv;
333         argv += 2, argc -= 2;
334
335         for (flags = 0; *ap; ++ap) {
336                 switch (*ap) {
337                 case 'b':
338                 case 'f':
339                 case 's':
340                         if (*argv == NULL) {
341                                 warnx("option requires an argument -- %c", *ap);
342                                 usage();
343                         }
344                         if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
345                                 err(1, NULL);
346                         nargv[0][0] = '-';
347                         nargv[0][1] = *ap;
348                         (void)strcpy(&nargv[0][2], *argv);
349                         ++argv;
350                         ++nargv;
351                         break;
352                 default:
353                         if (!flags) {
354                                 *p++ = '-';
355                                 flags = 1;
356                         }
357                         *p++ = *ap;
358                         break;
359                 }
360         }
361
362         /* Terminate flags. */
363         if (flags) {
364                 *p = '\0';
365                 *nargv++ = flagsp;
366         }
367
368         /* Copy remaining arguments. */
369         while ((*nargv++ = *argv++));
370
371         /* Update argument count. */
372         *argcp = nargv - *argvp - 1;
373 }