/* * Prompt user to load a new dump volume. * "Nextvol" is the next suggested volume to use. * This suggested volume is enforced when doing full * or incremental restores, but can be overridden by * the user when only extracting a subset of the files. */ void getvol(long nextvol) { int64_t prevtapea; long i, newvol, savecnt; union u_spcl tmpspcl; # define tmpbuf tmpspcl.s_spcl char buf[TP_BSIZE]; if (nextvol == 1) { tapesread = 0; gettingfile = 0; } prevtapea = tapeaddr; savecnt = blksread; if (pipein) { if (nextvol != 1) { panic("Changing volumes on pipe input?\n"); /* Avoid looping if we couldn't ask the user. */ if (yflag || ferror(terminal) || feof(terminal)) done(1); } if (volno == 1) return; goto gethdr; } again: if (pipein) done(1); /* pipes do not get a second chance */ if (command == 'R' || command == 'r' || curfile.action != SKIP) newvol = nextvol; else newvol = 0; while (newvol <= 0) { if (tapesread == 0) { fprintf(stderr, "%s%s%s%s%s%s%s", "You have not read any tapes yet.\n", "If you are extracting just a few files,", " start with the last volume\n", "and work towards the first; restore", " can quickly skip tapes that\n", "have no further files to extract.", " Otherwise, begin with volume 1.\n"); } else { fprintf(stderr, "You have read volumes"); strcpy(buf, ": "); for (i = 0; i < 32; i++) if (tapesread & (1 << i)) { fprintf(stderr, "%s%ld", buf, i + 1); strcpy(buf, ", "); } fprintf(stderr, "\n"); } do { fprintf(stderr, "Specify next volume #: "); (void) fflush(stderr); if (fgets(buf, BUFSIZ, terminal) == NULL) done(1); } while (buf[0] == '\n'); newvol = atoi(buf); if (newvol <= 0) { fprintf(stderr, "Volume numbers are positive numerics\n"); } } if (newvol == volno) { tapesread |= 1 << (volno - 1); return; } closemt(); fprintf(stderr, "Mount tape volume %ld\n", newvol); fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); (void) fflush(stderr); if (fgets(buf, BUFSIZ, terminal) == NULL) done(1); if (!strcmp(buf, "none\n")) { terminateinput(); return; } if (buf[0] != '\n') { (void) strcpy(magtape, buf); magtape[strlen(magtape) - 1] = '\0'; } if (pipecmdin) { char volno[sizeof("2147483647")]; (void)sprintf(volno, "%ld", newvol); if (setenv("RESTORE_VOLUME", volno, 1) == -1) { fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", strerror(errno)); done(1); } popenfp = popen(magtape, "r"); mt = popenfp ? fileno(popenfp) : -1; } else #ifdef RRESTORE if (host) mt = rmtopen(magtape, 0); else #endif mt = open(magtape, O_RDONLY, 0); if (mt == -1) { fprintf(stderr, "Cannot open %s\n", magtape); volno = -1; goto again; } gethdr: volno = newvol; setdumpnum(); FLUSHTAPEBUF(); if (gethead(&tmpbuf) == FAIL) { dprintf(stdout, "header read failed at %ld blocks\n", blksread); fprintf(stderr, "tape is not dump tape\n"); volno = 0; goto again; } if (tmpbuf.c_volume != volno) { fprintf(stderr, "Wrong volume (%jd)\n", (intmax_t)tmpbuf.c_volume); volno = 0; goto again; } if (_time64_to_time(tmpbuf.c_date) != dumpdate || _time64_to_time(tmpbuf.c_ddate) != dumptime) { time_t t = _time64_to_time(tmpbuf.c_date); fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t)); fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); volno = 0; goto again; } tapesread |= 1 << (volno - 1); blksread = savecnt; /* * If continuing from the previous volume, skip over any * blocks read already at the end of the previous volume. * * If coming to this volume at random, skip to the beginning * of the next record. */ dprintf(stdout, "last rec %jd, tape starts with %jd\n", (intmax_t)prevtapea, (intmax_t)tmpbuf.c_tapea); if (tmpbuf.c_type == TS_TAPE) { if (curfile.action != USING) { /* * XXX Dump incorrectly sets c_count to 1 in the * volume header of the first tape, so ignore * c_count when volno == 1. */ if (volno != 1) for (i = tmpbuf.c_count; i > 0; i--) readtape(buf); } else if (tmpbuf.c_tapea <= prevtapea) { /* * Normally the value of c_tapea in the volume * header is the record number of the header itself. * However in the volume header following an EOT- * terminated tape, it is the record number of the * first continuation data block (dump bug?). * * The next record we want is `prevtapea + 1'. */ i = prevtapea + 1 - tmpbuf.c_tapea; dprintf(stderr, "Skipping %ld duplicate record%s.\n", i, i > 1 ? "s" : ""); while (--i >= 0) readtape(buf); } } if (curfile.action == USING) { if (volno == 1) panic("active file into volume 1\n"); return; } (void) gethead(&spcl); findinode(&spcl); if (gettingfile) { gettingfile = 0; longjmp(restart, 1); } }
/* * Verify that the tape drive can be accessed and * that it actually is a dump tape. */ void setup(void) { int i, j, *ip; struct stat stbuf; vprintf(stdout, "Verify tape and initialize maps\n"); if (pipecmdin) { if (setenv("RESTORE_VOLUME", "1", 1) == -1) { fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", strerror(errno)); done(1); } popenfp = popen(magtape, "r"); mt = popenfp ? fileno(popenfp) : -1; } else #ifdef RRESTORE if (host) mt = rmtopen(magtape, 0); else #endif if (pipein) mt = 0; else mt = open(magtape, O_RDONLY, 0); if (mt < 0) { fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); done(1); } volno = 1; setdumpnum(); FLUSHTAPEBUF(); if (!pipein && !pipecmdin && !bflag) findtapeblksize(); if (gethead(&spcl) == FAIL) { fprintf(stderr, "Tape is not a dump tape\n"); done(1); } if (pipein) { endoftapemark.s_spcl.c_magic = FS_UFS2_MAGIC; endoftapemark.s_spcl.c_type = TS_END; ip = (int *)&endoftapemark; j = sizeof(union u_spcl) / sizeof(int); i = 0; do i += *ip++; while (--j); endoftapemark.s_spcl.c_checksum = CHECKSUM - i; } if (vflag || command == 't') printdumpinfo(); dumptime = _time64_to_time(spcl.c_ddate); dumpdate = _time64_to_time(spcl.c_date); if (stat(".", &stbuf) < 0) { fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); done(1); } if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) fssize = TP_BSIZE; if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) fssize = stbuf.st_blksize; if (((TP_BSIZE - 1) & stbuf.st_blksize) != 0) { fprintf(stderr, "Warning: filesystem with non-multiple-of-%d " "blocksize (%d);\n", TP_BSIZE, stbuf.st_blksize); fssize = roundup(fssize, TP_BSIZE); fprintf(stderr, "\twriting using blocksize %ld\n", fssize); } if (spcl.c_volume != 1) { fprintf(stderr, "Tape is not volume 1 of the dump\n"); done(1); } if (gethead(&spcl) == FAIL) { dprintf(stdout, "header read failed at %ld blocks\n", blksread); panic("no header after volume mark!\n"); } findinode(&spcl); if (spcl.c_type != TS_CLRI) { fprintf(stderr, "Cannot find file removal list\n"); done(1); } maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; dprintf(stdout, "maxino = %ju\n", (uintmax_t)maxino); map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); if (map == NULL) panic("no memory for active inode map\n"); usedinomap = map; curfile.action = USING; getfile(xtrmap, xtrmapskip, xtrmapskip); if (spcl.c_type != TS_BITS) { fprintf(stderr, "Cannot find file dump list\n"); done(1); } map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); if (map == (char *)NULL) panic("no memory for file dump list\n"); dumpmap = map; curfile.action = USING; getfile(xtrmap, xtrmapskip, xtrmapskip); /* * If there may be whiteout entries on the tape, pretend that the * whiteout inode exists, so that the whiteout entries can be * extracted. */ SETINO(WINO, dumpmap); /* 'r' restores don't call getvol() for tape 1, so mark it as read. */ if (command == 'r') tapesread = 1; }
/* * Verify that the tape drive can be accessed and * that it actually is a dump tape. */ void setup(void) { int i, j, *ip; struct stat stbuf; Vprintf(stdout, "Verify tape and initialize maps\n"); #ifdef RRESTORE if (host) mt = rmtopen(magtape, 0); else #endif if (pipein) mt = 0; else mt = open(magtape, O_RDONLY); if (mt < 0) err(1, "%s", magtape); volno = 1; setdumpnum(); FLUSHTAPEBUF(); if (!pipein && !bflag) findtapeblksize(); if (gethead(&spcl) == FAIL) { blkcnt--; /* push back this block */ blksread--; tpblksread--; cvtflag++; if (gethead(&spcl) == FAIL) errx(1, "Tape is not a dump tape"); (void)fputs("Converting to new file system format.\n", stderr); } if (pipein) { endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : FS_UFS2_MAGIC; endoftapemark.s_spcl.c_type = TS_END; ip = (int *)&endoftapemark; j = sizeof(union u_spcl) / sizeof(int); i = 0; do i += *ip++; while (--j); endoftapemark.s_spcl.c_checksum = CHECKSUM - i; } if (vflag || command == 't') printdumpinfo(); dumptime = (time_t)spcl.c_ddate; dumpdate = (time_t)spcl.c_date; if (stat(".", &stbuf) < 0) err(1, "cannot stat ."); if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) fssize = TP_BSIZE; if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) fssize = stbuf.st_blksize; if (((fssize - 1) & fssize) != 0) errx(1, "bad block size %ld", fssize); if (spcl.c_volume != 1) errx(1, "Tape is not volume 1 of the dump"); if (gethead(&spcl) == FAIL) { Dprintf(stdout, "header read failed at %ld blocks\n", blksread); panic("no header after volume mark!\n"); } findinode(&spcl); if (spcl.c_type != TS_CLRI) errx(1, "Cannot find file removal list"); maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; Dprintf(stdout, "maxino = %d\n", maxino); map = calloc(1, howmany(maxino, NBBY)); if (map == NULL) panic("no memory for active inode map\n"); usedinomap = map; curfile.action = USING; getfile(xtrmap, xtrmapskip); if (spcl.c_type != TS_BITS) errx(1, "Cannot find file dump list"); map = calloc(1, howmany(maxino, NBBY)); if (map == NULL) panic("no memory for file dump list\n"); dumpmap = map; curfile.action = USING; getfile(xtrmap, xtrmapskip); }
/* * Prompt user to load a new dump volume. * "Nextvol" is the next suggested volume to use. * This suggested volume is enforced when doing full * or incremental restores, but can be overrridden by * the user when only extracting a subset of the files. */ void getvol(long nextvol) { long newvol = 0, savecnt = 0, wantnext = 0, i; union u_spcl tmpspcl; # define tmpbuf tmpspcl.s_spcl char buf[TP_BSIZE]; const char *errstr; if (nextvol == 1) { tapesread = 0; gettingfile = 0; } if (pipein) { if (nextvol != 1) panic("Changing volumes on pipe input?\n"); if (volno == 1) return; goto gethdr; } savecnt = blksread; again: if (pipein) exit(1); /* pipes do not get a second chance */ if (command == 'R' || command == 'r' || curfile.action != SKIP) { newvol = nextvol; wantnext = 1; } else { newvol = 0; wantnext = 0; } while (newvol <= 0) { if (tapesread == 0) { fprintf(stderr, "%s%s%s%s%s", "You have not read any tapes yet.\n", "Unless you know which volume your", " file(s) are on you should start\n", "with the last volume and work", " towards the first.\n"); } else { fprintf(stderr, "You have read volumes"); strlcpy(buf, ": ", sizeof buf); for (i = 1; i < 32; i++) if (tapesread & (1 << i)) { fprintf(stderr, "%s%ld", buf, i); strlcpy(buf, ", ", sizeof buf); } fprintf(stderr, "\n"); } do { fprintf(stderr, "Specify next volume #: "); (void)fflush(stderr); if (fgets(buf, sizeof buf, terminal) == NULL) exit(1); buf[strcspn(buf, "\n")] = '\0'; newvol = strtonum(buf, 1, INT_MAX, &errstr); if (errstr) fprintf(stderr, "Volume number %s: %s\n", errstr, buf); } while (errstr); } if (newvol == volno) { tapesread |= 1 << volno; return; } closemt(); fprintf(stderr, "Mount tape volume %ld\n", newvol); fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); (void)fflush(stderr); if (fgets(buf, sizeof buf, terminal) == NULL || feof(terminal)) exit(1); buf[strcspn(buf, "\n")] = '\0'; if (strcmp(buf, "none") == 0) { terminateinput(); return; } if (buf[0] != '\0') (void)strlcpy(magtape, buf, sizeof magtape); #ifdef RRESTORE if (host) mt = rmtopen(magtape, 0); else #endif mt = open(magtape, O_RDONLY); if (mt == -1) { fprintf(stderr, "Cannot open %s\n", magtape); volno = -1; goto again; } gethdr: volno = newvol; setdumpnum(); FLUSHTAPEBUF(); if (gethead(&tmpbuf) == FAIL) { Dprintf(stdout, "header read failed at %ld blocks\n", blksread); fprintf(stderr, "tape is not dump tape\n"); volno = 0; goto again; } if (tmpbuf.c_volume != volno) { fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume); volno = 0; goto again; } if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) { time_t t = (time_t)tmpbuf.c_date; fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t)); fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); volno = 0; goto again; } tapesread |= 1 << volno; blksread = savecnt; /* * If continuing from the previous volume, skip over any * blocks read already at the end of the previous volume. * * If coming to this volume at random, skip to the beginning * of the next record. */ Dprintf(stdout, "read %ld recs, tape starts with %lld\n", tpblksread, tmpbuf.c_firstrec); if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) { if (!wantnext) { tpblksread = tmpbuf.c_firstrec; for (i = tmpbuf.c_count; i > 0; i--) readtape(buf); } else if (tmpbuf.c_firstrec > 0 && tmpbuf.c_firstrec < tpblksread - 1) { /* * -1 since we've read the volume header */ i = tpblksread - tmpbuf.c_firstrec - 1; Dprintf(stderr, "Skipping %ld duplicate record%s.\n", i, (i == 1) ? "" : "s"); while (--i >= 0) readtape(buf); } } if (curfile.action == USING) { if (volno == 1) panic("active file into volume 1\n"); return; } /* * Skip up to the beginning of the next record */ if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) for (i = tmpbuf.c_count; i > 0; i--) readtape(buf); (void)gethead(&spcl); findinode(&spcl); if (gettingfile) { gettingfile = 0; longjmp(restart, 1); } }
/* * Verify that the tape drive can be accessed and * that it actually is a dump tape. */ void setup(void) { int i, j, *ip; struct stat stbuf; vprintf(stdout, "Verify tape and initialize maps\n"); #ifdef RRESTORE if (host) mt = rmtopen(magtape, 0); else #endif if (pipein) mt = 0; else mt = open(magtape, O_RDONLY, 0); if (mt < 0) { fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); done(1); } volno = 1; setdumpnum(); FLUSHTAPEBUF(); if (!pipein && !bflag) findtapeblksize(); if (gethead(&spcl) == FAIL) { blkcnt--; /* push back this block */ blksread--; cvtflag++; if (gethead(&spcl) == FAIL) { fprintf(stderr, "Tape is not a dump tape\n"); done(1); } fprintf(stderr, "Converting to new file system format.\n"); } if (pipein) { endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC; endoftapemark.s_spcl.c_type = TS_END; ip = (int *)&endoftapemark; j = sizeof(union u_spcl) / sizeof(int); i = 0; do i += *ip++; while (--j); endoftapemark.s_spcl.c_checksum = CHECKSUM - i; } if (vflag || command == 't') printdumpinfo(); dumptime = spcl.c_ddate; dumpdate = spcl.c_date; if (stat(".", &stbuf) < 0) { fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); done(1); } if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) fssize = TP_BSIZE; if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) fssize = stbuf.st_blksize; if (((fssize - 1) & fssize) != 0) { fprintf(stderr, "bad block size %ld\n", fssize); done(1); } if (spcl.c_volume != 1) { fprintf(stderr, "Tape is not volume 1 of the dump\n"); done(1); } if (gethead(&spcl) == FAIL) { dprintf(stdout, "header read failed at %ld blocks\n", blksread); panic("no header after volume mark!\n"); } findinode(&spcl); if (spcl.c_type != TS_CLRI) { fprintf(stderr, "Cannot find file removal list\n"); done(1); } maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; dprintf(stdout, "maxino = %d\n", maxino); map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); if (map == NULL) panic("no memory for active inode map\n"); usedinomap = map; curfile.action = USING; getfile(xtrmap, xtrmapskip); if (spcl.c_type != TS_BITS) { fprintf(stderr, "Cannot find file dump list\n"); done(1); } map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); if (map == NULL) panic("no memory for file dump list\n"); dumpmap = map; curfile.action = USING; getfile(xtrmap, xtrmapskip); /* * If there may be whiteout entries on the tape, pretend that the * whiteout inode exists, so that the whiteout entries can be * extracted. */ if (oldinofmt == 0) SETINO(WINO, dumpmap); /* 'r' restores don't call getvol() for tape 1, so mark it as read. */ if (command == 'r') tapesread = 1; }