summaryrefslogtreecommitdiffstats
path: root/sbin/restore
diff options
context:
space:
mode:
authordwmalone <dwmalone@FreeBSD.org>2006-12-05 11:18:51 +0000
committerdwmalone <dwmalone@FreeBSD.org>2006-12-05 11:18:51 +0000
commit12df44b4252096a8dc10f2dfb0abcb91abacff85 (patch)
tree93515273cbec28074cbc2e6628a45e20d8f8745d /sbin/restore
parentf352d339195080f49c339692c92533746def6318 (diff)
downloadFreeBSD-src-12df44b4252096a8dc10f2dfb0abcb91abacff85.zip
FreeBSD-src-12df44b4252096a8dc10f2dfb0abcb91abacff85.tar.gz
Add a "-D" flag to restore which puts it into "degraded" mode. This
makes restore less efficient, but it makes a bigger effore to read corrupted dumps. Specifiacally, when in degreded mode: 1) Restore shifts the input by 1 byte if it sees a problem, rather than one tape block. 2) It doesn't assume the inodes are stored in ascending order. 3) It turns some panics into warning printfs. We also verify some fields more carefully than before. There's probably more a degreded mode could do, but this seems to help a lot. Approved by: imp, iedowse, mckusick MFC after: 3 weeks
Diffstat (limited to 'sbin/restore')
-rw-r--r--sbin/restore/main.c7
-rw-r--r--sbin/restore/restore.816
-rw-r--r--sbin/restore/restore.c12
-rw-r--r--sbin/restore/restore.h1
-rw-r--r--sbin/restore/tape.c90
5 files changed, 104 insertions, 22 deletions
diff --git a/sbin/restore/main.c b/sbin/restore/main.c
index 63fb4ef..91f4a83 100644
--- a/sbin/restore/main.c
+++ b/sbin/restore/main.c
@@ -60,7 +60,7 @@ __FBSDID("$FreeBSD$");
#include "restore.h"
#include "extern.h"
-int bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0;
+int bflag = 0, cvtflag = 0, dflag = 0, Dflag = 0, vflag = 0, yflag = 0;
int hflag = 1, mflag = 1, Nflag = 0;
int uflag = 0;
int pipecmd = 0;
@@ -97,7 +97,7 @@ main(int argc, char *argv[])
inputdev = NULL;
obsolete(&argc, &argv);
- while ((ch = getopt(argc, argv, "b:df:himNP:Rrs:tuvxy")) != -1)
+ while ((ch = getopt(argc, argv, "b:dDf:himNP:Rrs:tuvxy")) != -1)
switch(ch) {
case 'b':
/* Change default tape blocksize. */
@@ -111,6 +111,9 @@ main(int argc, char *argv[])
case 'd':
dflag = 1;
break;
+ case 'D':
+ Dflag = 1;
+ break;
case 'f':
if (pipecmd)
errx(1,
diff --git a/sbin/restore/restore.8 b/sbin/restore/restore.8
index 9db0d67..cf6a364 100644
--- a/sbin/restore/restore.8
+++ b/sbin/restore/restore.8
@@ -38,32 +38,32 @@
.Sh SYNOPSIS
.Nm
.Fl i
-.Op Fl dhmNuvy
+.Op Fl dDhmNuvy
.Op Fl b Ar blocksize
.Op Fl f Ar file | Fl P Ar pipecommand
.Op Fl s Ar fileno
.Nm
.Fl R
-.Op Fl dNuvy
+.Op Fl dDNuvy
.Op Fl b Ar blocksize
.Op Fl f Ar file | Fl P Ar pipecommand
.Op Fl s Ar fileno
.Nm
.Fl r
-.Op Fl dNuvy
+.Op Fl dDNuvy
.Op Fl b Ar blocksize
.Op Fl f Ar file | Fl P Ar pipecommand
.Op Fl s Ar fileno
.Nm
.Fl t
-.Op Fl dhNuvy
+.Op Fl dDhNuvy
.Op Fl b Ar blocksize
.Op Fl f Ar file | Fl P Ar pipecommand
.Op Fl s Ar fileno
.Op Ar
.Nm
.Fl x
-.Op Fl dhmNuvy
+.Op Fl dDhmNuvy
.Op Fl b Ar blocksize
.Op Fl f Ar file | Fl P Ar pipecommand
.Op Fl s Ar fileno
@@ -278,6 +278,12 @@ option is not specified,
tries to determine the media block size dynamically.
.It Fl d
Sends verbose debugging output to the standard error.
+.It Fl D
+This puts
+.Nm
+into degraded mode,
+causing restore to operate less efficiently
+but to try harder to read corrupted backups.
.It Fl f Ar file
Read the backup from
.Ar file ;
diff --git a/sbin/restore/restore.c b/sbin/restore/restore.c
index 046c0d2..e494cdb 100644
--- a/sbin/restore/restore.c
+++ b/sbin/restore/restore.c
@@ -687,6 +687,17 @@ createfiles(void)
*/
if (first > last)
return;
+ if (Dflag) {
+ if (curfile.ino == maxino)
+ return;
+ if((ep = lookupino(curfile.ino)) != NULL &&
+ (ep->e_flags & (NEW|EXTRACT))) {
+ goto justgetit;
+ } else {
+ skipfile();
+ continue;
+ }
+ }
/*
* Reject any volumes with inodes greater than the last
* one needed, so that we can quickly skip backwards to
@@ -749,6 +760,7 @@ createfiles(void)
ep = lookupino(next);
if (ep == NULL)
panic("corrupted symbol table\n");
+justgetit:
(void) extractfile(myname(ep));
ep->e_flags &= ~NEW;
if (volno != curvol)
diff --git a/sbin/restore/restore.h b/sbin/restore/restore.h
index 04048dc..43e4db5 100644
--- a/sbin/restore/restore.h
+++ b/sbin/restore/restore.h
@@ -40,6 +40,7 @@
*/
extern int bflag; /* set input block size */
extern int dflag; /* print out debugging info */
+extern int Dflag; /* degraded mode - try hard to get stuff back */
extern int hflag; /* restore heirarchies */
extern int mflag; /* restore by name instead of inode number */
extern int Nflag; /* do not write the disk */
diff --git a/sbin/restore/tape.c b/sbin/restore/tape.c
index 83f5ec8..eb9802f 100644
--- a/sbin/restore/tape.c
+++ b/sbin/restore/tape.c
@@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <limits.h>
#include <paths.h>
#include <setjmp.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -74,6 +75,7 @@ static int blkcnt;
static int numtrec;
static char *tapebuf;
static union u_spcl endoftapemark;
+static long byteslide = 0;
static long blksread; /* blocks read since last header */
static int64_t tapeaddr = 0; /* current TP_BSIZE tape record */
static long tapesread;
@@ -170,12 +172,13 @@ newtapebuf(long size)
if (size <= tapebufsize)
return;
if (tapebuf != NULL)
- free(tapebuf);
- tapebuf = malloc(size * TP_BSIZE);
+ free(tapebuf - TP_BSIZE);
+ tapebuf = malloc((size+1) * TP_BSIZE);
if (tapebuf == NULL) {
fprintf(stderr, "Cannot allocate space for tape buffer\n");
done(1);
}
+ tapebuf += TP_BSIZE;
tapebufsize = size;
}
@@ -733,6 +736,15 @@ getfile(void (*fill)(char *, long), void (*skip)(char *, long))
gettingfile++;
loop:
for (i = 0; i < spcl.c_count; i++) {
+ if (!readmapflag && i > TP_NINDIR) {
+ if (Dflag) {
+ fprintf(stderr, "spcl.c_count = %jd\n",
+ (intmax_t)spcl.c_count);
+ break;
+ } else
+ panic("spcl.c_count = %jd\n",
+ (intmax_t)spcl.c_count);
+ }
if (readmapflag || spcl.c_addr[i]) {
readtape(&buf[curblk++][0]);
if (curblk == fssize / TP_BSIZE) {
@@ -751,9 +763,20 @@ loop:
TP_BSIZE : size));
}
if ((size -= TP_BSIZE) <= 0) {
- for (i++; i < spcl.c_count; i++)
+ for (i++; i < spcl.c_count; i++) {
+ if (!readmapflag && i > TP_NINDIR) {
+ if (Dflag) {
+ fprintf(stderr,
+ "spcl.c_count = %jd\n",
+ (intmax_t)spcl.c_count);
+ break;
+ } else
+ panic("spcl.c_count = %jd\n",
+ (intmax_t)spcl.c_count);
+ }
if (readmapflag || spcl.c_addr[i])
readtape(junk);
+ }
break;
}
}
@@ -872,15 +895,19 @@ xtrnull(char *buf, long size)
static void
readtape(char *buf)
{
- long rd, newvol, i;
+ long rd, newvol, i, oldnumtrec;
int cnt, seek_failed;
- if (blkcnt < numtrec) {
- memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
+ if (blkcnt + (byteslide > 0) < numtrec) {
+ memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE);
blksread++;
tapeaddr++;
return;
}
+ if (numtrec > 0)
+ memmove(&tapebuf[-TP_BSIZE],
+ &tapebuf[(numtrec-1) * TP_BSIZE], (long)TP_BSIZE);
+ oldnumtrec = numtrec;
for (i = 0; i < ntrec; i++)
((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
if (numtrec == 0)
@@ -981,8 +1008,12 @@ getmore:
terminateinput();
memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
}
- blkcnt = 0;
- memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
+ if (oldnumtrec == 0)
+ blkcnt = 0;
+ else
+ blkcnt -= oldnumtrec;
+ memmove(buf,
+ &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE);
blksread++;
tapeaddr++;
}
@@ -1069,6 +1100,8 @@ gethead(struct s_spcl *buf)
}
if (checksum((int *)buf) == FAIL)
return (FAIL);
+ if (_time64_to_time(buf->c_date) != dumpdate)
+ fprintf(stderr, "Header with wrong dumpdate.\n");
if (Bcvt) {
swabst((u_char *)"8l4s1q8l2q17l", (u_char *)buf);
swabst((u_char *)"l",(u_char *) &buf->c_level);
@@ -1225,8 +1258,17 @@ findinode(struct s_spcl *header)
if (header->c_addr[i])
readtape(buf);
while (gethead(header) == FAIL ||
- _time64_to_time(header->c_date) != dumpdate)
+ _time64_to_time(header->c_date) != dumpdate) {
skipcnt++;
+ if (Dflag) {
+ byteslide++;
+ if (byteslide < TP_BSIZE) {
+ blkcnt--;
+ blksread--;
+ } else
+ byteslide = 0;
+ }
+ }
break;
case TS_INODE:
@@ -1263,18 +1305,36 @@ findinode(struct s_spcl *header)
break;
case TS_TAPE:
- panic("unexpected tape header\n");
- /* NOTREACHED */
+ if (Dflag)
+ fprintf(stderr, "unexpected tape header\n");
+ else
+ panic("unexpected tape header\n");
default:
- panic("unknown tape header type %d\n", spcl.c_type);
- /* NOTREACHED */
+ if (Dflag)
+ fprintf(stderr, "unknown tape header type %d\n",
+ spcl.c_type);
+ else
+ panic("unknown tape header type %d\n",
+ spcl.c_type);
+ while (gethead(header) == FAIL ||
+ _time64_to_time(header->c_date) != dumpdate) {
+ skipcnt++;
+ if (Dflag) {
+ byteslide++;
+ if (byteslide < TP_BSIZE) {
+ blkcnt--;
+ blksread--;
+ } else
+ byteslide = 0;
+ }
+ }
}
} while (htype == TS_ADDR);
if (skipcnt > 0)
- fprintf(stderr, "resync restore, skipped %ld blocks\n",
- skipcnt);
+ fprintf(stderr, "resync restore, skipped %ld %s\n",
+ skipcnt, Dflag ? "bytes" : "blocks");
skipcnt = 0;
}
OpenPOWER on IntegriCloud