summaryrefslogtreecommitdiffstats
path: root/sbin/restore
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2008-04-14 20:15:53 +0000
committermckusick <mckusick@FreeBSD.org>2008-04-14 20:15:53 +0000
commit1d41def9a35adf24894265b2d4847e3f1be14782 (patch)
treeb52c9a9ec39880056ba9ef47017729ae565d7b79 /sbin/restore
parent48d8d5e84eda19281b5b2ea4ad82bfc17474dfab (diff)
downloadFreeBSD-src-1d41def9a35adf24894265b2d4847e3f1be14782.zip
FreeBSD-src-1d41def9a35adf24894265b2d4847e3f1be14782.tar.gz
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
Diffstat (limited to 'sbin/restore')
-rw-r--r--sbin/restore/dirs.c92
1 files changed, 68 insertions, 24 deletions
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 = "<directory file - name unknown>";
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);
+}
OpenPOWER on IntegriCloud