[comp.sources.atari.st] v02i051: gnutar -- GNU's version of UNIX "tar" part05/08

koreth%panarthea.ebay@sun.com (Steven Grimm) (07/20/89)

Submitted-by: 7103_300@uwovax.uwo.ca (Eric R. Smith)
Posting-number: Volume 2, Issue 51
Archive-name: gnutar/part05

#!/bin/sh
# this is part 5 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file PORT.C continued
#
CurArch=5
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file PORT.C"
sed 's/^X//' << 'SHAR_EOF' >> PORT.C
X	    optind++;
X	  last_nonopt = optind;
X	}
X
X      /* Special ARGV-element `--' means premature end of options.
X	 Skip it like a null option,
X	 then exchange with previous non-options as if it were an option,
X	 then skip everything else like a non-option.  */
X
X      if (optind != argc && !strcmp (argv[optind], "--"))
X	{
X	  optind++;
X
X	  if (first_nonopt != last_nonopt && last_nonopt != optind)
X	    exchange (argv);
X	  else if (first_nonopt == last_nonopt)
X	    first_nonopt = optind;
X	  last_nonopt = argc;
X
X	  optind = argc;
X	}
X
X      /* If we have done all the ARGV-elements, stop the scan
X	 and back over any non-options that we skipped and permuted.  */
X
X      if (optind == argc)
X	{
X	  /* Set the next-arg-index to point at the non-options
X	     that we previously skipped, so the caller will digest them.  */
X	  if (first_nonopt != last_nonopt)
X	    optind = first_nonopt;
X	  return EOF;
X	}
X	 
X      /* If we have come to a non-option and did not permute it,
X	 either stop the scan or describe it to the caller and pass it by.  */
X
X      if (argv[optind][0] != '-' || argv[optind][1] == 0)
X	{
X	  if (ordering == REQUIRE_ORDER)
X	    return EOF;
X	  optarg = argv[optind++];
X	  return 0;
X	}
X
X      /* We have found another option-ARGV-element.
X	 Start decoding its characters.  */
X
X      nextchar = argv[optind] + 1;
X    }
X
X  /* Look at and handle the next option-character.  */
X
X  {
X    char c = *nextchar++;
X    char *temp = (char *) index (optstring, c);
X
X    /* Increment `optind' when we start to process its last character.  */
X    if (*nextchar == 0)
X      optind++;
X
X    if (temp == 0)
X      {
X	if (opterr != 0)
X	  {
X	    if (c < 040 || c >= 0177)
X	      fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
X		       argv[0], c);
X	    else
X	      fprintf (stderr, "%s: unrecognized option `-%c'\n",
X		       argv[0], c);
X	  }
X	return '?';
X      }
X    if (temp[1] == ':')
X      {
X	if (temp[2] == ':')
X	  {
X	    /* This is an option that accepts an argument optionally.  */
X	    if (*nextchar != 0)
X	      {
X	        optarg = nextchar;
X		optind++;
X	      }
X	    else
X	      optarg = 0;
X	    nextchar = 0;
X	  }
X	else
X	  {
X	    /* This is an option that requires an argument.  */
X	    if (*nextchar != 0)
X	      {
X		optarg = nextchar;
X		/* If we end this ARGV-element by taking the rest as an arg,
X		   we must advance to the next element now.  */
X		optind++;
X	      }
X	    else if (optind == argc)
X	      {
X		if (opterr != 0)
X		  fprintf (stderr, "%s: no argument for `-%c' option\n",
X			   argv[0], c);
X		optarg = 0;
X	      }
X	    else
X	      /* We already incremented `optind' once;
X		 increment it again when taking next ARGV-elt as argument.  */
X	      optarg = argv[optind++];
X	    nextchar = 0;
X	  }
X      }
X    return c;
X  }
X}
X
X#ifdef TEST
X
X/* Compile with -DTEST to make an executable for use in testing
X   the above definition of `getopt'.  */
X
Xint
Xmain (argc, argv)
X     int argc;
X     char **argv;
X{
X  char c;
X  int digit_optind = 0;
X
X  while (1)
X    {
X      int this_option_optind = optind;
X      if ((c = getopt (argc, argv, "abc:d:0123456789")) == EOF)
X	break;
X
X      switch (c)
X	{
X	case '0':
X	case '1':
X	case '2':
X	case '3':
X	case '4':
X	case '5':
X	case '6':
X	case '7':
X	case '8':
X	case '9':
X	  if (digit_optind != 0 && digit_optind != this_option_optind)
X	    printf ("digits occur in two different argv-elements.\n");
X	  digit_optind = this_option_optind;
X	  printf ("option %c\n", c);
X	  break;
X
X	case 'a':
X	  printf ("option a\n");
X	  break;
X
X	case 'b':
X	  printf ("option b\n");
X	  break;
X
X	case 'c':
X	  printf ("option c with value `%s'\n", optarg);
X	  break;
X
X	case '?':
X	  break;
X
X	default:
X	  printf ("?? getopt returned character code 0%o ??\n", c);
X	}
X    }
X
X  if (optind < argc)
X    {
X      printf ("non-option ARGV-elements: ");
X      while (optind < argc)
X	printf ("%s ", argv[optind++]);
X      printf ("\n");
X    }
X
X  return 0;
X}
X
X#endif /* TEST */
X
X#endif /* WANT_GETOPT */
X
X#ifdef WANT_STRSTR
X
X/*
X * strstr - find first occurrence of wanted in s
X */
X
Xchar *				/* found string, or NULL if none */
Xstrstr(s, wanted)
Xchar *s;
Xchar *wanted;
X{
X	register char *scan;
X	register size_t len;
X	register char firstc;
X	extern int strcmp();
X
X	/*
X	 * The odd placement of the two tests is so "" is findable.
X	 * Also, we inline the first char for speed.
X	 * The ++ on scan has been moved down for optimization.
X	 */
X	firstc = *wanted;
X	len = strlen(wanted);
X	for (scan = s; *scan != firstc || strncmp(scan, wanted, len) != 0; )
X		if (*scan++ == '\0')
X			return (char *)0;
X	return scan;
X}
X#endif
X
X#ifdef STDC_MSG
X#include <stdarg.h>
X
X
Xvoid
Xmsg(char *str,...)
X{
X	va_list args;
X
X	va_start(args,str);
X	fprintf(stderr,"%s: ",tar);
X	if(f_sayblock)
X		fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block));
X	vfprintf(stderr,str,args);
X	va_end(args);
X	putc('\n',stderr);
X}
X
Xvoid
Xmsg_perror(char *str,...)
X{
X	va_list args;
X	int save_e;
X	extern int errno;
X
X	save_e=errno;
X	fprintf(stderr,"%s: ",tar);
X	if(f_sayblock)
X		fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block));
X	va_start(args,str);
X	vfprintf(stderr,str,args);
X	va_end(args);
X	fprintf(stderr,": ");
X	errno=save_e;
X	perror((char *)0);
X}
X#endif
X
X#ifdef VARARGS_MSG
X#include <varargs.h>
Xvoid msg(str,va_alist)
Xchar *str;
Xva_dcl
X{
X	va_list args;
X
X	fprintf(stderr,"%s: ",tar);
X	if(f_sayblock)
X		fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block));
X	va_start(args);
X	vfprintf(stderr,str,args);
X	va_end(args);
X	putc('\n',stderr);
X}
X
Xvoid msg_perror(str,va_alist)
Xchar *str;
Xva_dcl
X{
X	va_list args;
X	int save_e;
X	extern int errno;
X
X	save_e=errno;
X	fprintf(stderr,"%s: ",tar);
X	if(f_sayblock)
X		fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block));
X	va_start(args);
X	vfprintf(stderr,str,args);
X	va_end(args);
X	fprintf(stderr,": ");
X	errno=save_e;
X	perror(0);
X}
X#endif
X
X#ifdef DOPRNT_MSG
Xvoid msg(str,args)
Xchar *str;
X{
X	fprintf(stderr,"%s: ",tar);
X	if(f_sayblock)
X		fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block));
X	_doprnt(str, &args, stderr);
X	putc('\n',stderr);
X}
X
Xvoid msg_perror(str,args)
Xchar *str;
X{
X	int save_e;
X	extern int errno;
X
X	save_e=errno;
X	fprintf(stderr,"%s: ",tar);
X	if(f_sayblock)
X		fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block));
X	_doprnt(str, &args, stderr);
X	fprintf(stderr,": ");
X	errno=save_e;
X	perror(0);
X}
X
X#endif
X#ifdef LOSING_MSG
Xvoid msg(str,a1,a2,a3,a4,a5,a6)
Xchar *str;
X{
X	fprintf(stderr,"%s: ",tar);
X	if(f_sayblock)
X		fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block));
X	fprintf(stderr,str,a1,a2,a3,a4,a5,a6);
X	putc('\n',stderr);
X}
X
Xvoid msg_perror(str,a1,a2,a3,a4,a5,a6)
Xchar *str;
X{
X	int save_e;
X	extern int errno;
X
X	save_e=errno;
X	fprintf(stderr,"%s: ",tar);
X	if(f_sayblock)
X		fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block));
X	fprintf(stderr,str,a1,a2,a3,a4,a5,a6);
X	fprintf(stderr,": ");
X	errno=save_e;
X	perror(0);
X}
X
X#endif
SHAR_EOF
echo "File PORT.C is complete"
chmod 0644 PORT.C || echo "restore of PORT.C fails"
echo "x - extracting PORT.H (Text)"
sed 's/^X//' << 'SHAR_EOF' > PORT.H &&
X/*
X
X	Copyright (C) 1988 Free Software Foundation
X
XGNU tar is distributed in the hope that it will be useful, but WITHOUT ANY
XWARRANTY.  No author or distributor accepts responsibility to anyone
Xfor the consequences of using it or for whether it serves any
Xparticular purpose or works at all, unless he says so in writing.
XRefer to the GNU tar General Public License for full details.
X
XEveryone is granted permission to copy, modify and redistribute GNU tar,
Xbut only under the conditions described in the GNU tar General Public
XLicense.  A copy of this license is supposed to have been given to you
Xalong with GNU tar so you can know your rights and responsibilities.  It
Xshould be in a file named COPYING.  Among other things, the copyright
Xnotice and this notice must be preserved on all copies.
X
XIn other words, go ahead and share GNU tar, but don't try to stop
Xanyone else from sharing it farther.  Help stamp out software hoarding!
X*/
X/*
X * Portability declarations for tar.
X *
X * @(#)port.h 1.3	87/11/11	by John Gilmore, 1986
X */
X
X/*
X * Everybody does wait() differently.  There seem to be no definitions
X * for this in V7 (e.g. you are supposed to shift and mask things out
X * using constant shifts and masks.)  So fuck 'em all -- my own non
X * standard but portable macros.  Don't change to a "union wait"
X * based approach -- the ordering of the elements of the struct 
X * depends on the byte-sex of the machine.  Foo!
X */
X#define	TERM_SIGNAL(status)	((status) & 0x7F)
X#define TERM_COREDUMP(status)	(((status) & 0x80) != 0)
X#define TERM_VALUE(status)	((status) >> 8)
X
X#ifdef	MSDOS
X/* missing things from sys/stat.h */
X#ifndef atarist
X#define	S_ISUID		0
X#define	S_ISGID		0
X#endif
X#define	S_ISVTX		0
X
X/* device stuff */
X#define	makedev(ma, mi)		((ma << 8) | mi)
X#define	major(dev)		(dev)
X#define	minor(dev)		(dev)
X#endif	/* MSDOS */
X
X#ifdef atarist
X#define MAXNAMLEN 64
X#endif
SHAR_EOF
chmod 0644 PORT.H || echo "restore of PORT.H fails"
echo "x - extracting README (Text)"
sed 's/^X//' << 'SHAR_EOF' > README &&
XThis is GNU tar.  It is based heavily on John Gilmore's public domain tar,
Xbut with added features.  See tar.texinfo for details.
X
XPlease send bug reports, etc to hack@gnu.ai.mit.edu hack@wheaties.ai.mit.edu
Xor hack@media-lab.media.mit.edu
X
X			hack
SHAR_EOF
chmod 0644 README || echo "restore of README fails"
echo "x - extracting README.ST (Text)"
sed 's/^X//' << 'SHAR_EOF' > README.ST &&
XHere is GNU tar, ported to the Atari ST. The source code is included
X(of course!). See the file "copying" for copyright information.
XPLEASE NOTE: THERE IS ABSOLUTELY NO WARRANTY FOR THIS PRODUCT. USE IT
XAT YOUR OWN RISK!
X
XAll the changes to the source that were necessary for this version
Xare surrounded by "#ifdef atarist". I used the GCC v1.34, with a new library,
Xto build it. If you're using another compiler, you may need to do some
Xwork. In particular, you'll probably want to add -Datarist to the CFLAGS
Xin the makefile.
X
XRead the enclosed manual (in tar.tex -- actually this should be
Xtar.texinfo, but GEMDOS doesn't know from long extensions) for general
Xinformation.
X
XST-specific information:
X
XTar is designed to run from a command line interpreter,
Xpreferably one that uses the MWC extended argument passing conventions
X(e.g. gulam). You can run it from the desktop if (a) your version of the
Xdesktop will pass lower case letters to programs, and (b) you don't mind
Xmessages disappearing from the screen when the desktop gets redrawn.
X
XThere is no default tar file; one must be explicitly specified on the
Xcommand line. The "-f" option is assumed, i.e typing "tar tv junk.tar"
Xis the same as "tar tvf junk.tar".
X
XSeveral of the options (e.g. -z to compress) are not applicable on the
XST, and will generate error messages.
X
XThe -N option only accepts a date in the form MM/DD/YYYY. (Theoretically,
Xif you have a shell that uses the MWC extended argument passing conventions,
Xyou could use "-NMM/DD/YYY hh:mm:ss" -- make sure you put quotes around
Xit).
X
XTimezones: generally, you will want to tell the program which time zone
Xyou're currently in. To do this, create an environment variable
Xcalled TZ with the format SSS[-]nn[:nn][DDD], (things in [] optional) where
XSSS is the name of your time zone, nn:nn is the offset in hours and minutes
Xfrom GMT (prefixed by '-' if necessary) and DDD, if present, is the name
Xused for your time zone when daylight savings time is in effect. Note
Xthat the rules for daylight savings time are very primitive indeed,
Xand will probably not work outside of North America.
XExample: I'm in the N. American Eastern time zone, and I use (in Gulam)
Xsetenv TZ "EST5EDT".
XIf no TZ environment variable is found, GMT is assumed. This only matters
Xif you're transferring tar files to/from other systems and you want
Xto make sure the dates are correct.
X
XGEMDOS filenames are translated to/from Unix; thus "subdir/file" gets
Xchanged to "subdir\file". This can (obviously) cause problems with GEMDOS
Xfiles which contain '/' in their names, or Unix files that contain '\'.
XWatch out for these. Also, some effort is made to translate names that
Xhave several extensions, e.g. "junk.c.bak" gets mapped to "junk,c.bak".
X
XMulti-volume tar files seem to work, but have not been thoroughly tested.
XI would not recommend using them to back up your hard disk, unless you're
Xfeeling particularly brave or don't care about your data.
X
XReport bugs, etc. to me at the address below:
X
XEric R. Smith                     email:
XDept. of Mathematics            7103_300@uwovax.uwo.ca
XUniversity of Western Ontario   7103_300@uwovax.bitnet
XLondon, Ont. Canada N6A 5B7     (a shared mailbox: put my name on
Xph: (519) 661-3638              the message, please!)
X
SHAR_EOF
chmod 0644 README.ST || echo "restore of README.ST fails"
echo "x - extracting RMT.H (Text)"
sed 's/^X//' << 'SHAR_EOF' > RMT.H &&
X/*
X
X	Copyright (C) 1988 Free Software Foundation
X
XGNU tar is distributed in the hope that it will be useful, but WITHOUT ANY
XWARRANTY.  No author or distributor accepts responsibility to anyone
Xfor the consequences of using it or for whether it serves any
Xparticular purpose or works at all, unless he says so in writing.
XRefer to the GNU tar General Public License for full details.
X
XEveryone is granted permission to copy, modify and redistribute GNU tar,
Xbut only under the conditions described in the GNU tar General Public
XLicense.  A copy of this license is supposed to have been given to you
Xalong with GNU tar so you can know your rights and responsibilities.  It
Xshould be in a file named COPYING.  Among other things, the copyright
Xnotice and this notice must be preserved on all copies.
X
XIn other words, go ahead and share GNU tar, but don't try to stop
Xanyone else from sharing it farther.  Help stamp out software hoarding!
X*/
X
X#ifdef NO_REMOTE
X#define rmtopen		open
X#define rmtaccess	access
X#define rmtstat		stat
X#define rmtcreat	creat
X#define rmtlstat	lstat
X#define rmtread		read
X#define rmtwrite	write
X#define rmtlseek	lseek
X#define rmtclose	close
X#define rmtioctl	ioctl
X#define rmtdup		dup
X#define rmtfstat	fstat
X#define rmtfcntl	fcntl
X#define rmtisatty	isatty
X
X#else
X#ifndef USG
X#define strchr index
X#endif
X
X#define __REM_BIAS	128
X#define RMTIOCTL
X
X#ifndef O_CREAT
X#define O_CREAT	01000
X#endif
Xextern char *__rmt_path;
Xextern char *strchr();
X
X#define _remdev(path)	((__rmt_path=strchr(path, ':')) && strncmp(__rmt_path, ":/dev/", 6)==0)
X#define _isrmt(fd)		((fd) >= __REM_BIAS)
X
X#define rmtopen(path,oflag,mode) (_remdev(path) ? __rmt_open(path, oflag, mode, __REM_BIAS) : open(path, oflag, mode))
X#define rmtaccess(path, amode)	(_remdev(path) ? 0 : access(path, amode))
X#define rmtstat(path, buf)	(_remdev(path) ? (errno = EOPNOTSUPP), -1 : stat(path, buf))
X#define rmtcreat(path, mode)	(_remdev(path) ? __rmt_open (path, 1 | O_CREAT, mode, __REM_BIAS) : creat(path, mode))
X#define rmtlstat(path,buf)	(_remdev(path) ? (errno = EOPNOTSUPP), -1 : lstat(path,buf))
X
X#define rmtread(fd, buf, n)	(_isrmt(fd) ? __rmt_read(fd - __REM_BIAS, buf, n) : read(fd, buf, n))
X#define rmtwrite(fd, buf, n)	(_isrmt(fd) ? __rmt_write(fd - __REM_BIAS, buf, n) : write(fd, buf, n))
X#define rmtlseek(fd, off, wh)	(_isrmt(fd) ? __rmt_lseek(fd - __REM_BIAS, off, wh) : lseek(fd, off, wh))
X#define rmtclose(fd)		(_isrmt(fd) ? __rmt_close(fd - __REM_BIAS) : close(fd))
X#ifdef RMTIOCTL
X#define rmtioctl(fd,req,arg)	(_isrmt(fd) ? __rmt_ioctl(fd - __REM_BIAS, req, arg) : ioctl(fd, req, arg))
X#else
X#define rmtioctl(fd,req,arg)	(_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : ioctl(fd, req, arg))
X#endif
X#define rmtdup(fd)		(_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : dup(fd))
X#define rmtfstat(fd, buf)	(_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : fstat(fd, buf))
X#define rmtfcntl(fd,cmd,arg)	(_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : fcntl (fd, cmd, arg))
X#define rmtisatty(fd)		(_isrmt(fd) ? 0 : isatty(fd))
X
X#undef RMTIOCTL
X#endif
SHAR_EOF
chmod 0644 RMT.H || echo "restore of RMT.H fails"
echo "x - extracting RTAPE_LI.C (Text)"
sed 's/^X//' << 'SHAR_EOF' > RTAPE_LI.C &&
X/*
X
X	Copyright (C) 1988 Free Software Foundation
X
XGNU tar is distributed in the hope that it will be useful, but WITHOUT ANY
XWARRANTY.  No author or distributor accepts responsibility to anyone
Xfor the consequences of using it or for whether it serves any
Xparticular purpose or works at all, unless he says so in writing.
XRefer to the GNU tar General Public License for full details.
X
XEveryone is granted permission to copy, modify and redistribute GNU tar,
Xbut only under the conditions described in the GNU tar General Public
XLicense.  A copy of this license is supposed to have been given to you
Xalong with GNU tar so you can know your rights and responsibilities.  It
Xshould be in a file named COPYING.  Among other things, the copyright
Xnotice and this notice must be preserved on all copies.
X
XIn other words, go ahead and share GNU tar, but don't try to stop
Xanyone else from sharing it farther.  Help stamp out software hoarding!
X*/
X
X#ifndef lint
Xstatic char *RCSid = "$Header: rmtlib.c,v 1.6 88/10/25 17:04:29 root Locked $";
X#endif
X
X/* JF: modified to make all rmtXXX calls into macros for speed */
X/*
X * $Log:	rmtlib.c,v $
X * Revision 1.6  88/10/25  17:04:29  root
X * rexec code and a bug fix from srs!dan, miscellanious cleanup. ADR.
X * 
X * Revision 1.5  88/10/25  16:30:17  root
X * Fix from jeff@gatech.edu for getting user@host:dev right. ADR.
X * 
X * Revision 1.4  87/10/30  10:36:12  root
X * Made 4.2 syntax a compile time option. ADR.
X * 
X * Revision 1.3  87/04/22  11:16:48  root
X * Two fixes from parmelee@wayback.cs.cornell.edu to correctly
X * do fd biasing and rmt protocol on 'S' command. ADR.
X * 
X * Revision 1.2  86/10/09  16:38:53  root
X * Changed to reflect 4.3BSD rcp syntax. ADR.
X * 
X * Revision 1.1  86/10/09  16:17:35  root
X * Initial revision
X * 
X */
X
X/*
X *	rmt --- remote tape emulator subroutines
X *
X *	Originally written by Jeff Lee, modified some by Arnold Robbins
X *
X *	WARNING:  The man page rmt(8) for /etc/rmt documents the remote mag
X *	tape protocol which rdump and rrestore use.  Unfortunately, the man
X *	page is *WRONG*.  The author of the routines I'm including originally
X *	wrote his code just based on the man page, and it didn't work, so he
X *	went to the rdump source to figure out why.  The only thing he had to
X *	change was to check for the 'F' return code in addition to the 'E',
X *	and to separate the various arguments with \n instead of a space.  I
X *	personally don't think that this is much of a problem, but I wanted to
X *	point it out.
X *	-- Arnold Robbins
X *
X *	Redone as a library that can replace open, read, write, etc, by
X *	Fred Fish, with some additional work by Arnold Robbins.
X */
X 
X/*
X *	MAXUNIT --- Maximum number of remote tape file units
X *
X *	READ --- Return the number of the read side file descriptor
X *	WRITE --- Return the number of the write side file descriptor
X */
X
X#define RMTIOCTL	1
X/* #define USE_REXEC	1	/* rexec code courtesy of Dan Kegel, srs!dan */
X
X#include <stdio.h>
X#include <signal.h>
X#include <sys/types.h>
X
X#ifdef RMTIOCTL
X#include <sys/ioctl.h>
X#include <sys/mtio.h>
X#endif
X
X#ifdef USE_REXEC
X#include <netdb.h>
X#endif
X
X#include <errno.h>
X#include <setjmp.h>
X#include <sys/stat.h>
X
X#define BUFMAGIC	64	/* a magic number for buffer sizes */
X#define MAXUNIT	4
X
X#define READ(fd)	(Ctp[fd][0])
X#define WRITE(fd)	(Ptc[fd][1])
X
Xstatic int Ctp[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
Xstatic int Ptc[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
X
Xextern int errno;
X
Xchar *__rmt_path;
X
X/*
X *	_rmt_panic --- close off a remote tape connection
X */
X
Xstatic void _rmt_panic(fildes)
Xint fildes;
X{
X	close(READ(fildes));
X	close(WRITE(fildes));
X	READ(fildes) = -1;
X	WRITE(fildes) = -1;
X}
X
X
X
X/*
X *	command --- attempt to perform a remote tape command
X */
X
Xstatic int command(fildes, buf)
Xint fildes;
Xchar *buf;
X{
X	register int blen;
X	int (*pstat)();
X
X/*
X *	save current pipe status and try to make the request
X */
X
X	blen = strlen(buf);
X	pstat = signal(SIGPIPE, SIG_IGN);
X	if (write(WRITE(fildes), buf, blen) == blen)
X	{
X		signal(SIGPIPE, pstat);
X		return(0);
X	}
X
X/*
X *	something went wrong. close down and go home
X */
X
X	signal(SIGPIPE, pstat);
X	_rmt_panic(fildes);
X
X	errno = EIO;
X	return(-1);
X}
X
X
X
X/*
X *	status --- retrieve the status from the pipe
X */
X
Xstatic int status(fildes)
Xint fildes;
X{
X	int i;
X	char c, *cp;
X	char buffer[BUFMAGIC];
X
X/*
X *	read the reply command line
X */
X
X	for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++)
X	{
X		if (read(READ(fildes), cp, 1) != 1)
X		{
X			_rmt_panic(fildes);
X			errno = EIO;
X			return(-1);
X		}
X		if (*cp == '\n')
X		{
X			*cp = 0;
X			break;
X		}
X	}
X
X	if (i == BUFMAGIC)
X	{
X		_rmt_panic(fildes);
X		errno = EIO;
X		return(-1);
X	}
X
X/*
X *	check the return status
X */
X
X	for (cp = buffer; *cp; cp++)
X		if (*cp != ' ')
X			break;
X
X	if (*cp == 'E' || *cp == 'F')
X	{
X		errno = atoi(cp + 1);
X		while (read(READ(fildes), &c, 1) == 1)
X			if (c == '\n')
X				break;
X
X		if (*cp == 'F')
X			_rmt_panic(fildes);
X
X		return(-1);
X	}
X
X/*
X *	check for mis-synced pipes
X */
X
X	if (*cp != 'A')
X	{
X		_rmt_panic(fildes);
X		errno = EIO;
X		return(-1);
X	}
X
X	return(atoi(cp + 1));
X}
X
X#ifdef USE_REXEC
X
X/*
X * _rmt_rexec
X *
X * execute /etc/rmt on a remote system using rexec().
X * Return file descriptor of bidirectional socket for stdin and stdout
X * If username is NULL, or an empty string, uses current username.
X *
X * ADR: By default, this code is not used, since it requires that
X * the user have a .netrc file in his/her home directory, or that the
X * application designer be willing to have rexec prompt for login and
X * password info. This may be unacceptable, and .rhosts files for use
X * with rsh are much more common on BSD systems.
X */
X
Xstatic int
X_rmt_rexec(host, user)
Xchar *host;
Xchar *user;		/* may be NULL */
X{
X	struct servent *rexecserv;
X
X	rexecserv = getservbyname("exec", "tcp");
X	if (NULL == rexecserv) {
X		fprintf (stderr, "? exec/tcp: service not available.");
X		exit (-1);
X	}
X	if ((user != NULL) && *user == '\0')
X		user = (char *) NULL;
X	return rexec (&host, rexecserv->s_port, user, NULL,
X			"/etc/rmt", (int *)NULL);
X}
X#endif /* USE_REXEC */
X
X/*
X *	_rmt_open --- open a magtape device on system specified, as given user
X *
X *	file name has the form [user@]system:/dev/????
X#ifdef COMPAT
X *	file name has the form system[.user]:/dev/????
X#endif
X */
X
X#define MAXHOSTLEN	257	/* BSD allows very long host names... */
X
Xint __rmt_open (path, oflag, mode, bias)
Xchar *path;
Xint oflag;
Xint mode;
Xint bias;
X{
X	int i, rc;
X	char buffer[BUFMAGIC];
X	char system[MAXHOSTLEN];
X	char device[BUFMAGIC];
X	char login[BUFMAGIC];
X	char *sys, *dev, *user;
X
X	sys = system;
X	dev = device;
X	user = login;
X
X/*
X *	first, find an open pair of file descriptors
X */
X
X	for (i = 0; i < MAXUNIT; i++)
X		if (READ(i) == -1 && WRITE(i) == -1)
X			break;
X
X	if (i == MAXUNIT)
X	{
X		errno = EMFILE;
X		return(-1);
X	}
X
X/*
X *	pull apart system and device, and optional user
X *	don't munge original string
X *	if COMPAT is defined, also handle old (4.2) style person.site notation.
X */
X
X	while (*path != '@'
X#ifdef COMPAT
X			&& *path != '.'
X#endif
X			&& *path != ':') {
X		*sys++ = *path++;
X	}
X	*sys = '\0';
X	path++;
X
X	if (*(path - 1) == '@')
X	{
X		(void) strcpy (user, system);	/* saw user part of user@host */
X		sys = system;			/* start over */
X		while (*path != ':') {
X			*sys++ = *path++;
X		}
X		*sys = '\0';
X		path++;
X	}
X#ifdef COMPAT
X	else if (*(path - 1) == '.')
X	{
X		while (*path != ':') {
X			*user++ = *path++;
X		}
X		*user = '\0';
X		path++;
X	}
X#endif
X	else
X		*user = '\0';
X
X	while (*path) {
X		*dev++ = *path++;
X	}
X	*dev = '\0';
X
X#ifdef USE_REXEC
X/* 
X *	Execute the remote command using rexec 
X */
X	READ(i) = WRITE(i) = _rmt_rexec(system, login);
X	if (READ(i) < 0)
X		return -1;
X#else
X/*
X *	setup the pipes for the 'rsh' command and fork
X */
X
X	if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
X		return(-1);
X
X	if ((rc = fork()) == -1)
X		return(-1);
X
X	if (rc == 0)
X	{
X		close(0);
X		dup(Ptc[i][0]);
X		close(Ptc[i][0]); close(Ptc[i][1]);
X		close(1);
X		dup(Ctp[i][1]);
X		close(Ctp[i][0]); close(Ctp[i][1]);
X		(void) setuid (getuid ());
X		(void) setgid (getgid ());
X		if (*user)
X		{
X			execl("/usr/ucb/rsh", "rsh", system, "-l", login,
X				"/etc/rmt", (char *) 0);
X			execl("/usr/bin/remsh", "remsh", system, "-l", login,
X				"/etc/rmt", (char *) 0);
X		}
X		else
X		{
X			execl("/usr/ucb/rsh", "rsh", system,
X				"/etc/rmt", (char *) 0);
X			execl("/usr/bin/remsh", "remsh", system,
X				"/etc/rmt", (char *) 0);
X		}
X
X/*
X *	bad problems if we get here
X */
X
X		perror("exec");
X		exit(1);
X	}
X
X	close(Ptc[i][0]); close(Ctp[i][1]);
X#endif
X
X/*
X *	now attempt to open the tape device
X */
X
X	sprintf(buffer, "O%s\n%d\n", device, oflag);
X	if (command(i, buffer) == -1 || status(i) == -1)
X		return(-1);
X
X	return(i+bias);
X}
X
X
X
X/*
X *	_rmt_close --- close a remote magtape unit and shut down
X */
X
X int __rmt_close(fildes)
Xint fildes;
X{
X	int rc;
X
X	if (command(fildes, "C\n") != -1)
X	{
X		rc = status(fildes);
X
X		_rmt_panic(fildes);
X		return(rc);
X	}
X
X	return(-1);
X}
X
X
X
X/*
X *	_rmt_read --- read a buffer from a remote tape
X */
X
Xint __rmt_read(fildes, buf, nbyte)
Xint fildes;
Xchar *buf;
Xunsigned int nbyte;
X{
X	int rc, i;
X	char buffer[BUFMAGIC];
X
X	sprintf(buffer, "R%d\n", nbyte);
X	if (command(fildes, buffer) == -1 || (rc = status(fildes)) == -1)
X		return(-1);
X
X	for (i = 0; i < rc; i += nbyte, buf += nbyte)
X	{
X		nbyte = read(READ(fildes), buf, rc);
X		if (nbyte <= 0)
X		{
X			_rmt_panic(fildes);
X			errno = EIO;
X			return(-1);
X		}
X	}
X
X	return(rc);
X}
X
X
X
X/*
X *	_rmt_write --- write a buffer to the remote tape
X */
X
Xint __rmt_write(fildes, buf, nbyte)
Xint fildes;
Xchar *buf;
Xunsigned int nbyte;
X{
X	char buffer[BUFMAGIC];
X	int (*pstat)();
X
X	sprintf(buffer, "W%d\n", nbyte);
X	if (command(fildes, buffer) == -1)
X		return(-1);
X
X	pstat = signal(SIGPIPE, SIG_IGN);
X	if (write(WRITE(fildes), buf, nbyte) == nbyte)
X	{
X		signal (SIGPIPE, pstat);
X		return(status(fildes));
X	}
X
X	signal (SIGPIPE, pstat);
X	_rmt_panic(fildes);
X	errno = EIO;
X	return(-1);
X}
X
X
X
X/*
X *	_rmt_lseek --- perform an imitation lseek operation remotely
X */
X
Xlong __rmt_lseek(fildes, offset, whence)
Xint fildes;
Xlong offset;
Xint whence;
X{
X	char buffer[BUFMAGIC];
X
X	sprintf(buffer, "L%d\n%d\n", offset, whence);
X	if (command(fildes, buffer) == -1)
X		return(-1);
X
X	return(status(fildes));
X}
X
X
X/*
X *	_rmt_ioctl --- perform raw tape operations remotely
X */
X
X#ifdef RMTIOCTL
X__rmt_ioctl(fildes, op, arg)
Xint fildes, op;
Xchar *arg;
X{
X	char c;
X	int rc, cnt;
X	char buffer[BUFMAGIC];
X
X/*
X *	MTIOCOP is the easy one. nothing is transfered in binary
X */
X
X	if (op == MTIOCTOP)
X	{
X		sprintf(buffer, "I%d\n%d\n", ((struct mtop *) arg)->mt_op,
X			((struct mtop *) arg)->mt_count);
X		if (command(fildes, buffer) == -1)
X			return(-1);
X		return(status(fildes));
X	}
X
X/*
X *	we can only handle 2 ops, if not the other one, punt
X */
X
X	if (op != MTIOCGET)
X	{
X		errno = EINVAL;
X		return(-1);
X	}
X
X/*
X *	grab the status and read it directly into the structure
X *	this assumes that the status buffer is (hopefully) not
X *	padded and that 2 shorts fit in a long without any word
X *	alignment problems, ie - the whole struct is contiguous
X *	NOTE - this is probably NOT a good assumption.
X */
X
X	if (command(fildes, "S") == -1 || (rc = status(fildes)) == -1)
X		return(-1);
X
X	for (; rc > 0; rc -= cnt, arg += cnt)
X	{
X		cnt = read(READ(fildes), arg, rc);
X		if (cnt <= 0)
X		{
X			_rmt_panic(fildes);
X			errno = EIO;
X			return(-1);
X		}
X	}
X
X/*
X *	now we check for byte position. mt_type is a small integer field
X *	(normally) so we will check its magnitude. if it is larger than
X *	256, we will assume that the bytes are swapped and go through
X *	and reverse all the bytes
X */
X
X	if (((struct mtget *) arg)->mt_type < 256)
X		return(0);
X
X	for (cnt = 0; cnt < rc; cnt += 2)
X	{
X		c = arg[cnt];
X		arg[cnt] = arg[cnt+1];
X		arg[cnt+1] = c;
X	}
X
X	return(0);
X  }
X#endif /* RMTIOCTL */
SHAR_EOF
chmod 0644 RTAPE_LI.C || echo "restore of RTAPE_LI.C fails"
echo "x - extracting RTAPE_SE.C (Text)"
sed 's/^X//' << 'SHAR_EOF' > RTAPE_SE.C &&
X/*
X * Copyright (c) 1983 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xchar copyright[] =
X"@(#) Copyright (c) 1983 Regents of the University of California.\n\
X All rights reserved.\n";
X#endif /* not lint */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)rmt.c	5.4 (Berkeley) 6/29/88";
X#endif /* not lint */
X
X/* JF added #ifdef about SO_RCVBUF in attempt to make this run on more
X   machines.  Maybe it'll work */
X/*
X * rmt
X */
X#include <stdio.h>
X#include <sgtty.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/mtio.h>
X#include <errno.h>
X
Xint	tape = -1;
X
Xchar	*record;
Xint	maxrecsize = -1;
Xchar	*checkbuf();
X
X#define	SSIZE	64
Xchar	device[SSIZE];
Xchar	count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE];
X
Xextern	errno;
Xchar	*sys_errlist[];
Xchar	resp[BUFSIZ];
X
Xlong	lseek();
X
XFILE	*debug;
X#define	DEBUG(f)	if (debug) fprintf(debug, f)
X#define	DEBUG1(f,a)	if (debug) fprintf(debug, f, a)
X#define	DEBUG2(f,a1,a2)	if (debug) fprintf(debug, f, a1, a2)
X
Xmain(argc, argv)
X	int argc;
X	char **argv;
X{
X	int rval;
X	char c;
X	int n, i, cc;
X
X	argc--, argv++;
X	if (argc > 0) {
X		debug = fopen(*argv, "w");
X		if (debug == 0)
X			exit(1);
X		(void) setbuf(debug, (char *)0);
X	}
Xtop:
X	errno = 0;
X	rval = 0;
X	if (read(0, &c, 1) != 1)
X		exit(0);
X	switch (c) {
X
X	case 'O':
X		if (tape >= 0)
X			(void) close(tape);
X		getstring(device); getstring(mode);
X		DEBUG2("rmtd: O %s %s\n", device, mode);
X		tape = open(device, atoi(mode),0666);
X		if (tape < 0)
X			goto ioerror;
X		goto respond;
X
X	case 'C':
X		DEBUG("rmtd: C\n");
X		getstring(device);		/* discard */
X		if (close(tape) < 0)
X			goto ioerror;
X		tape = -1;
X		goto respond;
X
X	case 'L':
X		getstring(count); getstring(pos);
X		DEBUG2("rmtd: L %s %s\n", count, pos);
X		rval = lseek(tape, (long) atoi(count), atoi(pos));
X		if (rval < 0)
X			goto ioerror;
X		goto respond;
X
X	case 'W':
X		getstring(count);
X		n = atoi(count);
X		DEBUG1("rmtd: W %s\n", count);
X		record = checkbuf(record, n);
X		for (i = 0; i < n; i += cc) {
X			cc = read(0, &record[i], n - i);
X			if (cc <= 0) {
X				DEBUG("rmtd: premature eof\n");
X				exit(2);
X			}
X		}
X		rval = write(tape, record, n);
X		if (rval < 0)
X			goto ioerror;
X		goto respond;
X
X	case 'R':
X		getstring(count);
X		DEBUG1("rmtd: R %s\n", count);
X		n = atoi(count);
X		record = checkbuf(record, n);
X		rval = read(tape, record, n);
X		if (rval < 0)
X			goto ioerror;
X		(void) sprintf(resp, "A%d\n", rval);
X		(void) write(1, resp, strlen(resp));
X		(void) write(1, record, rval);
X		goto top;
X
X	case 'I':
X		getstring(op); getstring(count);
X		DEBUG2("rmtd: I %s %s\n", op, count);
X		{ struct mtop mtop;
X		  mtop.mt_op = atoi(op);
X		  mtop.mt_count = atoi(count);
X		  if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0)
X			goto ioerror;
X		  rval = mtop.mt_count;
X		}
X		goto respond;
X
X	case 'S':		/* status */
X		DEBUG("rmtd: S\n");
X		{ struct mtget mtget;
X		  if (ioctl(tape, MTIOCGET, (char *)&mtget) < 0)
X			goto ioerror;
X		  rval = sizeof (mtget);
X		  (void) sprintf(resp, "A%d\n", rval);
X		  (void) write(1, resp, strlen(resp));
X		  (void) write(1, (char *)&mtget, sizeof (mtget));
X		  goto top;
X		}
X
X	default:
X		DEBUG1("rmtd: garbage command %c\n", c);
X		exit(3);
X	}
Xrespond:
X	DEBUG1("rmtd: A %d\n", rval);
X	(void) sprintf(resp, "A%d\n", rval);
X	(void) write(1, resp, strlen(resp));
X	goto top;
Xioerror:
X	error(errno);
X	goto top;
X}
X
Xgetstring(bp)
X	char *bp;
X{
X	int i;
X	char *cp = bp;
X
X	for (i = 0; i < SSIZE; i++) {
X		if (read(0, cp+i, 1) != 1)
X			exit(0);
X		if (cp[i] == '\n')
X			break;
X	}
X	cp[i] = '\0';
X}
X
Xchar *
Xcheckbuf(record, size)
X	char *record;
X	int size;
X{
X	extern char *malloc();
X
X	if (size <= maxrecsize)
X		return (record);
X	if (record != 0)
X		free(record);
X	record = malloc(size);
X	if (record == 0) {
X		DEBUG("rmtd: cannot allocate buffer space\n");
X		exit(4);
X	}
X	maxrecsize = size;
X#ifdef SO_RCVBUF
X	while (size > 1024 &&
X	       setsockopt(0, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) < 0)
X		size -= 1024;
X#else
X	size= 1+((size-1)%1024);
X#endif
X	return (record);
X}
X
Xerror(num)
X	int num;
X{
X
X	DEBUG2("rmtd: E %d (%s)\n", num, sys_errlist[num]);
X	(void) sprintf(resp, "E%d\n%s\n", num, sys_errlist[num]);
X	(void) write(1, resp, strlen (resp));
X}
SHAR_EOF
chmod 0644 RTAPE_SE.C || echo "restore of RTAPE_SE.C fails"
echo "x - extracting TAR.C (Text)"
sed 's/^X//' << 'SHAR_EOF' > TAR.C &&
X/*
X
X	Copyright (C) 1988 Free Software Foundation
X
XGNU tar is distributed in the hope that it will be useful, but WITHOUT ANY
XWARRANTY.  No author or distributor accepts responsibility to anyone
Xfor the consequences of using it or for whether it serves any
Xparticular purpose or works at all, unless he says so in writing.
XRefer to the GNU tar General Public License for full details.
X
XEveryone is granted permission to copy, modify and redistribute GNU tar,
Xbut only under the conditions described in the GNU tar General Public
XLicense.  A copy of this license is supposed to have been given to you
Xalong with GNU tar so you can know your rights and responsibilities.  It
Xshould be in a file named COPYING.  Among other things, the copyright
Xnotice and this notice must be preserved on all copies.
X
XIn other words, go ahead and share GNU tar, but don't try to stop
Xanyone else from sharing it farther.  Help stamp out software hoarding!
X*/
X
X/*
X * A tar(1) program.
X * 
X * Written by John Gilmore, ihnp4!hoptoad!gnu, starting 25 Aug 85.
X *
X * @(#)tar.c 1.34 11/6/87 - gnu
X */
X
X#include <stdio.h>
X#ifdef atarist
X#include <types.h>		/* Needed for typedefs in tar.h */
X#include <stat.h>		/* JF */
X#else
X#include <sys/types.h>		/* Needed for typedefs in tar.h */
X#include <sys/stat.h>		/* JF */
X#endif
X
X#ifdef USG
X#define rindex strrchr
X#endif
X
X#ifdef BSD42
X#include <sys/dir.h>
X#else
X#if (defined(MSDOS) && !defined(atarist))
X#include <sys/dir.h>
X#else
X#ifdef USG
X#include <dirent.h>
X#define direct dirent
X#define DP_NAMELEN(x) strlen((x)->d_name)
X#else
X/*
X * FIXME: On other systems there is no standard place for the header file
X * for the portable directory access routines.  Change the #include line
X * below to bring it in from wherever it is.
X */
X#include <dirent.h>
X#define direct dirent		/* if you have POSIX routines */
X#define DP_NAMELEN(x) strlen((x)->d_name)  /* ditto */
X#endif
X#endif
X#endif
X
X#ifndef DP_NAMELEN
X#define DP_NAMELEN(x)	(x)->d_namlen
X#endif
X
Xextern char 	*malloc();
Xextern char 	*getenv();
Xextern char	*strncpy();
Xextern char	*index();
Xextern char	*strcpy();	/* JF */
Xextern char	*strcat();	/* JF */
X
Xextern char	*optarg;	/* Pointer to argument */
Xextern int	optind;		/* Global argv index from getopt */
X
X/*
X * The following causes "tar.h" to produce definitions of all the
X * global variables, rather than just "extern" declarations of them.
X */
X#define TAR_EXTERN /**/
X#include "tar.h"
X
X/*
X * We should use a conversion routine that does reasonable error
X * checking -- atoi doesn't.  For now, punt.  FIXME.
X */
X#define intconv	atoi
Xextern int	getoldopt();
Xextern void	read_and();
Xextern void	list_archive();
Xextern void	extract_archive();
Xextern void	diff_archive();
Xextern void	create_archive();
Xextern void	update_archive();
Xextern void	junk_archive();
X
X/* JF */
Xextern time_t	getdate();
X#ifdef __GNU__
Xextern void *init_buffer();
X#else
Xextern char *init_buffer();
X#endif
Xextern char *get_buffer();
Xextern void add_buffer();
Xextern void flush_buffer();
X
Xtime_t new_time;
X
Xstatic FILE	*namef;		/* File to read names from */
Xstatic char	**n_argv;	/* Argv used by name routines */
Xstatic int	n_argc;	/* Argc used by name routines */
X				/* They also use "optind" from getopt(). */
X
Xvoid	describe();
Xvoid	options();
X
X#ifndef S_IFLNK
X#define lstat stat
X#endif
X
X#ifndef DEFBLOCKING
X#define DEFBLOCKING 20
X#endif
X
X#ifndef DEF_AR_FILE
X#define DEF_AR_FILE "tar.out"
X#endif
X
X#ifdef atarist
Xint setmode() { return 0; } /* MSDOS compatibility cruft */
X#endif
X
X/*
X * Main routine for tar.
X */
Xmain(argc, argv)
X	int	argc;
X	char	**argv;
X{
X#ifdef atarist
X	extern char *name_next();
X	extern int _unixmode;
X	static char archname[NAMSIZ+2];
X#endif
X	/* Uncomment this message in particularly buggy versions...
X	fprintf(stderr,
X	 "tar: You are running an experimental PD tar, maybe use /bin/tar.\n");
X	 */
X
X#ifdef atarist
X	_unixmode = 3;		/* convert filenames to/from Un*x */
X	tar = *argv[0] ? argv[0] : "tar";
X#else
X	tar = argv[0];		/* JF: was "tar" Set program name */
X#endif
X	options(argc, argv);
X
X	name_init(argc, argv);
X#ifdef atarist
X	if (ar_file == 0) {
X		strcpy(archname, name_next(0));
X		ar_file = archname;
X	}
X#endif
X	switch(cmd_mode) {
X	case CMD_CAT:
X	case CMD_UPDATE:
X	case CMD_APPEND:
X		update_archive();
X		break;
X	case CMD_DELETE:
X		junk_archive();
X		break;
X	case CMD_CREATE:
X		create_archive();
X		break;
X	case CMD_EXTRACT:
X		extr_init();
X		read_and(extract_archive);
X		break;
X	case CMD_LIST:
X		read_and(list_archive);
X		break;
X	case CMD_DIFF:
X		diff_init();
X		read_and(diff_archive);
X		break;
X	case CMD_NONE:
X		fprintf (stderr,
X#ifdef atarist
X"%s: you must specify exactly one of the r, c, t, x, or d options\n", tar);
X#else
X"tar: you must specify exactly one of the r, c, t, x, or d options\n");
X#endif
X		describe();
X		exit(EX_ARGSBAD);
X	}
X	exit(0);
X	/* NOTREACHED */
X}
X
X
X/*
X * Parse the options for tar.
X */
Xvoid
Xoptions(argc, argv)
X	int	argc;
X	char	**argv;
X{
X	register int	c;		/* Option letter */
X
X	/* Set default option values */
X	blocking = DEFBLOCKING;		/* From Makefile */
X	ar_file = getenv("TAPE");	/* From environment, or */
X	if (ar_file == 0)
X		ar_file = DEF_AR_FILE;	/* From Makefile */
X
X	/* Parse options */
X	while ((c = getoldopt(argc, argv, "01234567Ab:BcdDf:GhikK:lmMN:oOprRstT:uvV:wWxX:zZ")
X		) != EOF) {
X		switch (c) {
X		case '0':
X		case '1':
X		case '2':
X		case '3':
X		case '4':
X		case '5':
X		case '6':
X		case '7':
X			{
X				/* JF this'll have to be modified for other
X				   systems, of course! */
X#ifndef LOW_NUM
X#define LOW_NUM 0
X#define MID_NUM 8
X#define HGH_NUM 16
X#endif
X				int d,add;
X				static char buf[50];
X
X				d=getoldopt(argc,argv,"lmh");
X				if(d=='l') add=LOW_NUM;
X				else if(d=='m') add=MID_NUM;
X				else if(d=='h') add=HGH_NUM;
X				else goto badopt;
X				sprintf(buf,"/dev/rmt%d",add+c-'0');
X				ar_file=buf;
X			}
X			break;
X
X		case 'A':			/* Arguments are tar files,
X						   just cat them onto the end
X						   of the archive.  */
X			if(cmd_mode!=CMD_NONE)
X				goto badopt;
X			cmd_mode=CMD_CAT;
X			break;
X
X		case 'b':			/* Set blocking factor */
X			blocking = intconv(optarg);
X			break;
X
X		case 'B':			/* Try to reblock input */
X			f_reblock++;		/* For reading 4.2BSD pipes */
X			break;
X
X		case 'c':			/* Create an archive */
X			if(cmd_mode!=CMD_NONE)
X				goto badopt;
X			cmd_mode=CMD_CREATE;
X			break;
X
X		case 'd':			/* Find difference tape/disk */
X			if(cmd_mode!=CMD_NONE)
X				goto badopt;
X			cmd_mode=CMD_DIFF;
X			break;
X
X		case 'D':			/* Delete in the archive */
X			if(cmd_mode!=CMD_NONE)
X				goto badopt;
X			cmd_mode=CMD_DELETE;
X			break;
X
X		case 'f':			/* Use ar_file for the archive */
X			ar_file = optarg;
X			break;
X
X		case 'G':			/* We are making a GNU dump; save
X						   directories at the beginning of
X						   the archive, and include in each
X						   directory its contents */
X			if(f_oldarch)
X				goto badopt;
X			f_gnudump++;
X			break;
X
X		case 'h':
X			if(optind && argv[optind] && !strcmp(argv[optind],"-help")) {
X				printf("This is GNU tar, the tape archiving program.\n");
X				describe();
X				printf("For a more complete description of how to use tar, type 'info util tar'\n");
X				exit(1);
X			} else
X				f_follow_links++;	/* follow symbolic links */
X			break;
X
X		case 'i':
X			f_ignorez++;		/* Ignore zero records (eofs) */
X			/*
X			 * This can't be the default, because Unix tar
X			 * writes two records of zeros, then pads out the
X			 * block with garbage.
X			 */
X			break;
X
X		case 'k':			/* Don't overwrite files */
X#ifdef NO_OPEN3
X			fprintf(stderr,
X				"tar: can't do -k option on this system\n");
X			exit(EX_ARGSBAD);
X#else
X			f_keep++;
X#endif
X			break;
X
X		case 'K':
X			f_startfile++;
X			addname(optarg);
X			break;
X
X		case 'l':			/* When dumping directories, don't
X						   dump files/subdirectories that are
X						   on other filesystems. */
X			f_local_filesys++;
X			break;
X
X		case 'm':
X			f_modified++;
X			break;
X
X		case 'M':			/* Make Multivolume archive:
X						   When we can't write any more
X						   into the archive, re-open it,
X						   and continue writing */
X			f_multivol++;
X			break;
X
X		case 'N':			/* Only write files newer than X */
X			f_new_files++;
X			new_time=getdate(optarg,(struct timeb *)0);
X			break;
X
X		case 'o':			/* Generate old archive */
X			if(f_gnudump /* || f_dironly */)
X				goto badopt;
X			f_oldarch++;
X			break;
X
X		case 'O':
X			f_exstdout++;
X			break;
X
X		case 'p':
X			f_use_protection++;
X			break;
X
X		case 'r':			/* Append files to the archive */
X			if(cmd_mode!=CMD_NONE)
X				goto badopt;
X			cmd_mode=CMD_APPEND;
X			break;
X
X		case 'R':
X			f_sayblock++;		/* Print block #s for debug */
X			break;			/* of bad tar archives */
X
X		case 's':
X			f_sorted_names++;	/* Names to extr are sorted */
X			break;
X
X		case 't':
X			if(cmd_mode!=CMD_NONE)
X				goto badopt;
X			cmd_mode=CMD_LIST;
X			f_verbose++;		/* "t" output == "cv" or "xv" */
X			break;
X
X		case 'T':
X			name_file = optarg;
X			f_namefile++;
X			break;
X
X		case 'u':			/* Append files to the archive that
X						   aren't there, or are newer than the
X						   copy in the archive */
X			if(cmd_mode!=CMD_NONE)
X				goto badopt;
X			cmd_mode=CMD_UPDATE;
X			break;
X
X		case 'v':
X			if(optind && argv[optind] && !strcmp(argv[optind],"-version")) {
X				extern char version_string[];
X
X				fprintf(stderr,"%s\n",version_string);
X				while(getoldopt(argc,argv,"ersion")!='n')
X					;
X			} else {
X				f_verbose++;
X			}
X			break;
X
X		case 'V':
X			f_volhdr=optarg;
X			break;
X
X		case 'w':
X			f_confirm++;
X			break;
X
X		case 'W':
X			f_verify++;
X			break;
X
X		case 'x':			/* Extract files from the archive */
X			if(cmd_mode!=CMD_NONE)
X				goto badopt;
X			cmd_mode=CMD_EXTRACT;
X			break;
X
X		case 'X':
X			f_exclude++;
SHAR_EOF
echo "End of part 5"
echo "File TAR.C is continued in part 6"
echo "6" > s2_seq_.tmp
exit 0