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
This commit is contained in:
dwmalone 2006-12-05 11:18:51 +00:00
parent f352d33919
commit 12df44b425
5 changed files with 104 additions and 22 deletions

View File

@ -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,

View File

@ -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 ;

View File

@ -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)

View File

@ -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 */

View File

@ -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 @@ getfile(void (*fill)(char *, long), void (*skip)(char *, long))
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 @@ readtape(char *buf)
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;
}