bin/93603: restore fails if /tmp fills [patch]

Ken Lalonde ken at globalremit.com
Mon Feb 20 11:10:05 PST 2006


>Number:         93603
>Category:       bin
>Synopsis:       restore fails if /tmp fills [patch]
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Feb 20 19:10:03 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Ken Lalonde
>Release:        FreeBSD 6.0-RELEASE i386
>Organization:
Global Remittance Network
>Environment:
System: FreeBSD p2.torus.ca 6.0-RELEASE FreeBSD 6.0-RELEASE #1: Wed Feb 8 00:26:53 EST 2006 ken at p2.torus.ca:/usr/src/sys/i386/compile/P2 i386

>Description:
	restore(8) does not check for write failure while building two temp files
	containing directory and ownership data.  If /tmp fills, the console is
	blasted with zillions of "file system full" errors, and restore continues on,
	even though directory and/or ownership data has been lost.
	This is particularly likely to happen when running from the live CD,
	which has little /tmp space.

>How-To-Repeat:
	Boot the live CD and attempt to restore a large filesystem,
	or just inspect the code.

>Fix:
	The attached patch against the 6.0 source causes restore to quit
	with an appropriate error message in the event of write failure.
	If the failure is ENOSPC, a further suggestion is displayed.
	Also, failure to re-open the directory data file is now fatal.


--- d begins here ---
--- dirs.c	2006/02/18 00:22:58	1.1
+++ dirs.c	2006/02/20 18:22:47
@@ -118,6 +118,7 @@
 static void		 rst_seekdir(RST_DIR *, long, long);
 static long		 rst_telldir(RST_DIR *);
 static struct direct	*searchdir(ino_t, char *);
+static void		 tmp_write_failed(char *);
 
 /*
  *	Extract directory contents, building up a directory structure
@@ -171,13 +172,16 @@
 		curfile.name = "<directory file - name unknown>";
 		curfile.action = USING;
 		if (curfile.mode == 0 || (curfile.mode & IFMT) != IFDIR) {
-			(void) fclose(df);
+			if (fclose(df))
+				tmp_write_failed(dirfile);
 			dirp = opendirfile(dirfile);
-			if (dirp == NULL)
-				fprintf(stderr, "opendirfile: %s\n",
-				    strerror(errno));
+			if (dirp == NULL) {
+				warn(dirfile);
+				done(1);
+			}
 			if (mf != NULL)
-				(void) fclose(mf);
+				if (fclose(mf))
+					tmp_write_failed(modefile);
 			i = dirlookup(dot);
 			if (i == 0)
 				panic("Root directory is not on tape\n");
@@ -389,7 +393,8 @@
 	if (dirloc + dp->d_reclen > DIRBLKSIZ) {
 		((struct direct *)(dirbuf + prev))->d_reclen =
 		    DIRBLKSIZ - prev;
-		(void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
+		if (fwrite(dirbuf, DIRBLKSIZ, 1, df) != 1)
+			tmp_write_failed(dirfile);
 		dirloc = 0;
 	}
 	memmove(dirbuf + dirloc, dp, (long)dp->d_reclen);
@@ -404,7 +409,8 @@
 flushent(void)
 {
 	((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
-	(void) fwrite(dirbuf, (int)dirloc, 1, df);
+	if (fwrite(dirbuf, dirloc, 1, df) != 1)
+		tmp_write_failed(dirfile);
 	seekpt = ftell(df);
 	dirloc = 0;
 }
@@ -688,7 +694,8 @@
 	node.flags = ctxp->file_flags;
 	node.uid = ctxp->uid;
 	node.gid = ctxp->gid;
-	(void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
+	if (fwrite((char *)&node, sizeof(struct modeinfo), 1, mf) != 1)
+		tmp_write_failed(modefile);
 	return (itp);
 }
 
@@ -719,4 +726,19 @@
 	if (dirfile[0] != '#')
 		(void) unlink(dirfile);
 	exit(exitcode);
+}
+
+static void
+tmp_write_failed(char *path)
+{
+	const char *tmpdir;
+
+	warn("%s: write", path);
+	if (errno == ENOSPC) {
+		if ((tmpdir = getenv("TMPDIR")) == NULL || tmpdir[0] == '\0')
+			tmpdir = _PATH_TMP;
+		fprintf(stderr, "Try making space in %s, or set TMPDIR elsewhere.",
+			tmpdir);
+	}
+	done(1);
 }
--- d ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list