xref: /illumos-gate/usr/src/cmd/backup/restore/main.c (revision c0882bf4)
17c478bd9Sstevel@tonic-gate /*
233a5e6b2Srm  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
117c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
127c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate /*
167c478bd9Sstevel@tonic-gate  *	Modified to recursively extract all files within a subtree
177c478bd9Sstevel@tonic-gate  *	(supressed by the h option) and recreate the heirarchical
187c478bd9Sstevel@tonic-gate  *	structure of that subtree and move extracted files to their
197c478bd9Sstevel@tonic-gate  *	proper homes (supressed by the m option).
207c478bd9Sstevel@tonic-gate  *	Includes the s (skip files) option for use with multiple
217c478bd9Sstevel@tonic-gate  *	dumps on a single tape.
227c478bd9Sstevel@tonic-gate  *	8/29/80		by Mike Litzkow
237c478bd9Sstevel@tonic-gate  *
247c478bd9Sstevel@tonic-gate  *	Modified to work on the new file system and to recover from
257c478bd9Sstevel@tonic-gate  *	tape read errors.
267c478bd9Sstevel@tonic-gate  *	1/19/82		by Kirk McKusick
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  *	Full incremental restore running entirely in user code and
297c478bd9Sstevel@tonic-gate  *	interactive tape browser.
307c478bd9Sstevel@tonic-gate  *	1/19/83		by Kirk McKusick
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include "restore.h"
347c478bd9Sstevel@tonic-gate #include <signal.h>
357c478bd9Sstevel@tonic-gate #include <byteorder.h>
367c478bd9Sstevel@tonic-gate #include <priv_utils.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <euc.h>
397c478bd9Sstevel@tonic-gate #include <getwidth.h>
407c478bd9Sstevel@tonic-gate #include <sys/mtio.h>
417c478bd9Sstevel@tonic-gate eucwidth_t wp;
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate int	bflag = 0, dflag = 0, vflag = 0, yflag = 0;
447c478bd9Sstevel@tonic-gate int	hflag = 1, mflag = 1, paginating = 0, offline = 0, autoload = 0;
457c478bd9Sstevel@tonic-gate int	autoload_tries;
467c478bd9Sstevel@tonic-gate int	autoload_period;
477c478bd9Sstevel@tonic-gate int	cvtflag = 0;		/* Converting from old dump format */
487c478bd9Sstevel@tonic-gate char	command = '\0';
497c478bd9Sstevel@tonic-gate long	dumpnum = 1;
507c478bd9Sstevel@tonic-gate int	volno = 0;
517c478bd9Sstevel@tonic-gate uint_t	ntrec;			/* blocking factor, in KB */
527c478bd9Sstevel@tonic-gate uint_t	saved_ntrec;		/* saved blocking factor, in KB */
537c478bd9Sstevel@tonic-gate ssize_t	tape_rec_size = 0;	/* tape record size (ntrec * tp_bsize) */
547c478bd9Sstevel@tonic-gate size_t	newtapebuf_size = 0;	/* save size of last call to newtapebuf */
557c478bd9Sstevel@tonic-gate char	*progname;
567c478bd9Sstevel@tonic-gate char	*dumpmap;
577c478bd9Sstevel@tonic-gate char	*clrimap;
587c478bd9Sstevel@tonic-gate char	*c_label;		/* if non-NULL, we must see this tape label */
597c478bd9Sstevel@tonic-gate ino_t	maxino;
607c478bd9Sstevel@tonic-gate time_t	dumptime;
617c478bd9Sstevel@tonic-gate time_t	dumpdate;
627c478bd9Sstevel@tonic-gate FILE 	*terminal;
637c478bd9Sstevel@tonic-gate char	*tmpdir;
647c478bd9Sstevel@tonic-gate char	*pager_catenated;
657c478bd9Sstevel@tonic-gate char	**pager_vector;
667c478bd9Sstevel@tonic-gate int	pager_len;
677c478bd9Sstevel@tonic-gate int	inattrspace = 0;
687c478bd9Sstevel@tonic-gate int	savepwd;
697c478bd9Sstevel@tonic-gate int32_t	tp_bsize = TP_BSIZE_MIN;
707c478bd9Sstevel@tonic-gate struct byteorder_ctx *byteorder;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate static void set_tmpdir(void);
737c478bd9Sstevel@tonic-gate 
74*fe0e7ec4Smaheshvs int
main(int argc,char * argv[])75*fe0e7ec4Smaheshvs main(int argc, char *argv[])
767c478bd9Sstevel@tonic-gate {
777c478bd9Sstevel@tonic-gate 	static struct arglist alist = { 0, 0, 0, 0, 0 };
787c478bd9Sstevel@tonic-gate 	int  count;
797c478bd9Sstevel@tonic-gate 	char *cp;
807c478bd9Sstevel@tonic-gate 	char *fname;
817c478bd9Sstevel@tonic-gate 	ino_t ino;
827c478bd9Sstevel@tonic-gate 	char *inputdev;
837c478bd9Sstevel@tonic-gate 	char *archivefile = 0;
847c478bd9Sstevel@tonic-gate 	char *symtbl = RESTORESYMTABLE;
857c478bd9Sstevel@tonic-gate 	char name[MAXPATHLEN];
867c478bd9Sstevel@tonic-gate 	int  fflag = 0;
877c478bd9Sstevel@tonic-gate 	struct sigaction sa, osa;
887c478bd9Sstevel@tonic-gate 	int multiplier;
897c478bd9Sstevel@tonic-gate 	char units;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	if ((progname = strrchr(argv[0], '/')) != NULL)
927c478bd9Sstevel@tonic-gate 		progname++;
937c478bd9Sstevel@tonic-gate 	else
947c478bd9Sstevel@tonic-gate 		progname = argv[0];
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	if (strcmp("hsmrestore", progname) == 0) {
977c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
987c478bd9Sstevel@tonic-gate 		    gettext("hsmrestore emulation is no longer supported.\n"));
997c478bd9Sstevel@tonic-gate 		done(1);
1007c478bd9Sstevel@tonic-gate 	}
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	/*
1037c478bd9Sstevel@tonic-gate 	 * Convert the effective uid of 0 to the single privilege
1047c478bd9Sstevel@tonic-gate 	 * we really want.  When running with all privileges, this
1057c478bd9Sstevel@tonic-gate 	 * is a no-op.  When the set-uid bit is stripped restore
1067c478bd9Sstevel@tonic-gate 	 * still works for local tapes.  Fail when trying to access
1077c478bd9Sstevel@tonic-gate 	 * a remote tape in that case and not immediately.
1087c478bd9Sstevel@tonic-gate 	 */
1097c478bd9Sstevel@tonic-gate 	(void) __init_suid_priv(0, PRIV_NET_PRIVADDR, (char *)NULL);
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	inputdev = DEFTAPE;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	/*
1147c478bd9Sstevel@tonic-gate 	 * This doesn't work because ufsrestore is statically linked:
1157c478bd9Sstevel@tonic-gate 	 * (void) setlocale(LC_ALL, "");
1167c478bd9Sstevel@tonic-gate 	 * The problem seems to be with LC_COLLATE, so set all the
1177c478bd9Sstevel@tonic-gate 	 * others explicitly.  Bug 1157128 was created against the I18N
1187c478bd9Sstevel@tonic-gate 	 * library.  When that bug is fixed this should go back to the way
1197c478bd9Sstevel@tonic-gate 	 * it was.
1207c478bd9Sstevel@tonic-gate 	 * XXX 1157128 was closed as a dup of 1099747.  That bug was fixed by
1217c478bd9Sstevel@tonic-gate 	 * disallowing setlocale() to anything other than "C".  "" is
1227c478bd9Sstevel@tonic-gate 	 * allowed, but only if none of the envars LC_ALL, LC_COLLATE, or LANG
1237c478bd9Sstevel@tonic-gate 	 * select anything other than "C".
1247c478bd9Sstevel@tonic-gate 	 */
1257c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_CTYPE, "");
1267c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_NUMERIC, "");
1277c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_TIME, "");
1287c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_MONETARY, "");
1297c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_MESSAGES, "");
1307c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
1317c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
1327c478bd9Sstevel@tonic-gate #endif
1337c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1347c478bd9Sstevel@tonic-gate 	getwidth(&wp);
1357c478bd9Sstevel@tonic-gate 	if ((byteorder = byteorder_create()) == NULL) {
1367c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1377c478bd9Sstevel@tonic-gate 		    gettext("Cannot create byteorder context\n"));
1387c478bd9Sstevel@tonic-gate 		done(1);
1397c478bd9Sstevel@tonic-gate 	}
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	if ((savepwd = open(".", O_RDONLY)) < 0) {
1427c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1437c478bd9Sstevel@tonic-gate 		    gettext("Cannot save current directory context\n"));
1447c478bd9Sstevel@tonic-gate 		done(1);
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	set_tmpdir();
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	autoload_period = 12;
1507c478bd9Sstevel@tonic-gate 	autoload_tries = 12;	/* traditional default of ~2.5 minutes */
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	sa.sa_handler = onintr;
1537c478bd9Sstevel@tonic-gate 	sa.sa_flags = SA_RESTART;
1547c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sa.sa_mask);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGINT, &sa, &osa);
1577c478bd9Sstevel@tonic-gate 	if (osa.sa_handler == SIG_IGN)
1587c478bd9Sstevel@tonic-gate 		(void) sigaction(SIGINT, &osa, (struct sigaction *)0);
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGTERM, &sa, &osa);
1617c478bd9Sstevel@tonic-gate 	if (osa.sa_handler == SIG_IGN)
1627c478bd9Sstevel@tonic-gate 		(void) sigaction(SIGTERM, &osa, (struct sigaction *)0);
1637c478bd9Sstevel@tonic-gate 	if (argc < 2) {
1647c478bd9Sstevel@tonic-gate usage:
1657c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Usage:\n\
1667c478bd9Sstevel@tonic-gate \t%s tabcdfhsvyLloT [file file ...]\n\
1677c478bd9Sstevel@tonic-gate \t%s xabcdfhmsvyLloT [file file ...]\n\
1687c478bd9Sstevel@tonic-gate \t%s iabcdfhmsvyLloT\n\
1697c478bd9Sstevel@tonic-gate \t%s rabcdfsvyLloT\n\
1707c478bd9Sstevel@tonic-gate \t%s RabcdfsvyLloT\n\n\
1717c478bd9Sstevel@tonic-gate a requires an archive file name\n\
1727c478bd9Sstevel@tonic-gate b requires a blocking factor\n\
1737c478bd9Sstevel@tonic-gate f requires a dump file\n\
1747c478bd9Sstevel@tonic-gate s requires a file number\n\
1757c478bd9Sstevel@tonic-gate L requires a tape label\n\
1767c478bd9Sstevel@tonic-gate If set, the envar TMPDIR selects where temporary files are kept\n"),
1777c478bd9Sstevel@tonic-gate 		    progname, progname, progname, progname, progname);
1787c478bd9Sstevel@tonic-gate 		done(1);
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	argv++;			/* the bag-of-options */
1827c478bd9Sstevel@tonic-gate 	argc -= 2;		/* count of parameters to the options  */
1837c478bd9Sstevel@tonic-gate 	command = '\0';
1847c478bd9Sstevel@tonic-gate 	c_label = (char *)NULL;	/* any tape's acceptable */
1857c478bd9Sstevel@tonic-gate 	for (cp = *argv++; *cp; cp++) {
1867c478bd9Sstevel@tonic-gate 		switch (*cp) {		/* BE CAUTIOUS OF FALLTHROUGHS */
1877c478bd9Sstevel@tonic-gate 		case 'T':
1887c478bd9Sstevel@tonic-gate 			if (argc < 1) {
1897c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1907c478bd9Sstevel@tonic-gate 				    "Missing autoload timeout period\n"));
1917c478bd9Sstevel@tonic-gate 				done(1);
1927c478bd9Sstevel@tonic-gate 			}
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 			count = atoi(*argv);
1957c478bd9Sstevel@tonic-gate 			if (count < 1) {
1967c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1977c478bd9Sstevel@tonic-gate 			    "Unreasonable autoload timeout period `%s'\n"),
1987c478bd9Sstevel@tonic-gate 					*argv);
1997c478bd9Sstevel@tonic-gate 				done(1);
2007c478bd9Sstevel@tonic-gate 			}
2017c478bd9Sstevel@tonic-gate 			units = *(*argv + strlen(*argv) - 1);
2027c478bd9Sstevel@tonic-gate 			switch (units) {
2037c478bd9Sstevel@tonic-gate 			case 's':
2047c478bd9Sstevel@tonic-gate 				multiplier = 1;
2057c478bd9Sstevel@tonic-gate 				break;
2067c478bd9Sstevel@tonic-gate 			case 'h':
2077c478bd9Sstevel@tonic-gate 				multiplier = 3600;
2087c478bd9Sstevel@tonic-gate 				break;
2097c478bd9Sstevel@tonic-gate 			case '0': case '1': case '2': case '3': case '4':
2107c478bd9Sstevel@tonic-gate 			case '5': case '6': case '7': case '8': case '9':
2117c478bd9Sstevel@tonic-gate 			case 'm':
2127c478bd9Sstevel@tonic-gate 				multiplier = 60;
2137c478bd9Sstevel@tonic-gate 				break;
2147c478bd9Sstevel@tonic-gate 			default:
2157c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
2167c478bd9Sstevel@tonic-gate 				    "Unknown timeout units indicator `%c'\n"),
2177c478bd9Sstevel@tonic-gate 				    units);
2187c478bd9Sstevel@tonic-gate 				done(1);
2197c478bd9Sstevel@tonic-gate 			}
2207c478bd9Sstevel@tonic-gate 			autoload_tries = 1 +
2217c478bd9Sstevel@tonic-gate 			    ((count * multiplier) / autoload_period);
2227c478bd9Sstevel@tonic-gate 			argv++;
2237c478bd9Sstevel@tonic-gate 			argc--;
2247c478bd9Sstevel@tonic-gate 			break;
2257c478bd9Sstevel@tonic-gate 		case 'l':
2267c478bd9Sstevel@tonic-gate 			autoload++;
22733a5e6b2Srm 			break;
2287c478bd9Sstevel@tonic-gate 		case 'o':
2297c478bd9Sstevel@tonic-gate 			offline++;
2307c478bd9Sstevel@tonic-gate 			break;
2317c478bd9Sstevel@tonic-gate 		case '-':
2327c478bd9Sstevel@tonic-gate 			break;
2337c478bd9Sstevel@tonic-gate 		case 'a':
2347c478bd9Sstevel@tonic-gate 			if (argc < 1) {
2357c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
2367c478bd9Sstevel@tonic-gate 					gettext("missing archive file name\n"));
2377c478bd9Sstevel@tonic-gate 				done(1);
2387c478bd9Sstevel@tonic-gate 			}
2397c478bd9Sstevel@tonic-gate 			archivefile = *argv++;
2407c478bd9Sstevel@tonic-gate 			if (*archivefile == '\0') {
2417c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
2427c478bd9Sstevel@tonic-gate 				    gettext("empty archive file name\n"));
2437c478bd9Sstevel@tonic-gate 				done(1);
2447c478bd9Sstevel@tonic-gate 			}
2457c478bd9Sstevel@tonic-gate 			argc--;
2467c478bd9Sstevel@tonic-gate 			break;
2477c478bd9Sstevel@tonic-gate 		case 'c':
2487c478bd9Sstevel@tonic-gate 			cvtflag++;
2497c478bd9Sstevel@tonic-gate 			break;
2507c478bd9Sstevel@tonic-gate 		case 'd':
2517c478bd9Sstevel@tonic-gate 			dflag++;
2527c478bd9Sstevel@tonic-gate 			break;
2537c478bd9Sstevel@tonic-gate 		case 'D':
2547c478bd9Sstevel@tonic-gate 			/*
2557c478bd9Sstevel@tonic-gate 			 * This used to be the Dflag, but it doesn't
2567c478bd9Sstevel@tonic-gate 			 * hurt to always check, so was removed.  This
2577c478bd9Sstevel@tonic-gate 			 * case is here for backward compatability.
2587c478bd9Sstevel@tonic-gate 			 */
2597c478bd9Sstevel@tonic-gate 			break;
2607c478bd9Sstevel@tonic-gate 		case 'h':
2617c478bd9Sstevel@tonic-gate 			hflag = 0;
2627c478bd9Sstevel@tonic-gate 			break;
2637c478bd9Sstevel@tonic-gate 		case 'm':
2647c478bd9Sstevel@tonic-gate 			mflag = 0;
2657c478bd9Sstevel@tonic-gate 			break;
2667c478bd9Sstevel@tonic-gate 		case 'v':
2677c478bd9Sstevel@tonic-gate 			vflag++;
2687c478bd9Sstevel@tonic-gate 			break;
2697c478bd9Sstevel@tonic-gate 		case 'y':
2707c478bd9Sstevel@tonic-gate 			yflag++;
2717c478bd9Sstevel@tonic-gate 			break;
2727c478bd9Sstevel@tonic-gate 		case 'f':
2737c478bd9Sstevel@tonic-gate 			if (argc < 1) {
2747c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
2757c478bd9Sstevel@tonic-gate 				    gettext("missing device specifier\n"));
2767c478bd9Sstevel@tonic-gate 				done(1);
2777c478bd9Sstevel@tonic-gate 			}
2787c478bd9Sstevel@tonic-gate 			inputdev = *argv++;
2797c478bd9Sstevel@tonic-gate 			if (*inputdev == '\0') {
2807c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
2817c478bd9Sstevel@tonic-gate 				    gettext("empty device specifier\n"));
2827c478bd9Sstevel@tonic-gate 				done(1);
2837c478bd9Sstevel@tonic-gate 			}
2847c478bd9Sstevel@tonic-gate 			fflag++;
2857c478bd9Sstevel@tonic-gate 			argc--;
2867c478bd9Sstevel@tonic-gate 			break;
2877c478bd9Sstevel@tonic-gate 		case 'b':
2887c478bd9Sstevel@tonic-gate 			/*
2897c478bd9Sstevel@tonic-gate 			 * change default tape blocksize
2907c478bd9Sstevel@tonic-gate 			 */
2917c478bd9Sstevel@tonic-gate 			bflag++;
2927c478bd9Sstevel@tonic-gate 			if (argc < 1) {
2937c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
2947c478bd9Sstevel@tonic-gate 					gettext("missing block size\n"));
2957c478bd9Sstevel@tonic-gate 				done(1);
2967c478bd9Sstevel@tonic-gate 			}
2977c478bd9Sstevel@tonic-gate 			saved_ntrec = ntrec = atoi(*argv++);
2987c478bd9Sstevel@tonic-gate 			if (ntrec == 0 || (ntrec&1)) {
2997c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3007c478bd9Sstevel@tonic-gate 			    "Block size must be a positive, even integer\n"));
3017c478bd9Sstevel@tonic-gate 				done(1);
3027c478bd9Sstevel@tonic-gate 			}
3037c478bd9Sstevel@tonic-gate 			ntrec /= (tp_bsize/DEV_BSIZE);
3047c478bd9Sstevel@tonic-gate 			argc--;
3057c478bd9Sstevel@tonic-gate 			break;
3067c478bd9Sstevel@tonic-gate 		case 's':
3077c478bd9Sstevel@tonic-gate 			/*
3087c478bd9Sstevel@tonic-gate 			 * dumpnum (skip to) for multifile dump tapes
3097c478bd9Sstevel@tonic-gate 			 */
3107c478bd9Sstevel@tonic-gate 			if (argc < 1) {
3117c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3127c478bd9Sstevel@tonic-gate 					gettext("missing dump number\n"));
3137c478bd9Sstevel@tonic-gate 				done(1);
3147c478bd9Sstevel@tonic-gate 			}
3157c478bd9Sstevel@tonic-gate 			dumpnum = atoi(*argv++);
3167c478bd9Sstevel@tonic-gate 			if (dumpnum <= 0) {
3177c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3187c478bd9Sstevel@tonic-gate 			    "Dump number must be a positive integer\n"));
3197c478bd9Sstevel@tonic-gate 				done(1);
3207c478bd9Sstevel@tonic-gate 			}
3217c478bd9Sstevel@tonic-gate 			argc--;
3227c478bd9Sstevel@tonic-gate 			break;
3237c478bd9Sstevel@tonic-gate 		case 't':
3247c478bd9Sstevel@tonic-gate 		case 'R':
3257c478bd9Sstevel@tonic-gate 		case 'r':
3267c478bd9Sstevel@tonic-gate 		case 'x':
3277c478bd9Sstevel@tonic-gate 		case 'i':
3287c478bd9Sstevel@tonic-gate 			if (command != '\0') {
3297c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3307c478bd9Sstevel@tonic-gate 				    "%c and %c are mutually exclusive\n"),
3317c478bd9Sstevel@tonic-gate 				    (uchar_t)*cp, (uchar_t)command);
3327c478bd9Sstevel@tonic-gate 				goto usage;
3337c478bd9Sstevel@tonic-gate 			}
3347c478bd9Sstevel@tonic-gate 			command = *cp;
3357c478bd9Sstevel@tonic-gate 			break;
3367c478bd9Sstevel@tonic-gate 		case 'L':
3377c478bd9Sstevel@tonic-gate 			if (argc < 1 || **argv == '\0') {
3387c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3397c478bd9Sstevel@tonic-gate 				    gettext("Missing tape label name\n"));
3407c478bd9Sstevel@tonic-gate 				done(1);
3417c478bd9Sstevel@tonic-gate 			}
3427c478bd9Sstevel@tonic-gate 			c_label = *argv++; /* must get tape with this label */
3437c478bd9Sstevel@tonic-gate 			if (strlen(c_label) > (sizeof (spcl.c_label) - 1)) {
3447c478bd9Sstevel@tonic-gate 				c_label[sizeof (spcl.c_label) - 1] = '\0';
3457c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3467c478bd9Sstevel@tonic-gate 		    "Truncating label to maximum supported length: `%s'\n"),
3477c478bd9Sstevel@tonic-gate 				    c_label);
3487c478bd9Sstevel@tonic-gate 			}
3497c478bd9Sstevel@tonic-gate 			argc--;
3507c478bd9Sstevel@tonic-gate 			break;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 		default:
3537c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
3547c478bd9Sstevel@tonic-gate 			    gettext("Bad key character %c\n"), (uchar_t)*cp);
3557c478bd9Sstevel@tonic-gate 			goto usage;
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 	if (command == '\0') {
3597c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
3607c478bd9Sstevel@tonic-gate 		    gettext("must specify i, t, r, R, or x\n"));
3617c478bd9Sstevel@tonic-gate 		goto usage;
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 	setinput(inputdev, archivefile);
3647c478bd9Sstevel@tonic-gate 	if (argc == 0) {	/* re-use last argv slot for default */
3657c478bd9Sstevel@tonic-gate 		argc = 1;
3667c478bd9Sstevel@tonic-gate 		*--argv = mflag ? "." : "2";
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 	switch (command) {
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	/*
3717c478bd9Sstevel@tonic-gate 	 * Interactive mode.
3727c478bd9Sstevel@tonic-gate 	 */
3737c478bd9Sstevel@tonic-gate 	case 'i':
3747c478bd9Sstevel@tonic-gate 		setup();
3757c478bd9Sstevel@tonic-gate 		extractdirs(1);
3767c478bd9Sstevel@tonic-gate 		initsymtable((char *)0);
3777c478bd9Sstevel@tonic-gate 		initpagercmd();
3787c478bd9Sstevel@tonic-gate 		runcmdshell();
3797c478bd9Sstevel@tonic-gate 		done(0);
3807c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
3817c478bd9Sstevel@tonic-gate 	/*
3827c478bd9Sstevel@tonic-gate 	 * Incremental restoration of a file system.
3837c478bd9Sstevel@tonic-gate 	 */
3847c478bd9Sstevel@tonic-gate 	case 'r':
3857c478bd9Sstevel@tonic-gate 		setup();
3867c478bd9Sstevel@tonic-gate 		if (dumptime > 0) {
3877c478bd9Sstevel@tonic-gate 			/*
3887c478bd9Sstevel@tonic-gate 			 * This is an incremental dump tape.
3897c478bd9Sstevel@tonic-gate 			 */
3907c478bd9Sstevel@tonic-gate 			vprintf(stdout, gettext("Begin incremental restore\n"));
3917c478bd9Sstevel@tonic-gate 			initsymtable(symtbl);
3927c478bd9Sstevel@tonic-gate 			extractdirs(1);
3937c478bd9Sstevel@tonic-gate 			removeoldleaves();
3947c478bd9Sstevel@tonic-gate 			vprintf(stdout, gettext("Calculate node updates.\n"));
3957c478bd9Sstevel@tonic-gate 			strcpy(name, ".");
3967c478bd9Sstevel@tonic-gate 			name[2] = '\0';
3977c478bd9Sstevel@tonic-gate 			treescan(name, ROOTINO, nodeupdates);
3987c478bd9Sstevel@tonic-gate 			attrscan(1, nodeupdates);
3997c478bd9Sstevel@tonic-gate 			findunreflinks();
4007c478bd9Sstevel@tonic-gate 			removeoldnodes();
4017c478bd9Sstevel@tonic-gate 		} else {
4027c478bd9Sstevel@tonic-gate 			/*
4037c478bd9Sstevel@tonic-gate 			 * This is a level zero dump tape.
4047c478bd9Sstevel@tonic-gate 			 */
4057c478bd9Sstevel@tonic-gate 			vprintf(stdout, gettext("Begin level 0 restore\n"));
4067c478bd9Sstevel@tonic-gate 			initsymtable((char *)0);
4077c478bd9Sstevel@tonic-gate 			extractdirs(1);
4087c478bd9Sstevel@tonic-gate 			vprintf(stdout,
4097c478bd9Sstevel@tonic-gate 			    gettext("Calculate extraction list.\n"));
4107c478bd9Sstevel@tonic-gate 			strcpy(name, ".");
4117c478bd9Sstevel@tonic-gate 			name[2] = '\0';
4127c478bd9Sstevel@tonic-gate 			treescan(name, ROOTINO, nodeupdates);
4137c478bd9Sstevel@tonic-gate 			attrscan(1, nodeupdates);
4147c478bd9Sstevel@tonic-gate 		}
4157c478bd9Sstevel@tonic-gate 		createleaves(symtbl);
4167c478bd9Sstevel@tonic-gate 		createlinks();
4177c478bd9Sstevel@tonic-gate 		setdirmodes();
4187c478bd9Sstevel@tonic-gate 		checkrestore();
4197c478bd9Sstevel@tonic-gate 		if (dflag) {
4207c478bd9Sstevel@tonic-gate 			vprintf(stdout,
4217c478bd9Sstevel@tonic-gate 			    gettext("Verify the directory structure\n"));
4227c478bd9Sstevel@tonic-gate 			strcpy(name, ".");
4237c478bd9Sstevel@tonic-gate 			name[2] = '\0';
4247c478bd9Sstevel@tonic-gate 			treescan(name, ROOTINO, verifyfile);
4257c478bd9Sstevel@tonic-gate 		}
4267c478bd9Sstevel@tonic-gate 		dumpsymtable(symtbl, (long)1);
4277c478bd9Sstevel@tonic-gate 		done(0);
4287c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
4297c478bd9Sstevel@tonic-gate 	/*
4307c478bd9Sstevel@tonic-gate 	 * Resume an incremental file system restoration.
4317c478bd9Sstevel@tonic-gate 	 */
4327c478bd9Sstevel@tonic-gate 	case 'R':
4337c478bd9Sstevel@tonic-gate 		setupR();
4347c478bd9Sstevel@tonic-gate 		initsymtable(symtbl);
4357c478bd9Sstevel@tonic-gate 		skipmaps();
4367c478bd9Sstevel@tonic-gate 		skipdirs();
4377c478bd9Sstevel@tonic-gate 		createleaves(symtbl);
4387c478bd9Sstevel@tonic-gate 		createlinks();
4397c478bd9Sstevel@tonic-gate 		setdirmodes();
4407c478bd9Sstevel@tonic-gate 		checkrestore();
4417c478bd9Sstevel@tonic-gate 		dumpsymtable(symtbl, (long)1);
4427c478bd9Sstevel@tonic-gate 		done(0);
4437c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
4447c478bd9Sstevel@tonic-gate 	/*
4457c478bd9Sstevel@tonic-gate 	 * List contents of tape.
4467c478bd9Sstevel@tonic-gate 	 */
4477c478bd9Sstevel@tonic-gate 	case 't':
4487c478bd9Sstevel@tonic-gate 		setup();
4497c478bd9Sstevel@tonic-gate 		extractdirs(0);
4507c478bd9Sstevel@tonic-gate 		initsymtable((char *)0);
4517c478bd9Sstevel@tonic-gate 		if (vflag)
4527c478bd9Sstevel@tonic-gate 			printdumpinfo();
4537c478bd9Sstevel@tonic-gate 		while (argc--) {
4547c478bd9Sstevel@tonic-gate 			canon(*argv++, name, sizeof (name));
4557c478bd9Sstevel@tonic-gate 			name[strlen(name)+1] = '\0';
4567c478bd9Sstevel@tonic-gate 			ino = dirlookup(name);
4577c478bd9Sstevel@tonic-gate 			if (ino == 0)
4587c478bd9Sstevel@tonic-gate 				continue;
4597c478bd9Sstevel@tonic-gate 			treescan(name, ino, listfile);
4607c478bd9Sstevel@tonic-gate 		}
4617c478bd9Sstevel@tonic-gate 		done(0);
4627c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
4637c478bd9Sstevel@tonic-gate 	/*
4647c478bd9Sstevel@tonic-gate 	 * Batch extraction of tape contents.
4657c478bd9Sstevel@tonic-gate 	 */
4667c478bd9Sstevel@tonic-gate 	case 'x':
4677c478bd9Sstevel@tonic-gate 		setup();
4687c478bd9Sstevel@tonic-gate 		extractdirs(1);
4697c478bd9Sstevel@tonic-gate 		initsymtable((char *)0);
4707c478bd9Sstevel@tonic-gate 		while (argc--) {
4717c478bd9Sstevel@tonic-gate 			if (mflag) {
4727c478bd9Sstevel@tonic-gate 				canon(*argv++, name, sizeof (name));
4737c478bd9Sstevel@tonic-gate 				if (expand(name, 0, &alist) == 0) {
4747c478bd9Sstevel@tonic-gate 					/* no meta-characters to expand */
4757c478bd9Sstevel@tonic-gate 					ino = dirlookup(name);
4767c478bd9Sstevel@tonic-gate 					if (ino == 0)
4777c478bd9Sstevel@tonic-gate 						continue;
4787c478bd9Sstevel@tonic-gate 					pathcheck(name);
4797c478bd9Sstevel@tonic-gate 				} else {
4807c478bd9Sstevel@tonic-gate 					/* add each of the expansions */
4817c478bd9Sstevel@tonic-gate 					while ((alist.last - alist.head) > 0) {
4827c478bd9Sstevel@tonic-gate 						fname = alist.head->fname;
4837c478bd9Sstevel@tonic-gate 						ino = dirlookup(fname);
4847c478bd9Sstevel@tonic-gate 						if (ino != 0) {
4857c478bd9Sstevel@tonic-gate 							pathcheck(fname);
4867c478bd9Sstevel@tonic-gate 							treescan(fname, ino,
4877c478bd9Sstevel@tonic-gate 							    addfile);
4887c478bd9Sstevel@tonic-gate 						}
4897c478bd9Sstevel@tonic-gate 						freename(fname);
4907c478bd9Sstevel@tonic-gate 						alist.head++;
4917c478bd9Sstevel@tonic-gate 					}
4927c478bd9Sstevel@tonic-gate 					alist.head = (struct afile *)NULL;
4937c478bd9Sstevel@tonic-gate 					continue; /* argc loop */
4947c478bd9Sstevel@tonic-gate 				}
4957c478bd9Sstevel@tonic-gate 			} else {
4967c478bd9Sstevel@tonic-gate 				ino = (ino_t)atol(*argv);
4977c478bd9Sstevel@tonic-gate 				if ((*(*argv++) == '-') || ino < ROOTINO) {
4987c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
4997c478bd9Sstevel@tonic-gate 					    "bad inode number: %ld\n"),
5007c478bd9Sstevel@tonic-gate 					    ino);
5017c478bd9Sstevel@tonic-gate 					done(1);
5027c478bd9Sstevel@tonic-gate 				}
5037c478bd9Sstevel@tonic-gate 				name[0] = '\0';
5047c478bd9Sstevel@tonic-gate 			}
5057c478bd9Sstevel@tonic-gate 			treescan(name, ino, addfile);
5067c478bd9Sstevel@tonic-gate 			attrscan(0, addfile);
5077c478bd9Sstevel@tonic-gate 		}
5087c478bd9Sstevel@tonic-gate 		createfiles();
5097c478bd9Sstevel@tonic-gate 		createlinks();
5107c478bd9Sstevel@tonic-gate 		setdirmodes();
5117c478bd9Sstevel@tonic-gate 		if (dflag)
5127c478bd9Sstevel@tonic-gate 			checkrestore();
5137c478bd9Sstevel@tonic-gate 		done(0);
5147c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
5157c478bd9Sstevel@tonic-gate 	}
5167c478bd9Sstevel@tonic-gate 	return (0);
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate /*
5207c478bd9Sstevel@tonic-gate  * Determine where the user wants us to put our temporary files,
5217c478bd9Sstevel@tonic-gate  * and make sure we can actually do so.  Bail out if there's a problem.
5227c478bd9Sstevel@tonic-gate  */
5237c478bd9Sstevel@tonic-gate void
set_tmpdir(void)5247c478bd9Sstevel@tonic-gate set_tmpdir(void)
5257c478bd9Sstevel@tonic-gate {
5267c478bd9Sstevel@tonic-gate 	int fd;
5277c478bd9Sstevel@tonic-gate 	char name[MAXPATHLEN];
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	tmpdir = getenv("TMPDIR");
5307c478bd9Sstevel@tonic-gate 	if ((tmpdir == (char *)NULL) || (*tmpdir == '\0'))
5317c478bd9Sstevel@tonic-gate 		tmpdir = "/tmp";
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	if (*tmpdir != '/') {
5347c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
5357c478bd9Sstevel@tonic-gate 		    gettext("TMPDIR is not an absolute path (`%s').\n"),
5367c478bd9Sstevel@tonic-gate 		    tmpdir);
5377c478bd9Sstevel@tonic-gate 		done(1);
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	/*
5417c478bd9Sstevel@tonic-gate 	 * The actual use of tmpdir is in dirs.c, and is of the form
5427c478bd9Sstevel@tonic-gate 	 * tmpdir + "/rst" + type (three characters) + "%ld.XXXXXX" +
5437c478bd9Sstevel@tonic-gate 	 * a trailing NUL, where %ld is an arbitrary time_t.
5447c478bd9Sstevel@tonic-gate 	 *
5457c478bd9Sstevel@tonic-gate 	 * Thus, the magic 31 is strlen(itoa(MAX_TIME_T)) + "/rst" +
5467c478bd9Sstevel@tonic-gate 	 * ".XXXXXX" + '\0'.  A time_t is 64 bits, so MAX_TIME_T is
5477c478bd9Sstevel@tonic-gate 	 * LONG_MAX - nineteen digits.  In theory, so many things in
5487c478bd9Sstevel@tonic-gate 	 * ufsrestore will break once time_t's value goes beyond 32
5497c478bd9Sstevel@tonic-gate 	 * bits that it's not worth worrying about this particular
5507c478bd9Sstevel@tonic-gate 	 * instance at this time, but we've got to start somewhere.
5517c478bd9Sstevel@tonic-gate 	 *
5527c478bd9Sstevel@tonic-gate 	 * Note that the use of a pid below is just for testing the
5537c478bd9Sstevel@tonic-gate 	 * validity of the named directory.
5547c478bd9Sstevel@tonic-gate 	 */
5557c478bd9Sstevel@tonic-gate 	if (strlen(tmpdir) > (MAXPATHLEN - 31)) {
5567c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("TMPDIR too long\n"));
5577c478bd9Sstevel@tonic-gate 		done(1);
5587c478bd9Sstevel@tonic-gate 	}
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	/* Guaranteed to fit by above test (sizeof(time_t) >= sizeof(pid_t)) */
5617c478bd9Sstevel@tonic-gate 	(void) snprintf(name, sizeof (name), "%s/rstdir.%ld", tmpdir, getpid());
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	/*
5647c478bd9Sstevel@tonic-gate 	 * This is effectively a stripped-down version of safe_open(),
5657c478bd9Sstevel@tonic-gate 	 * because if the file exists, we want to fail.
5667c478bd9Sstevel@tonic-gate 	 */
5677c478bd9Sstevel@tonic-gate 	fd = open(name, O_CREAT|O_EXCL|O_RDWR, 0600);
5687c478bd9Sstevel@tonic-gate 	if (fd < 0) {
5697c478bd9Sstevel@tonic-gate 		perror(gettext("Can not create temporary file"));
5707c478bd9Sstevel@tonic-gate 		done(1);
5717c478bd9Sstevel@tonic-gate 	}
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	(void) close(fd);
5747c478bd9Sstevel@tonic-gate 	if (unlink(name) < 0) {
5757c478bd9Sstevel@tonic-gate 		perror(gettext("Can not delete temporary file"));
5767c478bd9Sstevel@tonic-gate 		done(1);
5777c478bd9Sstevel@tonic-gate 	}
5787c478bd9Sstevel@tonic-gate }
579