[net.bugs.4bsd] Bug in dump

dmmartindale (12/08/82)

When specifying the device to be dumped, you can give either the device
name or the name that the filesystem is normally mounted on.  Unfortunately,
the code which does the string matching is wrong, and so "/u" will match
"/usr".  Basically, strncmp is passed the wrong length and ends up
checking to see if one name is a prefix of the other.  The following diff
shows the needed changes from the 4.1BSD distribution (don't expect line
numbers to match though).

	Dave Martindale

*** /usr/distr/4.1/usr/src/cmd/dump/dumpoptr.c	Thu Dec 18 03:52:59 1980
--- dumpoptr.c	Tue Dec  7 17:00:46 1982
***************
*** 230,236
  			(((1.0*(tnow - tstart_writing))/blockswritten) * esize);
  		msg("%3.2f%% done, finished in %d:%02d\n",
  			(blockswritten*100.0)/esize,
! 			deltat/3600, (deltat%3600)/60);
  	}
  }
  

--- 230,236 -----
  			(((1.0*(tnow - tstart_writing))/blockswritten) * esize);
  		msg("%3.2f%% done, finished in %d:%02d\n",
  			(blockswritten*100.0)/esize,
! 			(int)deltat/3600, ((int)deltat%3600)/60);
  	}
  }
  
***************
*** 315,321
  {
  	register	struct	fstab *dt;
  			int	i;
- 			int	keylength;
  			char	*rawname();
  
  	keylength = min(strlen(key), sizeof (dt->fs_file));

--- 315,320 -----
  {
  	register	struct	fstab *dt;
  			int	i;
  			char	*rawname();
  
  	for (i = 0, dt = fstab; i < nfstab; i++, dt++){
***************
*** 318,324
  			int	keylength;
  			char	*rawname();
  
- 	keylength = min(strlen(key), sizeof (dt->fs_file));
  	for (i = 0, dt = fstab; i < nfstab; i++, dt++){
  		if (strncmp(dt->fs_file, key, keylength) == 0)
  			return(dt);

--- 317,322 -----
  			int	i;
  			char	*rawname();
  
  	for (i = 0, dt = fstab; i < nfstab; i++, dt++){
  		if (strncmp(dt->fs_file, key, sizeof(dt->fs_file)) == 0)
  			return(dt);
***************
*** 320,326
  
  	keylength = min(strlen(key), sizeof (dt->fs_file));
  	for (i = 0, dt = fstab; i < nfstab; i++, dt++){
! 		if (strncmp(dt->fs_file, key, keylength) == 0)
  			return(dt);
  		if (strncmp(dt->fs_spec, key, keylength) == 0)
  			return(dt);

--- 318,324 -----
  			char	*rawname();
  
  	for (i = 0, dt = fstab; i < nfstab; i++, dt++){
! 		if (strncmp(dt->fs_file, key, sizeof(dt->fs_file)) == 0)
  			return(dt);
  		if (strncmp(dt->fs_spec, key, sizeof(dt->fs_spec)) == 0)
  			return(dt);
***************
*** 322,328
  	for (i = 0, dt = fstab; i < nfstab; i++, dt++){
  		if (strncmp(dt->fs_file, key, keylength) == 0)
  			return(dt);
! 		if (strncmp(dt->fs_spec, key, keylength) == 0)
  			return(dt);
  		if (strncmp(rawname(dt->fs_spec), key, keylength) == 0)
  			return(dt);

--- 320,326 -----
  	for (i = 0, dt = fstab; i < nfstab; i++, dt++){
  		if (strncmp(dt->fs_file, key, sizeof(dt->fs_file)) == 0)
  			return(dt);
! 		if (strncmp(dt->fs_spec, key, sizeof(dt->fs_spec)) == 0)
  			return(dt);
  		if (strcmp(rawname(dt->fs_spec), key) == 0)
  			return(dt);
***************
*** 324,330
  			return(dt);
  		if (strncmp(dt->fs_spec, key, keylength) == 0)
  			return(dt);
! 		if (strncmp(rawname(dt->fs_spec), key, keylength) == 0)
  			return(dt);
  
  		if (key[0] != '/'){

--- 322,328 -----
  			return(dt);
  		if (strncmp(dt->fs_spec, key, sizeof(dt->fs_spec)) == 0)
  			return(dt);
! 		if (strcmp(rawname(dt->fs_spec), key) == 0)
  			return(dt);
  
  		if (key[0] != '/'){
***************
*** 329,335
  
  		if (key[0] != '/'){
  			if (   (dt->fs_spec[0] == '/')
! 			    && (strncmp(dt->fs_spec+1, key, keylength) == 0))
  				return(dt);
  			if (   (dt->fs_file[0] == '/')
  			    && (strncmp(dt->fs_file+1, key, keylength) == 0))

--- 327,333 -----
  
  		if (key[0] != '/'){
  			if (   (dt->fs_spec[0] == '/')
! 			    && (strncmp(dt->fs_spec+1, key, sizeof(dt->fs_spec)-1) == 0))
  				return(dt);
  			if (   (dt->fs_file[0] == '/')
  			    && (strncmp(dt->fs_file+1, key, sizeof(dt->fs_file)-1) == 0))
***************
*** 332,338
  			    && (strncmp(dt->fs_spec+1, key, keylength) == 0))
  				return(dt);
  			if (   (dt->fs_file[0] == '/')
! 			    && (strncmp(dt->fs_file+1, key, keylength) == 0))
  				return(dt);
  		}
  	}

--- 330,336 -----
  			    && (strncmp(dt->fs_spec+1, key, sizeof(dt->fs_spec)-1) == 0))
  				return(dt);
  			if (   (dt->fs_file[0] == '/')
! 			    && (strncmp(dt->fs_file+1, key, sizeof(dt->fs_file)-1) == 0))
  				return(dt);
  		}
  	}

mckusick@ucbvax.UUCP (Kirk Mckusick) (03/25/84)

From: dlw@berkeley (David L Wasley)
Subject: bug in dump
Index:	/usr/src/etc/dump	4.2	Fix

Description:
	The problem is that restore needs the full inode bitmap
	for the filesystem. Dump, as distributed, truncates the
	map to the smallest size possible (the highest inode of
	interest). This causes restore to FAIL in some cases.

Repeat-by:
	newfs /dev/rra0h ra81
	dump 0 /dev/rra0h
	...(add stuff to the filesystem)...
	dump 3 /dev/rra0h

	Now try to restore it.

Fix:
	Below is a diff of dumptraverse.c that will fix the bug.
	The line numbers may not match yours. The routine is
	``bitmap()''.
------
diff  dumptraverse.c.old  dumptraverse.c
------
210,218c211
< 	n = -1;
< 	for (i = 0; i < msiz; i++)
< 		if(map[i])
< 			n = i;
< 	if (n < 0)
< 		return;
< 	n++;
<
< 	spcl.c_count = howmany(n * sizeof(map[0]), TP_BSIZE);
---
> 	spcl.c_count = howmany(msiz * sizeof(map[0]), TP_BSIZE);

srradia@watmath.UUCP (sanjay Radia) (06/25/84)

Index: dump 4.2 Fix

Description:
	A serious bug exists in dump.
Dump makes a pass through all the inodes and marks the inodes to be
dumped in dirmap & nodmap. However, if the system is busy the inodes
can be deleted and possibly reallocated for other files.
In the next pass, when dumping inodes, dump does not bother to check to see if
the inodes are still allocated and in the case of directories does not check to
see the inode is still a directory.

	Now, the dump tape has a bunch of directories (directory-zone) followed
by non-directories and as soon as restore sees a non-directory it thinks it has
scanned the directory-zone. Thus if a directory inode is delelted (and maybe
realloced to a file) between the 1st & 2nd passes of dump, the dump tape
will not be correctly read by restore (you will loose some (a lot) of the
directory information).

Repeated-By:
	Create about 3 directories and start a dump on the file system.
When dump asks you to mount the tape delete one of the three
directories (the one with the lowest inode #). Now continue with the
dump. 
	Do a "/etc/restore ivd". You will see that restore will not
know of any directories with inodes greater than the the one you deleted
(ie they will be marked as regular files and not as directories). You
can check this out by doing a "lc" in restore's interactive mode.


Fix:
	The following is a fix to dump. Since our dump has changed, the line
numbers might not match.
Note that restore can be fixed to ignore free inodes (in function
dirextract() in dirs.c) but there is no nice way to by-pass file-inodes
in the directory-zone. There should have been a special record between
the directory-zone and the file-zone (if you put this in, your old & new tapes
will not be compatible).



****** dumpmain.c
>change the line marked with ! (the context and old/new versions given
OLD *** 265,271
  	bitmap(clrmap, TS_CLRI);
  
  	msg("dumping (Pass III) [directories]\n");
! 	pass(dump, dirmap);
  
  	msg("dumping (Pass IV) [regular files]\n");
  	pass(dump, nodmap);

NEW --- 288,295 -----
  	bitmap(clrmap, TS_CLRI);
  
  	msg("dumping (Pass III) [directories]\n");
! 	pass(dirdump, dirmap);
  
  	msg("dumping (Pass IV) [regular files]\n");
  	pass(dump, nodmap);






--- dumptraverse.c
> add the function dirdump() (marked with +) (add an extern in dump.h)
> and add the lines marked with '+' in dump() (the context is given)
  
+ dirdump(ip)
+ 	struct dinode *ip;
+ {
+ 	/* watchout for dir inodes deleted and maybe reallocated */
+ 	if ((ip->di_mode & IFMT) != IFDIR)
+ 		return;
+ 	dump(ip);
+ }
+ 
+ 
  dump(ip)
 	struct dinode *ip;
  {
	........
	......
	.....
  	i = ip->di_mode & IFMT;
+ 
+ 	if (i == 0) /* free inode */
+ 		return;
+ 
  	if ((i != IFDIR && i != IFREG && i != IFLNK) || ip->di_size == 0) {
  		spclrec();
  		return;
-- 
			sanjay
			{allegra,decvax}!watmath!srradia

henry@utzoo.UUCP (Henry Spencer) (06/26/84)

You've just discovered a reason (one of several) why people who really
want to trust their dumps run them single-user so the filesystems are
guaranteed to be static.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry