Subject: bin/4118: restoring a root partition is a pain
To: None <gnats-bugs@gnats.netbsd.org>
From: Michael C. Richardson <mcr@sandelman.ottawa.on.ca>
List: netbsd-bugs
Date: 09/17/1997 14:17:04
>Number:         4118
>Category:       bin
>Synopsis:       restore doesn't pay attention to $TMPDIR, no unlink option.
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Sep 17 11:20:01 1997
>Last-Modified:
>Originator:     Michael C. Richardson
>Organization:
Sandelman Software Works
>Release:        1.2
>Environment:
	
System: NetBSD istari.sandelman.ottawa.on.ca 1.2D NetBSD 1.2D (SSW) #10: Wed Jun 11 00:01:01 EDT 1997 mcr@istari.sandelman.ottawa.on.ca:/j/netbsd/src/sys/arch/i386/compile/SSW i386
Architecture: i386

>Description:
	I was moving my root disk to a faster drive, and decided to test
	my backup system (the tape gave me problems half way, so it failed,
	by the way). I did learn two things about restore.
	1. restore wants to write to /tmp. But that is the SSTO ramdisk.
	2. if I copy the SSTO ramdisk to my /mnt'ed root (which is otherwise
	empty), chroot and restore, then I get a hosed system.
	
	[I put restore on a floppy since it and MT aren't on the SSTO disk]

	{BTW: pathnames.h in restore and dump redefines _PATH_DEFTAPE. That fix
	not included}

>How-To-Repeat:
	backup and restore a root system on an i386.
>Fix:
	Taught restore about $TMPDIR and added -u option. Tested.

*** /w/netbsd/src/sbin/restore/tape.c	Mon Sep 15 07:17:04 1997
--- tape.c	Wed Sep 17 13:45:19 1997
***************
*** 1,4 ****
! /*	$NetBSD: tape.c,v 1.28 1997/09/15 08:04:40 lukem Exp $	*/
  
  /*
   * Copyright (c) 1983, 1993
--- 1,4 ----
! /*	$NetBSD: tape.c,v 1.25 1997/03/19 08:42:55 lukem Exp $	*/
  
  /*
   * Copyright (c) 1983, 1993
***************
*** 38,49 ****
   * SUCH DAMAGE.
   */
  
- #include <sys/cdefs.h>
  #ifndef lint
  #if 0
  static char sccsid[] = "@(#)tape.c	8.6 (Berkeley) 9/13/94";
  #else
! __RCSID("$NetBSD: tape.c,v 1.28 1997/09/15 08:04:40 lukem Exp $");
  #endif
  #endif /* not lint */
  
--- 38,48 ----
   * SUCH DAMAGE.
   */
  
  #ifndef lint
  #if 0
  static char sccsid[] = "@(#)tape.c	8.6 (Berkeley) 9/13/94";
  #else
! static char rcsid[] = "$NetBSD: tape.c,v 1.25 1997/03/19 08:42:55 lukem Exp $";
  #endif
  #endif /* not lint */
  
***************
*** 57,63 ****
  #include <protocols/dumprestore.h>
  
  #include <errno.h>
- #include <paths.h>
  #include <setjmp.h>
  #include <stdio.h>
  #include <stdlib.h>
--- 56,61 ----
***************
*** 66,73 ****
  
  #include "restore.h"
  #include "extern.h"
  
! static u_int32_t fssize = MAXBSIZE;
  static int	mt = -1;
  static int	pipein = 0;
  static char	magtape[BUFSIZ];
--- 64,72 ----
  
  #include "restore.h"
  #include "extern.h"
+ #include "pathnames.h"
  
! static long	fssize = MAXBSIZE;
  static int	mt = -1;
  static int	pipein = 0;
  static char	magtape[BUFSIZ];
***************
*** 75,83 ****
  static int	numtrec;
  static char	*tapebuf;
  static union	u_spcl endoftapemark;
! static int	blksread;		/* blocks read since last header */
! static int	tpblksread = 0;		/* TP_BSIZE blocks read */
! static int	tapesread;
  static jmp_buf	restart;
  static int	gettingfile = 0;	/* restart has a valid frame */
  static char	*host = NULL;
--- 74,82 ----
  static int	numtrec;
  static char	*tapebuf;
  static union	u_spcl endoftapemark;
! static long	blksread;		/* blocks read since last header */
! static long	tpblksread = 0;		/* TP_BSIZE blocks read */
! static long	tapesread;
  static jmp_buf	restart;
  static int	gettingfile = 0;	/* restart has a valid frame */
  static char	*host = NULL;
***************
*** 91,96 ****
--- 90,98 ----
  int		Bcvt;		/* Swap Bytes (for CCI or sun) */
  static int	Qcvt;		/* Swap quads (for sun) */
  
+ extern	uid_t uid;		/* real uid */
+ extern	uid_t euid;		/* effective uid */
+ 
  #define	FLUSHTAPEBUF()	blkcnt = ntrec + 1
  
  static void	 accthdr __P((struct s_spcl *));
***************
*** 152,157 ****
--- 154,160 ----
  		}
  		pipein++;
  	}
