From 1d41def9a35adf24894265b2d4847e3f1be14782 Mon Sep 17 00:00:00 2001 From: mckusick Date: Mon, 14 Apr 2008 20:15:53 +0000 Subject: 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. PR: bin/93603, also probably bin/107213 Fix from: Ken Lalonde --- sbin/restore/dirs.c | 92 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 24 deletions(-) (limited to 'sbin/restore') diff --git a/sbin/restore/dirs.c b/sbin/restore/dirs.c index fbd85ef..2f796cb 100644 --- a/sbin/restore/dirs.c +++ b/sbin/restore/dirs.c @@ -120,6 +120,7 @@ static void putent(struct direct *); static void rst_seekdir(RST_DIR *, long, long); static long rst_telldir(RST_DIR *); static struct direct *searchdir(ino_t, char *); +static void fail_dirtmp(char *); /* * Extract directory contents, building up a directory structure @@ -147,7 +148,7 @@ extractdirs(int genmode) if (fd == -1 || (df = fdopen(fd, "w")) == NULL) { if (fd != -1) close(fd); - warn("%s - cannot create directory temporary\nfopen", dirfile); + warn("%s: cannot create directory database", dirfile); done(1); } if (genmode != 0) { @@ -160,7 +161,7 @@ extractdirs(int genmode) if (fd == -1 || (mf = fdopen(fd, "w")) == NULL) { if (fd != -1) close(fd); - warn("%s - cannot create modefile\nfopen", modefile); + warn("%s: cannot create modefile", modefile); done(1); } } @@ -172,25 +173,24 @@ extractdirs(int genmode) for (;;) { curfile.name = ""; curfile.action = USING; - if (curfile.mode == 0 || (curfile.mode & IFMT) != IFDIR) { - (void) fclose(df); - dirp = opendirfile(dirfile); - if (dirp == NULL) - fprintf(stderr, "opendirfile: %s\n", - strerror(errno)); - if (mf != NULL) - (void) fclose(mf); - i = dirlookup(dot); - if (i == 0) - panic("Root directory is not on tape\n"); - return; - } + if (curfile.mode == 0 || (curfile.mode & IFMT) != IFDIR) + break; itp = allocinotab(&curfile, seekpt); getfile(putdir, putdirattrs, xtrnull); putent(&nulldir); flushent(); itp->t_size = seekpt - itp->t_seekpt; } + if (fclose(df) != 0) + fail_dirtmp(dirfile); + dirp = opendirfile(dirfile); + if (dirp == NULL) + fprintf(stderr, "opendirfile: %s\n", strerror(errno)); + if (mf != NULL && fclose(mf) != 0) + fail_dirtmp(modefile); + i = dirlookup(dot); + if (i == 0) + panic("Root directory is not on tape\n"); } /* @@ -390,7 +390,8 @@ putent(struct direct *dp) 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) + fail_dirtmp(dirfile); dirloc = 0; } memmove(dirbuf + dirloc, dp, (long)dp->d_reclen); @@ -405,7 +406,8 @@ static void flushent(void) { ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; - (void) fwrite(dirbuf, (int)dirloc, 1, df); + if (fwrite(dirbuf, (int)dirloc, 1, df) != 1) + fail_dirtmp(dirfile); seekpt = ftell(df); dirloc = 0; } @@ -417,8 +419,8 @@ static void putdirattrs(char *buf, long size) { - if (mf != NULL) - (void) fwrite(buf, 1, size, mf); + if (mf != NULL && fwrite(buf, size, 1, mf) != 1) + fail_dirtmp(modefile); } /* @@ -582,6 +584,11 @@ setdirmodes(int flags) myuid = getuid(); for (;;) { (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); + if (ferror(mf)) { + warn("%s: cannot read modefile.", modefile); + fprintf(stderr, "Mode, owner, and times not set.\n"); + break; + } if (feof(mf)) break; if (node.extsize > 0) { @@ -596,8 +603,22 @@ setdirmodes(int flags) } if (bufsize >= node.extsize) { (void) fread(buf, 1, node.extsize, mf); + if (ferror(mf)) { + warn("%s: cannot read modefile.", + modefile); + fprintf(stderr, "Not all external "); + fprintf(stderr, "attributes set.\n"); + break; + } } else { (void) fseek(mf, node.extsize, SEEK_CUR); + if (ferror(mf)) { + warn("%s: cannot seek in modefile.", + modefile); + fprintf(stderr, "Not all directory "); + fprintf(stderr, "attributes set.\n"); + break; + } } } ep = lookupino(node.ino); @@ -639,8 +660,6 @@ setdirmodes(int flags) } if (bufsize > 0) free(buf); - if (ferror(mf)) - panic("error setting directory modes\n"); (void) fclose(mf); } @@ -734,7 +753,8 @@ allocinotab(struct context *ctxp, long seekpt) 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) + fail_dirtmp(modefile); return (itp); } @@ -760,9 +780,33 @@ done(int exitcode) { closemt(); - if (modefile[0] != '#') + if (modefile[0] != '#') { + (void) truncate(modefile, 0); (void) unlink(modefile); - if (dirfile[0] != '#') + } + if (dirfile[0] != '#') { + (void) truncate(dirfile, 0); (void) unlink(dirfile); + } exit(exitcode); } + +/* + * Print out information about the failure to save directory, + * extended attribute, and mode information. + */ +static void +fail_dirtmp(char *filename) +{ + const char *tmpdir; + + warn("%s: cannot write directory database", filename); + if (errno == ENOSPC) { + if ((tmpdir = getenv("TMPDIR")) == NULL || tmpdir[0] == '\0') + tmpdir = _PATH_TMP; + fprintf(stderr, "Try making space in %s, %s\n%s\n", tmpdir, + "or set environment variable TMPDIR", + "to an alternate location with more disk space."); + } + done(1); +} -- cgit v1.1