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