+ 	(void) setuid(uid); /* rmthost() is the only reason to be setuid */
  	(void) strcpy(magtape, source);
  }
  
***************
*** 288,301 ****
   */
  void
  getvol(nextvol)
! 	int nextvol;
  {
! 	int newvol, savecnt, wantnext, i;
  	union u_spcl tmpspcl;
  #	define tmpbuf tmpspcl.s_spcl
  	char buf[TP_BSIZE];
  
- 	newvol = savecnt = wantnext = 0;
  	if (nextvol == 1) {
  		tapesread = 0;
  		gettingfile = 0;
--- 291,303 ----
   */
  void
  getvol(nextvol)
! 	long nextvol;
  {
! 	long newvol, savecnt, wantnext, i;
  	union u_spcl tmpspcl;
  #	define tmpbuf tmpspcl.s_spcl
  	char buf[TP_BSIZE];
  
  	if (nextvol == 1) {
  		tapesread = 0;
  		gettingfile = 0;
***************
*** 413,419 ****
   	 * of the next record.
   	 */
  	dprintf(stdout, "read %ld recs, tape starts with %ld\n", 
! 		(long)tpblksread, (long)tmpbuf.c_firstrec);
   	if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
   		if (!wantnext) {
   			tpblksread = tmpbuf.c_firstrec;
--- 415,421 ----
   	 * of the next record.
   	 */
  	dprintf(stdout, "read %ld recs, tape starts with %ld\n", 
! 		tpblksread, tmpbuf.c_firstrec);
   	if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
   		if (!wantnext) {
   			tpblksread = tmpbuf.c_firstrec;
***************
*** 514,519 ****
--- 516,523 ----
  extractfile(name)
  	char *name;
  {
+   extern int unlinkflag;
+ 
  	int flags;
  	mode_t mode;
  	struct timeval timep[2];
***************
*** 559,564 ****
--- 563,569 ----
  			    "%s: zero length symbolic link (ignored)\n", name);
  			return (GOOD);
  		}
+ 		if(unlinkflag) unlink(name);
  		return (linkit(lnkbuf, name, SYMLINK));
  
  	case IFCHR:
***************
*** 568,573 ****
--- 573,579 ----
  			skipfile();
  			return (GOOD);
  		}
+ 		if(unlinkflag) unlink(name);
  		if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
  			fprintf(stderr, "%s: cannot create special file: %s\n",
  			    name, strerror(errno));
***************
*** 587,592 ****
--- 593,599 ----
  			skipfile();
  			return (GOOD);
  		}
+ 		if(unlinkflag) unlink(name);
  		if (mkfifo(name, mode) < 0) {
  			fprintf(stderr, "%s: cannot create fifo: %s\n",
  			    name, strerror(errno));
***************
*** 606,611 ****
--- 613,619 ----
  			skipfile();
  			return (GOOD);
  		}
+ 		if(unlinkflag) unlink(name);
  		if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
  		    0666)) < 0) {
  			fprintf(stderr, "%s: cannot create file: %s\n",
***************
*** 664,674 ****
  	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
  	char junk[TP_BSIZE];
  
- #ifdef __GNUC__			/* XXX: to shut up gcc warnings */
- 	(void)&curblk;
- 	(void)&size;
- #endif
- 
  	if (spcl.c_type == TS_END)
  		panic("ran off end of tape\n");
  	if (spcl.c_magic != NFS_MAGIC)
--- 672,677 ----
***************
*** 834,840 ****
  readtape(buf)
  	char *buf;
  {
! 	int rd, newvol, i;
  	int cnt, seek_failed;
  
  	if (blkcnt < numtrec) {
--- 837,843 ----
  readtape(buf)
  	char *buf;
  {
! 	long rd, newvol, i;
  	int cnt, seek_failed;
  
  	if (blkcnt < numtrec) {
***************
*** 969,977 ****
  		exit(1);
  	}
  	if (i % TP_BSIZE != 0) {
! 		fprintf(stderr, "Tape block size (%ld) %s (%ld)\n",
! 			(long)i, "is not a multiple of dump block size",
! 			(long)TP_BSIZE);
  		exit(1);
  	}
  	ntrec = i / TP_BSIZE;
--- 972,979 ----
  		exit(1);
  	}
  	if (i % TP_BSIZE != 0) {
! 		fprintf(stderr, "Tape block size (%d) %s (%d)\n",
! 			i, "is not a multiple of dump block size", TP_BSIZE);
  		exit(1);
  	}
  	ntrec = i / TP_BSIZE;
***************
*** 1179,1186 ****
  		break;
  	}
  	if (predict != blksread - 1)
! 		fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
! 			(long)predict, (long)(blksread - 1));
  	fprintf(stderr, "\n");
  newcalc:
  	blks = 0;
--- 1181,1188 ----
  		break;
  	}
  	if (predict != blksread - 1)
! 		fprintf(stderr, "; predicted %d blocks, got %d blocks",
! 			predict, blksread - 1);
  	fprintf(stderr, "\n");
  newcalc:
  	blks = 0;
***************
*** 1259,1266 ****
  		}
  	} while (header->c_type == TS_ADDR);
  	if (skipcnt > 0)
