vix@ubvax.UB.Com (Paul Vixie) (10/23/87)
Subject: restore has bugs and deficiencies with small volumes (floppies) +FIX Index: /usr/src/etc/restore/{restore.h,dirs.c,tape.c} 4.3BSD Description: When used with small volumes (like floppies), dump and restore don't always work. For one thing, a 'long int' bit mask was used to keep track of which volumes were read -- so dumps of more than 32 volumes (gag me) were not gracefully handled by restore. More important, though, there is a bug in restore that makes a dump set unusable if all the nonterminal inodes did not fit onto the first volume. This is arguably a bug in dump, but the obvious place to account for the problem is in restore. Repeat-By: Create a dump set of more than 32 volumes -- use dump 0s 10 / or something. Dump to files if you'd prefer; you'll have to ^Z and rename the file after each volume. After you create the dump set, try to use interactive restore on it, and notice that it will not be able to remember when you have read volumes #33, #34, etc. Next, create a dump set where all directories (nonterminal inodes) do not fit on the first volume. Something like dump 0s 2 / will probably do the trick. Using interactive restore, notice that the "reading directories" phase ends about 0.0001% into the second volume. Then notice that many of the things you know to be directories are not marked as such in restore's interactive "ls" command (i.e., no trailing "/"). Note that you cannot "cd" into these directories, and that therefore you could not restore any files from those direct- ories if you wanted to. Fix: Apply the following patches in the /usr/src/etc/restore directory. These will make it possible to have dump sets of up to 128 volumes (set in a #define, but this value seems sufficiently unreasonable); also, restore will no longer stop reading directories when it encounters a BITS or CLRI header (which are put there by dump for some bizarre reason). diff -c2 /usr/src/etc/restore/dirs.c ./dirs.c *** /usr/src/etc/restore/dirs.c Wed Apr 23 12:05:16 1986 --- ./dirs.c Fri Oct 16 15:20:01 1987 *************** *** 69,73 **** int genmode; { ! register int i; register struct dinode *ip; struct inotab *itp; --- 69,73 ---- int genmode; { ! register int i, ts; register struct dinode *ip; struct inotab *itp; *************** *** 104,108 **** curfile.action = USING; ip = curfile.dip; ! if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { (void) fclose(df); dirp = opendir(dirfile); --- 104,115 ---- curfile.action = USING; ip = curfile.dip; ! ts = curfile.ts; ! if (ts != TS_END && ts != TS_INODE) { ! getfile(null, null); ! continue; ! } ! if ( (ts == TS_INODE && (ip->di_mode & IFMT) != IFDIR) ! || (ts == TS_END) ! ) { (void) fclose(df); dirp = opendir(dirfile); diff -c2 /usr/src/etc/restore/restore.h ./restore.h *** /usr/src/etc/restore/restore.h Tue May 28 15:18:47 1985 --- ./restore.h Fri Oct 16 14:46:26 1987 *************** *** 94,98 **** ino_t ino; /* inumber of file */ struct dinode *dip; /* pointer to inode */ ! char action; /* action being taken on this file */ } curfile; /* actions */ --- 94,99 ---- ino_t ino; /* inumber of file */ struct dinode *dip; /* pointer to inode */ ! int action; /* action being taken on this file */ ! int ts; /* TS_* type of tape record */ } curfile; /* actions */ diff -c2 /usr/src/etc/restore/tape.c ./tape.c *** /usr/src/etc/restore/tape.c Fri May 2 11:05:17 1986 --- ./tape.c Fri Oct 16 14:00:16 1987 *************** *** 17,20 **** --- 17,22 ---- #include <sys/stat.h> + #define MAXTAPES 128 + static long fssize = MAXBSIZE; static int mt = -1; *************** *** 25,29 **** static union u_spcl endoftapemark; static long blksread; ! static long tapesread; static jmp_buf restart; static int gettingfile = 0; /* restart has a valid frame */ --- 27,31 ---- static union u_spcl endoftapemark; static long blksread; ! static u_char tapesread[MAXTAPES]; static jmp_buf restart; static int gettingfile = 0; /* restart has a valid frame */ *************** *** 215,219 **** if (nextvol == 1) { ! tapesread = 0; gettingfile = 0; } --- 217,222 ---- if (nextvol == 1) { ! for (i = 0; i < MAXTAPES; i++) ! tapesread[i] = 0; gettingfile = 0; } *************** *** 234,238 **** newvol = 0; while (newvol <= 0) { ! if (tapesread == 0) { fprintf(stderr, "%s%s%s%s%s", "You have not read any tapes yet.\n", --- 237,246 ---- newvol = 0; while (newvol <= 0) { ! int n = 0; ! ! for (i = 0; i < MAXTAPES; i++) ! if (tapesread[i]) ! n++; ! if (n == 0) { fprintf(stderr, "%s%s%s%s%s", "You have not read any tapes yet.\n", *************** *** 244,250 **** fprintf(stderr, "You have read volumes"); strcpy(tbf, ": "); ! for (i = 1; i < 32; i++) ! if (tapesread & (1 << i)) { ! fprintf(stderr, "%s%d", tbf, i); strcpy(tbf, ", "); } --- 252,258 ---- fprintf(stderr, "You have read volumes"); strcpy(tbf, ": "); ! for (i = 0; i < MAXTAPES; i++) ! if (tapesread[i]) { ! fprintf(stderr, "%s%d", tbf, i+1); strcpy(tbf, ", "); } *************** *** 263,269 **** "Volume numbers are positive numerics\n"); } } if (newvol == volno) { ! tapesread |= 1 << volno; return; } --- 271,283 ---- "Volume numbers are positive numerics\n"); } + if (newvol > MAXTAPES) { + fprintf(stderr, + "This program can only deal with %d volumes\n", + MAXTAPES); + newvol = 0; + } } if (newvol == volno) { ! tapesread[volno-1]++; return; } *************** *** 310,314 **** goto again; } ! tapesread |= 1 << volno; blksread = savecnt; if (curfile.action == USING) { --- 324,328 ---- goto again; } ! tapesread[volno-1]++; blksread = savecnt; if (curfile.action == USING) { *************** *** 936,939 **** --- 950,954 ---- curfile.dip = (struct dinode *)NIL; curfile.ino = 0; + curfile.ts = 0; if (ishead(header) == FAIL) { skipcnt++; *************** *** 945,948 **** --- 960,964 ---- curfile.dip = &header->c_dinode; curfile.ino = header->c_inumber; + curfile.ts = TS_INODE; break; } *************** *** 949,952 **** --- 965,969 ---- if (checktype(header, TS_END) == GOOD) { curfile.ino = maxino; + curfile.ts = TS_END; break; } *************** *** 953,956 **** --- 970,974 ---- if (checktype(header, TS_CLRI) == GOOD) { curfile.name = "<file removal list>"; + curfile.ts = TS_CLRI; break; } *************** *** 957,960 **** --- 975,979 ---- if (checktype(header, TS_BITS) == GOOD) { curfile.name = "<file dump list>"; + curfile.ts = TS_BITS; break; } -- Paul Vixie Consultant Work: 408-562-7798 vix@ubvax.ub.com Ungermann-Bass Home: 415-647-7023 ames!pyramid!ubvax!vix Santa Clara, CA <<I do not speak for Ungermann-Bass>>
roy@phri.UUCP (Roy Smith) (10/24/87)
[The referenced aritcle was in comp.bugs.4bsd, but comp.unix.wizards seemed a better place for discussion, so I've directed followups there] In article <3067@ubvax.UB.Com> vix@ubvax.UUCP (Paul Vixie) writes (regarding creating multi-volume dumps on disk files): > you'll have to ^Z and rename the file after each volume. Earlier versions of dump had a flag to increment the last character of the file name between volumes. Presumably this was so you could do a 4-tape dump by loading up all four of your tape drives and then telling dump to use /dev/mt0, and increment to mt1, mt2, mt3 as needed, and without human intervention. Of course, I've never actually seen a Unix system with more than one tape transport (although I'm sure they exist). Why was this option taken out of later versions? Seems simple enough to implement, and it was already there. -- Roy Smith, {allegra,cmcl2,philabs}!phri!roy System Administrator, Public Health Research Institute 455 First Avenue, New York, NY 10016