Bug 14250

Summary: restore(8) can loop if tty goes away or with -y option
Product: Base System Reporter: iedowse <iedowse>
Component: binAssignee: iedowse
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 3.3-STABLE   
Hardware: Any   
OS: Any   

Description iedowse 1999-10-10 20:30:01 UTC
	restore(8) can get stuck in a loop under certain conditions:
	- If run in the background, and the user logs out while it is
	  still running, restore may start looping at the point where it
	  asks if the permissions on "." should be set. It does check for
	  tty EOF conditions with feof(3), but some types of tty errors
	  generate an EIO error rather than an end-of-file condition.
	  As well as looping, restore also fails to set permissions on
	  most of the directories it has extracted.

	- If the '-y' option is specified, or an end-of-file or error
	  condition occurs on the tty, a truncated pipe input will
	  result in an infinite loop of 'Changing volumes on pipe input?'
	  messages. This problem is related to that in PR bin/4176.

Fix: 

Apply the following patches in src/sbin/restore:

--- tape.c	1999/08/28 00:14:08	1.16
+++ tape.c	1999/10/10 18:36:34
@@ -305,8 +305,12 @@
 		gettingfile = 0;
 	}
 	if (pipein) {
-		if (nextvol != 1)
+		if (nextvol != 1) {
 			panic("Changing volumes on pipe input?\n");
+			/* Avoid looping if we weren't asking a tty */
+			if (yflag || ferror(terminal) || feof(terminal))
+				done(1);
+		}
 		if (volno == 1)
 			return;
 		goto gethdr;
@@ -343,10 +347,9 @@
 		do	{
 			fprintf(stderr, "Specify next volume #: ");
 			(void) fflush(stderr);
-			(void) fgets(buf, BUFSIZ, terminal);
-		} while (!feof(terminal) && buf[0] == '\n');
-		if (feof(terminal))
-			done(1);
+			if (fgets(buf, BUFSIZ, terminal) == NULL)
+				done(1);
+		} while (buf[0] == '\n');
 		newvol = atoi(buf);
 		if (newvol <= 0) {
 			fprintf(stderr,
@@ -362,8 +365,7 @@
 	fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
 	fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
 	(void) fflush(stderr);
-	(void) fgets(buf, BUFSIZ, terminal);
-	if (feof(terminal))
+	if (fgets(buf, BUFSIZ, terminal) == NULL)
 		done(1);
 	if (!strcmp(buf, "none\n")) {
 		terminateinput();
--- utilities.c	1999/08/28 00:14:09	1.8
+++ utilities.c	1999/10/10 18:06:01
@@ -405,14 +405,14 @@
 reply(question)
 	char *question;
 {
-	char c;
+	int c;
 
 	do	{
 		fprintf(stderr, "%s? [yn] ", question);
 		(void) fflush(stderr);
 		c = getc(terminal);
 		while (c != '\n' && getc(terminal) != '\n')
-			if (feof(terminal))
+			if (c == EOF)
 				return (FAIL);
 	} while (c != 'y' && c != 'n');
 	if (c == 'y')
--- interactive.c	1999/08/28 00:14:05	1.8
+++ interactive.c	1999/10/10 18:34:29
@@ -325,12 +325,11 @@
 	do	{
 		fprintf(stderr, "restore > ");
 		(void) fflush(stderr);
-		(void) fgets(input, BUFSIZ, terminal);
-	} while (!feof(terminal) && input[0] == '\n');
-	if (feof(terminal)) {
-		(void) strcpy(cmd, "quit");
-		return;
-	}
+		if (fgets(input, BUFSIZ, terminal) == NULL) {
+			(void) strcpy(cmd, "quit");
+			return;
+		}
+	} while (input[0] == '\n');
 	for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--)
 		/* trim off trailing white space and newline */;
 	*++cp = '\0';
How-To-Repeat: 
	- Run the command:
		cat dumpfile | restore xf - &
	  and then log out (I used tcsh - but this may not be important).
	  The restore process will loop when it gets to the end, and not
	  set all permissions correctly.

	- Truncate a dump file, and run the command:
		cat dumpfile | restore xyf -
Comment 1 cjc 2000-05-31 16:54:13 UTC
I am running into the second problem outlined. I run an
automated dump over ssh. Sometimes if things do not finish
just right, I get the infinite loop. The messages,

  Changing volumes on pipe input?
  Changing volumes on pipe input?
  Changing volumes on pipe input?

Keep coming until they fill up the disk,

  # ls -l /var/spool/mqueue
  total 741960
  -rw-------  1 root  daemon  759382016 May 31 04:12 dfWAA01445
  -rw-------  1 root  daemon          0 May 30 22:30 qfWAA01445
  -rw-------  1 root  daemon          0 May 30 22:30 xfWAA01445
  # df /var
  Filesystem   1K-blocks     Used    Avail Capacity  Mounted on
  /dev/ad0s1e     916639   912239   -68931   108%    /usr

Why have these patches not been commited?
-- 
Crist J. Clark                              cjc@scitec.com
SciTec, Inc                             (609)921-3892 x252
Comment 2 dwmalone freebsd_committer freebsd_triage 2000-07-11 12:36:16 UTC
Responsible Changed
From-To: freebsd-bugs->dwmalone

Local PR
Comment 3 iedowse freebsd_committer freebsd_triage 2000-12-07 21:26:46 UTC
Responsible Changed
From-To: dwmalone->iedowse

My PR, so I'll deal with it now that I can.
Comment 4 iedowse freebsd_committer freebsd_triage 2001-01-03 14:36:35 UTC
State Changed
From-To: open->closed

Fixed in -current and -stable.