Merge branch 'vendor/GCC44'
[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  * @(#) Copyright (c) 1983, 1993 The Regents of the University of California.  All rights reserved.
34  * @(#)main.c   8.6 (Berkeley) 5/4/95
35  * $FreeBSD: src/sbin/restore/main.c,v 1.10.2.3 2001/10/02 08:30:17 cjc Exp $
36  * $DragonFly: src/sbin/restore/main.c,v 1.8 2005/11/06 12:49:25 swildner Exp $
37  */
38
39 #include <sys/param.h>
40 #include <sys/stat.h>
41
42 #include <vfs/ufs/dinode.h>
43 #include <protocols/dumprestore.h>
44
45 #include <err.h>
46 #include <paths.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51
52 #include "restore.h"
53 #include "extern.h"
54
55 int     bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0;
56 int     hflag = 1, mflag = 1, Nflag = 0;
57 int     uflag = 0;
58 int     dokerberos = 0;
59 char    command = '\0';
60 long    dumpnum = 1;
61 long    volno = 0;
62 long    ntrec;
63 char    *dumpmap;
64 char    *usedinomap;
65 ufs1_ino_t maxino;
66 time_t  dumptime;
67 time_t  dumpdate;
68 FILE    *terminal;
69
70 static void obsolete(int *, char **[]);
71 static void usage(void);
72
73 int
74 main(int argc, char **argv)
75 {
76         int ch;
77         ufs1_ino_t ino;
78         char *inputdev;
79         char *symtbl = "./restoresymtable";
80         char *p, name[MAXPATHLEN];
81
82         /* Temp files should *not* be readable.  We set permissions later. */
83         umask(077);
84
85         if (argc < 2)
86                 usage();
87
88         if ((inputdev = getenv("TAPE")) == NULL)
89                 inputdev = _PATH_DEFTAPE;
90         obsolete(&argc, &argv);
91 #ifdef KERBEROS
92 #define optlist "b:cdf:hikmNRrs:tuvxy"
93 #else
94 #define optlist "b:cdf:himNRrs:tuvxy"
95 #endif
96         while ((ch = getopt(argc, argv, optlist)) != -1)
97                 switch(ch) {
98                 case 'b':
99                         /* Change default tape blocksize. */
100                         bflag = 1;
101                         ntrec = strtol(optarg, &p, 10);
102                         if (*p)
103                                 errx(1, "illegal blocksize -- %s", optarg);
104                         if (ntrec <= 0)
105                                 errx(1, "block size must be greater than 0");
106                         break;
107                 case 'c':
108                         cvtflag = 1;
109                         break;
110                 case 'd':
111                         dflag = 1;
112                         break;
113                 case 'f':
114                         inputdev = optarg;
115                         break;
116                 case 'h':
117                         hflag = 0;
118                         break;
119 #ifdef KERBEROS
120                 case 'k':
121                         dokerberos = 1;
122                         break;
123 #endif
124                 case 'i':
125                 case 'R':
126                 case 'r':
127                 case 't':
128                 case 'x':
129                         if (command != '\0')
130                                 errx(1,
131                                     "%c and %c options are mutually exclusive",
132                                     ch, command);
133                         command = ch;
134                         break;
135                 case 'm':
136                         mflag = 0;
137                         break;
138                 case 'N':
139                         Nflag = 1;
140                         break;
141                 case 's':
142                         /* Dumpnum (skip to) for multifile dump tapes. */
143                         dumpnum = strtol(optarg, &p, 10);
144                         if (*p)
145                                 errx(1, "illegal dump number -- %s", optarg);
146                         if (dumpnum <= 0)
147                                 errx(1, "dump number must be greater than 0");
148                         break;
149                 case 'u':
150                         uflag = 1;
151                         break;
152                 case 'v':
153                         vflag = 1;
154                         break;
155                 case 'y':
156                         yflag = 1;
157                         break;
158                 default:
159                         usage();
160                 }
161         argc -= optind;
162         argv += optind;
163
164         if (command == '\0')
165                 errx(1, "none of i, R, r, t or x options specified");
166
167         if (signal(SIGINT, onintr) == SIG_IGN)
168                 signal(SIGINT, SIG_IGN);
169         if (signal(SIGTERM, onintr) == SIG_IGN)
170                 signal(SIGTERM, SIG_IGN);
171         setlinebuf(stderr);
172
173         setinput(inputdev);
174
175         if (argc == 0) {
176                 argc = 1;
177                 *--argv = ".";
178         }
179
180         switch (command) {
181         /*
182          * Interactive mode.
183          */
184         case 'i':
185                 setup();
186                 extractdirs(1);
187                 initsymtable(NULL);
188                 runcmdshell();
189                 break;
190         /*
191          * Incremental restoration of a file system.
192          */
193         case 'r':
194                 setup();
195                 if (dumptime > 0) {
196                         /*
197                          * This is an incremental dump tape.
198                          */
199                         vprintf(stdout, "Begin incremental restore\n");
200                         initsymtable(symtbl);
201                         extractdirs(1);
202                         removeoldleaves();
203                         vprintf(stdout, "Calculate node updates.\n");
204                         treescan(".", ROOTINO, nodeupdates);
205                         findunreflinks();
206                         removeoldnodes();
207                 } else {
208                         /*
209                          * This is a level zero dump tape.
210                          */
211                         vprintf(stdout, "Begin level 0 restore\n");
212                         initsymtable(NULL);
213                         extractdirs(1);
214                         vprintf(stdout, "Calculate extraction list.\n");
215                         treescan(".", ROOTINO, nodeupdates);
216                 }
217                 createleaves(symtbl);
218                 createlinks();
219                 setdirmodes(FORCE);
220                 checkrestore();
221                 if (dflag) {
222                         vprintf(stdout, "Verify the directory structure\n");
223                         treescan(".", ROOTINO, verifyfile);
224                 }
225                 dumpsymtable(symtbl, (long)1);
226                 break;
227         /*
228          * Resume an incremental file system restoration.
229          */
230         case 'R':
231                 initsymtable(symtbl);
232                 skipmaps();
233                 skipdirs();
234                 createleaves(symtbl);
235                 createlinks();
236                 setdirmodes(FORCE);
237                 checkrestore();
238                 dumpsymtable(symtbl, (long)1);
239                 break;
240         /*
241          * List contents of tape.
242          */
243         case 't':
244                 setup();
245                 extractdirs(0);
246                 initsymtable(NULL);
247                 while (argc--) {
248                         canon(*argv++, name, sizeof(name));
249                         ino = dirlookup(name);
250                         if (ino == 0)
251                                 continue;
252                         treescan(name, ino, listfile);
253                 }
254                 break;
255         /*
256          * Batch extraction of tape contents.
257          */
258         case 'x':
259                 setup();
260                 extractdirs(1);
261                 initsymtable(NULL);
262                 while (argc--) {
263                         canon(*argv++, name, sizeof(name));
264                         ino = dirlookup(name);
265                         if (ino == 0)
266                                 continue;
267                         if (mflag)
268                                 pathcheck(name);
269                         treescan(name, ino, addfile);
270                 }
271                 createfiles();
272                 createlinks();
273                 setdirmodes(0);
274                 if (dflag)
275                         checkrestore();
276                 break;
277         }
278         done(0);
279         /* NOTREACHED */
280 }
281
282 static void
283 usage(void)
284 {
285         fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n",
286           "restore -i [-cdhkmNuvy] [-b blocksize] [-f file] [-s fileno]",
287           "restore -r [-cdkNuvy] [-b blocksize] [-f file] [-s fileno]",
288           "restore -R [-cdkNuvy] [-b blocksize] [-f file] [-s fileno]",
289           "restore -x [-cdhkmNuvy] [-b blocksize] [-f file] [-s fileno] [file ...]",
290           "restore -t [-cdhkNuvy] [-b blocksize] [-f file] [-s fileno] [file ...]");
291         done(1);
292 }
293
294 /*
295  * obsolete --
296  *      Change set of key letters and ordered arguments into something
297  *      getopt(3) will like.
298  */
299 static void
300 obsolete(int *argcp, char **argvp[])
301 {
302         int argc, flags;
303         char *ap, **argv, *flagsp, **nargv, *p;
304
305         /* Setup. */
306         argv = *argvp;
307         argc = *argcp;
308
309         /* Return if no arguments or first argument has leading dash. */
310         ap = argv[1];
311         if (argc == 1 || *ap == '-')
312                 return;
313
314         /* Allocate space for new arguments. */
315         if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
316             (p = flagsp = malloc(strlen(ap) + 2)) == NULL)
317                 err(1, NULL);
318
319         *nargv++ = *argv;
320         argv += 2, argc -= 2;
321
322         for (flags = 0; *ap; ++ap) {
323                 switch (*ap) {
324                 case 'b':
325                 case 'f':
326                 case 's':
327                         if (*argv == NULL) {
328                                 warnx("option requires an argument -- %c", *ap);
329                                 usage();
330                         }
331                         if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
332                                 err(1, NULL);
333                         nargv[0][0] = '-';
334                         nargv[0][1] = *ap;
335                         strcpy(&nargv[0][2], *argv);
336                         ++argv;
337                         ++nargv;
338                         break;
339                 default:
340                         if (!flags) {
341                                 *p++ = '-';
342                                 flags = 1;
343                         }
344                         *p++ = *ap;
345                         break;
346                 }
347         }
348
349         /* Terminate flags. */
350         if (flags) {
351                 *p = '\0';
352                 *nargv++ = flagsp;
353         }
354
355         /* Copy remaining arguments. */
356         while ((*nargv++ = *argv++));
357
358         /* Update argument count. */
359         *argcp = nargv - *argvp - 1;
360 }