! 		fprintf(stderr, "resync restore, skipped %ld blocks\n",
! 		    (long)skipcnt);
  	skipcnt = 0;
  }
  
--- 1261,1267 ----
  		}
  	} while (header->c_type == TS_ADDR);
  	if (skipcnt > 0)
! 		fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
  	skipcnt = 0;
  }
  
*** /w/netbsd/src/sbin/restore/pathnames.h	Fri Oct 13 21:13:31 1995
--- pathnames.h	Wed Sep 17 13:37:53 1997
***************
*** 43,45 ****
--- 43,47 ----
  #include <paths.h>
  
  #define	_PATH_DEFTAPE	"/dev/rmt8"
+ 
+ extern char *tmpdir;
*** /w/netbsd/src/sbin/restore/dirs.c	Mon Sep 15 07:16:48 1997
--- dirs.c	Wed Sep 17 13:38:40 1997
***************
*** 1,4 ****
! /*	$NetBSD: dirs.c,v 1.28 1997/09/15 08:04:28 lukem Exp $	*/
  
  /*
   * Copyright (c) 1983, 1993
--- 1,4 ----
! /*	$NetBSD: dirs.c,v 1.22 1997/03/19 08:42:51 lukem Exp $	*/
  
  /*
   * Copyright (c) 1983, 1993
***************
*** 38,49 ****
   * SUCH DAMAGE.
   */
  
- #include <sys/cdefs.h>
  #ifndef lint
  #if 0
  static char sccsid[] = "@(#)dirs.c	8.5 (Berkeley) 8/31/94";
  #else
! __RCSID("$NetBSD: dirs.c,v 1.28 1997/09/15 08:04:28 lukem Exp $");
  #endif
  #endif /* not lint */
  
--- 38,48 ----
   * SUCH DAMAGE.
   */
  
  #ifndef lint
  #if 0
  static char sccsid[] = "@(#)dirs.c	8.5 (Berkeley) 8/31/94";
  #else
! static char rcsid[] = "$NetBSD: dirs.c,v 1.22 1997/03/19 08:42:51 lukem Exp $";
  #endif
  #endif /* not lint */
  
***************
*** 57,65 ****
  #include <ufs/ufs/dir.h>
  #include <protocols/dumprestore.h>
  
- #include <err.h>
  #include <errno.h>
- #include <paths.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
--- 56,62 ----
***************
*** 67,72 ****
--- 64,70 ----
  
  #include <machine/endian.h>
  
+ #include "pathnames.h"
  #include "restore.h"
  #include "extern.h"
  
