rsalz@uunet.uu.net (Rich Salz) (02/04/89)
Submitted-by: Mark H. Colburn <mark@jhereg.jhereg.mn.org> Posting-number: Volume 17, Issue 77 Archive-name: pax/part04 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 4 (of 6)." # Contents: extract.c list.c pax.1 # Wrapped by mark@jhereg on Tue Dec 27 19:37:53 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f extract.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"extract.c\" else echo shar: Extracting \"extract.c\" \(14327 characters\) sed "s/^X//" >extract.c <<'END_OF_extract.c' X/* $Source: /u/mark/src/pax/RCS/extract.c,v $ X * X * $Revision: 1.1 $ X * X * extract.c - Extract files from a tar archive. X * X * DESCRIPTION X * X * AUTHOR X * X * Mark H. Colburn, NAPS International (mark@jhereg.mn.org) X * X * Sponsored by The USENIX Association for public distribution. X * X * Copyright (c) 1989 Mark H. Colburn. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice is duplicated in all such X * forms and that any documentation, advertising materials, and other X * materials related to such distribution and use acknowledge that the X * software was developed * by Mark H. Colburn and sponsored by The X * USENIX Association. X * 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 * $Log: extract.c,v $ X * Revision 1.1 88/12/23 18:02:07 mark X * Initial revision X * X */ X X#ifndef lint Xstatic char *ident = "$Id: extract.c,v 1.1 88/12/23 18:02:07 mark Rel $"; Xstatic char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n"; X#endif /* ! lint */ X X X/* Headers */ X X#include "pax.h" X X X/* Defines */ X X/* X * Swap bytes. X */ X#define SWAB(n) ((((ushort)(n) >> 8) & 0xff) | (((ushort)(n) << 8) & 0xff00)) X X X/* Function Prototypes */ X X#ifdef __STDC__ X Xstatic int inbinary(char *, char *, Stat *); Xstatic int inascii(char *, char *, Stat *); Xstatic int inswab(char *, char *, Stat *); Xstatic int readtar(char *, Stat *); Xstatic int readcpio(char *, Stat *); X X#else /* !__STDC__ */ X Xstatic int inbinary(); Xstatic int inascii(); Xstatic int inswab(); Xstatic int readtar(); Xstatic int readcpio(); X X#endif /* __STDC__ */ X X X/* read_archive - read in an archive X * X * DESCRIPTION X * X * Read_archive is the central entry point for reading archives. X * Read_archive determines the proper archive functions to call X * based upon the archive type being processed. X * X * RETURNS X * X */ X X#ifdef __STDC__ X Xint read_archive(void) X X#else X Xint read_archive() X X#endif X{ X Stat sb; X char name[PATH_MAX + 1]; X int match; X int pad; X X name_gather(); /* get names from command line */ X name[0] = '\0'; X while (get_header(name, &sb) == 0) { X match = name_match(name) ^ f_reverse_match; X if (f_list) { /* only wanted a table of contents */ X if (match) { X print_entry(name, &sb); X } X if (((ar_format == TAR) X ? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE)) X : buf_skip((OFFSET) sb.sb_size)) < 0) { X warn(name, "File data is corrupt"); X } X } else if (match) { X if (rplhead != NULL) { X rpl_name(name); X if (strlen(name) == 0) { X continue; X } X } X if (get_disposition("extract", name) || X get_newname(name, sizeof(name))) { X /* skip file... */ X if (((ar_format == TAR) X ? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE)) X : buf_skip((OFFSET) sb.sb_size)) < 0) { X warn(name, "File data is corrupt"); X } X continue; X } X if (inentry(name, &sb) < 0) { X warn(name, "File data is corrupt"); X } X if (f_verbose) { X print_entry(name, &sb); X } X if (ar_format == TAR && sb.sb_nlink > 1) { X /* X * This kludge makes sure that the link table is cleared X * before attempting to process any other links. X */ X if (sb.sb_nlink > 1) { X linkfrom(name, &sb); X } X } X if (ar_format == TAR && (pad = sb.sb_size % BLOCKSIZE) != 0) { X pad = BLOCKSIZE - pad; X buf_skip((OFFSET) pad); X } X } else { X if (((ar_format == TAR) X ? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE)) X : buf_skip((OFFSET) sb.sb_size)) < 0) { X warn(name, "File data is corrupt"); X } X } X } X X close_archive(); X} X X X X/* get_header - figures which type of header needs to be read. X * X * DESCRIPTION X * X * This is merely a single entry point for the two types of archive X * headers which are supported. The correct header is selected X * depending on the archive type. X * X * PARAMETERS X * X * char *name - name of the file (passed to header routine) X * Stat *asb - Stat block for the file (passed to header routine) X * X * RETURNS X * X * Returns the value which was returned by the proper header X * function. X */ X X#ifdef __STDC__ X Xint get_header(char *name, Stat *asb) X X#else X Xint get_header(name, asb) Xchar *name; XStat *asb; X X#endif X{ X if (ar_format == TAR) { X return(readtar(name, asb)); X } else { X return(readcpio(name, asb)); X } X} X X X/* readtar - read a tar header X * X * DESCRIPTION X * X * Tar_head read a tar format header from the archive. The name X * and asb parameters are modified as appropriate for the file listed X * in the header. Name is assumed to be a pointer to an array of X * at least PATH_MAX bytes. X * X * PARAMETERS X * X * char *name - name of the file for which the header is X * for. This is modified and passed back to X * the caller. X * Stat *asb - Stat block for the file for which the header X * is for. The fields of the stat structure are X * extracted from the archive header. This is X * also passed back to the caller. X * X * RETURNS X * X * Returns 0 if a valid header was found, or -1 if EOF is X * encountered. X */ X X#ifdef __STDC__ X Xstatic int readtar(char *name, Stat *asb) X X#else X Xstatic int readtar(name, asb) Xchar *name; XStat *asb; X X#endif X{ X int status = 3; /* Initial status at start of archive */ X static int prev_status; X X for (;;) { X prev_status = status; X status = read_header(name, asb); X switch (status) { X case 1: /* Valid header */ X return(0); X case 0: /* Invalid header */ X switch (prev_status) { X case 3: /* Error on first record */ X warn(ar_file, "This doesn't look like a tar archive"); X /* FALLTHRU */ X case 2: /* Error after record of zeroes */ X case 1: /* Error after header rec */ X warn(ar_file, "Skipping to next file..."); X /* FALLTHRU */ X default: X case 0: /* Error after error */ X break; X } X break; X X case 2: /* Record of zeroes */ X case EOF: /* End of archive */ X default: X return(-1); X } X } X} X X X/* readcpio - read a CPIO header X * X * DESCRIPTION X * X * Read in a cpio header. Understands how to determine and read ASCII, X * binary and byte-swapped binary headers. Quietly translates X * old-fashioned binary cpio headers (and arranges to skip the possible X * alignment byte). Returns zero if successful, -1 upon archive trailer. X * X * PARAMETERS X * X * char *name - name of the file for which the header is X * for. This is modified and passed back to X * the caller. X * Stat *asb - Stat block for the file for which the header X * is for. The fields of the stat structure are X * extracted from the archive header. This is X * also passed back to the caller. X * X * RETURNS X * X * Returns 0 if a valid header was found, or -1 if EOF is X * encountered. X */ X X#ifdef __STDC__ X Xstatic int readcpio(char *name, Stat *asb) X X#else X Xstatic int readcpio(name, asb) Xchar *name; XStat *asb; X X#endif X{ X OFFSET skipped; X char magic[M_STRLEN]; X static int align; X X if (align > 0) { X buf_skip((OFFSET) align); X } X align = 0; X for (;;) { X buf_read(magic, M_STRLEN); X skipped = 0; X while ((align = inascii(magic, name, asb)) < 0 X && (align = inbinary(magic, name, asb)) < 0 X && (align = inswab(magic, name, asb)) < 0) { X if (++skipped == 1) { X if (total - sizeof(magic) == 0) { X fatal("Unrecognizable archive"); X } X warnarch("Bad magic number", (OFFSET) sizeof(magic)); X if (name[0]) { X warn(name, "May be corrupt"); X } X } X memcpy(magic, magic + 1, sizeof(magic) - 1); X buf_read(magic + sizeof(magic) - 1, 1); X } X if (skipped) { X warnarch("Apparently resynchronized", (OFFSET) sizeof(magic)); X warn(name, "Continuing"); X } X if (strcmp(name, TRAILER) == 0) { X return (-1); X } X if (nameopt(name) >= 0) { X break; X } X buf_skip((OFFSET) asb->sb_size + align); X } X#ifdef S_IFLNK X if ((asb->sb_mode & S_IFMT) == S_IFLNK) { X if (buf_read(asb->sb_link, (uint) asb->sb_size) < 0) { X warn(name, "Corrupt symbolic link"); X return (readcpio(name, asb)); X } X asb->sb_link[asb->sb_size] = '\0'; X asb->sb_size = 0; X } X#endif /* S_IFLNK */ X X /* destroy absolute pathnames for security reasons */ X if (name[0] == '/') { X if (name[1]) { X while (name[0] = name[1]) { X ++name; X } X } else { X name[0] = '.'; X } X } X asb->sb_atime = asb->sb_ctime = asb->sb_mtime; X if (asb->sb_nlink > 1) { X linkto(name, asb); X } X return (0); X} X X X/* inswab - read a reversed by order binary header X * X * DESCRIPTIONS X * X * Reads a byte-swapped CPIO binary archive header X * X * PARMAMETERS X * X * char *magic - magic number to match X * char *name - name of the file which is stored in the header. X * (modified and passed back to caller). X * Stat *asb - stat block for the file (modified and passed back X * to the caller). X * X * X * RETURNS X * X * Returns the number of trailing alignment bytes to skip; -1 if X * unsuccessful. X * X */ X X#ifdef __STDC__ X Xstatic int inswab(char *magic, char *name, Stat *asb) X X#else X Xstatic int inswab(magic, name, asb) Xchar *magic; Xchar *name; XStat *asb; X X#endif X{ X ushort namesize; X uint namefull; X Binary binary; X X if (*((ushort *) magic) != SWAB(M_BINARY)) { X return (-1); X } X memcpy((char *) &binary, X magic + sizeof(ushort), X M_STRLEN - sizeof(ushort)); X if (buf_read((char *) &binary + M_STRLEN - sizeof(ushort), X sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0) { X warnarch("Corrupt swapped header", X (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort))); X return (-1); X } X asb->sb_dev = (dev_t) SWAB(binary.b_dev); X asb->sb_ino = (ino_t) SWAB(binary.b_ino); X asb->sb_mode = SWAB(binary.b_mode); X asb->sb_uid = SWAB(binary.b_uid); X asb->sb_gid = SWAB(binary.b_gid); X asb->sb_nlink = SWAB(binary.b_nlink); X asb->sb_rdev = (dev_t) SWAB(binary.b_rdev); X asb->sb_mtime = SWAB(binary.b_mtime[0]) << 16 | SWAB(binary.b_mtime[1]); X asb->sb_size = SWAB(binary.b_size[0]) << 16 | SWAB(binary.b_size[1]); X if ((namesize = SWAB(binary.b_name)) == 0 || namesize >= PATH_MAX) { X warnarch("Bad swapped pathname length", X (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort))); X return (-1); X } X if (buf_read(name, namefull = namesize + namesize % 2) < 0) { X warnarch("Corrupt swapped pathname", (OFFSET) namefull); X return (-1); X } X if (name[namesize - 1] != '\0') { X warnarch("Bad swapped pathname", (OFFSET) namefull); X return (-1); X } X return (asb->sb_size % 2); X} X X X/* inascii - read in an ASCII cpio header X * X * DESCRIPTION X * X * Reads an ASCII format cpio header X * X * PARAMETERS X * X * char *magic - magic number to match X * char *name - name of the file which is stored in the header. X * (modified and passed back to caller). X * Stat *asb - stat block for the file (modified and passed back X * to the caller). X * X * RETURNS X * X * Returns zero if successful; -1 otherwise. Assumes that the entire X * magic number has been read. X */ X X#ifdef __STDC__ X Xstatic int inascii(char *magic, char *name, Stat *asb) X X#else X Xstatic int inascii(magic, name, asb) Xchar *magic; Xchar *name; XStat *asb; X X#endif X{ X uint namelen; X char header[H_STRLEN + 1]; X X if (strncmp(magic, M_ASCII, M_STRLEN) != 0) { X return (-1); X } X if (buf_read(header, H_STRLEN) < 0) { X warnarch("Corrupt ASCII header", (OFFSET) H_STRLEN); X return (-1); X } X header[H_STRLEN] = '\0'; X if (sscanf(header, H_SCAN, &asb->sb_dev, X &asb->sb_ino, &asb->sb_mode, &asb->sb_uid, X &asb->sb_gid, &asb->sb_nlink, &asb->sb_rdev, X &asb->sb_mtime, &namelen, &asb->sb_size) != H_COUNT) { X warnarch("Bad ASCII header", (OFFSET) H_STRLEN); X return (-1); X } X if (namelen == 0 || namelen >= PATH_MAX) { X warnarch("Bad ASCII pathname length", (OFFSET) H_STRLEN); X return (-1); X } X if (buf_read(name, namelen) < 0) { X warnarch("Corrupt ASCII pathname", (OFFSET) namelen); X return (-1); X } X if (name[namelen - 1] != '\0') { X warnarch("Bad ASCII pathname", (OFFSET) namelen); X return (-1); X } X return (0); X} X X X/* inbinary - read a binary header X * X * DESCRIPTION X * X * Reads a CPIO format binary header. X * X * PARAMETERS X * X * char *magic - magic number to match X * char *name - name of the file which is stored in the header. X * (modified and passed back to caller). X * Stat *asb - stat block for the file (modified and passed back X * to the caller). X * X * RETURNS X * X * Returns the number of trailing alignment bytes to skip; -1 if X * unsuccessful. X */ X X#ifdef __STDC__ X Xstatic int inbinary(char *magic, char *name, Stat *asb) X X#else X Xstatic int inbinary(magic, name, asb) Xchar *magic; Xchar *name; XStat *asb; X X#endif X{ X uint namefull; X Binary binary; X X if (*((ushort *) magic) != M_BINARY) { X return (-1); X } X memcpy((char *) &binary, X magic + sizeof(ushort), X M_STRLEN - sizeof(ushort)); X if (buf_read((char *) &binary + M_STRLEN - sizeof(ushort), X sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0) { X warnarch("Corrupt binary header", X (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort))); X return (-1); X } X asb->sb_dev = binary.b_dev; X asb->sb_ino = binary.b_ino; X asb->sb_mode = binary.b_mode; X asb->sb_uid = binary.b_uid; X asb->sb_gid = binary.b_gid; X asb->sb_nlink = binary.b_nlink; X asb->sb_rdev = binary.b_rdev; X asb->sb_mtime = binary.b_mtime[0] << 16 | binary.b_mtime[1]; X asb->sb_size = binary.b_size[0] << 16 | binary.b_size[1]; X if (binary.b_name == 0 || binary.b_name >= PATH_MAX) { X warnarch("Bad binary pathname length", X (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort))); X return (-1); X } X if (buf_read(name, namefull = binary.b_name + binary.b_name % 2) < 0) { X warnarch("Corrupt binary pathname", (OFFSET) namefull); X return (-1); X } X if (name[binary.b_name - 1] != '\0') { X warnarch("Bad binary pathname", (OFFSET) namefull); X return (-1); X } X return (asb->sb_size % 2); X} END_OF_extract.c if test 14327 -ne `wc -c <extract.c`; then echo shar: \"extract.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f list.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"list.c\" else echo shar: Extracting \"list.c\" \(16229 characters\) sed "s/^X//" >list.c <<'END_OF_list.c' X/* $Source: /u/mark/src/pax/RCS/list.c,v $ X * X * $Revision: 1.1 $ X * X * list.c - List all files on an archive X * X * DESCRIPTION X * X * These function are needed to support archive table of contents and X * verbose mode during extraction and creation of achives. X * X * AUTHOR X * X * Mark H. Colburn, NAPS International (mark@jhereg.mn.org) X * X * Sponsored by The USENIX Association for public distribution. X * X * Copyright (c) 1989 Mark H. Colburn. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice is duplicated in all such X * forms and that any documentation, advertising materials, and other X * materials related to such distribution and use acknowledge that the X * software was developed * by Mark H. Colburn and sponsored by The X * USENIX Association. X * 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 * $Log: list.c,v $ X * Revision 1.1 88/12/23 18:02:14 mark X * Initial revision X * X */ X X#ifndef lint Xstatic char *ident = "$Id: list.c,v 1.1 88/12/23 18:02:14 mark Rel $"; Xstatic char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n"; X#endif /* ! lint */ X X X/* Headers */ X X#include "pax.h" X X X/* Defines */ X X/* X * isodigit returns non zero iff argument is an octal digit, zero otherwise X */ X#define ISODIGIT(c) (((c) >= '0') && ((c) <= '7')) X X X/* Function Prototypes */ X X#ifdef __STDC__ X Xstatic void cpio_entry(char *, Stat *); Xstatic void tar_entry(char *, Stat *); Xstatic void pax_entry(char *, Stat *); Xstatic void print_mode(ushort); Xstatic long from_oct(int digs, char *where); X X#else /* !__STDC__ */ X Xstatic void cpio_entry(); Xstatic void tar_entry(); Xstatic void pax_entry(); Xstatic void print_mode(); Xstatic long from_oct(); X X#endif /* __STDC__ */ X X X/* Internal Identifiers */ X Xstatic char *monnames[] = { X "Jan", "Feb", "Mar", "Apr", "May", "Jun", X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" X}; X X X/* read_header - read a header record X * X * DESCRIPTION X * X * Read a record that's supposed to be a header record. Return its X * address in "head", and if it is good, the file's size in X * asb->sb_size. Decode things from a file header record into a "Stat". X * Also set "head_standard" to !=0 or ==0 depending whether header record X * is "Unix Standard" tar format or regular old tar format. X * X * PARAMETERS X * X * char *name - pointer which will contain name of file X * Stat *asb - pointer which will contain stat info X * X * RETURNS X * X * Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a X * record full of zeros (EOF marker). X */ X X#ifdef __STDC__ X Xint read_header(char *name, Stat *asb) X X#else X Xint read_header(name, asb) Xchar *name; XStat *asb; X X#endif X{ X int i; X long sum; X long recsum; X Link *link; X char *p; X char hdrbuf[BLOCKSIZE]; X X memset((char *)asb, 0, sizeof(Stat)); X /* read the header from the buffer */ X if (buf_read(hdrbuf, BLOCKSIZE) != 0) { X return (EOF); X } X X strcpy(name, hdrbuf); X X recsum = from_oct(8, &hdrbuf[148]); X sum = 0; X p = hdrbuf; X for (i = 0 ; i < 500; i++) { X X /* X * We can't use unsigned char here because of old compilers, e.g. V7. X */ X sum += 0xFF & *p++; X } X X /* Adjust checksum to count the "chksum" field as blanks. */ X for (i = 0; i < 8; i++) { X sum -= 0xFF & hdrbuf[148 + i]; X } X sum += ' ' * 8; X X if (sum == 8 * ' ') { X X /* X * This is a zeroed record...whole record is 0's except for the 8 X * blanks we faked for the checksum field. X */ X return (2); X } X if (sum == recsum) { X /* X * Good record. Decode file size and return. X */ X if (hdrbuf[156] != LNKTYPE) { X asb->sb_size = from_oct(1 + 12, &hdrbuf[124]); X } X asb->sb_mtime = from_oct(1 + 12, &hdrbuf[136]); X asb->sb_mode = from_oct(8, &hdrbuf[100]); X X if (strcmp(&hdrbuf[257], TMAGIC) == 0) { X /* Unix Standard tar archive */ X head_standard = 1; X#ifdef NONAMES X asb->sb_uid = from_oct(8, &hdrbuf[108]); X asb->sb_gid = from_oct(8, &hdrbuf[116]); X#else X asb->sb_uid = finduid(&hdrbuf[265]); X asb->sb_gid = findgid(&hdrbuf[297]); X#endif X switch (hdrbuf[156]) { X case BLKTYPE: X case CHRTYPE: X asb->sb_rdev = makedev(from_oct(8, &hdrbuf[329]), X from_oct(8, &hdrbuf[337])); X break; X default: X /* do nothing... */ X break; X } X } else { X /* Old fashioned tar archive */ X head_standard = 0; X asb->sb_uid = from_oct(8, &hdrbuf[108]); X asb->sb_gid = from_oct(8, &hdrbuf[116]); X } X X switch (hdrbuf[156]) { X case REGTYPE: X case AREGTYPE: X /* X * Berkeley tar stores directories as regular files with a X * trailing / X */ X if (name[strlen(name) - 1] == '/') { X name[strlen(name) - 1] = '\0'; X asb->sb_mode |= S_IFDIR; X } else { X asb->sb_mode |= S_IFREG; X } X break; X case LNKTYPE: X asb->sb_nlink = 2; X linkto(&hdrbuf[157], asb); X linkto(name, asb); X asb->sb_mode |= S_IFREG; X break; X case BLKTYPE: X asb->sb_mode |= S_IFBLK; X break; X case CHRTYPE: X asb->sb_mode |= S_IFCHR; X break; X case DIRTYPE: X asb->sb_mode |= S_IFDIR; X break; X#ifdef S_IFLNK X case SYMTYPE: X asb->sb_mode |= S_IFLNK; X strcpy(asb->sb_link, &hdrbuf[157]); X break; X#endif X#ifdef S_IFIFO X case FIFOTYPE: X asb->sb_mode |= S_IFIFO; X break; X#endif X#ifdef S_IFCTG X case CONTTYPE: X asb->sb_mode |= S_IFCTG; X break; X#endif X } X return (1); X } X return (0); X} X X X/* print_entry - print a single table-of-contents entry X * X * DESCRIPTION X * X * Print_entry prints a single line of file information. The format X * of the line is the same as that used by the LS command. For some X * archive formats, various fields may not make any sense, such as X * the link count on tar archives. No error checking is done for bad X * or invalid data. X * X * PARAMETERS X * X * char *name - pointer to name to print an entry for X * Stat *asb - pointer to the stat structure for the file X */ X X#ifdef __STDC__ X Xvoid print_entry(char *name, Stat *asb) X X#else X Xvoid print_entry(name, asb) Xchar *name; XStat *asb; X X#endif X{ X switch (ar_interface) { X case TAR: X tar_entry(name, asb); X break; X case CPIO: X cpio_entry(name, asb); X break; X case PAX: pax_entry(name, asb); X break; X } X} X X X/* cpio_entry - print a verbose cpio-style entry X * X * DESCRIPTION X * X * Print_entry prints a single line of file information. The format X * of the line is the same as that used by the traditional cpio X * command. No error checking is done for bad or invalid data. X * X * PARAMETERS X * X * char *name - pointer to name to print an entry for X * Stat *asb - pointer to the stat structure for the file X */ X X#ifdef __STDC__ X Xstatic void cpio_entry(char *name, Stat *asb) X X#else X Xstatic void cpio_entry(name, asb) Xchar *name; XStat *asb; X X#endif X{ X struct tm *atm; X Link *from; X struct passwd *pwp; X struct group *grp; X X if (f_list && f_verbose) { X fprintf(msgfile, "%-7o", asb->sb_mode); X atm = localtime(&asb->sb_mtime); X if (pwp = getpwuid((int) USH(asb->sb_uid))) { X fprintf(msgfile, "%-6s", pwp->pw_name); X } else { X fprintf(msgfile, "%-6u", USH(asb->sb_uid)); X } X fprintf(msgfile,"%7ld %3s %2d %02d:%02d:%02d %4d ", X asb->sb_size, monnames[atm->tm_mon], X atm->tm_mday, atm->tm_hour, atm->tm_min, X atm->tm_sec, atm->tm_year + 1900); X } X fprintf(msgfile, "%s", name); X if ((asb->sb_nlink > 1) && (from = islink(name, asb))) { X fprintf(msgfile, " linked to %s", from->l_name); X } X#ifdef S_IFLNK X if ((asb->sb_mode & S_IFMT) == S_IFLNK) { X fprintf(msgfile, " symbolic link to %s", asb->sb_link); X } X#endif /* S_IFLNK */ X putc('\n', msgfile); X} X X X/* tar_entry - print a tar verbose mode entry X * X * DESCRIPTION X * X * Print_entry prints a single line of tar file information. The format X * of the line is the same as that produced by the traditional tar X * command. No error checking is done for bad or invalid data. X * X * PARAMETERS X * X * char *name - pointer to name to print an entry for X * Stat *asb - pointer to the stat structure for the file X */ X X#ifdef __STDC__ X Xstatic void tar_entry(char *name, Stat *asb) X X#else X Xstatic void tar_entry(name, asb) Xchar *name; XStat *asb; X X#endif X{ X struct tm *atm; X int i; X int mode; X char *symnam = "NULL"; X Link *link; X X if ((mode = asb->sb_mode & S_IFMT) == S_IFDIR) { X return; /* don't print directories */ X } X if (f_extract) { X switch (mode) { X#ifdef S_IFLNK X case S_IFLNK: /* This file is a symbolic link */ X i = readlink(name, symnam, PATH_MAX - 1); X if (i < 0) { /* Could not find symbolic link */ X warn("can't read symbolic link", syserr()); X } else { /* Found symbolic link filename */ X symnam[i] = '\0'; X fprintf(msgfile, "x %s symbolic link to %s\n", name, symnam); X } X break; X#endif X case S_IFREG: /* It is a link or a file */ X if ((asb->sb_nlink > 1) && (link = islink(name, asb))) { X fprintf(msgfile, "%s linked to %s\n", name, link->l_name); X } else { X fprintf(msgfile, "x %s, %d bytes, %d tape blocks\n", X name, asb->sb_size, ROUNDUP(asb->sb_size, X BLOCKSIZE) / BLOCKSIZE); X } X } X } else if (f_append || f_create) { X switch (mode) { X#ifdef S_IFLNK X case S_IFLNK: /* This file is a symbolic link */ X i = readlink(name, symnam, PATH_MAX - 1); X if (i < 0) { /* Could not find symbolic link */ X warn("can't read symbolic link", syserr()); X } else { /* Found symbolic link filename */ X symnam[i] = '\0'; X fprintf(msgfile, "a %s symbolic link to %s\n", name, symnam); X } X break; X#endif X case S_IFREG: /* It is a link or a file */ X fprintf(msgfile, "a %s ", name); X if ((asb->sb_nlink > 1) && (link = islink(name, asb))) { X fprintf(msgfile, "link to %s\n", link->l_name); X } else { X fprintf(msgfile, "%d Blocks\n", X ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE); X } X break; X } X } else if (f_list) { X if (f_verbose) { X atm = localtime(&asb->sb_mtime); X print_mode(asb->sb_mode); X fprintf(msgfile," %d/%d %6d %3s %2d %02d:%02d %4d %s", X asb->sb_uid, asb->sb_gid, asb->sb_size, X monnames[atm->tm_mon], atm->tm_mday, atm->tm_hour, X atm->tm_min, atm->tm_year + 1900, name); X } else { X fprintf(msgfile, "%s", name); X } X switch (mode) { X#ifdef S_IFLNK X case S_IFLNK: /* This file is a symbolic link */ X i = readlink(name, symnam, PATH_MAX - 1); X if (i < 0) { /* Could not find symbolic link */ X warn("can't read symbolic link", syserr()); X } else { /* Found symbolic link filename */ X symnam[i] = '\0'; X fprintf(msgfile, " symbolic link to %s", name, symnam); X } X break; X#endif X case S_IFREG: /* It is a link or a file */ X if ((asb->sb_nlink > 1) && (link = islink(name, asb))) { X fprintf(msgfile, " linked to %s", link->l_name); X } X break; /* Do not print out directories */ X } X fputc('\n', msgfile); X } else { X fprintf(msgfile, "? %s %d blocks\n", name, X ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE); X } X} X X X/* pax_entry - print a verbose cpio-style entry X * X * DESCRIPTION X * X * Print_entry prints a single line of file information. The format X * of the line is the same as that used by the LS command. X * No error checking is done for bad or invalid data. X * X * PARAMETERS X * X * char *name - pointer to name to print an entry for X * Stat *asb - pointer to the stat structure for the file X */ X X#ifdef __STDC__ X Xstatic void pax_entry(char *name, Stat *asb) X X#else X Xstatic void pax_entry(name, asb) Xchar *name; XStat *asb; X X#endif X{ X struct tm *atm; X Link *from; X struct passwd *pwp; X struct group *grp; X X if (f_list && f_verbose) { X print_mode(asb->sb_mode); X fprintf(msgfile, " %2d", asb->sb_nlink); X atm = localtime(&asb->sb_mtime); X if (pwp = getpwuid((int) USH(asb->sb_uid))) { X fprintf(msgfile, " %-8s", pwp->pw_name); X } else { X fprintf(msgfile, " %-8u", USH(asb->sb_uid)); X } X if (grp = getgrgid((int) USH(asb->sb_gid))) { X fprintf(msgfile, " %-8s", grp->gr_name); X } else { X fprintf(msgfile, " %-8u", USH(asb->sb_gid)); X } X switch (asb->sb_mode & S_IFMT) { X case S_IFBLK: X case S_IFCHR: X fprintf(msgfile, "\t%3d, %3d", X major(asb->sb_rdev), minor(asb->sb_rdev)); X break; X case S_IFREG: X fprintf(msgfile, "\t%8ld", asb->sb_size); X break; X default: X fprintf(msgfile, "\t "); X } X fprintf(msgfile," %3s %2d %02d:%02d ", X monnames[atm->tm_mon], atm->tm_mday, X atm->tm_hour, atm->tm_min); X } X fprintf(msgfile, "%s", name); X if ((asb->sb_nlink > 1) && (from = islink(name, asb))) { X fprintf(msgfile, " == %s", from->l_name); X } X#ifdef S_IFLNK X if ((asb->sb_mode & S_IFMT) == S_IFLNK) { X fprintf(msgfile, " -> %s", asb->sb_link); X } X#endif /* S_IFLNK */ X putc('\n', msgfile); X} X X X X X/* print_mode - fancy file mode display X * X * DESCRIPTION X * X * Print_mode displays a numeric file mode in the standard unix X * representation, ala ls (-rwxrwxrwx). No error checking is done X * for bad mode combinations. FIFOS, sybmbolic links, sticky bits, X * block- and character-special devices are supported if supported X * by the hosting implementation. X * X * PARAMETERS X * X * ushort mode - The integer representation of the mode to print. X */ X X#ifdef __STDC__ X Xstatic void print_mode(ushort mode) X X#else X Xstatic void print_mode(mode) Xushort mode; X X#endif X{ X /* Tar does not print the leading identifier... */ X if (ar_interface != TAR) { X switch (mode & S_IFMT) { X case S_IFDIR: X putc('d', msgfile); X break; X#ifdef S_IFLNK X case S_IFLNK: X putc('l', msgfile); X break; X#endif /* S_IFLNK */ X case S_IFBLK: X putc('b', msgfile); X break; X case S_IFCHR: X putc('c', msgfile); X break; X#ifdef S_IFIFO X case S_IFIFO: X putc('p', msgfile); X break; X#endif /* S_IFIFO */ X case S_IFREG: X default: X putc('-', msgfile); X break; X } X } X putc(mode & 0400 ? 'r' : '-', msgfile); X putc(mode & 0200 ? 'w' : '-', msgfile); X putc(mode & 0100 X ? mode & 04000 ? 's' : 'x' X : mode & 04000 ? 'S' : '-', msgfile); X putc(mode & 0040 ? 'r' : '-', msgfile); X putc(mode & 0020 ? 'w' : '-', msgfile); X putc(mode & 0010 X ? mode & 02000 ? 's' : 'x' X : mode & 02000 ? 'S' : '-', msgfile); X putc(mode & 0004 ? 'r' : '-', msgfile); X putc(mode & 0002 ? 'w' : '-', msgfile); X putc(mode & 0001 X ? mode & 01000 ? 't' : 'x' X : mode & 01000 ? 'T' : '-', msgfile); X} X X X/* from_oct - quick and dirty octal conversion X * X * DESCRIPTION X * X * From_oct will convert an ASCII representation of an octal number X * to the numeric representation. The number of characters to convert X * is given by the parameter "digs". If there are less numbers than X * specified by "digs", then the routine returns -1. X * X * PARAMETERS X * X * int digs - Number to of digits to convert X * char *where - Character representation of octal number X * X * RETURNS X * X * The value of the octal number represented by the first digs X * characters of the string where. Result is -1 if the field X * is invalid (all blank, or nonoctal). X * X * ERRORS X * X * If the field is all blank, then the value returned is -1. X * X */ X X#ifdef __STDC__ X Xstatic long from_oct(int digs, char *where) X X#else X Xstatic long from_oct(digs, where) Xint digs; /* number of characters to convert */ Xchar *where; /* character representation of octal number */ X X#endif X{ X long value; X X while (isspace(*where)) { /* Skip spaces */ X where++; X if (--digs <= 0) { X return(-1); /* All blank field */ X } X } X value = 0; X while (digs > 0 && ISODIGIT(*where)) { /* Scan til nonoctal */ X value = (value << 3) | (*where++ - '0'); X --digs; X } X X if (digs > 0 && *where && !isspace(*where)) { X return(-1); /* Ended on non-space/nul */ X } X return(value); X} END_OF_list.c if test 16229 -ne `wc -c <list.c`; then echo shar: \"list.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f pax.1 -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"pax.1\" else echo shar: Extracting \"pax.1\" \(13279 characters\) sed "s/^X//" >pax.1 <<'END_OF_pax.1' X.\" $Id: pax.1,v 1.1 88/12/23 18:02:22 mark Rel $ X.TH PAX 1 "USENIX Association" "" X.SH NAME Xpax \- portable archive exchange X.SH SYNOPSIS X.TP \w'\fBpax\fR\ 'u X.B pax X.RB [ \-cimopuvy ] X.RI "[\fB\-f\fR" " archive" ] X.RI "[\fB\-s\fR" " replstr" ] X.RI "[\fB\-t\fR" " device" ] X.RI [ pattern... ] X.TP \w'\fBpax\ \-r\fR\ 'u X.B "pax\ \-r" X.RB [ \-cimnopuvy ] X.RI "[\fB\-f\fR" " archive" ] X.RI "[\fB\-s\fR" " replstr" ] X.RI "[\fB\-t\fR" " device" ] X.RI [ pattern... ] X.TP \w'\fBpax\ \-w\fR\ 'u X.B "pax\ \-w" X.RB [ \-adimuvy ] X.RI "[\fB\-b\fR" " blocking" ] X.RI "[\fB\-f\fR" " archive" ] X.RI "[\fB\-s\fR" " replstr" ] X.RI "[\fB\-t\fR" " device" ] X.RI "[\fB\-x\fR" " format" ] X.RI [ pathname... ] X.TP \w'\fBpax\ \-rw\fR\ 'u X.B "pax\ \-rw" X.RB [ \-ilmopuvy ] X.RI "[\fB\-s\fR" " replstr" ] X.RI [ pathname... ] Xdirectory X.SH DESCRIPTION X.I Pax Xreads and writes archive files which conform to the X.B "Archive/Interchange File Format" Xspecified in X.IR "IEEE Std. 1003.1-1988" . X.I Pax Xcan also read, but not write, a number of other file formats Xin addition to those specified in the X.B "Archive/Interchange File Format" Xdescription. XSupport for these traditional file formats, such as V7 X.I "tar" Xand System V binary X.I "cpio" Xformat archives, Xis provided for backward compatibility and to maximize portability. X.PP X.I Pax Xwill also support traditional X.I cpio Xand XSystem V X.I tar Xinterfaces if invoked with the name X"cpio" or "tar" respectively. XSee the X.I cpio(1) Xor X.I tar(1) Xmanual pages for more details. X.PP XCombinations of the X.B \-r Xand X.B \-w Xcommand line arguments specify whether X.I pax Xwill read, write or list the contents of the specified archive, Xor move the specified files to another directory. X.PP XThe command line arguments are: X.TP .5i X.B \-w Xwrites the files and directories specified by X.I pathname Xoperands to the standard output together with the pathname and status Xinformation prescribed by the archive format used. XA directory X.I pathname Xoperand refers to the files and (recursively) subdirectories of that Xdirectory. XIf no X.I pathname Xoperands are given, then the standard input is read to get a Xlist of pathnames to copy, one pathname per line. XIn this case, only those pathnames appearing on the standard input are Xcopied. X.TP .5i X.B \-r X.I Pax Xreads an archive file from the standard input. XOnly files with names that match any of the X.I pattern Xoperands are selected for extraction. XThe selected files are conditionally created and copied relative to the Xcurrent directory tree, subject to the options described below. XBy default, the owner and group of selected files will be that of the Xinvoking process, and the permissions and modification times will be the Xsames as those in the archive. X.RS .5i X.PP XThe supported archive formats are automatically detected on input. XThe default output format is X.IR ustar , Xbut may be overridden by the X.B \-x X.I format Xoption described below. X.RE X.TP .5i X.B \-rw X.I Pax Xreads the files and directories named in the X.I pathname Xoperands and copies them to the destination X.IR directory . XA directory X.I pathname Xoperand refers to the files and (recursively) subdirectories of that Xdirectory. XIf no X.I pathname Xoperands are given, the standard input is read to get a list of pathnames Xto copy, one pathname per line. XIn this case, only those pathnames appearing on the standard input are Xcopied. XThe directory named by the X.I directory Xoperand must exist and have the proper permissions before the copy can Xoccur. X.PP XIf neither the X.BR \-r " or " \-w Xoptions are given, then X.I pax Xwill list the contents of the specified archive. XIn this mode, X.I pax Xlists normal files one per line, hard link pathnames as X.sp X.RS 1i X.IR pathname " == " linkname X.RE X.sp Xand symbolic link pathnames (if supported by the implementation) as X.sp X.RS 1i X.IR pathname " -> " linkname X.RE X.sp Xwhere X.I pathname Xis the name of the file being extracted, and X.I linkname Xis the name of a file which appeared earlier in the archive. X.PP XIf the X.B \-v Xoption is specified, then X.I pax Xlist normal pathnames in the same format used by the X.I ls Xutility with the X.B \-l Xoption. XHard links are shown as X.sp X.RS 1i X.IR "<ls -l listing>" " == " linkname X.RE X.sp Xand symbolic links (if supported) are shown as X.sp X.RS 1i X.IR "<ls -l listing>" " -> " linkname X.RE X.sp X.PP X.I Pax Xis capable of reading and writing archives which span multiple physical Xvolumes. XUpon detecting an end of medium on an archive which is not yet completed, X.I pax Xwill prompt the user for the next volume of the archive and will allow the Xuser to specify the location of the next volume. X.SS Options XThe following options are available: X.TP 1i X.B \-a XThe files specified by X.I pathname Xare appended to the specified archive. X.TP 1i X.BI \-b " blocking" XBlock the output at X.I blocking Xbytes per write to the archive file. XA X.B k Xsuffix multiplies X.I blocking Xby 1024, a X.B b Xsuffix multiplies X.I blocking Xby 512 and a X.B m Xsuffix multiplies X.I blocking Xby 1048576 (1 megabyte). XIf not specified, X.I blocking Xis automatically determined on input and is ignored for X.B \-rw. X.TP 1i X.B \-c XComplement the match sense of the the X.I pattern Xoperands. X.TP 1i X.B \-d XIntermediate directories not explicitly listed in the archive are not Xcreated. XThis option is ignored unless Xthe X.B \-r Xoption is specified. X.TP 1i X.BI \-f " archive" XThe X.I archive Xoption specifies the pathname of the input or output archive, Xoverriding the default of standard input for X.B \-r Xor standard output for X.BR \-w . X.TP 1i X.B \-i XInteractively rename files. XSubstitutions specified by X.B \-s Xoptions (described below) Xare performed before requesting the new file name from the user. XA file is skipped if an empty line is entered and X.I pax Xexits with an exit status of 0 if X.B EOF Xis encountered. X.TP 1i X.B \-l XFiles are linked rather than copied when possible. X.TP 1i X.B \-m XFile modification times are not retained. X.TP 1i X.B \-n XWhen X.B \-r Xis specified, but X.B \-w Xis not, the X.I pattern Xarguments are treated as ordinary file names. XOnly the first occurrence of each of these files in the input archive Xis read. XThe X.B pax Xutility exits with a zero exit status after all files in the list have been Xread. XIf one or more files in the list is not found, X.B pax Xwrites a diagnostic to standard error for each of the files and exits with Xa non-zero exit status. Xthe file names are compared before any of the X.BR \-i , X.BR \-s , Xor X.B \-y Xoptions are applied. X.TP 1i X.B \-o XRestore file ownership as specified in the archive. XThe invoking process must have appropriate privileges to accomplish this. X.TP 1i X.B \-p XPreserve the access time of the input files after they have been copied. X.TP 1i X.BI \-s " replstr" XFile names are modified according to the substitution expression using the Xsyntax of X.I "ed(1)" Xas shown: X.sp X.RS 2i X-s /\fIold\fR/\fInew\fR/\fB[\fRgp\fB]\fR X.RE X.RS 1i X.PP XAny non null character may be used as a delimiter (a / is used here as an Xexample). XMultiple X.B \-s Xexpressions may be specified; the expressions are applied in the order Xspecified terminating with the first successful substitution. XThe optional trailing X.B p Xcauses successful mappings to be listed on standard error. XThe optional trailing X.B g Xcauses the X.I old Xexpression to be replaced each time it occurs in the source string. XFiles that substitute to an empty string are ignored both on input and Xoutput. X.RE X.TP 1i X.BI \-t " device" XThe X.I device Xoption argument is an implementation-defined identifier that names the input Xor output archive device, overriding the default of standard input for X.B \-r Xand standard output for X.BR \-w . X.TP 1i X.B \-u XCopy each file only if it is newer than a pre-existing file with the same Xname. XThis implies X.BR \-a . X.TP 1i X.B \-v XList file names as they are encountered. XProduces a verbose table of contents listing on the standard output when both X.B \-r Xand X.B \-w Xare omitted, Xotherwise the file names are printed to standard error as they are Xencountered in the archive. X.TP 1i X.BI \-x " format" XSpecifies the output archive X.IR format . XThe input format, which must be one of the following, is automatically Xdetermined when the X.B \-r Xoption is used. XThe supported formats are: X.TP 1i X.I cpio XThe extended X.I CPIO Xinterchange format specified in X.B "Extended CPIO Format" in X.I "IEEE Std. 1003.1-1988." X.TP 1i X.I ustar XThe extended X.I TAR Xinterchange format specified in X.B "Extended TAR Format" in X.I "IEEE Std. 1003.1-1988." XThis is the default archive format. X.RE X.TP 1i X.B \-y XInteractively prompt for the disposition of each file. XSubstitutions specified by X.B \-s Xoptions (described above) Xare performed before prompting the user for disposition. X.B EOF Xor an input line starting with the character X.B q Xcaused X.I pax Xto exit. XOtherwise, an input line starting with anything other than X.B y Xcauses the file to be ignored. XThis option cannot be used in conjunction with the X.B \-i Xoption. X.PP XOnly the last of multiple X.B \-f Xor X.B \-t Xoptions take effect. X.PP XWhen writing to an archive, the Xstandard input is used as a list of pathnames if no X.I pathname Xoperands are specified. XThe format is one pathname per line. XOtherwise, the standard input is the archive file, Xwhich is formatted according to one of the specifications in X.B "Archive/Interchange File format" Xin X.IR "IEEE Std. 1003.1-1988" , Xor some other implementation-defined format. X.PP XThe user ID and group ID of the process, together with the appropriate Xprivileges, affect the ability of X.I pax Xto restore ownership and permissions attributes of the archived files. X(See X.I "format-reading utility" Xin X.B "Archive/Interchange File Format" Xin X.IR "IEEE Std. 1003.1-1988" ".)" X.PP XThe options X.BR \-a , X.BR \-c , X.BR \-d , X.BR \-i , X.BR \-l , X.BR \-p , X.BR \-t , X.BR \-u , Xand X.BR \-y Xare provided for functional compatibility with the historical X.I cpio Xand X.I tar Xutilities. XThe option defaults were chosen based on the most common usage of these Xoptions, therefore, some of the options have meanings different than Xthose of the historical commands. X.SS Operands XThe following operands are available: X.TP 1i X.I directory XThe destination directory pathname for copies when both the X.B \-r Xand X.B \-w Xoptions are specified. XThe directory must exist and be writable before the copy or and error Xresults. X.TP 1i X.I pathname XA file whose contents are used instead of the files named on the standard Xinput. XWhen a directory is named, all of its files and (recursively) Xsubdirectories Xare copied as well. X.TP 1i X.IR pattern XA X.I pattern Xis given in the standard shell pattern matching notation. XThe default if no X.I pattern Xis specified is X.BR * \, Xwhich selects all files. X.SH EXAMPLES XThe following command X.sp X.RS 1i Xpax \-w \-f /dev/rmt0 \. X.RE X.sp Xcopies the contents of the current directory to tape drive 0. X.PP XThe commands X.sp X.RS 1i X.RI mkdir " newdir" X.br X.RI cd " olddir" X.br X.RI "pax -rw . " newdir X.RE X.sp Xcopies the contents of X.I olddir Xto X.I newdir . X.PP XThe command X.sp X.RS 1i Xpax \-r \-s ',//*usr//*,,' -f pax.out X.RE X.sp Xreads the archive X.B pax.out Xwith all files rooted in "/usr" in the archive extracted Xrelative to the current directory. X.SH FILES X.TP 1i X/dev/tty Xused to prompt the user for information when the X.BR \-i " or " \-y Xoptions are specified. X.SH "SEE ALSO" Xcpio(1), find(1), tar(1), cpio(5), tar(5) X.SH DIAGNOSTICS X.I Pax Xwill terminate immediately, without processing any Xadditional files on the command line or in the archive. X.SH "EXIT CODES" X.I Pax Xwill exit with one of the following values: X.IP 0 .5i XAll files in the archive were processed successfully. X.IP ">0" .5i X.I Pax Xaborted due to errors encountered during operation. X.SH BUGS XSpecial permissions may be required to copy or extract special files. X.PP XDevice, user ID, and group ID numbers larger than 65535 cause additional Xheader records to be output. XThese records are ignored by some historical version of X.I "cpio(1)" Xand X.IR "tar(1)" . X.PP XThe archive formats described in X.B "Archive/Interchange File Format" Xhave certain restrictions that have Xbeen carried over from historical usage. XFor example, there are restrictions on the length of pathnames stored in Xthe archive. X.PP XWhen getting an "ls -l" style listing on X.I tar Xformat archives, link counts are listed as zero since the X.I ustar Xarchive format does not keep link count information. X.SH COPYRIGHT XCopyright (c) 1989 Mark H. Colburn. X.br XAll rights reserved. X.PP XRedistribution and use in source and binary forms are permitted Xprovided that the above copyright notice is duplicated in all such Xforms and that any documentation, advertising materials, and other Xmaterials related to such distribution and use acknowledge that the Xsoftware was developed by Mark H. Colburn and sponsored by The XUSENIX Association. X.PP XTHE SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR XIMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED XWARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X.SH AUTHOR XMark H. Colburn X.br XNAPS International X.br X117 Mackubin Street, Suite 1 X.br XSt. Paul, MN 55102 X.br Xmark@jhereg.MN.ORG X.sp 2 XSponsored by X.B "The USENIX Association" Xfor public distribution. END_OF_pax.1 if test 13279 -ne `wc -c <pax.1`; then echo shar: \"pax.1\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 4 \(of 6\). cp /dev/null ark4isdone MISSING="" for I in 1 2 3 4 5 6 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 6 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.