1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
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#ifndef lint
33static const char copyright[] =
34"@(#) Copyright (c) 1983, 1993\n\
35	The Regents of the University of California.  All rights reserved.\n";
36#endif /* not lint */
37
38#ifndef lint
39#if 0
40static char sccsid[] = "@(#)main.c	8.6 (Berkeley) 5/4/95";
41#endif
42#endif /* not lint */
43
44#include <sys/cdefs.h>
45__FBSDID("$FreeBSD$");
46
47#include <sys/param.h>
48#include <sys/stat.h>
49
50#include <ufs/ufs/dinode.h>
51#include <protocols/dumprestore.h>
52
53#include <err.h>
54#include <limits.h>
55#include <locale.h>
56#include <paths.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
65int	bflag = 0, cvtflag = 0, dflag = 0, Dflag = 0, vflag = 0, yflag = 0;
66int	hflag = 1, mflag = 1, Nflag = 0;
67int	uflag = 0;
68int	pipecmd = 0;
69char	command = '\0';
70long	dumpnum = 1;
71long	volno = 0;
72long	ntrec;
73char	*dumpmap;
74char	*usedinomap;
75ino_t	maxino;
76time_t	dumptime;
77time_t	dumpdate;
78FILE 	*terminal;
79
80static void obsolete(int *, char **[]);
81static void usage(void) __dead2;
82
83int
84main(int argc, char *argv[])
85{
86	int ch;
87	ino_t ino;
88	char *inputdev;
89	char *symtbl = "./restoresymtable";
90	char *p, name[MAXPATHLEN];
91
92	/* Temp files should *not* be readable.  We set permissions later. */
93	(void) umask(077);
94
95	if (argc < 2)
96		usage();
97
98	(void)setlocale(LC_ALL, "");
99
100	inputdev = NULL;
101	obsolete(&argc, &argv);
102	while ((ch = getopt(argc, argv, "b:dDf:himNP:Rrs:tuvxy")) != -1)
103		switch(ch) {
104		case 'b':
105			/* Change default tape blocksize. */
106			bflag = 1;
107			ntrec = strtol(optarg, &p, 10);
108			if (*p)
109				errx(1, "illegal blocksize -- %s", optarg);
110			if (ntrec <= 0)
111				errx(1, "block size must be greater than 0");
112			break;
113		case 'd':
114			dflag = 1;
115			break;
116		case 'D':
117			Dflag = 1;
118			break;
119		case 'f':
120			if (pipecmd)
121				errx(1,
122				    "-P and -f options are mutually exclusive");
123			inputdev = optarg;
124			break;
125		case 'P':
126			if (!pipecmd && inputdev)
127				errx(1,
128				    "-P and -f options are mutually exclusive");
129			inputdev = optarg;
130			pipecmd = 1;
131			break;
132		case 'h':
133			hflag = 0;
134			break;
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	if (inputdev == NULL && (inputdev = getenv("TAPE")) == NULL)
185		inputdev = _PATH_DEFTAPE;
186	setinput(inputdev, pipecmd);
187
188	if (argc == 0) {
189		argc = 1;
190		*--argv = ".";
191	}
192
193	switch (command) {
194	/*
195	 * Interactive mode.
196	 */
197	case 'i':
198		setup();
199		extractdirs(1);
200		initsymtable(NULL);
201		runcmdshell();
202		break;
203	/*
204	 * Incremental restoration of a file system.
205	 */
206	case 'r':
207		setup();
208		if (dumptime > 0) {
209			/*
210			 * This is an incremental dump tape.
211			 */
212			vprintf(stdout, "Begin incremental restore\n");
213			initsymtable(symtbl);
214			extractdirs(1);
215			removeoldleaves();
216			vprintf(stdout, "Calculate node updates.\n");
217			treescan(".", UFS_ROOTINO, nodeupdates);
218			findunreflinks();
219			removeoldnodes();
220		} else {
221			/*
222			 * This is a level zero dump tape.
223			 */
224			vprintf(stdout, "Begin level 0 restore\n");
225			initsymtable((char *)0);
226			extractdirs(1);
227			vprintf(stdout, "Calculate extraction list.\n");
228			treescan(".", UFS_ROOTINO, nodeupdates);
229		}
230		createleaves(symtbl);
231		createlinks();
232		setdirmodes(FORCE);
233		checkrestore();
234		if (dflag) {
235			vprintf(stdout, "Verify the directory structure\n");
236			treescan(".", UFS_ROOTINO, verifyfile);
237		}
238		dumpsymtable(symtbl, (long)1);
239		break;
240	/*
241	 * Resume an incremental file system restoration.
242	 */
243	case 'R':
244		initsymtable(symtbl);
245		skipmaps();
246		skipdirs();
247		createleaves(symtbl);
248		createlinks();
249		setdirmodes(FORCE);
250		checkrestore();
251		dumpsymtable(symtbl, (long)1);
252		break;
253	/*
254	 * List contents of tape.
255	 */
256	case 't':
257		setup();
258		extractdirs(0);
259		initsymtable((char *)0);
260		while (argc--) {
261			canon(*argv++, name, sizeof(name));
262			ino = dirlookup(name);
263			if (ino == 0)
264				continue;
265			treescan(name, ino, listfile);
266		}
267		break;
268	/*
269	 * Batch extraction of tape contents.
270	 */
271	case 'x':
272		setup();
273		extractdirs(1);
274		initsymtable((char *)0);
275		while (argc--) {
276			canon(*argv++, name, sizeof(name));
277			ino = dirlookup(name);
278			if (ino == 0)
279				continue;
280			if (mflag)
281				pathcheck(name);
282			treescan(name, ino, addfile);
283		}
284		createfiles();
285		createlinks();
286		setdirmodes(0);
287		if (dflag)
288			checkrestore();
289		break;
290	}
291	done(0);
292	/* NOTREACHED */
293}
294
295static void
296usage()
297{
298	const char *const common =
299	    "[-b blocksize] [-f file | -P pipecommand] [-s fileno]";
300	const char *const fileell = "[file ...]";
301
302	(void)fprintf(stderr, "usage:\t%s %s\n\t%s %s\n\t%s %s\n"
303	    "\t%s %s %s\n\t%s %s %s\n",
304	    "restore -i [-dhmNuvy]", common,
305	    "restore -R [-dNuvy]", common,
306	    "restore -r [-dNuvy]", common,
307	    "restore -t [-dhNuvy]", common, fileell,
308	    "restore -x [-dhmNuvy]", common, fileell);
309	done(1);
310}
311
312/*
313 * obsolete --
314 *	Change set of key letters and ordered arguments into something
315 *	getopt(3) will like.
316 */
317static void
318obsolete(int *argcp, char **argvp[])
319{
320	int argc, flags;
321	char *ap, **argv, *flagsp, **nargv, *p;
322
323	/* Setup. */
324	argv = *argvp;
325	argc = *argcp;
326
327	/* Return if no arguments or first argument has leading dash. */
328	ap = argv[1];
329	if (argc == 1 || *ap == '-')
330		return;
331
332	/* Allocate space for new arguments. */
333	if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
334	    (p = flagsp = malloc(strlen(ap) + 2)) == NULL)
335		err(1, NULL);
336
337	*nargv++ = *argv;
338	argv += 2, argc -= 2;
339
340	for (flags = 0; *ap; ++ap) {
341		switch (*ap) {
342		case 'b':
343		case 'f':
344		case 's':
345			if (*argv == NULL) {
346				warnx("option requires an argument -- %c", *ap);
347				usage();
348			}
349			if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
350				err(1, NULL);
351			nargv[0][0] = '-';
352			nargv[0][1] = *ap;
353			(void)strcpy(&nargv[0][2], *argv);
354			++argv;
355			++nargv;
356			break;
357		default:
358			if (!flags) {
359				*p++ = '-';
360				flags = 1;
361			}
362			*p++ = *ap;
363			break;
364		}
365	}
366
367	/* Terminate flags. */
368	if (flags) {
369		*p = '\0';
370		*nargv++ = flagsp;
371	} else
372		free(flagsp);
373
374	/* Copy remaining arguments. */
375	while ((*nargv++ = *argv++));
376
377	/* Update argument count. */
378	*argcp = nargv - *argvp - 1;
379}
380