xref: /onnv-gate/usr/src/cmd/backup/restore/main.c (revision 1053:667012633a0d)
10Sstevel@tonic-gate /*
2426Srm88369  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
70Sstevel@tonic-gate /*	  All Rights Reserved	*/
80Sstevel@tonic-gate 
90Sstevel@tonic-gate /*
100Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
110Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
120Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
130Sstevel@tonic-gate  */
140Sstevel@tonic-gate 
150Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
160Sstevel@tonic-gate 
170Sstevel@tonic-gate /*
180Sstevel@tonic-gate  *	Modified to recursively extract all files within a subtree
190Sstevel@tonic-gate  *	(supressed by the h option) and recreate the heirarchical
200Sstevel@tonic-gate  *	structure of that subtree and move extracted files to their
210Sstevel@tonic-gate  *	proper homes (supressed by the m option).
220Sstevel@tonic-gate  *	Includes the s (skip files) option for use with multiple
230Sstevel@tonic-gate  *	dumps on a single tape.
240Sstevel@tonic-gate  *	8/29/80		by Mike Litzkow
250Sstevel@tonic-gate  *
260Sstevel@tonic-gate  *	Modified to work on the new file system and to recover from
270Sstevel@tonic-gate  *	tape read errors.
280Sstevel@tonic-gate  *	1/19/82		by Kirk McKusick
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  *	Full incremental restore running entirely in user code and
310Sstevel@tonic-gate  *	interactive tape browser.
320Sstevel@tonic-gate  *	1/19/83		by Kirk McKusick
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include "restore.h"
360Sstevel@tonic-gate #include <signal.h>
370Sstevel@tonic-gate #include <byteorder.h>
380Sstevel@tonic-gate #include <priv_utils.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #include <euc.h>
410Sstevel@tonic-gate #include <getwidth.h>
420Sstevel@tonic-gate #include <sys/mtio.h>
430Sstevel@tonic-gate eucwidth_t wp;
440Sstevel@tonic-gate 
450Sstevel@tonic-gate int	bflag = 0, dflag = 0, vflag = 0, yflag = 0;
460Sstevel@tonic-gate int	hflag = 1, mflag = 1, paginating = 0, offline = 0, autoload = 0;
470Sstevel@tonic-gate int	autoload_tries;
480Sstevel@tonic-gate int	autoload_period;
490Sstevel@tonic-gate int	cvtflag = 0;		/* Converting from old dump format */
500Sstevel@tonic-gate char	command = '\0';
510Sstevel@tonic-gate long	dumpnum = 1;
520Sstevel@tonic-gate int	volno = 0;
530Sstevel@tonic-gate uint_t	ntrec;			/* blocking factor, in KB */
540Sstevel@tonic-gate uint_t	saved_ntrec;		/* saved blocking factor, in KB */
550Sstevel@tonic-gate ssize_t	tape_rec_size = 0;	/* tape record size (ntrec * tp_bsize) */
560Sstevel@tonic-gate size_t	newtapebuf_size = 0;	/* save size of last call to newtapebuf */
570Sstevel@tonic-gate char	*progname;
580Sstevel@tonic-gate char	*dumpmap;
590Sstevel@tonic-gate char	*clrimap;
600Sstevel@tonic-gate char	*c_label;		/* if non-NULL, we must see this tape label */
610Sstevel@tonic-gate ino_t	maxino;
620Sstevel@tonic-gate time_t	dumptime;
630Sstevel@tonic-gate time_t	dumpdate;
640Sstevel@tonic-gate FILE 	*terminal;
650Sstevel@tonic-gate char	*tmpdir;
660Sstevel@tonic-gate char	*pager_catenated;
670Sstevel@tonic-gate char	**pager_vector;
680Sstevel@tonic-gate int	pager_len;
690Sstevel@tonic-gate int	inattrspace = 0;
700Sstevel@tonic-gate int	savepwd;
710Sstevel@tonic-gate int32_t	tp_bsize = TP_BSIZE_MIN;
720Sstevel@tonic-gate struct byteorder_ctx *byteorder;
730Sstevel@tonic-gate 
740Sstevel@tonic-gate static void set_tmpdir(void);
750Sstevel@tonic-gate 
76*1053Smaheshvs int
main(int argc,char * argv[])77*1053Smaheshvs main(int argc, char *argv[])
780Sstevel@tonic-gate {
790Sstevel@tonic-gate 	static struct arglist alist = { 0, 0, 0, 0, 0 };
800Sstevel@tonic-gate 	int  count;
810Sstevel@tonic-gate 	char *cp;
820Sstevel@tonic-gate 	char *fname;
830Sstevel@tonic-gate 	ino_t ino;
840Sstevel@tonic-gate 	char *inputdev;
850Sstevel@tonic-gate 	char *archivefile = 0;
860Sstevel@tonic-gate 	char *symtbl = RESTORESYMTABLE;
870Sstevel@tonic-gate 	char name[MAXPATHLEN];
880Sstevel@tonic-gate 	int  fflag = 0;
890Sstevel@tonic-gate 	struct sigaction sa, osa;
900Sstevel@tonic-gate 	int multiplier;
910Sstevel@tonic-gate 	char units;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	if ((progname = strrchr(argv[0], '/')) != NULL)
940Sstevel@tonic-gate 		progname++;
950Sstevel@tonic-gate 	else
960Sstevel@tonic-gate 		progname = argv[0];
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	if (strcmp("hsmrestore", progname) == 0) {
990Sstevel@tonic-gate 		(void) fprintf(stderr,
1000Sstevel@tonic-gate 		    gettext("hsmrestore emulation is no longer supported.\n"));
1010Sstevel@tonic-gate 		done(1);
1020Sstevel@tonic-gate 	}
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	/*
1050Sstevel@tonic-gate 	 * Convert the effective uid of 0 to the single privilege
1060Sstevel@tonic-gate 	 * we really want.  When running with all privileges, this
1070Sstevel@tonic-gate 	 * is a no-op.  When the set-uid bit is stripped restore
1080Sstevel@tonic-gate 	 * still works for local tapes.  Fail when trying to access
1090Sstevel@tonic-gate 	 * a remote tape in that case and not immediately.
1100Sstevel@tonic-gate 	 */
1110Sstevel@tonic-gate 	(void) __init_suid_priv(0, PRIV_NET_PRIVADDR, (char *)NULL);
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	inputdev = DEFTAPE;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	/*
1160Sstevel@tonic-gate 	 * This doesn't work because ufsrestore is statically linked:
1170Sstevel@tonic-gate 	 * (void) setlocale(LC_ALL, "");
1180Sstevel@tonic-gate 	 * The problem seems to be with LC_COLLATE, so set all the
1190Sstevel@tonic-gate 	 * others explicitly.  Bug 1157128 was created against the I18N
1200Sstevel@tonic-gate 	 * library.  When that bug is fixed this should go back to the way
1210Sstevel@tonic-gate 	 * it was.
1220Sstevel@tonic-gate 	 * XXX 1157128 was closed as a dup of 1099747.  That bug was fixed by
1230Sstevel@tonic-gate 	 * disallowing setlocale() to anything other than "C".  "" is
1240Sstevel@tonic-gate 	 * allowed, but only if none of the envars LC_ALL, LC_COLLATE, or LANG
1250Sstevel@tonic-gate 	 * select anything other than "C".
1260Sstevel@tonic-gate 	 */
1270Sstevel@tonic-gate 	(void) setlocale(LC_CTYPE, "");
1280Sstevel@tonic-gate 	(void) setlocale(LC_NUMERIC, "");
1290Sstevel@tonic-gate 	(void) setlocale(LC_TIME, "");
1300Sstevel@tonic-gate 	(void) setlocale(LC_MONETARY, "");
1310Sstevel@tonic-gate 	(void) setlocale(LC_MESSAGES, "");
1320Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
1330Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
1340Sstevel@tonic-gate #endif
1350Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1360Sstevel@tonic-gate 	getwidth(&wp);
1370Sstevel@tonic-gate 	if ((byteorder = byteorder_create()) == NULL) {
1380Sstevel@tonic-gate 		(void) fprintf(stderr,
1390Sstevel@tonic-gate 		    gettext("Cannot create byteorder context\n"));
1400Sstevel@tonic-gate 		done(1);
1410Sstevel@tonic-gate 	}
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	if ((savepwd = open(".", O_RDONLY)) < 0) {
1440Sstevel@tonic-gate 		(void) fprintf(stderr,
1450Sstevel@tonic-gate 		    gettext("Cannot save current directory context\n"));
1460Sstevel@tonic-gate 		done(1);
1470Sstevel@tonic-gate 	}
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	set_tmpdir();
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	autoload_period = 12;
1520Sstevel@tonic-gate 	autoload_tries = 12;	/* traditional default of ~2.5 minutes */
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	sa.sa_handler = onintr;
1550Sstevel@tonic-gate 	sa.sa_flags = SA_RESTART;
1560Sstevel@tonic-gate 	(void) sigemptyset(&sa.sa_mask);
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	(void) sigaction(SIGINT, &sa, &osa);
1590Sstevel@tonic-gate 	if (osa.sa_handler == SIG_IGN)
1600Sstevel@tonic-gate 		(void) sigaction(SIGINT, &osa, (struct sigaction *)0);
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	(void) sigaction(SIGTERM, &sa, &osa);
1630Sstevel@tonic-gate 	if (osa.sa_handler == SIG_IGN)
1640Sstevel@tonic-gate 		(void) sigaction(SIGTERM, &osa, (struct sigaction *)0);
1650Sstevel@tonic-gate 	if (argc < 2) {
1660Sstevel@tonic-gate usage:
1670Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Usage:\n\
1680Sstevel@tonic-gate \t%s tabcdfhsvyLloT [file file ...]\n\
1690Sstevel@tonic-gate \t%s xabcdfhmsvyLloT [file file ...]\n\
1700Sstevel@tonic-gate \t%s iabcdfhmsvyLloT\n\
1710Sstevel@tonic-gate \t%s rabcdfsvyLloT\n\
1720Sstevel@tonic-gate \t%s RabcdfsvyLloT\n\n\
1730Sstevel@tonic-gate a requires an archive file name\n\
1740Sstevel@tonic-gate b requires a blocking factor\n\
1750Sstevel@tonic-gate f requires a dump file\n\
1760Sstevel@tonic-gate s requires a file number\n\
1770Sstevel@tonic-gate L requires a tape label\n\
1780Sstevel@tonic-gate If set, the envar TMPDIR selects where temporary files are kept\n"),
1790Sstevel@tonic-gate 		    progname, progname, progname, progname, progname);
1800Sstevel@tonic-gate 		done(1);
1810Sstevel@tonic-gate 	}
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	argv++;			/* the bag-of-options */
1840Sstevel@tonic-gate 	argc -= 2;		/* count of parameters to the options  */
1850Sstevel@tonic-gate 	command = '\0';
1860Sstevel@tonic-gate 	c_label = (char *)NULL;	/* any tape's acceptable */
1870Sstevel@tonic-gate 	for (cp = *argv++; *cp; cp++) {
1880Sstevel@tonic-gate 		switch (*cp) {		/* BE CAUTIOUS OF FALLTHROUGHS */
1890Sstevel@tonic-gate 		case 'T':
1900Sstevel@tonic-gate 			if (argc < 1) {
1910Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1920Sstevel@tonic-gate 				    "Missing autoload timeout period\n"));
1930Sstevel@tonic-gate 				done(1);
1940Sstevel@tonic-gate 			}
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 			count = atoi(*argv);
1970Sstevel@tonic-gate 			if (count < 1) {
1980Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1990Sstevel@tonic-gate 			    "Unreasonable autoload timeout period `%s'\n"),
2000Sstevel@tonic-gate 					*argv);
2010Sstevel@tonic-gate 				done(1);
2020Sstevel@tonic-gate 			}
2030Sstevel@tonic-gate 			units = *(*argv + strlen(*argv) - 1);
2040Sstevel@tonic-gate 			switch (units) {
2050Sstevel@tonic-gate 			case 's':
2060Sstevel@tonic-gate 				multiplier = 1;
2070Sstevel@tonic-gate 				break;
2080Sstevel@tonic-gate 			case 'h':
2090Sstevel@tonic-gate 				multiplier = 3600;
2100Sstevel@tonic-gate 				break;
2110Sstevel@tonic-gate 			case '0': case '1': case '2': case '3': case '4':
2120Sstevel@tonic-gate 			case '5': case '6': case '7': case '8': case '9':
2130Sstevel@tonic-gate 			case 'm':
2140Sstevel@tonic-gate 				multiplier = 60;
2150Sstevel@tonic-gate 				break;
2160Sstevel@tonic-gate 			default:
2170Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
2180Sstevel@tonic-gate 				    "Unknown timeout units indicator `%c'\n"),
2190Sstevel@tonic-gate 				    units);
2200Sstevel@tonic-gate 				done(1);
2210Sstevel@tonic-gate 			}
2220Sstevel@tonic-gate 			autoload_tries = 1 +
2230Sstevel@tonic-gate 			    ((count * multiplier) / autoload_period);
2240Sstevel@tonic-gate 			argv++;
2250Sstevel@tonic-gate 			argc--;
2260Sstevel@tonic-gate 			break;
2270Sstevel@tonic-gate 		case 'l':
2280Sstevel@tonic-gate 			autoload++;
229426Srm88369 			break;
2300Sstevel@tonic-gate 		case 'o':
2310Sstevel@tonic-gate 			offline++;
2320Sstevel@tonic-gate 			break;
2330Sstevel@tonic-gate 		case '-':
2340Sstevel@tonic-gate 			break;
2350Sstevel@tonic-gate 		case 'a':
2360Sstevel@tonic-gate 			if (argc < 1) {
2370Sstevel@tonic-gate 				(void) fprintf(stderr,
2380Sstevel@tonic-gate 					gettext("missing archive file name\n"));
2390Sstevel@tonic-gate 				done(1);
2400Sstevel@tonic-gate 			}
2410Sstevel@tonic-gate 			archivefile = *argv++;
2420Sstevel@tonic-gate 			if (*archivefile == '\0') {
2430Sstevel@tonic-gate 				(void) fprintf(stderr,
2440Sstevel@tonic-gate 				    gettext("empty archive file name\n"));
2450Sstevel@tonic-gate 				done(1);
2460Sstevel@tonic-gate 			}
2470Sstevel@tonic-gate 			argc--;
2480Sstevel@tonic-gate 			break;
2490Sstevel@tonic-gate 		case 'c':
2500Sstevel@tonic-gate 			cvtflag++;
2510Sstevel@tonic-gate 			break;
2520Sstevel@tonic-gate 		case 'd':
2530Sstevel@tonic-gate 			dflag++;
2540Sstevel@tonic-gate 			break;
2550Sstevel@tonic-gate 		case 'D':
2560Sstevel@tonic-gate 			/*
2570Sstevel@tonic-gate 			 * This used to be the Dflag, but it doesn't
2580Sstevel@tonic-gate 			 * hurt to always check, so was removed.  This
2590Sstevel@tonic-gate 			 * case is here for backward compatability.
2600Sstevel@tonic-gate 			 */
2610Sstevel@tonic-gate 			break;
2620Sstevel@tonic-gate 		case 'h':
2630Sstevel@tonic-gate 			hflag = 0;
2640Sstevel@tonic-gate 			break;
2650Sstevel@tonic-gate 		case 'm':
2660Sstevel@tonic-gate 			mflag = 0;
2670Sstevel@tonic-gate 			break;
2680Sstevel@tonic-gate 		case 'v':
2690Sstevel@tonic-gate 			vflag++;
2700Sstevel@tonic-gate 			break;
2710Sstevel@tonic-gate 		case 'y':
2720Sstevel@tonic-gate 			yflag++;
2730Sstevel@tonic-gate 			break;
2740Sstevel@tonic-gate 		case 'f':
2750Sstevel@tonic-gate 			if (argc < 1) {
2760Sstevel@tonic-gate 				(void) fprintf(stderr,
2770Sstevel@tonic-gate 				    gettext("missing device specifier\n"));
2780Sstevel@tonic-gate 				done(1);
2790Sstevel@tonic-gate 			}
2800Sstevel@tonic-gate 			inputdev = *argv++;
2810Sstevel@tonic-gate 			if (*inputdev == '\0') {
2820Sstevel@tonic-gate 				(void) fprintf(stderr,
2830Sstevel@tonic-gate 				    gettext("empty device specifier\n"));
2840Sstevel@tonic-gate 				done(1);
2850Sstevel@tonic-gate 			}
2860Sstevel@tonic-gate 			fflag++;
2870Sstevel@tonic-gate 			argc--;
2880Sstevel@tonic-gate 			break;
2890Sstevel@tonic-gate 		case 'b':
2900Sstevel@tonic-gate 			/*
2910Sstevel@tonic-gate 			 * change default tape blocksize
2920Sstevel@tonic-gate 			 */
2930Sstevel@tonic-gate 			bflag++;
2940Sstevel@tonic-gate 			if (argc < 1) {
2950Sstevel@tonic-gate 				(void) fprintf(stderr,
2960Sstevel@tonic-gate 					gettext("missing block size\n"));
2970Sstevel@tonic-gate 				done(1);
2980Sstevel@tonic-gate 			}
2990Sstevel@tonic-gate 			saved_ntrec = ntrec = atoi(*argv++);
3000Sstevel@tonic-gate 			if (ntrec == 0 || (ntrec&1)) {
3010Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3020Sstevel@tonic-gate 			    "Block size must be a positive, even integer\n"));
3030Sstevel@tonic-gate 				done(1);
3040Sstevel@tonic-gate 			}
3050Sstevel@tonic-gate 			ntrec /= (tp_bsize/DEV_BSIZE);
3060Sstevel@tonic-gate 			argc--;
3070Sstevel@tonic-gate 			break;
3080Sstevel@tonic-gate 		case 's':
3090Sstevel@tonic-gate 			/*
3100Sstevel@tonic-gate 			 * dumpnum (skip to) for multifile dump tapes
3110Sstevel@tonic-gate 			 */
3120Sstevel@tonic-gate 			if (argc < 1) {
3130Sstevel@tonic-gate 				(void) fprintf(stderr,
3140Sstevel@tonic-gate 					gettext("missing dump number\n"));
3150Sstevel@tonic-gate 				done(1);
3160Sstevel@tonic-gate 			}
3170Sstevel@tonic-gate 			dumpnum = atoi(*argv++);
3180Sstevel@tonic-gate 			if (dumpnum <= 0) {
3190Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3200Sstevel@tonic-gate 			    "Dump number must be a positive integer\n"));
3210Sstevel@tonic-gate 				done(1);
3220Sstevel@tonic-gate 			}
3230Sstevel@tonic-gate 			argc--;
3240Sstevel@tonic-gate 			break;
3250Sstevel@tonic-gate 		case 't':
3260Sstevel@tonic-gate 		case 'R':
3270Sstevel@tonic-gate 		case 'r':
3280Sstevel@tonic-gate 		case 'x':
3290Sstevel@tonic-gate 		case 'i':
3300Sstevel@tonic-gate 			if (command != '\0') {
3310Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3320Sstevel@tonic-gate 				    "%c and %c are mutually exclusive\n"),
3330Sstevel@tonic-gate 				    (uchar_t)*cp, (uchar_t)command);
3340Sstevel@tonic-gate 				goto usage;
3350Sstevel@tonic-gate 			}
3360Sstevel@tonic-gate 			command = *cp;
3370Sstevel@tonic-gate 			break;
3380Sstevel@tonic-gate 		case 'L':
3390Sstevel@tonic-gate 			if (argc < 1 || **argv == '\0') {
3400Sstevel@tonic-gate 				(void) fprintf(stderr,
3410Sstevel@tonic-gate 				    gettext("Missing tape label name\n"));
3420Sstevel@tonic-gate 				done(1);
3430Sstevel@tonic-gate 			}
3440Sstevel@tonic-gate 			c_label = *argv++; /* must get tape with this label */
3450Sstevel@tonic-gate 			if (strlen(c_label) > (sizeof (spcl.c_label) - 1)) {
3460Sstevel@tonic-gate 				c_label[sizeof (spcl.c_label) - 1] = '\0';
3470Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3480Sstevel@tonic-gate 		    "Truncating label to maximum supported length: `%s'\n"),
3490Sstevel@tonic-gate 				    c_label);
3500Sstevel@tonic-gate 			}
3510Sstevel@tonic-gate 			argc--;
3520Sstevel@tonic-gate 			break;
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 		default:
3550Sstevel@tonic-gate 			(void) fprintf(stderr,
3560Sstevel@tonic-gate 			    gettext("Bad key character %c\n"), (uchar_t)*cp);
3570Sstevel@tonic-gate 			goto usage;
3580Sstevel@tonic-gate 		}
3590Sstevel@tonic-gate 	}
3600Sstevel@tonic-gate 	if (command == '\0') {
3610Sstevel@tonic-gate 		(void) fprintf(stderr,
3620Sstevel@tonic-gate 		    gettext("must specify i, t, r, R, or x\n"));
3630Sstevel@tonic-gate 		goto usage;
3640Sstevel@tonic-gate 	}
3650Sstevel@tonic-gate 	setinput(inputdev, archivefile);
3660Sstevel@tonic-gate 	if (argc == 0) {	/* re-use last argv slot for default */
3670Sstevel@tonic-gate 		argc = 1;
3680Sstevel@tonic-gate 		*--argv = mflag ? "." : "2";
3690Sstevel@tonic-gate 	}
3700Sstevel@tonic-gate 	switch (command) {
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	/*
3730Sstevel@tonic-gate 	 * Interactive mode.
3740Sstevel@tonic-gate 	 */
3750Sstevel@tonic-gate 	case 'i':
3760Sstevel@tonic-gate 		setup();
3770Sstevel@tonic-gate 		extractdirs(1);
3780Sstevel@tonic-gate 		initsymtable((char *)0);
3790Sstevel@tonic-gate 		initpagercmd();
3800Sstevel@tonic-gate 		runcmdshell();
3810Sstevel@tonic-gate 		done(0);
3820Sstevel@tonic-gate 		/* NOTREACHED */
3830Sstevel@tonic-gate 	/*
3840Sstevel@tonic-gate 	 * Incremental restoration of a file system.
3850Sstevel@tonic-gate 	 */
3860Sstevel@tonic-gate 	case 'r':
3870Sstevel@tonic-gate 		setup();
3880Sstevel@tonic-gate 		if (dumptime > 0) {
3890Sstevel@tonic-gate 			/*
3900Sstevel@tonic-gate 			 * This is an incremental dump tape.
3910Sstevel@tonic-gate 			 */
3920Sstevel@tonic-gate 			vprintf(stdout, gettext("Begin incremental restore\n"));
3930Sstevel@tonic-gate 			initsymtable(symtbl);
3940Sstevel@tonic-gate 			extractdirs(1);
3950Sstevel@tonic-gate 			removeoldleaves();
3960Sstevel@tonic-gate 			vprintf(stdout, gettext("Calculate node updates.\n"));
3970Sstevel@tonic-gate 			strcpy(name, ".");
3980Sstevel@tonic-gate 			name[2] = '\0';
3990Sstevel@tonic-gate 			treescan(name, ROOTINO, nodeupdates);
4000Sstevel@tonic-gate 			attrscan(1, nodeupdates);
4010Sstevel@tonic-gate 			findunreflinks();
4020Sstevel@tonic-gate 			removeoldnodes();
4030Sstevel@tonic-gate 		} else {
4040Sstevel@tonic-gate 			/*
4050Sstevel@tonic-gate 			 * This is a level zero dump tape.
4060Sstevel@tonic-gate 			 */
4070Sstevel@tonic-gate 			vprintf(stdout, gettext("Begin level 0 restore\n"));
4080Sstevel@tonic-gate 			initsymtable((char *)0);
4090Sstevel@tonic-gate 			extractdirs(1);
4100Sstevel@tonic-gate 			vprintf(stdout,
4110Sstevel@tonic-gate 			    gettext("Calculate extraction list.\n"));
4120Sstevel@tonic-gate 			strcpy(name, ".");
4130Sstevel@tonic-gate 			name[2] = '\0';
4140Sstevel@tonic-gate 			treescan(name, ROOTINO, nodeupdates);
4150Sstevel@tonic-gate 			attrscan(1, nodeupdates);
4160Sstevel@tonic-gate 		}
4170Sstevel@tonic-gate 		createleaves(symtbl);
4180Sstevel@tonic-gate 		createlinks();
4190Sstevel@tonic-gate 		setdirmodes();
4200Sstevel@tonic-gate 		checkrestore();
4210Sstevel@tonic-gate 		if (dflag) {
4220Sstevel@tonic-gate 			vprintf(stdout,
4230Sstevel@tonic-gate 			    gettext("Verify the directory structure\n"));
4240Sstevel@tonic-gate 			strcpy(name, ".");
4250Sstevel@tonic-gate 			name[2] = '\0';
4260Sstevel@tonic-gate 			treescan(name, ROOTINO, verifyfile);
4270Sstevel@tonic-gate 		}
4280Sstevel@tonic-gate 		dumpsymtable(symtbl, (long)1);
4290Sstevel@tonic-gate 		done(0);
4300Sstevel@tonic-gate 		/* NOTREACHED */
4310Sstevel@tonic-gate 	/*
4320Sstevel@tonic-gate 	 * Resume an incremental file system restoration.
4330Sstevel@tonic-gate 	 */
4340Sstevel@tonic-gate 	case 'R':
4350Sstevel@tonic-gate 		setupR();
4360Sstevel@tonic-gate 		initsymtable(symtbl);
4370Sstevel@tonic-gate 		skipmaps();
4380Sstevel@tonic-gate 		skipdirs();
4390Sstevel@tonic-gate 		createleaves(symtbl);
4400Sstevel@tonic-gate 		createlinks();
4410Sstevel@tonic-gate 		setdirmodes();
4420Sstevel@tonic-gate 		checkrestore();
4430Sstevel@tonic-gate 		dumpsymtable(symtbl, (long)1);
4440Sstevel@tonic-gate 		done(0);
4450Sstevel@tonic-gate 		/* NOTREACHED */
4460Sstevel@tonic-gate 	/*
4470Sstevel@tonic-gate 	 * List contents of tape.
4480Sstevel@tonic-gate 	 */
4490Sstevel@tonic-gate 	case 't':
4500Sstevel@tonic-gate 		setup();
4510Sstevel@tonic-gate 		extractdirs(0);
4520Sstevel@tonic-gate 		initsymtable((char *)0);
4530Sstevel@tonic-gate 		if (vflag)
4540Sstevel@tonic-gate 			printdumpinfo();
4550Sstevel@tonic-gate 		while (argc--) {
4560Sstevel@tonic-gate 			canon(*argv++, name, sizeof (name));
4570Sstevel@tonic-gate 			name[strlen(name)+1] = '\0';
4580Sstevel@tonic-gate 			ino = dirlookup(name);
4590Sstevel@tonic-gate 			if (ino == 0)
4600Sstevel@tonic-gate 				continue;
4610Sstevel@tonic-gate 			treescan(name, ino, listfile);
4620Sstevel@tonic-gate 		}
4630Sstevel@tonic-gate 		done(0);
4640Sstevel@tonic-gate 		/* NOTREACHED */
4650Sstevel@tonic-gate 	/*
4660Sstevel@tonic-gate 	 * Batch extraction of tape contents.
4670Sstevel@tonic-gate 	 */
4680Sstevel@tonic-gate 	case 'x':
4690Sstevel@tonic-gate 		setup();
4700Sstevel@tonic-gate 		extractdirs(1);
4710Sstevel@tonic-gate 		initsymtable((char *)0);
4720Sstevel@tonic-gate 		while (argc--) {
4730Sstevel@tonic-gate 			if (mflag) {
4740Sstevel@tonic-gate 				canon(*argv++, name, sizeof (name));
4750Sstevel@tonic-gate 				if (expand(name, 0, &alist) == 0) {
4760Sstevel@tonic-gate 					/* no meta-characters to expand */
4770Sstevel@tonic-gate 					ino = dirlookup(name);
4780Sstevel@tonic-gate 					if (ino == 0)
4790Sstevel@tonic-gate 						continue;
4800Sstevel@tonic-gate 					pathcheck(name);
4810Sstevel@tonic-gate 				} else {
4820Sstevel@tonic-gate 					/* add each of the expansions */
4830Sstevel@tonic-gate 					while ((alist.last - alist.head) > 0) {
4840Sstevel@tonic-gate 						fname = alist.head->fname;
4850Sstevel@tonic-gate 						ino = dirlookup(fname);
4860Sstevel@tonic-gate 						if (ino != 0) {
4870Sstevel@tonic-gate 							pathcheck(fname);
4880Sstevel@tonic-gate 							treescan(fname, ino,
4890Sstevel@tonic-gate 							    addfile);
4900Sstevel@tonic-gate 						}
4910Sstevel@tonic-gate 						freename(fname);
4920Sstevel@tonic-gate 						alist.head++;
4930Sstevel@tonic-gate 					}
4940Sstevel@tonic-gate 					alist.head = (struct afile *)NULL;
4950Sstevel@tonic-gate 					continue; /* argc loop */
4960Sstevel@tonic-gate 				}
4970Sstevel@tonic-gate 			} else {
4980Sstevel@tonic-gate 				ino = (ino_t)atol(*argv);
4990Sstevel@tonic-gate 				if ((*(*argv++) == '-') || ino < ROOTINO) {
5000Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
5010Sstevel@tonic-gate 					    "bad inode number: %ld\n"),
5020Sstevel@tonic-gate 					    ino);
5030Sstevel@tonic-gate 					done(1);
5040Sstevel@tonic-gate 				}
5050Sstevel@tonic-gate 				name[0] = '\0';
5060Sstevel@tonic-gate 			}
5070Sstevel@tonic-gate 			treescan(name, ino, addfile);
5080Sstevel@tonic-gate 			attrscan(0, addfile);
5090Sstevel@tonic-gate 		}
5100Sstevel@tonic-gate 		createfiles();
5110Sstevel@tonic-gate 		createlinks();
5120Sstevel@tonic-gate 		setdirmodes();
5130Sstevel@tonic-gate 		if (dflag)
5140Sstevel@tonic-gate 			checkrestore();
5150Sstevel@tonic-gate 		done(0);
5160Sstevel@tonic-gate 		/* NOTREACHED */
5170Sstevel@tonic-gate 	}
5180Sstevel@tonic-gate 	return (0);
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate /*
5220Sstevel@tonic-gate  * Determine where the user wants us to put our temporary files,
5230Sstevel@tonic-gate  * and make sure we can actually do so.  Bail out if there's a problem.
5240Sstevel@tonic-gate  */
5250Sstevel@tonic-gate void
set_tmpdir(void)5260Sstevel@tonic-gate set_tmpdir(void)
5270Sstevel@tonic-gate {
5280Sstevel@tonic-gate 	int fd;
5290Sstevel@tonic-gate 	char name[MAXPATHLEN];
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	tmpdir = getenv("TMPDIR");
5320Sstevel@tonic-gate 	if ((tmpdir == (char *)NULL) || (*tmpdir == '\0'))
5330Sstevel@tonic-gate 		tmpdir = "/tmp";
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	if (*tmpdir != '/') {
5360Sstevel@tonic-gate 		(void) fprintf(stderr,
5370Sstevel@tonic-gate 		    gettext("TMPDIR is not an absolute path (`%s').\n"),
5380Sstevel@tonic-gate 		    tmpdir);
5390Sstevel@tonic-gate 		done(1);
5400Sstevel@tonic-gate 	}
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	/*
5430Sstevel@tonic-gate 	 * The actual use of tmpdir is in dirs.c, and is of the form
5440Sstevel@tonic-gate 	 * tmpdir + "/rst" + type (three characters) + "%ld.XXXXXX" +
5450Sstevel@tonic-gate 	 * a trailing NUL, where %ld is an arbitrary time_t.
5460Sstevel@tonic-gate 	 *
5470Sstevel@tonic-gate 	 * Thus, the magic 31 is strlen(itoa(MAX_TIME_T)) + "/rst" +
5480Sstevel@tonic-gate 	 * ".XXXXXX" + '\0'.  A time_t is 64 bits, so MAX_TIME_T is
5490Sstevel@tonic-gate 	 * LONG_MAX - nineteen digits.  In theory, so many things in
5500Sstevel@tonic-gate 	 * ufsrestore will break once time_t's value goes beyond 32
5510Sstevel@tonic-gate 	 * bits that it's not worth worrying about this particular
5520Sstevel@tonic-gate 	 * instance at this time, but we've got to start somewhere.
5530Sstevel@tonic-gate 	 *
5540Sstevel@tonic-gate 	 * Note that the use of a pid below is just for testing the
5550Sstevel@tonic-gate 	 * validity of the named directory.
5560Sstevel@tonic-gate 	 */
5570Sstevel@tonic-gate 	if (strlen(tmpdir) > (MAXPATHLEN - 31)) {
5580Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("TMPDIR too long\n"));
5590Sstevel@tonic-gate 		done(1);
5600Sstevel@tonic-gate 	}
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	/* Guaranteed to fit by above test (sizeof(time_t) >= sizeof(pid_t)) */
5630Sstevel@tonic-gate 	(void) snprintf(name, sizeof (name), "%s/rstdir.%ld", tmpdir, getpid());
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	/*
5660Sstevel@tonic-gate 	 * This is effectively a stripped-down version of safe_open(),
5670Sstevel@tonic-gate 	 * because if the file exists, we want to fail.
5680Sstevel@tonic-gate 	 */
5690Sstevel@tonic-gate 	fd = open(name, O_CREAT|O_EXCL|O_RDWR, 0600);
5700Sstevel@tonic-gate 	if (fd < 0) {
5710Sstevel@tonic-gate 		perror(gettext("Can not create temporary file"));
5720Sstevel@tonic-gate 		done(1);
5730Sstevel@tonic-gate 	}
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	(void) close(fd);
5760Sstevel@tonic-gate 	if (unlink(name) < 0) {
5770Sstevel@tonic-gate 		perror(gettext("Can not delete temporary file"));
5780Sstevel@tonic-gate 		done(1);
5790Sstevel@tonic-gate 	}
5800Sstevel@tonic-gate }
581