11558Srgrimes/*
21558Srgrimes * Copyright (c) 1983, 1993
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * Redistribution and use in source and binary forms, with or without
61558Srgrimes * modification, are permitted provided that the following conditions
71558Srgrimes * are met:
81558Srgrimes * 1. Redistributions of source code must retain the above copyright
91558Srgrimes *    notice, this list of conditions and the following disclaimer.
101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111558Srgrimes *    notice, this list of conditions and the following disclaimer in the
121558Srgrimes *    documentation and/or other materials provided with the distribution.
131558Srgrimes * 4. Neither the name of the University nor the names of its contributors
141558Srgrimes *    may be used to endorse or promote products derived from this software
151558Srgrimes *    without specific prior written permission.
161558Srgrimes *
171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271558Srgrimes * SUCH DAMAGE.
281558Srgrimes */
291558Srgrimes
301558Srgrimes#ifndef lint
3137906Scharnierstatic const char copyright[] =
321558Srgrimes"@(#) Copyright (c) 1983, 1993\n\
331558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
341558Srgrimes#endif /* not lint */
351558Srgrimes
361558Srgrimes#ifndef lint
3737906Scharnier#if 0
3823685Speterstatic char sccsid[] = "@(#)main.c	8.6 (Berkeley) 5/4/95";
3937906Scharnier#endif
401558Srgrimes#endif /* not lint */
411558Srgrimes
42146754Scharnier#include <sys/cdefs.h>
43146754Scharnier__FBSDID("$FreeBSD$");
44146754Scharnier
451558Srgrimes#include <sys/param.h>
4637906Scharnier#include <sys/stat.h>
471558Srgrimes
4823685Speter#include <ufs/ufs/dinode.h>
491558Srgrimes#include <protocols/dumprestore.h>
501558Srgrimes
511558Srgrimes#include <err.h>
52103949Smike#include <limits.h>
53118526Sache#include <locale.h>
5473986Sobrien#include <paths.h>
551558Srgrimes#include <stdio.h>
561558Srgrimes#include <stdlib.h>
5778732Sdd#include <string.h>
5823685Speter#include <unistd.h>
591558Srgrimes
601558Srgrimes#include "restore.h"
611558Srgrimes#include "extern.h"
621558Srgrimes
63164911Sdwmaloneint	bflag = 0, cvtflag = 0, dflag = 0, Dflag = 0, vflag = 0, yflag = 0;
641558Srgrimesint	hflag = 1, mflag = 1, Nflag = 0;
6535852Sjkhint	uflag = 0;
66128175Sgreenint	pipecmd = 0;
671558Srgrimeschar	command = '\0';
681558Srgrimeslong	dumpnum = 1;
691558Srgrimeslong	volno = 0;
701558Srgrimeslong	ntrec;
711558Srgrimeschar	*dumpmap;
7223685Speterchar	*usedinomap;
731558Srgrimesino_t	maxino;
741558Srgrimestime_t	dumptime;
751558Srgrimestime_t	dumpdate;
761558SrgrimesFILE 	*terminal;
771558Srgrimes
7892837Simpstatic void obsolete(int *, char **[]);
7992837Simpstatic void usage(void) __dead2;
801558Srgrimes
811558Srgrimesint
8292837Simpmain(int argc, char *argv[])
831558Srgrimes{
841558Srgrimes	int ch;
851558Srgrimes	ino_t ino;
8621149Simp	char *inputdev;
871558Srgrimes	char *symtbl = "./restoresymtable";
881558Srgrimes	char *p, name[MAXPATHLEN];
891558Srgrimes
9021149Simp	/* Temp files should *not* be readable.  We set permissions later. */
9121149Simp	(void) umask(077);
9221149Simp
931558Srgrimes	if (argc < 2)
941558Srgrimes		usage();
951558Srgrimes
96118526Sache	(void)setlocale(LC_ALL, "");
97118526Sache
98128175Sgreen	inputdev = NULL;
991558Srgrimes	obsolete(&argc, &argv);
100164911Sdwmalone	while ((ch = getopt(argc, argv, "b:dDf:himNP:Rrs:tuvxy")) != -1)
1011558Srgrimes		switch(ch) {
1021558Srgrimes		case 'b':
1031558Srgrimes			/* Change default tape blocksize. */
1041558Srgrimes			bflag = 1;
1051558Srgrimes			ntrec = strtol(optarg, &p, 10);
1061558Srgrimes			if (*p)
1071558Srgrimes				errx(1, "illegal blocksize -- %s", optarg);
1081558Srgrimes			if (ntrec <= 0)
1091558Srgrimes				errx(1, "block size must be greater than 0");
1101558Srgrimes			break;
1111558Srgrimes		case 'd':
1121558Srgrimes			dflag = 1;
1131558Srgrimes			break;
114164911Sdwmalone		case 'D':
115164911Sdwmalone			Dflag = 1;
116164911Sdwmalone			break;
1171558Srgrimes		case 'f':
118128175Sgreen			if (pipecmd)
119128175Sgreen				errx(1,
120128175Sgreen				    "-P and -f options are mutually exclusive");
1211558Srgrimes			inputdev = optarg;
1221558Srgrimes			break;
123128175Sgreen		case 'P':
124128175Sgreen			if (!pipecmd && inputdev)
125128175Sgreen				errx(1,
126128175Sgreen				    "-P and -f options are mutually exclusive");
127128175Sgreen			inputdev = optarg;
128128175Sgreen			pipecmd = 1;
129128175Sgreen			break;
1301558Srgrimes		case 'h':
1311558Srgrimes			hflag = 0;
1321558Srgrimes			break;
1331558Srgrimes		case 'i':
1341558Srgrimes		case 'R':
1351558Srgrimes		case 'r':
1361558Srgrimes		case 't':
1371558Srgrimes		case 'x':
1381558Srgrimes			if (command != '\0')
1391558Srgrimes				errx(1,
1401558Srgrimes				    "%c and %c options are mutually exclusive",
1411558Srgrimes				    ch, command);
1421558Srgrimes			command = ch;
1431558Srgrimes			break;
1441558Srgrimes		case 'm':
1451558Srgrimes			mflag = 0;
1461558Srgrimes			break;
1471558Srgrimes		case 'N':
1481558Srgrimes			Nflag = 1;
1491558Srgrimes			break;
1501558Srgrimes		case 's':
1511558Srgrimes			/* Dumpnum (skip to) for multifile dump tapes. */
1521558Srgrimes			dumpnum = strtol(optarg, &p, 10);
1531558Srgrimes			if (*p)
1541558Srgrimes				errx(1, "illegal dump number -- %s", optarg);
1551558Srgrimes			if (dumpnum <= 0)
1561558Srgrimes				errx(1, "dump number must be greater than 0");
1571558Srgrimes			break;
15835852Sjkh		case 'u':
15935852Sjkh			uflag = 1;
16035852Sjkh			break;
1611558Srgrimes		case 'v':
1621558Srgrimes			vflag = 1;
1631558Srgrimes			break;
1641558Srgrimes		case 'y':
1651558Srgrimes			yflag = 1;
1661558Srgrimes			break;
1671558Srgrimes		default:
1681558Srgrimes			usage();
1691558Srgrimes		}
1701558Srgrimes	argc -= optind;
1711558Srgrimes	argv += optind;
1721558Srgrimes
1731558Srgrimes	if (command == '\0')
1741558Srgrimes		errx(1, "none of i, R, r, t or x options specified");
1751558Srgrimes
1761558Srgrimes	if (signal(SIGINT, onintr) == SIG_IGN)
1771558Srgrimes		(void) signal(SIGINT, SIG_IGN);
1781558Srgrimes	if (signal(SIGTERM, onintr) == SIG_IGN)
1791558Srgrimes		(void) signal(SIGTERM, SIG_IGN);
1801558Srgrimes	setlinebuf(stderr);
1811558Srgrimes
182128175Sgreen	if (inputdev == NULL && (inputdev = getenv("TAPE")) == NULL)
183128175Sgreen		inputdev = _PATH_DEFTAPE;
184128175Sgreen	setinput(inputdev, pipecmd);
1851558Srgrimes
1861558Srgrimes	if (argc == 0) {
1871558Srgrimes		argc = 1;
1881558Srgrimes		*--argv = ".";
1891558Srgrimes	}
1901558Srgrimes
1911558Srgrimes	switch (command) {
1921558Srgrimes	/*
1931558Srgrimes	 * Interactive mode.
1941558Srgrimes	 */
1951558Srgrimes	case 'i':
1961558Srgrimes		setup();
1971558Srgrimes		extractdirs(1);
1981558Srgrimes		initsymtable(NULL);
1991558Srgrimes		runcmdshell();
2001558Srgrimes		break;
2011558Srgrimes	/*
202102231Strhodes	 * Incremental restoration of a file system.
2031558Srgrimes	 */
2041558Srgrimes	case 'r':
2051558Srgrimes		setup();
2061558Srgrimes		if (dumptime > 0) {
2071558Srgrimes			/*
2081558Srgrimes			 * This is an incremental dump tape.
2091558Srgrimes			 */
2101558Srgrimes			vprintf(stdout, "Begin incremental restore\n");
2111558Srgrimes			initsymtable(symtbl);
2121558Srgrimes			extractdirs(1);
2131558Srgrimes			removeoldleaves();
2141558Srgrimes			vprintf(stdout, "Calculate node updates.\n");
2151558Srgrimes			treescan(".", ROOTINO, nodeupdates);
2161558Srgrimes			findunreflinks();
2171558Srgrimes			removeoldnodes();
2181558Srgrimes		} else {
2191558Srgrimes			/*
2201558Srgrimes			 * This is a level zero dump tape.
2211558Srgrimes			 */
2221558Srgrimes			vprintf(stdout, "Begin level 0 restore\n");
2231558Srgrimes			initsymtable((char *)0);
2241558Srgrimes			extractdirs(1);
2251558Srgrimes			vprintf(stdout, "Calculate extraction list.\n");
2261558Srgrimes			treescan(".", ROOTINO, nodeupdates);
2271558Srgrimes		}
2281558Srgrimes		createleaves(symtbl);
2291558Srgrimes		createlinks();
2301558Srgrimes		setdirmodes(FORCE);
2311558Srgrimes		checkrestore();
2321558Srgrimes		if (dflag) {
2331558Srgrimes			vprintf(stdout, "Verify the directory structure\n");
2341558Srgrimes			treescan(".", ROOTINO, verifyfile);
2351558Srgrimes		}
2361558Srgrimes		dumpsymtable(symtbl, (long)1);
2371558Srgrimes		break;
2381558Srgrimes	/*
239102231Strhodes	 * Resume an incremental file system restoration.
2401558Srgrimes	 */
2411558Srgrimes	case 'R':
2421558Srgrimes		initsymtable(symtbl);
2431558Srgrimes		skipmaps();
2441558Srgrimes		skipdirs();
2451558Srgrimes		createleaves(symtbl);
2461558Srgrimes		createlinks();
2471558Srgrimes		setdirmodes(FORCE);
2481558Srgrimes		checkrestore();
2491558Srgrimes		dumpsymtable(symtbl, (long)1);
2501558Srgrimes		break;
2511558Srgrimes	/*
2521558Srgrimes	 * List contents of tape.
2531558Srgrimes	 */
2541558Srgrimes	case 't':
2551558Srgrimes		setup();
2561558Srgrimes		extractdirs(0);
2571558Srgrimes		initsymtable((char *)0);
2581558Srgrimes		while (argc--) {
25921174Sguido			canon(*argv++, name, sizeof(name));
2601558Srgrimes			ino = dirlookup(name);
2611558Srgrimes			if (ino == 0)
2621558Srgrimes				continue;
2631558Srgrimes			treescan(name, ino, listfile);
2641558Srgrimes		}
2651558Srgrimes		break;
2661558Srgrimes	/*
2671558Srgrimes	 * Batch extraction of tape contents.
2681558Srgrimes	 */
2691558Srgrimes	case 'x':
2701558Srgrimes		setup();
2711558Srgrimes		extractdirs(1);
2721558Srgrimes		initsymtable((char *)0);
2731558Srgrimes		while (argc--) {
27421174Sguido			canon(*argv++, name, sizeof(name));
2751558Srgrimes			ino = dirlookup(name);
2761558Srgrimes			if (ino == 0)
2771558Srgrimes				continue;
2781558Srgrimes			if (mflag)
2791558Srgrimes				pathcheck(name);
2801558Srgrimes			treescan(name, ino, addfile);
2811558Srgrimes		}
2821558Srgrimes		createfiles();
2831558Srgrimes		createlinks();
2841558Srgrimes		setdirmodes(0);
2851558Srgrimes		if (dflag)
2861558Srgrimes			checkrestore();
2871558Srgrimes		break;
2881558Srgrimes	}
2891558Srgrimes	done(0);
2901558Srgrimes	/* NOTREACHED */
2911558Srgrimes}
2921558Srgrimes
2931558Srgrimesstatic void
2941558Srgrimesusage()
2951558Srgrimes{
296128175Sgreen	const char *const common =
297141611Sru	    "[-b blocksize] [-f file | -P pipecommand] [-s fileno]";
298128175Sgreen	const char *const fileell = "[file ...]";
299128175Sgreen
300128175Sgreen	(void)fprintf(stderr, "usage:\t%s %s\n\t%s %s\n\t%s %s\n"
301128175Sgreen	    "\t%s %s %s\n\t%s %s %s\n",
302143817Simp	    "restore -i [-dhmNuvy]", common,
303143817Simp	    "restore -R [-dNuvy]", common,
304143817Simp	    "restore -r [-dNuvy]", common,
305143817Simp	    "restore -t [-dhNuvy]", common, fileell,
306143817Simp	    "restore -x [-dhmNuvy]", common, fileell);
3071558Srgrimes	done(1);
3081558Srgrimes}
3091558Srgrimes
3101558Srgrimes/*
3111558Srgrimes * obsolete --
3121558Srgrimes *	Change set of key letters and ordered arguments into something
3131558Srgrimes *	getopt(3) will like.
3141558Srgrimes */
3151558Srgrimesstatic void
31692837Simpobsolete(int *argcp, char **argvp[])
3171558Srgrimes{
3181558Srgrimes	int argc, flags;
3191558Srgrimes	char *ap, **argv, *flagsp, **nargv, *p;
3201558Srgrimes
3211558Srgrimes	/* Setup. */
3221558Srgrimes	argv = *argvp;
3231558Srgrimes	argc = *argcp;
3241558Srgrimes
3251558Srgrimes	/* Return if no arguments or first argument has leading dash. */
3261558Srgrimes	ap = argv[1];
3271558Srgrimes	if (argc == 1 || *ap == '-')
3281558Srgrimes		return;
3291558Srgrimes
3301558Srgrimes	/* Allocate space for new arguments. */
3311558Srgrimes	if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
3321558Srgrimes	    (p = flagsp = malloc(strlen(ap) + 2)) == NULL)
3331558Srgrimes		err(1, NULL);
3341558Srgrimes
3351558Srgrimes	*nargv++ = *argv;
33617261Sjkh	argv += 2, argc -= 2;
3371558Srgrimes
3381558Srgrimes	for (flags = 0; *ap; ++ap) {
33923685Speter		switch (*ap) {
3401558Srgrimes		case 'b':
3411558Srgrimes		case 'f':
3421558Srgrimes		case 's':
34323685Speter			if (*argv == NULL) {
34423685Speter				warnx("option requires an argument -- %c", *ap);
34523685Speter				usage();
34623685Speter			}
3471558Srgrimes			if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
3481558Srgrimes				err(1, NULL);
3491558Srgrimes			nargv[0][0] = '-';
3501558Srgrimes			nargv[0][1] = *ap;
3511558Srgrimes			(void)strcpy(&nargv[0][2], *argv);
35223685Speter			++argv;
3531558Srgrimes			++nargv;
3541558Srgrimes			break;
3551558Srgrimes		default:
3561558Srgrimes			if (!flags) {
3571558Srgrimes				*p++ = '-';
3581558Srgrimes				flags = 1;
3591558Srgrimes			}
3601558Srgrimes			*p++ = *ap;
3611558Srgrimes			break;
3621558Srgrimes		}
3631558Srgrimes	}
3641558Srgrimes
3651558Srgrimes	/* Terminate flags. */
3661558Srgrimes	if (flags) {
3671558Srgrimes		*p = '\0';
3681558Srgrimes		*nargv++ = flagsp;
369299148Spfg	} else
370299148Spfg		free(flagsp);
3711558Srgrimes
3721558Srgrimes	/* Copy remaining arguments. */
37337906Scharnier	while ((*nargv++ = *argv++));
37423685Speter
37523685Speter	/* Update argument count. */
37623685Speter	*argcp = nargv - *argvp - 1;
3771558Srgrimes}
378