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