***************
*** 154,163 ****
  
  	vprintf(stdout, "Extract directories from tape\n");
  	(void) snprintf(dirfile, sizeof(dirfile), "%s/rstdir%d",
! 	    tmpdir, (int)dumpdate);
  	if (command != 'r' && command != 'R') {
  		(void) snprintf(dirfile, sizeof(dirfile), "%s/rstdir%d-XXXXXX",
! 		    tmpdir, (int)dumpdate);
  		if ((dfd = mkstemp(dirfile)) == -1)
  			err(1, "cannot mkstemp temporary file %s", dirfile);
  		df = fdopen(dfd, "w");
--- 152,161 ----
  
  	vprintf(stdout, "Extract directories from tape\n");
  	(void) snprintf(dirfile, sizeof(dirfile), "%s/rstdir%d",
! 	    tmpdir, dumpdate);
  	if (command != 'r' && command != 'R') {
  		(void) snprintf(dirfile, sizeof(dirfile), "%s/rstdir%d-XXXXXX",
! 		    tmpdir, dumpdate);
  		if ((dfd = mkstemp(dirfile)) == -1)
  			err(1, "cannot mkstemp temporary file %s", dirfile);
  		df = fdopen(dfd, "w");
***************
*** 169,178 ****
  
  	if (genmode != 0) {
  		(void) snprintf(modefile, sizeof(modefile), "%s/rstmode%d",
! 		    tmpdir, (int)dumpdate);
  		if (command != 'r' && command != 'R') {
  			(void) snprintf(modefile, sizeof(modefile),
! 			    "%s/rstmode%d-XXXXXX", tmpdir, (int)dumpdate);
  			if ((mfd = mkstemp(modefile)) == -1)
  				err(1, "cannot mkstemp temporary file %s",
  				    modefile);
--- 167,176 ----
  
  	if (genmode != 0) {
  		(void) snprintf(modefile, sizeof(modefile), "%s/rstmode%d",
! 		    tmpdir, dumpdate);
  		if (command != 'r' && command != 'R') {
  			(void) snprintf(modefile, sizeof(modefile),
! 			    "%s/rstmode%d-XXXXXX", tmpdir, dumpdate);
  			if ((mfd = mkstemp(modefile)) == -1)
  				err(1, "cannot mkstemp temporary file %s",
  				    modefile);
***************
*** 226,232 ****
  }
  
  /*
!  *	Recursively find names and inumbers of all files in subtree
   *	pname and pass them off to be processed.
   */
  void
--- 224,230 ----
  }
  
  /*
!  *	Recursively find names and inumbers of all files in subtree 
   *	pname and pass them off to be processed.
   */
  void
***************
*** 283,289 ****
  				locname, dp->d_name, sizeof(locname) - 1);
  		} else {
  			(void) strncat(locname, dp->d_name, (int)dp->d_namlen);
- 			locname[namelen + dp->d_namlen] = '\0';
  			treescan(locname, dp->d_ino, todo);
  			rst_seekdir(dirp, bpt, itp->t_seekpt);
  		}
--- 281,286 ----
***************
*** 309,315 ****
  	while (*path == '/')
  		path++;
  	dp = NULL;
! 	while ((name = strsep(&path, "/")) != NULL && *name != '\0') {
  		if ((dp = searchdir(ino, name)) == NULL)
  			return (NULL);
  		ino = dp->d_ino;
--- 306,312 ----
  	while (*path == '/')
  		path++;
  	dp = NULL;
! 	while ((name = strsep(&path, "/")) != NULL && *name != NULL) {
  		if ((dp = searchdir(ino, name)) == NULL)
  			return (NULL);
  		ino = dp->d_ino;
***************
*** 477,484 ****
  		return;
  	loc -= base;
  	if (loc < 0)
! 		fprintf(stderr, "bad seek pointer to rst_seekdir %d\n",
! 		    (int)loc);
  	(void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET);
  	dirp->dd_loc = loc & (DIRBLKSIZ - 1);
  	if (dirp->dd_loc != 0)
--- 474,480 ----
  		return;
  	loc -= base;
  	if (loc < 0)
! 		fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc);
  	(void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET);
  	dirp->dd_loc = loc & (DIRBLKSIZ - 1);
  	if (dirp->dd_loc != 0)
***************
*** 496,502 ****
  
  	for (;;) {
  		if (dirp->dd_loc == 0) {
! 			dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
  			    DIRBLKSIZ);
  			if (dirp->dd_size <= 0) {
  				dprintf(stderr, "error reading directory\n");
--- 492,498 ----
  
  	for (;;) {
  		if (dirp->dd_loc == 0) {
! 			dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 
  			    DIRBLKSIZ);
  			if (dirp->dd_size <= 0) {
  				dprintf(stderr, "error reading directory\n");
***************
*** 602,612 ****
  	struct modeinfo node;
  	struct entry *ep;
  	char *cp;
! 
  	vprintf(stdout, "Set directory mode, owner, and times.\n");
  	if (command == 'r' || command == 'R')
  		(void) snprintf(modefile, sizeof(modefile), "%s/rstmode%d",
! 		    tmpdir, (int)dumpdate);
  	if (modefile[0] == '#') {
  		panic("modefile not defined\n");
  		fprintf(stderr, "directory mode, owner, and times not set\n");
--- 598,608 ----
  	struct modeinfo node;
  	struct entry *ep;
  	char *cp;
! 	
  	vprintf(stdout, "Set directory mode, owner, and times.\n");
  	if (command == 'r' || command == 'R')
  		(void) snprintf(modefile, sizeof(modefile), "%s/rstmode%d",
! 		    tmpdir, dumpdate);
  	if (modefile[0] == '#') {
  		panic("modefile not defined\n");
  		fprintf(stderr, "directory mode, owner, and times not set\n");
*** /w/netbsd/src/sbin/restore/main.c	Mon Sep 15 07:16:52 1997
--- main.c	Wed Sep 17 13:37:30 1997
***************
*** 1,4 ****
! /*	$NetBSD: main.c,v 1.15 1997/09/15 08:04:33 lukem Exp $	*/
  
  /*
   * Copyright (c) 1983, 1993
--- 1,4 ----
! /*	$NetBSD: main.c,v 1.11 1996/03/15 22:39:39 scottr Exp $	*/
  
  /*
   * Copyright (c) 1983, 1993
***************
*** 33,49 ****
   * SUCH DAMAGE.
   */
  
- #include <sys/cdefs.h>
  #ifndef lint
! __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
! 	The Regents of the University of California.  All rights reserved.\n");
  #endif /* not lint */
  
  #ifndef lint
  #if 0
  static char sccsid[] = "@(#)main.c	8.3 (Berkeley) 9/13/94";
  #else
! __RCSID("$NetBSD: main.c,v 1.15 1997/09/15 08:04:33 lukem Exp $");
  #endif
  #endif /* not lint */
  
--- 33,49 ----
   * SUCH DAMAGE.
   */
  
  #ifndef lint
! static char copyright[] =
! "@(#) Copyright (c) 1983, 1993\n\
! 	The Regents of the University of California.  All rights reserved.\n";
  #endif /* not lint */
  
  #ifndef lint
  #if 0
  static char sccsid[] = "@(#)main.c	8.3 (Berkeley) 9/13/94";
  #else
! static char rcsid[] = "$NetBSD: main.c,v 1.11 1996/03/15 22:39:39 scottr Exp $";
  #endif
  #endif /* not lint */
  
***************
*** 56,89 ****
  
  #include <err.h>
  #include <errno.h>
- #include <paths.h>
  #include <signal.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  
  #include "restore.h"
  #include "extern.h"
  
- extern char *__progname;	/* from crt0.o */
- 
  int	bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0;
! int	hflag = 1, mflag = 1, Nflag = 0;
  char	command = '\0';
! int32_t	dumpnum = 1;
! int32_t	volno = 0;
! int32_t	ntrec;
  char	*dumpmap;
  char	*usedinomap;
  ino_t	maxino;
  time_t	dumptime;
  time_t	dumpdate;
  FILE 	*terminal;
! char	*tmpdir;
  
! int	main __P((int, char *[]));
! static	void obsolete __P((int *, char **[]));
! static	void usage __P((void));
  
  int
  main(argc, argv)
--- 56,88 ----
  
  #include <err.h>
  #include <errno.h>
  #include <signal.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  
+ #include "pathnames.h"
  #include "restore.h"
  #include "extern.h"
  
  int	bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0;
! int	hflag = 1, mflag = 1, Nflag = 0, unlinkflag = 0;
  char	command = '\0';
! long	dumpnum = 1;
! long	volno = 0;
! long	ntrec;
  char	*dumpmap;
  char	*usedinomap;
  ino_t	maxino;
  time_t	dumptime;
  time_t	dumpdate;
  FILE 	*terminal;
! uid_t	uid;		/* real uid */
! uid_t	euid;		/* effective uid */
! char    *tmpdir;
  
! static void obsolete __P((int *, char **[]));
! static void usage __P((void));
  
  int
  main(argc, argv)
***************
*** 96,110 ****
  	char *symtbl = "./restoresymtable";
  	char *p, name[MAXPATHLEN];
  
  	if (argc < 2)
  		usage();
  
  	if ((inputdev = getenv("TAPE")) == NULL)
  		inputdev = _PATH_DEFTAPE;
! 	if ((tmpdir = getenv("TMPDIR")) == NULL)
! 		tmpdir = _PATH_TMP;
  	obsolete(&argc, &argv);
! 	while ((ch = getopt(argc, argv, "b:cdf:himNRrs:tvxy")) != -1)
  		switch(ch) {
  		case 'b':
  			/* Change default tape blocksize. */
--- 95,116 ----
  	char *symtbl = "./restoresymtable";
  	char *p, name[MAXPATHLEN];
  
+ 	uid = getuid();
+ 	euid = geteuid();
+ 	(void) seteuid(uid);
+ 
  	if (argc < 2)
  		usage();
  
  	if ((inputdev = getenv("TAPE")) == NULL)
  		inputdev = _PATH_DEFTAPE;
! 	
! 	if ((tmpdir = getenv("TMPDIR")) == NULL) {
! 	  tmpdir = _PATH_TMP;
! 	}
! 	  
  	obsolete(&argc, &argv);
! 	while ((ch = getopt(argc, argv, "b:cdf:himNRrs:tuvxy")) != EOF)
  		switch(ch) {
  		case 'b':
  			/* Change default tape blocksize. */
***************
*** 155,160 ****
--- 161,169 ----
  		case 'v':
  			vflag = 1;
  			break;
+ 		case 'u':
+ 		        unlinkflag = 1;
+ 			break;
  		case 'y':
  			yflag = 1;
  			break;
***************
*** 288,308 ****
  usage()
  {
  
! 	(void)fprintf(stderr,
! 	    "usage: %s -i [-chmvy] [-b blocksize] [-f file] [-s fileno]\n",
! 	    __progname);
! 	(void)fprintf(stderr,
! 	    "\t%s -R [-cvy] [-b blocksize] [-f file] [-s fileno]\n",
! 	    __progname);
! 	(void)fprintf(stderr,
! 	    "\t%s -r [-cvy] [-b blocksize] [-f file] [-s fileno]\n",
! 	    __progname);
! 	(void)fprintf(stderr,
! 	    "\t%s -t [-chvy] [-b blocksize] [-f file] [-s fileno] [file ...]\n",
! 	    __progname);
! 	(void)fprintf(stderr,
! 	    "\t%s -x [-chmvy] [-b blocksize] [-f file] [-s fileno] [file ...]\n",
! 	    __progname);
  	exit(1);
  }
  
--- 297,307 ----
  usage()
  {
  
! 	(void)fprintf(stderr, "usage: restore -i [-chmvy] [-b blocksize] [-f file] [-s fileno]\n");
! 	(void)fprintf(stderr, "       restore -R [-cvy] [-b blocksize] [-f file] [-s fileno]\n");
! 	(void)fprintf(stderr, "       restore -r [-cvy] [-b blocksize] [-f file] [-s fileno]\n");
! 	(void)fprintf(stderr, "       restore -t [-chvy] [-b blocksize] [-f file] [-s fileno] [file ...]\n");
! 	(void)fprintf(stderr, "       restore -x [-chmvy] [-b blocksize] [-f file] [-s fileno] [file ...]\n");
  	exit(1);
  }
  
***************
*** 331,337 ****
  	/* Allocate space for new arguments. */
  	if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
  	    (p = flagsp = malloc(strlen(ap) + 2)) == NULL)
! 		err(1, "%s", "");
  
  	*nargv++ = *argv;
  	argv += 2;
--- 330,336 ----
  	/* Allocate space for new arguments. */
  	if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
  	    (p = flagsp = malloc(strlen(ap) + 2)) == NULL)
! 		err(1, NULL);
  
  	*nargv++ = *argv;
  	argv += 2;
***************
*** 346,352 ****
  				usage();
  			}
  			if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
! 				err(1, "%s", "");
  			nargv[0][0] = '-';
  			nargv[0][1] = *ap;
  			(void)strcpy(&nargv[0][2], *argv);
--- 345,351 ----
  				usage();
  			}
  			if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
! 				err(1, NULL);
  			nargv[0][0] = '-';
  			nargv[0][1] = *ap;
  			(void)strcpy(&nargv[0][2], *argv);
***************
*** 370,377 ****
  	}
  
  	/* Copy remaining arguments. */
! 	while ((*nargv++ = *argv++) != NULL)
! 		;
  
  	/* Update argument count. */
  	*argcp = nargv - *argvp - 1;
--- 369,375 ----
  	}
  
  	/* Copy remaining arguments. */
! 	while (*nargv++ = *argv++);
  
  	/* Update argument count. */
  	*argcp = nargv - *argvp - 1;
*** /w/netbsd/src/sbin/restore/restore.8	Mon Sep 15 07:16:54 1997
--- restore.8	Wed Sep 17 13:59:43 1997
***************
*** 1,4 ****
! .\"	$NetBSD: restore.8,v 1.16 1997/09/15 08:04:34 lukem Exp $
  .\"
  .\" Copyright (c) 1985, 1991, 1993
  .\"	The Regents of the University of California.  All rights reserved.
--- 1,4 ----
! .\"	$NetBSD: restore.8,v 1.13 1996/12/24 02:32:25 mikel Exp $
  .\"
  .\" Copyright (c) 1985, 1991, 1993
  .\"	The Regents of the University of California.  All rights reserved.
***************
*** 33,46 ****
  .\"
  .\"     @(#)restore.8	8.3 (Berkeley) 6/1/94
  .\"
! .Dd July 1, 1997
  .Dt RESTORE 8
  .Os BSD 4
  .Sh NAME
  .Nm restore
  .Nd "restore files or file systems from backups made with dump"
  .Sh SYNOPSIS
! .Nm
  .Fl i
  .Op Fl chmvy
  .Op Fl b Ar blocksize
--- 33,46 ----
  .\"
  .\"     @(#)restore.8	8.3 (Berkeley) 6/1/94
  .\"
! .Dd June 1, 1994
  .Dt RESTORE 8
  .Os BSD 4
  .Sh NAME
  .Nm restore
  .Nd "restore files or file systems from backups made with dump"
  .Sh SYNOPSIS
! .Nm restore
  .Fl i
  .Op Fl chmvy
  .Op Fl b Ar blocksize
***************
*** 80,86 ****
  is not documented here.)
  .Sh DESCRIPTION
  The
! .Nm
  command performs the inverse function of
  .Xr dump 8 .
  A full backup of a file system may be restored and
--- 80,86 ----
  is not documented here.)
  .Sh DESCRIPTION
  The
! .Nm restore
  command performs the inverse function of
  .Xr dump 8 .
  A full backup of a file system may be restored and
***************
*** 88,94 ****
  Single files and
  directory subtrees may be restored from full or partial
  backups.
! .Nm
  works across a network;
  to do this see the
  .Fl f
--- 88,94 ----
  Single files and
  directory subtrees may be restored from full or partial
  backups.
! .Nm Restore
  works across a network;
  to do this see the
  .Fl f
***************
*** 106,112 ****
  .It Fl i
  This mode allows interactive restoration of files from a dump.
  After reading in the directory information from the dump,
! .Nm
  provides a shell like interface that allows the user to move
  around the directory tree selecting files to be extracted.
  The available commands are given below;
--- 106,112 ----
  .It Fl i
  This mode allows interactive restoration of files from a dump.
  After reading in the directory information from the dump,
! .Nm restore
  provides a shell like interface that allows the user to move
  around the directory tree selecting files to be extracted.
  The available commands are given below;
***************
*** 140,146 ****
  .It Ic extract
  All the files that are on the extraction list are extracted
  from the dump.
! .Nm
  will ask which volume the user wishes to mount.
  The fastest way to extract a few files is to
  start with the last volume, and work towards the first volume.
--- 140,146 ----
  .It Ic extract
  All the files that are on the extraction list are extracted
  from the dump.
! .Nm Restore
  will ask which volume the user wishes to mount.
  The fastest way to extract a few files is to
  start with the last volume, and work towards the first volume.
***************
*** 170,180 ****
  .Ic ls
  command to list the inode numbers of all entries.
  It also causes
! .Nm
  to print out information about each file as it is extracted.
  .El
  .It Fl R
! .Nm
  requests a particular tape of a multi volume set on which to restart
  a full restore
  (see the
--- 170,180 ----
  .Ic ls
  command to list the inode numbers of all entries.
  It also causes
! .Nm restore
  to print out information about each file as it is extracted.
  .El
  .It Fl R
! .Nm Restore
  requests a particular tape of a multi volume set on which to restart
  a full restore
  (see the
***************
*** 207,213 ****
  .Ed
  .Pp
  Note that 
! .Nm
  leaves a file 
  .Pa restoresymtable
  in the root directory to pass information between incremental
--- 207,213 ----
  .Ed
  .Pp
  Note that 
! .Nm restore
  leaves a file 
  .Pa restoresymtable
  in the root directory to pass information between incremental
***************
*** 215,221 ****
  This file should be removed when the last incremental has been
  restored.
  .Pp
! .Nm "" ,
  in conjunction with
  .Xr newfs 8
  and
--- 215,221 ----
  This file should be removed when the last incremental has been
  restored.
  .Pp
! .Nm Restore ,
  in conjunction with
  .Xr newfs 8
  and
***************
*** 264,274 ****
  If the
  .Fl b
  option is not specified,
! .Nm
  tries to determine the block size dynamically.
  .It Fl c
  Normally,
! .Nm
  will try to determine dynamically whether the dump was made from an
  old (pre-4.4) or new format file sytem.  The
  .Fl c
--- 264,274 ----
  If the
  .Fl b
  option is not specified,
! .Nm restore
  tries to determine the block size dynamically.
  .It Fl c
  Normally,
! .Nm restore
  will try to determine dynamically whether the dump was made from an
  old (pre-4.4) or new format file sytem.  The
  .Fl c
***************
*** 280,286 ****
  .Ar file
  may be a special device file
  like
! .Pa /dev/rst0
  (a tape drive),
  .Pa /dev/rsd1c
  (a disk drive),
--- 280,286 ----
  .Ar file
  may be a special device file
  like
! .Pa /dev/rmt12
  (a tape drive),
  .Pa /dev/rsd1c
  (a disk drive),
***************
*** 292,298 ****
  .Dq host:file ,
  or
  .Dq user@host:file ,
! .Nm
  reads from the named file on the remote host using
  .Xr rmt 8 .
  .Pp
--- 292,298 ----
  .Dq host:file ,
  or
  .Dq user@host:file ,
! .Nm restore
  reads from the named file on the remote host using
  .Xr rmt 8 .
  .Pp
***************
*** 311,319 ****
  .Ar fileno
  on a multi-file tape.
  File numbering starts at 1.
  .It Fl v
  Normally
! .Nm
  does its work silently.
  The
  .Fl v
--- 311,323 ----
  .Ar fileno
  on a multi-file tape.
  File numbering starts at 1.
+ .It Fl u
+ Normally restore complains if a file already exists and does not
+ replace it. This option causes restore to unlink the file before
+ replace it.
  .It Fl v
  Normally
! .Nm restore
  does its work silently.
  The
  .Fl v
***************
*** 330,353 ****
  .Fl y
  has been specified, or the user responds
  .Ql y ,
! .Nm
  will attempt to continue the restore.
  .Pp
  If a backup was made using more than one tape volume,
! .Nm
  will notify the user when it is time to mount the next volume.
  If the
  .Fl x
  or
  .Fl i
  flag has been specified,
! .Nm
  will also ask which volume the user wishes to mount.
  The fastest way to extract a few files is to
  start with the last volume, and work towards the first volume.
  .Pp
  There are numerous consistency checks that can be listed by
! .Nm "" .
  Most checks are self-explanatory or can ``never happen''.
  Common errors are given below.
  .Pp
--- 334,357 ----
  .Fl y
  has been specified, or the user responds
  .Ql y ,
! .Nm restore
  will attempt to continue the restore.
  .Pp
  If a backup was made using more than one tape volume,
! .Nm restore
  will notify the user when it is time to mount the next volume.
  If the
  .Fl x
  or
  .Fl i
  flag has been specified,
! .Nm restore
  will also ask which volume the user wishes to mount.
  The fastest way to extract a few files is to
  start with the last volume, and work towards the first volume.
  .Pp
  There are numerous consistency checks that can be listed by
! .Nm restore .
  Most checks are self-explanatory or can ``never happen''.
  Common errors are given below.
  .Pp
***************
*** 389,414 ****
  .Pp
  .It resync restore, skipped <num> blocks
  After a dump read error, 
! .Nm
  may have to resynchronize itself.
  This message lists the number of blocks that were skipped over.
  .El
- .Sh ENVIRONMENT
- If the following environment variable exists it will be utilized by
- .Nm "" :
- .Bl -tag -width "TMPDIR" -compact
- .It TMPDIR
- The directory given in TMPDIR will be used
- instead of
- .Pa /tmp
- to store temporary files.
- Refer to
- .Xr environ 7
- for more information.
- .El
  .Sh FILES
  .Bl -tag -width "./restoresymtable" -compact
! .It Pa /dev/rst0
  the default tape drive
  .It Pa /dev/rst*
  Raw SCSI tape interface
--- 393,405 ----
  .Pp
  .It resync restore, skipped <num> blocks
  After a dump read error, 
! .Nm restore
  may have to resynchronize itself.
  This message lists the number of blocks that were skipped over.
  .El
  .Sh FILES
  .Bl -tag -width "./restoresymtable" -compact
! .It Pa /dev/rmt8
  the default tape drive
  .It Pa /dev/rst*
  Raw SCSI tape interface
***************
*** 420,439 ****
  information passed between incremental restores.
  .El
  .Sh SEE ALSO
- .Xr environ 7 ,
  .Xr dump 8 ,
  .Xr newfs 8 ,
  .Xr mount 8 ,
  .Xr rmt 8
  .Sh BUGS
! .Nm
  can get confused when doing incremental restores from
  dumps that were made on active file systems.
  .Pp
  A level zero dump must be done after a full restore.
! Because
! .Nm
! runs in user code,
  it has no control over inode allocation;
  thus a full dump must be done to get a new set of directories
  reflecting the new inode numbering,
--- 411,427 ----
  information passed between incremental restores.
  .El
  .Sh SEE ALSO
  .Xr dump 8 ,
  .Xr newfs 8 ,
  .Xr mount 8 ,
  .Xr rmt 8
  .Sh BUGS
! .Nm Restore
  can get confused when doing incremental restores from
  dumps that were made on active file systems.
  .Pp
  A level zero dump must be done after a full restore.
! Because restore runs in user code,
  it has no control over inode allocation;
  thus a full dump must be done to get a new set of directories
  reflecting the new inode numbering,
***************
*** 459,467 ****
  be the same across different processes.
  In all other cases, the files are unique because it is possible to
  have two different dumps started at the same time, and separate
! operations shouldn't conflict with each other.
  .Sh HISTORY
  The
! .Nm
  command appeared in
  .Bx 4.2 .
--- 447,456 ----
  be the same across different processes.
  In all other cases, the files are unique because it is possible to
  have two different dumps started at the same time, and separate
! operations shouldn't conflict with each other. The environment
! variable TMPDIR may be set to change the location of these files.
  .Sh HISTORY
  The
! .Nm restore
  command appeared in
  .Bx 4.2 .

>Audit-Trail:
>Unformatted: