[comp.bugs.4bsd] tar does not understand FIFO special files

arnold@emory.uucp (Arnold D. Robbins {EUCC}) (08/06/88)

(This does not really apply to strict Vanilla 4.3 BSD. But there are lots
of hybrids out there, and this does apply to Sun systems.)

Subject: tar does not understand FIFO special files
Index:	/usr/src/bin/tar.c 4.3BSD + NFS
Index:	/usr/man/man5/tar.5 4.3BSD + NFS

Description:
	On systems which support System V 'fifo' special files (named
	pipes), tar does not recognize such files.
Repeat-By:
	On a Mt. Xinu or SunOS 4.0 system, create a FIFO special file, via
	mknod. Try to archive it with tar. Watch tar decide that it is
	not a file.
Fix:
	Apply the following two fixes to the source and the tar(5) man
	page respectively. Based on John Gilmore's pdtar, I have used a
	linkflag of '6' for fifos; he was following the POSIX spec.
	(Yes, I suppose I could switch to his version of tar.)

	Your line numbers may vary. In particular, I have Guy Harris's
	fix for not unlinking directories already installed.

*** /tmp/,RCSt1016378	Fri Aug  5 15:57:34 1988
--- tar.c	Fri Aug  5 12:29:41 1988
***************
*** 659,664 ****
--- 659,714 ----
  			putempty();
  		break;
  
+ #ifdef S_IFIFO
+ 	case S_IFIFO:
+ 		tomodes(&stbuf);
+ 		if (strlen(longname) >= NAMSIZ) {
+ 			fprintf(stderr, "tar: %s: file name too long\n",
+ 			    longname);
+ 			return;
+ 		}
+ 		strcpy(dblock.dbuf.name, longname);
+ 		if (stbuf.st_nlink > 1) {
+ 			struct linkbuf *lp;
+ 			int found = 0;
+ 
+ 			for (lp = ihead; lp != NULL; lp = lp->nextp)
+ 				if (lp->inum == stbuf.st_ino &&
+ 				    lp->devnum == stbuf.st_dev) {
+ 					found++;
+ 					break;
+ 				}
+ 			if (found) {
+ 				strcpy(dblock.dbuf.linkname, lp->pathname);
+ 				dblock.dbuf.linkflag = '1';
+ 				sprintf(dblock.dbuf.chksum, "%6o", checksum());
+ 				(void) writetape( (char *) &dblock);
+ 				if (vflag)
+ 					fprintf(vfile, "a %s link to %s\n",
+ 					    longname, lp->pathname);
+ 				lp->count--;
+ 				return;
+ 			}
+ 			lp = (struct linkbuf *) getmem(sizeof(*lp));
+ 			if (lp != NULL) {
+ 				lp->nextp = ihead;
+ 				ihead = lp;
+ 				lp->inum = stbuf.st_ino;
+ 				lp->devnum = stbuf.st_dev;
+ 				lp->count = stbuf.st_nlink - 1;
+ 				strcpy(lp->pathname, longname);
+ 			}
+ 		}
+ 		dblock.dbuf.linkname[i] = '\0';
+ 		dblock.dbuf.linkflag = '6';	/* from POSIX */
+ 		sprintf(dblock.dbuf.size, "%11lo", 0);
+ 		sprintf(dblock.dbuf.chksum, "%6o", checksum());
+ 		if (vflag)
+ 			fprintf (vfile, "a %s FIFO special file\n", longname);
+ 		(void) writetape((char *)&dblock);
+ 		break;
+ #endif
+ 
  	default:
  		fprintf(stderr, "tar: %s is not a file. Not dumped\n",
  		    longname);
***************
*** 698,703 ****
--- 748,774 ----
  				dodirtimes(&dblock);
  			continue;
  		}
+ 		if (dblock.dbuf.linkflag == '6') {	/* FIFO */
+ 			/*
+ 			 * only unlink non directories or empty
+ 			 * directories
+ 			 */
+ 			if (rmdir(dblock.dbuf.name) < 0) {
+ 				if (errno == ENOTDIR)
+ 					unlink(dblock.dbuf.name);
+ 			}
+ 			if (mkfifo(dblock.dbuf.name, stbuf.st_mode&0xfff) < 0) {
+ 				fprintf (stderr, "tar: can't make FIFO %s: ",
+ 					dblock.dbuf.name);
+ 				perror ("");
+ 				continue;
+ 			}
+ 			chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
+ 			if (vflag)
+ 				fprintf (vfile, "x %s FIFO special file\n",
+ 					dblock.dbuf.name);
+ 			continue;
+ 		}
  		if (dblock.dbuf.linkflag == '2') {	/* symlink */
  			/*
  			 * only unlink non directories or empty
***************
*** 1433,1436 ****
--- 1504,1531 ----
  		freemem = 0;
  	}
  	return (p);
+ }
+ 
+ /*
+  * mkfifo
+  *
+  * POSIX call to make a fifo.
+  * This should be either a library routine,
+  * or a system call.
+  *
+  * At some point in the future, will this be where
+  * UNIX domain sockets are made?
+  */
+ 
+ int
+ mkfifo (path, mode)
+ char *path;
+ int mode;
+ {
+ #ifdef S_IFIFO
+ 	return mknod (path, mode | S_IFIFO, 0);
+ #else
+ 	errno = EOPNOTSUPP;	/* XXX - for now */
+ 	return -1;
+ #endif
  }


*** /tmp/,RCSt1016434	Fri Aug  5 16:02:47 1988
--- tar.5	Fri Aug  5 16:02:23 1988
***************
*** 112,118 ****
  .IR Linkflag
  is NULL if the file is ``normal'' or a special file, ASCII `1'
  if it is an hard link, and ASCII `2'
! if it is a symbolic link.  The name linked-to, if any, is in
  .IR linkname,
  with a trailing null.
  Unused fields of the header are binary zeros (and are included in the
--- 112,121 ----
  .IR Linkflag
  is NULL if the file is ``normal'' or a special file, ASCII `1'
  if it is an hard link, and ASCII `2'
! if it is a symbolic link.
! .I Linkflag
! will be an ASCII `6' if the file is a FIFO special file.
! The name linked-to, if any, is in
  .IR linkname,
  with a trailing null.
  Unused fields of the header are binary zeros (and are included in the
-- 
Arnold Robbins
ARPA, CSNET:	arnold@emory.ARPA	BITNET: arnold@emory
UUCP: { decvax, gatech, }!emory!arnold	DOMAIN: arnold@emory.edu (soon)
	``csh: just say NO!''