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