|
|
1.1 ! root 1: # This is a shell archive. Remove anything before this line, then unpack ! 2: # it by saving it into a file and typing "sh file". To overwrite existing ! 3: # files, type "sh file -c". You can also feed this as standard input via ! 4: # unshar, or by typing "sh <file", e.g.. If this archive is complete, you ! 5: # will see the following message at the end: ! 6: # "End of archive 4 (of 6)." ! 7: # Contents: extract.c list.c pax.1 ! 8: # Wrapped by mark@jhereg on Tue Dec 27 19:37:53 1988 ! 9: PATH=/bin:/usr/bin:/usr/ucb ; export PATH ! 10: if test -f extract.c -a "${1}" != "-c" ; then ! 11: echo shar: Will not over-write existing file \"extract.c\" ! 12: else ! 13: echo shar: Extracting \"extract.c\" \(14327 characters\) ! 14: sed "s/^X//" >extract.c <<'END_OF_extract.c' ! 15: X/* $Source: /u/mark/src/pax/RCS/extract.c,v $ ! 16: X * ! 17: X * $Revision: 1.1 $ ! 18: X * ! 19: X * extract.c - Extract files from a tar archive. ! 20: X * ! 21: X * DESCRIPTION ! 22: X * ! 23: X * AUTHOR ! 24: X * ! 25: X * Mark H. Colburn, NAPS International ([email protected]) ! 26: X * ! 27: X * Sponsored by The USENIX Association for public distribution. ! 28: X * ! 29: X * Copyright (c) 1989 Mark H. Colburn. ! 30: X * All rights reserved. ! 31: X * ! 32: X * Redistribution and use in source and binary forms are permitted ! 33: X * provided that the above copyright notice is duplicated in all such ! 34: X * forms and that any documentation, advertising materials, and other ! 35: X * materials related to such distribution and use acknowledge that the ! 36: X * software was developed * by Mark H. Colburn and sponsored by The ! 37: X * USENIX Association. ! 38: X * ! 39: X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 40: X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 41: X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 42: X * ! 43: X * $Log: extract.c,v $ ! 44: X * Revision 1.1 88/12/23 18:02:07 mark ! 45: X * Initial revision ! 46: X * ! 47: X */ ! 48: X ! 49: X#ifndef lint ! 50: Xstatic char *ident = "$Id: extract.c,v 1.1 88/12/23 18:02:07 mark Rel $"; ! 51: Xstatic char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n"; ! 52: X#endif /* ! lint */ ! 53: X ! 54: X ! 55: X/* Headers */ ! 56: X ! 57: X#include "pax.h" ! 58: X ! 59: X ! 60: X/* Defines */ ! 61: X ! 62: X/* ! 63: X * Swap bytes. ! 64: X */ ! 65: X#define SWAB(n) ((((ushort)(n) >> 8) & 0xff) | (((ushort)(n) & 0xff00)) << 8) ! 66: X ! 67: X ! 68: X/* Function Prototypes */ ! 69: X ! 70: X#ifdef __STDC__ ! 71: X ! 72: Xstatic int inbinary(char *, char *, Stat *); ! 73: Xstatic int inascii(char *, char *, Stat *); ! 74: Xstatic int inswab(char *, char *, Stat *); ! 75: Xstatic int readtar(char *, Stat *); ! 76: Xstatic int readcpio(char *, Stat *); ! 77: X ! 78: X#else /* !__STDC__ */ ! 79: X ! 80: Xstatic int inbinary(); ! 81: Xstatic int inascii(); ! 82: Xstatic int inswab(); ! 83: Xstatic int readtar(); ! 84: Xstatic int readcpio(); ! 85: X ! 86: X#endif /* __STDC__ */ ! 87: X ! 88: X ! 89: X/* read_archive - read in an archive ! 90: X * ! 91: X * DESCRIPTION ! 92: X * ! 93: X * Read_archive is the central entry point for reading archives. ! 94: X * Read_archive determines the proper archive functions to call ! 95: X * based upon the archive type being processed. ! 96: X * ! 97: X * RETURNS ! 98: X * ! 99: X */ ! 100: X ! 101: X#ifdef __STDC__ ! 102: X ! 103: Xint read_archive(void) ! 104: X ! 105: X#else ! 106: X ! 107: Xint read_archive() ! 108: X ! 109: X#endif ! 110: X{ ! 111: X Stat sb; ! 112: X char name[PATH_MAX + 1]; ! 113: X int match; ! 114: X int pad; ! 115: X ! 116: X name_gather(); /* get names from command line */ ! 117: X name[0] = '\0'; ! 118: X while (get_header(name, &sb) == 0) { ! 119: X match = name_match(name) ^ f_reverse_match; ! 120: X if (f_list) { /* only wanted a table of contents */ ! 121: X if (match) { ! 122: X print_entry(name, &sb); ! 123: X } ! 124: X if (((ar_format == TAR) ! 125: X ? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE)) ! 126: X : buf_skip((OFFSET) sb.sb_size)) < 0) { ! 127: X warn(name, "File data is corrupt"); ! 128: X } ! 129: X } else if (match) { ! 130: X if (rplhead != NULL) { ! 131: X rpl_name(name); ! 132: X if (strlen(name) == 0) { ! 133: X continue; ! 134: X } ! 135: X } ! 136: X if (get_disposition("extract", name) || ! 137: X get_newname(name, sizeof(name))) { ! 138: X /* skip file... */ ! 139: X if (((ar_format == TAR) ! 140: X ? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE)) ! 141: X : buf_skip((OFFSET) sb.sb_size)) < 0) { ! 142: X warn(name, "File data is corrupt"); ! 143: X } ! 144: X continue; ! 145: X } ! 146: X if (inentry(name, &sb) < 0) { ! 147: X warn(name, "File data is corrupt"); ! 148: X } ! 149: X if (f_verbose) { ! 150: X print_entry(name, &sb); ! 151: X } ! 152: X if (ar_format == TAR && sb.sb_nlink > 1) { ! 153: X /* ! 154: X * This kludge makes sure that the link table is cleared ! 155: X * before attempting to process any other links. ! 156: X */ ! 157: X if (sb.sb_nlink > 1) { ! 158: X linkfrom(name, &sb); ! 159: X } ! 160: X } ! 161: X if (ar_format == TAR && (pad = sb.sb_size % BLOCKSIZE) != 0) { ! 162: X pad = BLOCKSIZE - pad; ! 163: X buf_skip((OFFSET) pad); ! 164: X } ! 165: X } else { ! 166: X if (((ar_format == TAR) ! 167: X ? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE)) ! 168: X : buf_skip((OFFSET) sb.sb_size)) < 0) { ! 169: X warn(name, "File data is corrupt"); ! 170: X } ! 171: X } ! 172: X } ! 173: X ! 174: X close_archive(); ! 175: X} ! 176: X ! 177: X ! 178: X ! 179: X/* get_header - figures which type of header needs to be read. ! 180: X * ! 181: X * DESCRIPTION ! 182: X * ! 183: X * This is merely a single entry point for the two types of archive ! 184: X * headers which are supported. The correct header is selected ! 185: X * depending on the archive type. ! 186: X * ! 187: X * PARAMETERS ! 188: X * ! 189: X * char *name - name of the file (passed to header routine) ! 190: X * Stat *asb - Stat block for the file (passed to header routine) ! 191: X * ! 192: X * RETURNS ! 193: X * ! 194: X * Returns the value which was returned by the proper header ! 195: X * function. ! 196: X */ ! 197: X ! 198: X#ifdef __STDC__ ! 199: X ! 200: Xint get_header(char *name, Stat *asb) ! 201: X ! 202: X#else ! 203: X ! 204: Xint get_header(name, asb) ! 205: Xchar *name; ! 206: XStat *asb; ! 207: X ! 208: X#endif ! 209: X{ ! 210: X if (ar_format == TAR) { ! 211: X return(readtar(name, asb)); ! 212: X } else { ! 213: X return(readcpio(name, asb)); ! 214: X } ! 215: X} ! 216: X ! 217: X ! 218: X/* readtar - read a tar header ! 219: X * ! 220: X * DESCRIPTION ! 221: X * ! 222: X * Tar_head read a tar format header from the archive. The name ! 223: X * and asb parameters are modified as appropriate for the file listed ! 224: X * in the header. Name is assumed to be a pointer to an array of ! 225: X * at least PATH_MAX bytes. ! 226: X * ! 227: X * PARAMETERS ! 228: X * ! 229: X * char *name - name of the file for which the header is ! 230: X * for. This is modified and passed back to ! 231: X * the caller. ! 232: X * Stat *asb - Stat block for the file for which the header ! 233: X * is for. The fields of the stat structure are ! 234: X * extracted from the archive header. This is ! 235: X * also passed back to the caller. ! 236: X * ! 237: X * RETURNS ! 238: X * ! 239: X * Returns 0 if a valid header was found, or -1 if EOF is ! 240: X * encountered. ! 241: X */ ! 242: X ! 243: X#ifdef __STDC__ ! 244: X ! 245: Xstatic int readtar(char *name, Stat *asb) ! 246: X ! 247: X#else ! 248: X ! 249: Xstatic int readtar(name, asb) ! 250: Xchar *name; ! 251: XStat *asb; ! 252: X ! 253: X#endif ! 254: X{ ! 255: X int status = 3; /* Initial status at start of archive */ ! 256: X static int prev_status; ! 257: X ! 258: X for (;;) { ! 259: X prev_status = status; ! 260: X status = read_header(name, asb); ! 261: X switch (status) { ! 262: X case 1: /* Valid header */ ! 263: X return(0); ! 264: X case 0: /* Invalid header */ ! 265: X switch (prev_status) { ! 266: X case 3: /* Error on first record */ ! 267: X warn(ar_file, "This doesn't look like a tar archive"); ! 268: X /* FALLTHRU */ ! 269: X case 2: /* Error after record of zeroes */ ! 270: X case 1: /* Error after header rec */ ! 271: X warn(ar_file, "Skipping to next file..."); ! 272: X /* FALLTHRU */ ! 273: X default: ! 274: X case 0: /* Error after error */ ! 275: X break; ! 276: X } ! 277: X break; ! 278: X ! 279: X case 2: /* Record of zeroes */ ! 280: X case EOF: /* End of archive */ ! 281: X default: ! 282: X return(-1); ! 283: X } ! 284: X } ! 285: X} ! 286: X ! 287: X ! 288: X/* readcpio - read a CPIO header ! 289: X * ! 290: X * DESCRIPTION ! 291: X * ! 292: X * Read in a cpio header. Understands how to determine and read ASCII, ! 293: X * binary and byte-swapped binary headers. Quietly translates ! 294: X * old-fashioned binary cpio headers (and arranges to skip the possible ! 295: X * alignment byte). Returns zero if successful, -1 upon archive trailer. ! 296: X * ! 297: X * PARAMETERS ! 298: X * ! 299: X * char *name - name of the file for which the header is ! 300: X * for. This is modified and passed back to ! 301: X * the caller. ! 302: X * Stat *asb - Stat block for the file for which the header ! 303: X * is for. The fields of the stat structure are ! 304: X * extracted from the archive header. This is ! 305: X * also passed back to the caller. ! 306: X * ! 307: X * RETURNS ! 308: X * ! 309: X * Returns 0 if a valid header was found, or -1 if EOF is ! 310: X * encountered. ! 311: X */ ! 312: X ! 313: X#ifdef __STDC__ ! 314: X ! 315: Xstatic int readcpio(char *name, Stat *asb) ! 316: X ! 317: X#else ! 318: X ! 319: Xstatic int readcpio(name, asb) ! 320: Xchar *name; ! 321: XStat *asb; ! 322: X ! 323: X#endif ! 324: X{ ! 325: X OFFSET skipped; ! 326: X char magic[M_STRLEN]; ! 327: X static int align; ! 328: X ! 329: X if (align > 0) { ! 330: X buf_skip((OFFSET) align); ! 331: X } ! 332: X align = 0; ! 333: X for (;;) { ! 334: X buf_read(magic, M_STRLEN); ! 335: X skipped = 0; ! 336: X while ((align = inascii(magic, name, asb)) < 0 ! 337: X && (align = inbinary(magic, name, asb)) < 0 ! 338: X && (align = inswab(magic, name, asb)) < 0) { ! 339: X if (++skipped == 1) { ! 340: X if (total - sizeof(magic) == 0) { ! 341: X fatal("Unrecognizable archive"); ! 342: X } ! 343: X warnarch("Bad magic number", (OFFSET) sizeof(magic)); ! 344: X if (name[0]) { ! 345: X warn(name, "May be corrupt"); ! 346: X } ! 347: X } ! 348: X memcpy(magic, magic + 1, sizeof(magic) - 1); ! 349: X buf_read(magic + sizeof(magic) - 1, 1); ! 350: X } ! 351: X if (skipped) { ! 352: X warnarch("Apparently resynchronized", (OFFSET) sizeof(magic)); ! 353: X warn(name, "Continuing"); ! 354: X } ! 355: X if (strcmp(name, TRAILER) == 0) { ! 356: X return (-1); ! 357: X } ! 358: X if (nameopt(name) >= 0) { ! 359: X break; ! 360: X } ! 361: X buf_skip((OFFSET) asb->sb_size + align); ! 362: X } ! 363: X#ifdef S_IFLNK ! 364: X if ((asb->sb_mode & S_IFMT) == S_IFLNK) { ! 365: X if (buf_read(asb->sb_link, (uint) asb->sb_size) < 0) { ! 366: X warn(name, "Corrupt symbolic link"); ! 367: X return (readcpio(name, asb)); ! 368: X } ! 369: X asb->sb_link[asb->sb_size] = '\0'; ! 370: X asb->sb_size = 0; ! 371: X } ! 372: X#endif /* S_IFLNK */ ! 373: X ! 374: X /* destroy absolute pathnames for security reasons */ ! 375: X if (name[0] == '/') { ! 376: X if (name[1]) { ! 377: X while (name[0] = name[1]) { ! 378: X ++name; ! 379: X } ! 380: X } else { ! 381: X name[0] = '.'; ! 382: X } ! 383: X } ! 384: X asb->sb_atime = asb->sb_ctime = asb->sb_mtime; ! 385: X if (asb->sb_nlink > 1) { ! 386: X linkto(name, asb); ! 387: X } ! 388: X return (0); ! 389: X} ! 390: X ! 391: X ! 392: X/* inswab - read a reversed by order binary header ! 393: X * ! 394: X * DESCRIPTIONS ! 395: X * ! 396: X * Reads a byte-swapped CPIO binary archive header ! 397: X * ! 398: X * PARMAMETERS ! 399: X * ! 400: X * char *magic - magic number to match ! 401: X * char *name - name of the file which is stored in the header. ! 402: X * (modified and passed back to caller). ! 403: X * Stat *asb - stat block for the file (modified and passed back ! 404: X * to the caller). ! 405: X * ! 406: X * ! 407: X * RETURNS ! 408: X * ! 409: X * Returns the number of trailing alignment bytes to skip; -1 if ! 410: X * unsuccessful. ! 411: X * ! 412: X */ ! 413: X ! 414: X#ifdef __STDC__ ! 415: X ! 416: Xstatic int inswab(char *magic, char *name, Stat *asb) ! 417: X ! 418: X#else ! 419: X ! 420: Xstatic int inswab(magic, name, asb) ! 421: Xchar *magic; ! 422: Xchar *name; ! 423: XStat *asb; ! 424: X ! 425: X#endif ! 426: X{ ! 427: X ushort namesize; ! 428: X uint namefull; ! 429: X Binary binary; ! 430: X ! 431: X if (*((ushort *) magic) != SWAB(M_BINARY)) { ! 432: X return (-1); ! 433: X } ! 434: X memcpy((char *) &binary, ! 435: X magic + sizeof(ushort), ! 436: X M_STRLEN - sizeof(ushort)); ! 437: X if (buf_read((char *) &binary + M_STRLEN - sizeof(ushort), ! 438: X sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0) { ! 439: X warnarch("Corrupt swapped header", ! 440: X (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort))); ! 441: X return (-1); ! 442: X } ! 443: X asb->sb_dev = (dev_t) SWAB(binary.b_dev); ! 444: X asb->sb_ino = (ino_t) SWAB(binary.b_ino); ! 445: X asb->sb_mode = SWAB(binary.b_mode); ! 446: X asb->sb_uid = SWAB(binary.b_uid); ! 447: X asb->sb_gid = SWAB(binary.b_gid); ! 448: X asb->sb_nlink = SWAB(binary.b_nlink); ! 449: X asb->sb_rdev = (dev_t) SWAB(binary.b_rdev); ! 450: X asb->sb_mtime = SWAB(binary.b_mtime[0]) | SWAB(binary.b_mtime[1]); << 16 ! 451: X asb->sb_size = SWAB(binary.b_size[0]) | SWAB(binary.b_size[1]); << 16 ! 452: X if ((namesize = SWAB(binary.b_name)) == 0 || namesize >= PATH_MAX) { ! 453: X warnarch("Bad swapped pathname length", ! 454: X (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort))); ! 455: X return (-1); ! 456: X } ! 457: X if (buf_read(name, namefull = namesize + namesize % 2) < 0) { ! 458: X warnarch("Corrupt swapped pathname", (OFFSET) namefull); ! 459: X return (-1); ! 460: X } ! 461: X if (name[namesize - 1] != '\0') { ! 462: X warnarch("Bad swapped pathname", (OFFSET) namefull); ! 463: X return (-1); ! 464: X } ! 465: X return (asb->sb_size % 2); ! 466: X} ! 467: X ! 468: X ! 469: X/* inascii - read in an ASCII cpio header ! 470: X * ! 471: X * DESCRIPTION ! 472: X * ! 473: X * Reads an ASCII format cpio header ! 474: X * ! 475: X * PARAMETERS ! 476: X * ! 477: X * char *magic - magic number to match ! 478: X * char *name - name of the file which is stored in the header. ! 479: X * (modified and passed back to caller). ! 480: X * Stat *asb - stat block for the file (modified and passed back ! 481: X * to the caller). ! 482: X * ! 483: X * RETURNS ! 484: X * ! 485: X * Returns zero if successful; -1 otherwise. Assumes that the entire ! 486: X * magic number has been read. ! 487: X */ ! 488: X ! 489: X#ifdef __STDC__ ! 490: X ! 491: Xstatic int inascii(char *magic, char *name, Stat *asb) ! 492: X ! 493: X#else ! 494: X ! 495: Xstatic int inascii(magic, name, asb) ! 496: Xchar *magic; ! 497: Xchar *name; ! 498: XStat *asb; ! 499: X ! 500: X#endif ! 501: X{ ! 502: X uint namelen; ! 503: X char header[H_STRLEN + 1]; ! 504: X ! 505: X if (strncmp(magic, M_ASCII, M_STRLEN) != 0) { ! 506: X return (-1); ! 507: X } ! 508: X if (buf_read(header, H_STRLEN) < 0) { ! 509: X warnarch("Corrupt ASCII header", (OFFSET) H_STRLEN); ! 510: X return (-1); ! 511: X } ! 512: X header[H_STRLEN] = '\0'; ! 513: X if (sscanf(header, H_SCAN, &asb->sb_dev, ! 514: X &asb->sb_ino, &asb->sb_mode, &asb->sb_uid, ! 515: X &asb->sb_gid, &asb->sb_nlink, &asb->sb_rdev, ! 516: X &asb->sb_mtime, &namelen, &asb->sb_size) != H_COUNT) { ! 517: X warnarch("Bad ASCII header", (OFFSET) H_STRLEN); ! 518: X return (-1); ! 519: X } ! 520: X if (namelen == 0 || namelen >= PATH_MAX) { ! 521: X warnarch("Bad ASCII pathname length", (OFFSET) H_STRLEN); ! 522: X return (-1); ! 523: X } ! 524: X if (buf_read(name, namelen) < 0) { ! 525: X warnarch("Corrupt ASCII pathname", (OFFSET) namelen); ! 526: X return (-1); ! 527: X } ! 528: X if (name[namelen - 1] != '\0') { ! 529: X warnarch("Bad ASCII pathname", (OFFSET) namelen); ! 530: X return (-1); ! 531: X } ! 532: X return (0); ! 533: X} ! 534: X ! 535: X ! 536: X/* inbinary - read a binary header ! 537: X * ! 538: X * DESCRIPTION ! 539: X * ! 540: X * Reads a CPIO format binary header. ! 541: X * ! 542: X * PARAMETERS ! 543: X * ! 544: X * char *magic - magic number to match ! 545: X * char *name - name of the file which is stored in the header. ! 546: X * (modified and passed back to caller). ! 547: X * Stat *asb - stat block for the file (modified and passed back ! 548: X * to the caller). ! 549: X * ! 550: X * RETURNS ! 551: X * ! 552: X * Returns the number of trailing alignment bytes to skip; -1 if ! 553: X * unsuccessful. ! 554: X */ ! 555: X ! 556: X#ifdef __STDC__ ! 557: X ! 558: Xstatic int inbinary(char *magic, char *name, Stat *asb) ! 559: X ! 560: X#else ! 561: X ! 562: Xstatic int inbinary(magic, name, asb) ! 563: Xchar *magic; ! 564: Xchar *name; ! 565: XStat *asb; ! 566: X ! 567: X#endif ! 568: X{ ! 569: X uint namefull; ! 570: X Binary binary; ! 571: X ! 572: X if (*((ushort *) magic) != M_BINARY) { ! 573: X return (-1); ! 574: X } ! 575: X memcpy((char *) &binary, ! 576: X magic + sizeof(ushort), ! 577: X M_STRLEN - sizeof(ushort)); ! 578: X if (buf_read((char *) &binary + M_STRLEN - sizeof(ushort), ! 579: X sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0) { ! 580: X warnarch("Corrupt binary header", ! 581: X (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort))); ! 582: X return (-1); ! 583: X } ! 584: X asb->sb_dev = binary.b_dev; ! 585: X asb->sb_ino = binary.b_ino; ! 586: X asb->sb_mode = binary.b_mode; ! 587: X asb->sb_uid = binary.b_uid; ! 588: X asb->sb_gid = binary.b_gid; ! 589: X asb->sb_nlink = binary.b_nlink; ! 590: X asb->sb_rdev = binary.b_rdev; ! 591: X asb->sb_mtime = binary.b_mtime[0] | binary.b_mtime[1]; << 16 ! 592: X asb->sb_size = binary.b_size[0] | binary.b_size[1]; << 16 ! 593: X if (binary.b_name == 0 || binary.b_name >= PATH_MAX) { ! 594: X warnarch("Bad binary pathname length", ! 595: X (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort))); ! 596: X return (-1); ! 597: X } ! 598: X if (buf_read(name, namefull = binary.b_name + binary.b_name % 2) < 0) { ! 599: X warnarch("Corrupt binary pathname", (OFFSET) namefull); ! 600: X return (-1); ! 601: X } ! 602: X if (name[binary.b_name - 1] != '\0') { ! 603: X warnarch("Bad binary pathname", (OFFSET) namefull); ! 604: X return (-1); ! 605: X } ! 606: X return (asb->sb_size % 2); ! 607: X} ! 608: END_OF_extract.c ! 609: if test 14327 -ne `wc -c <extract.c`; then ! 610: echo shar: \"extract.c\" unpacked with wrong size! ! 611: fi ! 612: # end of overwriting check ! 613: fi ! 614: if test -f list.c -a "${1}" != "-c" ; then ! 615: echo shar: Will not over-write existing file \"list.c\" ! 616: else ! 617: echo shar: Extracting \"list.c\" \(16229 characters\) ! 618: sed "s/^X//" >list.c <<'END_OF_list.c' ! 619: X/* $Source: /u/mark/src/pax/RCS/list.c,v $ ! 620: X * ! 621: X * $Revision: 1.1 $ ! 622: X * ! 623: X * list.c - List all files on an archive ! 624: X * ! 625: X * DESCRIPTION ! 626: X * ! 627: X * These function are needed to support archive table of contents and ! 628: X * verbose mode during extraction and creation of achives. ! 629: X * ! 630: X * AUTHOR ! 631: X * ! 632: X * Mark H. Colburn, NAPS International ([email protected]) ! 633: X * ! 634: X * Sponsored by The USENIX Association for public distribution. ! 635: X * ! 636: X * Copyright (c) 1989 Mark H. Colburn. ! 637: X * All rights reserved. ! 638: X * ! 639: X * Redistribution and use in source and binary forms are permitted ! 640: X * provided that the above copyright notice is duplicated in all such ! 641: X * forms and that any documentation, advertising materials, and other ! 642: X * materials related to such distribution and use acknowledge that the ! 643: X * software was developed * by Mark H. Colburn and sponsored by The ! 644: X * USENIX Association. ! 645: X * ! 646: X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 647: X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 648: X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 649: X * ! 650: X * $Log: list.c,v $ ! 651: X * Revision 1.1 88/12/23 18:02:14 mark ! 652: X * Initial revision ! 653: X * ! 654: X */ ! 655: X ! 656: X#ifndef lint ! 657: Xstatic char *ident = "$Id: list.c,v 1.1 88/12/23 18:02:14 mark Rel $"; ! 658: Xstatic char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n"; ! 659: X#endif /* ! lint */ ! 660: X ! 661: X ! 662: X/* Headers */ ! 663: X ! 664: X#include "pax.h" ! 665: X ! 666: X ! 667: X/* Defines */ ! 668: X ! 669: X/* ! 670: X * isodigit returns non zero iff argument is an octal digit, zero otherwise ! 671: X */ ! 672: X#define ISODIGIT(c) (((c) >= '0') && ((c) <= '7')) ! 673: X ! 674: X ! 675: X/* Function Prototypes */ ! 676: X ! 677: X#ifdef __STDC__ ! 678: X ! 679: Xstatic void cpio_entry(char *, Stat *); ! 680: Xstatic void tar_entry(char *, Stat *); ! 681: Xstatic void pax_entry(char *, Stat *); ! 682: Xstatic void print_mode(ushort); ! 683: Xstatic long from_oct(int digs, char *where); ! 684: X ! 685: X#else /* !__STDC__ */ ! 686: X ! 687: Xstatic void cpio_entry(); ! 688: Xstatic void tar_entry(); ! 689: Xstatic void pax_entry(); ! 690: Xstatic void print_mode(); ! 691: Xstatic long from_oct(); ! 692: X ! 693: X#endif /* __STDC__ */ ! 694: X ! 695: X ! 696: X/* Internal Identifiers */ ! 697: X ! 698: Xstatic char *monnames[] = { ! 699: X "Jan", "Feb", "Mar", "Apr", "May", "Jun", ! 700: X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ! 701: X}; ! 702: X ! 703: X ! 704: X/* read_header - read a header record ! 705: X * ! 706: X * DESCRIPTION ! 707: X * ! 708: X * Read a record that's supposed to be a header record. Return its ! 709: X * address in "head", and if it is good, the file's size in ! 710: X * asb->sb_size. Decode things from a file header record into a "Stat". ! 711: X * Also set "head_standard" to !=0 or ==0 depending whether header record ! 712: X * is "Unix Standard" tar format or regular old tar format. ! 713: X * ! 714: X * PARAMETERS ! 715: X * ! 716: X * char *name - pointer which will contain name of file ! 717: X * Stat *asb - pointer which will contain stat info ! 718: X * ! 719: X * RETURNS ! 720: X * ! 721: X * Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a ! 722: X * record full of zeros (EOF marker). ! 723: X */ ! 724: X ! 725: X#ifdef __STDC__ ! 726: X ! 727: Xint read_header(char *name, Stat *asb) ! 728: X ! 729: X#else ! 730: X ! 731: Xint read_header(name, asb) ! 732: Xchar *name; ! 733: XStat *asb; ! 734: X ! 735: X#endif ! 736: X{ ! 737: X int i; ! 738: X long sum; ! 739: X long recsum; ! 740: X Link *link; ! 741: X char *p; ! 742: X char hdrbuf[BLOCKSIZE]; ! 743: X ! 744: X memset((char *)asb, 0, sizeof(Stat)); ! 745: X /* read the header from the buffer */ ! 746: X if (buf_read(hdrbuf, BLOCKSIZE) != 0) { ! 747: X return (EOF); ! 748: X } ! 749: X ! 750: X strcpy(name, hdrbuf); ! 751: X ! 752: X recsum = from_oct(8, &hdrbuf[148]); ! 753: X sum = 0; ! 754: X p = hdrbuf; ! 755: X for (i = 0 ; i < 500; i++) { ! 756: X ! 757: X /* ! 758: X * We can't use unsigned char here because of old compilers, e.g. V7. ! 759: X */ ! 760: X sum += 0xFF & *p++; ! 761: X } ! 762: X ! 763: X /* Adjust checksum to count the "chksum" field as blanks. */ ! 764: X for (i = 0; i < 8; i++) { ! 765: X sum -= 0xFF & hdrbuf[148 + i]; ! 766: X } ! 767: X sum += ' ' * 8; ! 768: X ! 769: X if (sum == 8 * ' ') { ! 770: X ! 771: X /* ! 772: X * This is a zeroed record...whole record is 0's except for the 8 ! 773: X * blanks we faked for the checksum field. ! 774: X */ ! 775: X return (2); ! 776: X } ! 777: X if (sum == recsum) { ! 778: X /* ! 779: X * Good record. Decode file size and return. ! 780: X */ ! 781: X if (hdrbuf[156] != LNKTYPE) { ! 782: X asb->sb_size = from_oct(1 + 12, &hdrbuf[124]); ! 783: X } ! 784: X asb->sb_mtime = from_oct(1 + 12, &hdrbuf[136]); ! 785: X asb->sb_mode = from_oct(8, &hdrbuf[100]); ! 786: X ! 787: X if (strcmp(&hdrbuf[257], TMAGIC) == 0) { ! 788: X /* Unix Standard tar archive */ ! 789: X head_standard = 1; ! 790: X#ifdef NONAMES ! 791: X asb->sb_uid = from_oct(8, &hdrbuf[108]); ! 792: X asb->sb_gid = from_oct(8, &hdrbuf[116]); ! 793: X#else ! 794: X asb->sb_uid = finduid(&hdrbuf[265]); ! 795: X asb->sb_gid = findgid(&hdrbuf[297]); ! 796: X#endif ! 797: X switch (hdrbuf[156]) { ! 798: X case BLKTYPE: ! 799: X case CHRTYPE: ! 800: X asb->sb_rdev = makedev(from_oct(8, &hdrbuf[329]), ! 801: X from_oct(8, &hdrbuf[337])); ! 802: X break; ! 803: X default: ! 804: X /* do nothing... */ ! 805: X break; ! 806: X } ! 807: X } else { ! 808: X /* Old fashioned tar archive */ ! 809: X head_standard = 0; ! 810: X asb->sb_uid = from_oct(8, &hdrbuf[108]); ! 811: X asb->sb_gid = from_oct(8, &hdrbuf[116]); ! 812: X } ! 813: X ! 814: X switch (hdrbuf[156]) { ! 815: X case REGTYPE: ! 816: X case AREGTYPE: ! 817: X /* ! 818: X * Berkeley tar stores directories as regular files with a ! 819: X * trailing / ! 820: X */ ! 821: X if (name[strlen(name) - 1] == '/') { ! 822: X name[strlen(name) - 1] = '\0'; ! 823: X asb->sb_mode |= S_IFDIR; ! 824: X } else { ! 825: X asb->sb_mode |= S_IFREG; ! 826: X } ! 827: X break; ! 828: X case LNKTYPE: ! 829: X asb->sb_nlink = 2; ! 830: X linkto(&hdrbuf[157], asb); ! 831: X linkto(name, asb); ! 832: X asb->sb_mode |= S_IFREG; ! 833: X break; ! 834: X case BLKTYPE: ! 835: X asb->sb_mode |= S_IFBLK; ! 836: X break; ! 837: X case CHRTYPE: ! 838: X asb->sb_mode |= S_IFCHR; ! 839: X break; ! 840: X case DIRTYPE: ! 841: X asb->sb_mode |= S_IFDIR; ! 842: X break; ! 843: X#ifdef S_IFLNK ! 844: X case SYMTYPE: ! 845: X asb->sb_mode |= S_IFLNK; ! 846: X strcpy(asb->sb_link, &hdrbuf[157]); ! 847: X break; ! 848: X#endif ! 849: X#ifdef S_IFIFO ! 850: X case FIFOTYPE: ! 851: X asb->sb_mode |= S_IFIFO; ! 852: X break; ! 853: X#endif ! 854: X#ifdef S_IFCTG ! 855: X case CONTTYPE: ! 856: X asb->sb_mode |= S_IFCTG; ! 857: X break; ! 858: X#endif ! 859: X } ! 860: X return (1); ! 861: X } ! 862: X return (0); ! 863: X} ! 864: X ! 865: X ! 866: X/* print_entry - print a single table-of-contents entry ! 867: X * ! 868: X * DESCRIPTION ! 869: X * ! 870: X * Print_entry prints a single line of file information. The format ! 871: X * of the line is the same as that used by the LS command. For some ! 872: X * archive formats, various fields may not make any sense, such as ! 873: X * the link count on tar archives. No error checking is done for bad ! 874: X * or invalid data. ! 875: X * ! 876: X * PARAMETERS ! 877: X * ! 878: X * char *name - pointer to name to print an entry for ! 879: X * Stat *asb - pointer to the stat structure for the file ! 880: X */ ! 881: X ! 882: X#ifdef __STDC__ ! 883: X ! 884: Xvoid print_entry(char *name, Stat *asb) ! 885: X ! 886: X#else ! 887: X ! 888: Xvoid print_entry(name, asb) ! 889: Xchar *name; ! 890: XStat *asb; ! 891: X ! 892: X#endif ! 893: X{ ! 894: X switch (ar_interface) { ! 895: X case TAR: ! 896: X tar_entry(name, asb); ! 897: X break; ! 898: X case CPIO: ! 899: X cpio_entry(name, asb); ! 900: X break; ! 901: X case PAX: pax_entry(name, asb); ! 902: X break; ! 903: X } ! 904: X} ! 905: X ! 906: X ! 907: X/* cpio_entry - print a verbose cpio-style entry ! 908: X * ! 909: X * DESCRIPTION ! 910: X * ! 911: X * Print_entry prints a single line of file information. The format ! 912: X * of the line is the same as that used by the traditional cpio ! 913: X * command. No error checking is done for bad or invalid data. ! 914: X * ! 915: X * PARAMETERS ! 916: X * ! 917: X * char *name - pointer to name to print an entry for ! 918: X * Stat *asb - pointer to the stat structure for the file ! 919: X */ ! 920: X ! 921: X#ifdef __STDC__ ! 922: X ! 923: Xstatic void cpio_entry(char *name, Stat *asb) ! 924: X ! 925: X#else ! 926: X ! 927: Xstatic void cpio_entry(name, asb) ! 928: Xchar *name; ! 929: XStat *asb; ! 930: X ! 931: X#endif ! 932: X{ ! 933: X struct tm *atm; ! 934: X Link *from; ! 935: X struct passwd *pwp; ! 936: X struct group *grp; ! 937: X ! 938: X if (f_list && f_verbose) { ! 939: X fprintf(msgfile, "%-7o", asb->sb_mode); ! 940: X atm = localtime(&asb->sb_mtime); ! 941: X if (pwp = getpwuid((int) USH(asb->sb_uid))) { ! 942: X fprintf(msgfile, "%-6s", pwp->pw_name); ! 943: X } else { ! 944: X fprintf(msgfile, "%-6u", USH(asb->sb_uid)); ! 945: X } ! 946: X fprintf(msgfile,"%7ld %3s %2d %02d:%02d:%02d %4d ", ! 947: X asb->sb_size, monnames[atm->tm_mon], ! 948: X atm->tm_mday, atm->tm_hour, atm->tm_min, ! 949: X atm->tm_sec, atm->tm_year + 1900); ! 950: X } ! 951: X fprintf(msgfile, "%s", name); ! 952: X if ((asb->sb_nlink > 1) && (from = islink(name, asb))) { ! 953: X fprintf(msgfile, " linked to %s", from->l_name); ! 954: X } ! 955: X#ifdef S_IFLNK ! 956: X if ((asb->sb_mode & S_IFMT) == S_IFLNK) { ! 957: X fprintf(msgfile, " symbolic link to %s", asb->sb_link); ! 958: X } ! 959: X#endif /* S_IFLNK */ ! 960: X putc('\n', msgfile); ! 961: X} ! 962: X ! 963: X ! 964: X/* tar_entry - print a tar verbose mode entry ! 965: X * ! 966: X * DESCRIPTION ! 967: X * ! 968: X * Print_entry prints a single line of tar file information. The format ! 969: X * of the line is the same as that produced by the traditional tar ! 970: X * command. No error checking is done for bad or invalid data. ! 971: X * ! 972: X * PARAMETERS ! 973: X * ! 974: X * char *name - pointer to name to print an entry for ! 975: X * Stat *asb - pointer to the stat structure for the file ! 976: X */ ! 977: X ! 978: X#ifdef __STDC__ ! 979: X ! 980: Xstatic void tar_entry(char *name, Stat *asb) ! 981: X ! 982: X#else ! 983: X ! 984: Xstatic void tar_entry(name, asb) ! 985: Xchar *name; ! 986: XStat *asb; ! 987: X ! 988: X#endif ! 989: X{ ! 990: X struct tm *atm; ! 991: X int i; ! 992: X int mode; ! 993: X char *symnam = "NULL"; ! 994: X Link *link; ! 995: X ! 996: X if ((mode = asb->sb_mode & S_IFMT) == S_IFDIR) { ! 997: X return; /* don't print directories */ ! 998: X } ! 999: X if (f_extract) { ! 1000: X switch (mode) { ! 1001: X#ifdef S_IFLNK ! 1002: X case S_IFLNK: /* This file is a symbolic link */ ! 1003: X i = readlink(name, symnam, PATH_MAX - 1); ! 1004: X if (i < 0) { /* Could not find symbolic link */ ! 1005: X warn("can't read symbolic link", syserr()); ! 1006: X } else { /* Found symbolic link filename */ ! 1007: X symnam[i] = '\0'; ! 1008: X fprintf(msgfile, "x %s symbolic link to %s\n", name, symnam); ! 1009: X } ! 1010: X break; ! 1011: X#endif ! 1012: X case S_IFREG: /* It is a link or a file */ ! 1013: X if ((asb->sb_nlink > 1) && (link = islink(name, asb))) { ! 1014: X fprintf(msgfile, "%s linked to %s\n", name, link->l_name); ! 1015: X } else { ! 1016: X fprintf(msgfile, "x %s, %d bytes, %d tape blocks\n", ! 1017: X name, asb->sb_size, ROUNDUP(asb->sb_size, ! 1018: X BLOCKSIZE) / BLOCKSIZE); ! 1019: X } ! 1020: X } ! 1021: X } else if (f_append || f_create) { ! 1022: X switch (mode) { ! 1023: X#ifdef S_IFLNK ! 1024: X case S_IFLNK: /* This file is a symbolic link */ ! 1025: X i = readlink(name, symnam, PATH_MAX - 1); ! 1026: X if (i < 0) { /* Could not find symbolic link */ ! 1027: X warn("can't read symbolic link", syserr()); ! 1028: X } else { /* Found symbolic link filename */ ! 1029: X symnam[i] = '\0'; ! 1030: X fprintf(msgfile, "a %s symbolic link to %s\n", name, symnam); ! 1031: X } ! 1032: X break; ! 1033: X#endif ! 1034: X case S_IFREG: /* It is a link or a file */ ! 1035: X fprintf(msgfile, "a %s ", name); ! 1036: X if ((asb->sb_nlink > 1) && (link = islink(name, asb))) { ! 1037: X fprintf(msgfile, "link to %s\n", link->l_name); ! 1038: X } else { ! 1039: X fprintf(msgfile, "%d Blocks\n", ! 1040: X ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE); ! 1041: X } ! 1042: X break; ! 1043: X } ! 1044: X } else if (f_list) { ! 1045: X if (f_verbose) { ! 1046: X atm = localtime(&asb->sb_mtime); ! 1047: X print_mode(asb->sb_mode); ! 1048: X fprintf(msgfile," %d/%d %6d %3s %2d %02d:%02d %4d %s", ! 1049: X asb->sb_uid, asb->sb_gid, asb->sb_size, ! 1050: X monnames[atm->tm_mon], atm->tm_mday, atm->tm_hour, ! 1051: X atm->tm_min, atm->tm_year + 1900, name); ! 1052: X } else { ! 1053: X fprintf(msgfile, "%s", name); ! 1054: X } ! 1055: X switch (mode) { ! 1056: X#ifdef S_IFLNK ! 1057: X case S_IFLNK: /* This file is a symbolic link */ ! 1058: X i = readlink(name, symnam, PATH_MAX - 1); ! 1059: X if (i < 0) { /* Could not find symbolic link */ ! 1060: X warn("can't read symbolic link", syserr()); ! 1061: X } else { /* Found symbolic link filename */ ! 1062: X symnam[i] = '\0'; ! 1063: X fprintf(msgfile, " symbolic link to %s", name, symnam); ! 1064: X } ! 1065: X break; ! 1066: X#endif ! 1067: X case S_IFREG: /* It is a link or a file */ ! 1068: X if ((asb->sb_nlink > 1) && (link = islink(name, asb))) { ! 1069: X fprintf(msgfile, " linked to %s", link->l_name); ! 1070: X } ! 1071: X break; /* Do not print out directories */ ! 1072: X } ! 1073: X fputc('\n', msgfile); ! 1074: X } else { ! 1075: X fprintf(msgfile, "? %s %d blocks\n", name, ! 1076: X ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE); ! 1077: X } ! 1078: X} ! 1079: X ! 1080: X ! 1081: X/* pax_entry - print a verbose cpio-style entry ! 1082: X * ! 1083: X * DESCRIPTION ! 1084: X * ! 1085: X * Print_entry prints a single line of file information. The format ! 1086: X * of the line is the same as that used by the LS command. ! 1087: X * No error checking is done for bad or invalid data. ! 1088: X * ! 1089: X * PARAMETERS ! 1090: X * ! 1091: X * char *name - pointer to name to print an entry for ! 1092: X * Stat *asb - pointer to the stat structure for the file ! 1093: X */ ! 1094: X ! 1095: X#ifdef __STDC__ ! 1096: X ! 1097: Xstatic void pax_entry(char *name, Stat *asb) ! 1098: X ! 1099: X#else ! 1100: X ! 1101: Xstatic void pax_entry(name, asb) ! 1102: Xchar *name; ! 1103: XStat *asb; ! 1104: X ! 1105: X#endif ! 1106: X{ ! 1107: X struct tm *atm; ! 1108: X Link *from; ! 1109: X struct passwd *pwp; ! 1110: X struct group *grp; ! 1111: X ! 1112: X if (f_list && f_verbose) { ! 1113: X print_mode(asb->sb_mode); ! 1114: X fprintf(msgfile, " %2d", asb->sb_nlink); ! 1115: X atm = localtime(&asb->sb_mtime); ! 1116: X if (pwp = getpwuid((int) USH(asb->sb_uid))) { ! 1117: X fprintf(msgfile, " %-8s", pwp->pw_name); ! 1118: X } else { ! 1119: X fprintf(msgfile, " %-8u", USH(asb->sb_uid)); ! 1120: X } ! 1121: X if (grp = getgrgid((int) USH(asb->sb_gid))) { ! 1122: X fprintf(msgfile, " %-8s", grp->gr_name); ! 1123: X } else { ! 1124: X fprintf(msgfile, " %-8u", USH(asb->sb_gid)); ! 1125: X } ! 1126: X switch (asb->sb_mode & S_IFMT) { ! 1127: X case S_IFBLK: ! 1128: X case S_IFCHR: ! 1129: X fprintf(msgfile, "\t%3d, %3d", ! 1130: X major(asb->sb_rdev), minor(asb->sb_rdev)); ! 1131: X break; ! 1132: X case S_IFREG: ! 1133: X fprintf(msgfile, "\t%8ld", asb->sb_size); ! 1134: X break; ! 1135: X default: ! 1136: X fprintf(msgfile, "\t "); ! 1137: X } ! 1138: X fprintf(msgfile," %3s %2d %02d:%02d ", ! 1139: X monnames[atm->tm_mon], atm->tm_mday, ! 1140: X atm->tm_hour, atm->tm_min); ! 1141: X } ! 1142: X fprintf(msgfile, "%s", name); ! 1143: X if ((asb->sb_nlink > 1) && (from = islink(name, asb))) { ! 1144: X fprintf(msgfile, " == %s", from->l_name); ! 1145: X } ! 1146: X#ifdef S_IFLNK ! 1147: X if ((asb->sb_mode & S_IFMT) == S_IFLNK) { ! 1148: X fprintf(msgfile, " -> %s", asb->sb_link); ! 1149: X } ! 1150: X#endif /* S_IFLNK */ ! 1151: X putc('\n', msgfile); ! 1152: X} ! 1153: X ! 1154: X ! 1155: X ! 1156: X ! 1157: X/* print_mode - fancy file mode display ! 1158: X * ! 1159: X * DESCRIPTION ! 1160: X * ! 1161: X * Print_mode displays a numeric file mode in the standard unix ! 1162: X * representation, ala ls (-rwxrwxrwx). No error checking is done ! 1163: X * for bad mode combinations. FIFOS, sybmbolic links, sticky bits, ! 1164: X * block- and character-special devices are supported if supported ! 1165: X * by the hosting implementation. ! 1166: X * ! 1167: X * PARAMETERS ! 1168: X * ! 1169: X * ushort mode - The integer representation of the mode to print. ! 1170: X */ ! 1171: X ! 1172: X#ifdef __STDC__ ! 1173: X ! 1174: Xstatic void print_mode(ushort mode) ! 1175: X ! 1176: X#else ! 1177: X ! 1178: Xstatic void print_mode(mode) ! 1179: Xushort mode; ! 1180: X ! 1181: X#endif ! 1182: X{ ! 1183: X /* Tar does not print the leading identifier... */ ! 1184: X if (ar_interface != TAR) { ! 1185: X switch (mode & S_IFMT) { ! 1186: X case S_IFDIR: ! 1187: X putc('d', msgfile); ! 1188: X break; ! 1189: X#ifdef S_IFLNK ! 1190: X case S_IFLNK: ! 1191: X putc('l', msgfile); ! 1192: X break; ! 1193: X#endif /* S_IFLNK */ ! 1194: X case S_IFBLK: ! 1195: X putc('b', msgfile); ! 1196: X break; ! 1197: X case S_IFCHR: ! 1198: X putc('c', msgfile); ! 1199: X break; ! 1200: X#ifdef S_IFIFO ! 1201: X case S_IFIFO: ! 1202: X putc('p', msgfile); ! 1203: X break; ! 1204: X#endif /* S_IFIFO */ ! 1205: X case S_IFREG: ! 1206: X default: ! 1207: X putc('-', msgfile); ! 1208: X break; ! 1209: X } ! 1210: X } ! 1211: X putc(mode & 0400 ? 'r' : '-', msgfile); ! 1212: X putc(mode & 0200 ? 'w' : '-', msgfile); ! 1213: X putc(mode & 0100 ! 1214: X ? mode & 04000 ? 's' : 'x' ! 1215: X : mode & 04000 ? 'S' : '-', msgfile); ! 1216: X putc(mode & 0040 ? 'r' : '-', msgfile); ! 1217: X putc(mode & 0020 ? 'w' : '-', msgfile); ! 1218: X putc(mode & 0010 ! 1219: X ? mode & 02000 ? 's' : 'x' ! 1220: X : mode & 02000 ? 'S' : '-', msgfile); ! 1221: X putc(mode & 0004 ? 'r' : '-', msgfile); ! 1222: X putc(mode & 0002 ? 'w' : '-', msgfile); ! 1223: X putc(mode & 0001 ! 1224: X ? mode & 01000 ? 't' : 'x' ! 1225: X : mode & 01000 ? 'T' : '-', msgfile); ! 1226: X} ! 1227: X ! 1228: X ! 1229: X/* from_oct - quick and dirty octal conversion ! 1230: X * ! 1231: X * DESCRIPTION ! 1232: X * ! 1233: X * From_oct will convert an ASCII representation of an octal number ! 1234: X * to the numeric representation. The number of characters to convert ! 1235: X * is given by the parameter "digs". If there are less numbers than ! 1236: X * specified by "digs", then the routine returns -1. ! 1237: X * ! 1238: X * PARAMETERS ! 1239: X * ! 1240: X * int digs - Number to of digits to convert ! 1241: X * char *where - Character representation of octal number ! 1242: X * ! 1243: X * RETURNS ! 1244: X * ! 1245: X * The value of the octal number represented by the first digs ! 1246: X * characters of the string where. Result is -1 if the field ! 1247: X * is invalid (all blank, or nonoctal). ! 1248: X * ! 1249: X * ERRORS ! 1250: X * ! 1251: X * If the field is all blank, then the value returned is -1. ! 1252: X * ! 1253: X */ ! 1254: X ! 1255: X#ifdef __STDC__ ! 1256: X ! 1257: Xstatic long from_oct(int digs, char *where) ! 1258: X ! 1259: X#else ! 1260: X ! 1261: Xstatic long from_oct(digs, where) ! 1262: Xint digs; /* number of characters to convert */ ! 1263: Xchar *where; /* character representation of octal number */ ! 1264: X ! 1265: X#endif ! 1266: X{ ! 1267: X long value; ! 1268: X ! 1269: X while (isspace(*where)) { /* Skip spaces */ ! 1270: X where++; ! 1271: X if (--digs <= 0) { ! 1272: X return(-1); /* All blank field */ ! 1273: X } ! 1274: X } ! 1275: X value = 0; ! 1276: X while (digs > 0 && ISODIGIT(*where)) { /* Scan til nonoctal */ ! 1277: X value = (value | (*where++ - '0'); << 3) ! 1278: X --digs; ! 1279: X } ! 1280: X ! 1281: X if (digs > 0 && *where && !isspace(*where)) { ! 1282: X return(-1); /* Ended on non-space/nul */ ! 1283: X } ! 1284: X return(value); ! 1285: X} ! 1286: END_OF_list.c ! 1287: if test 16229 -ne `wc -c <list.c`; then ! 1288: echo shar: \"list.c\" unpacked with wrong size! ! 1289: fi ! 1290: # end of overwriting check ! 1291: fi ! 1292: if test -f pax.1 -a "${1}" != "-c" ; then ! 1293: echo shar: Will not over-write existing file \"pax.1\" ! 1294: else ! 1295: echo shar: Extracting \"pax.1\" \(13279 characters\) ! 1296: sed "s/^X//" >pax.1 <<'END_OF_pax.1' ! 1297: X.\" $Id: pax.1,v 1.1 88/12/23 18:02:22 mark Rel $ ! 1298: X.TH PAX 1 "USENIX Association" "" ! 1299: X.SH NAME ! 1300: Xpax \- portable archive exchange ! 1301: X.SH SYNOPSIS ! 1302: X.TP \w'\fBpax\fR\ 'u ! 1303: X.B pax ! 1304: X.RB [ \-cimopuvy ] ! 1305: X.RI "[\fB\-f\fR" " archive" ] ! 1306: X.RI "[\fB\-s\fR" " replstr" ] ! 1307: X.RI "[\fB\-t\fR" " device" ] ! 1308: X.RI [ pattern... ] ! 1309: X.TP \w'\fBpax\ \-r\fR\ 'u ! 1310: X.B "pax\ \-r" ! 1311: X.RB [ \-cimnopuvy ] ! 1312: X.RI "[\fB\-f\fR" " archive" ] ! 1313: X.RI "[\fB\-s\fR" " replstr" ] ! 1314: X.RI "[\fB\-t\fR" " device" ] ! 1315: X.RI [ pattern... ] ! 1316: X.TP \w'\fBpax\ \-w\fR\ 'u ! 1317: X.B "pax\ \-w" ! 1318: X.RB [ \-adimuvy ] ! 1319: X.RI "[\fB\-b\fR" " blocking" ] ! 1320: X.RI "[\fB\-f\fR" " archive" ] ! 1321: X.RI "[\fB\-s\fR" " replstr" ] ! 1322: X.RI "[\fB\-t\fR" " device" ] ! 1323: X.RI "[\fB\-x\fR" " format" ] ! 1324: X.RI [ pathname... ] ! 1325: X.TP \w'\fBpax\ \-rw\fR\ 'u ! 1326: X.B "pax\ \-rw" ! 1327: X.RB [ \-ilmopuvy ] ! 1328: X.RI "[\fB\-s\fR" " replstr" ] ! 1329: X.RI [ pathname... ] ! 1330: Xdirectory ! 1331: X.SH DESCRIPTION ! 1332: X.I Pax ! 1333: Xreads and writes archive files which conform to the ! 1334: X.B "Archive/Interchange File Format" ! 1335: Xspecified in ! 1336: X.IR "IEEE Std. 1003.1-1988" . ! 1337: X.I Pax ! 1338: Xcan also read, but not write, a number of other file formats ! 1339: Xin addition to those specified in the ! 1340: X.B "Archive/Interchange File Format" ! 1341: Xdescription. ! 1342: XSupport for these traditional file formats, such as V7 ! 1343: X.I "tar" ! 1344: Xand System V binary ! 1345: X.I "cpio" ! 1346: Xformat archives, ! 1347: Xis provided for backward compatibility and to maximize portability. ! 1348: X.PP ! 1349: X.I Pax ! 1350: Xwill also support traditional ! 1351: X.I cpio ! 1352: Xand ! 1353: XSystem V ! 1354: X.I tar ! 1355: Xinterfaces if invoked with the name ! 1356: X"cpio" or "tar" respectively. ! 1357: XSee the ! 1358: X.I cpio(1) ! 1359: Xor ! 1360: X.I tar(1) ! 1361: Xmanual pages for more details. ! 1362: X.PP ! 1363: XCombinations of the ! 1364: X.B \-r ! 1365: Xand ! 1366: X.B \-w ! 1367: Xcommand line arguments specify whether ! 1368: X.I pax ! 1369: Xwill read, write or list the contents of the specified archive, ! 1370: Xor move the specified files to another directory. ! 1371: X.PP ! 1372: XThe command line arguments are: ! 1373: X.TP .5i ! 1374: X.B \-w ! 1375: Xwrites the files and directories specified by ! 1376: X.I pathname ! 1377: Xoperands to the standard output together with the pathname and status ! 1378: Xinformation prescribed by the archive format used. ! 1379: XA directory ! 1380: X.I pathname ! 1381: Xoperand refers to the files and (recursively) subdirectories of that ! 1382: Xdirectory. ! 1383: XIf no ! 1384: X.I pathname ! 1385: Xoperands are given, then the standard input is read to get a ! 1386: Xlist of pathnames to copy, one pathname per line. ! 1387: XIn this case, only those pathnames appearing on the standard input are ! 1388: Xcopied. ! 1389: X.TP .5i ! 1390: X.B \-r ! 1391: X.I Pax ! 1392: Xreads an archive file from the standard input. ! 1393: XOnly files with names that match any of the ! 1394: X.I pattern ! 1395: Xoperands are selected for extraction. ! 1396: XThe selected files are conditionally created and copied relative to the ! 1397: Xcurrent directory tree, subject to the options described below. ! 1398: XBy default, the owner and group of selected files will be that of the ! 1399: Xinvoking process, and the permissions and modification times will be the ! 1400: Xsames as those in the archive. ! 1401: X.RS .5i ! 1402: X.PP ! 1403: XThe supported archive formats are automatically detected on input. ! 1404: XThe default output format is ! 1405: X.IR ustar , ! 1406: Xbut may be overridden by the ! 1407: X.B \-x ! 1408: X.I format ! 1409: Xoption described below. ! 1410: X.RE ! 1411: X.TP .5i ! 1412: X.B \-rw ! 1413: X.I Pax ! 1414: Xreads the files and directories named in the ! 1415: X.I pathname ! 1416: Xoperands and copies them to the destination ! 1417: X.IR directory . ! 1418: XA directory ! 1419: X.I pathname ! 1420: Xoperand refers to the files and (recursively) subdirectories of that ! 1421: Xdirectory. ! 1422: XIf no ! 1423: X.I pathname ! 1424: Xoperands are given, the standard input is read to get a list of pathnames ! 1425: Xto copy, one pathname per line. ! 1426: XIn this case, only those pathnames appearing on the standard input are ! 1427: Xcopied. ! 1428: XThe directory named by the ! 1429: X.I directory ! 1430: Xoperand must exist and have the proper permissions before the copy can ! 1431: Xoccur. ! 1432: X.PP ! 1433: XIf neither the ! 1434: X.BR \-r " or " \-w ! 1435: Xoptions are given, then ! 1436: X.I pax ! 1437: Xwill list the contents of the specified archive. ! 1438: XIn this mode, ! 1439: X.I pax ! 1440: Xlists normal files one per line, hard link pathnames as ! 1441: X.sp ! 1442: X.RS 1i ! 1443: X.IR pathname " == " linkname ! 1444: X.RE ! 1445: X.sp ! 1446: Xand symbolic link pathnames (if supported by the implementation) as ! 1447: X.sp ! 1448: X.RS 1i ! 1449: X.IR pathname " -> " linkname ! 1450: X.RE ! 1451: X.sp ! 1452: Xwhere ! 1453: X.I pathname ! 1454: Xis the name of the file being extracted, and ! 1455: X.I linkname ! 1456: Xis the name of a file which appeared earlier in the archive. ! 1457: X.PP ! 1458: XIf the ! 1459: X.B \-v ! 1460: Xoption is specified, then ! 1461: X.I pax ! 1462: Xlist normal pathnames in the same format used by the ! 1463: X.I ls ! 1464: Xutility with the ! 1465: X.B \-l ! 1466: Xoption. ! 1467: XHard links are shown as ! 1468: X.sp ! 1469: X.RS 1i ! 1470: X.IR "<ls -l listing>" " == " linkname ! 1471: X.RE ! 1472: X.sp ! 1473: Xand symbolic links (if supported) are shown as ! 1474: X.sp ! 1475: X.RS 1i ! 1476: X.IR "<ls -l listing>" " -> " linkname ! 1477: X.RE ! 1478: X.sp ! 1479: X.PP ! 1480: X.I Pax ! 1481: Xis capable of reading and writing archives which span multiple physical ! 1482: Xvolumes. ! 1483: XUpon detecting an end of medium on an archive which is not yet completed, ! 1484: X.I pax ! 1485: Xwill prompt the user for the next volume of the archive and will allow the ! 1486: Xuser to specify the location of the next volume. ! 1487: X.SS Options ! 1488: XThe following options are available: ! 1489: X.TP 1i ! 1490: X.B \-a ! 1491: XThe files specified by ! 1492: X.I pathname ! 1493: Xare appended to the specified archive. ! 1494: X.TP 1i ! 1495: X.BI \-b " blocking" ! 1496: XBlock the output at ! 1497: X.I blocking ! 1498: Xbytes per write to the archive file. ! 1499: XA ! 1500: X.B k ! 1501: Xsuffix multiplies ! 1502: X.I blocking ! 1503: Xby 1024, a ! 1504: X.B b ! 1505: Xsuffix multiplies ! 1506: X.I blocking ! 1507: Xby 512 and a ! 1508: X.B m ! 1509: Xsuffix multiplies ! 1510: X.I blocking ! 1511: Xby 1048576 (1 megabyte). ! 1512: XIf not specified, ! 1513: X.I blocking ! 1514: Xis automatically determined on input and is ignored for ! 1515: X.B \-rw. ! 1516: X.TP 1i ! 1517: X.B \-c ! 1518: XComplement the match sense of the the ! 1519: X.I pattern ! 1520: Xoperands. ! 1521: X.TP 1i ! 1522: X.B \-d ! 1523: XIntermediate directories not explicitly listed in the archive are not ! 1524: Xcreated. ! 1525: XThis option is ignored unless ! 1526: Xthe ! 1527: X.B \-r ! 1528: Xoption is specified. ! 1529: X.TP 1i ! 1530: X.BI \-f " archive" ! 1531: XThe ! 1532: X.I archive ! 1533: Xoption specifies the pathname of the input or output archive, ! 1534: Xoverriding the default of standard input for ! 1535: X.B \-r ! 1536: Xor standard output for ! 1537: X.BR \-w . ! 1538: X.TP 1i ! 1539: X.B \-i ! 1540: XInteractively rename files. ! 1541: XSubstitutions specified by ! 1542: X.B \-s ! 1543: Xoptions (described below) ! 1544: Xare performed before requesting the new file name from the user. ! 1545: XA file is skipped if an empty line is entered and ! 1546: X.I pax ! 1547: Xexits with an exit status of 0 if ! 1548: X.B EOF ! 1549: Xis encountered. ! 1550: X.TP 1i ! 1551: X.B \-l ! 1552: XFiles are linked rather than copied when possible. ! 1553: X.TP 1i ! 1554: X.B \-m ! 1555: XFile modification times are not retained. ! 1556: X.TP 1i ! 1557: X.B \-n ! 1558: XWhen ! 1559: X.B \-r ! 1560: Xis specified, but ! 1561: X.B \-w ! 1562: Xis not, the ! 1563: X.I pattern ! 1564: Xarguments are treated as ordinary file names. ! 1565: XOnly the first occurrence of each of these files in the input archive ! 1566: Xis read. ! 1567: XThe ! 1568: X.B pax ! 1569: Xutility exits with a zero exit status after all files in the list have been ! 1570: Xread. ! 1571: XIf one or more files in the list is not found, ! 1572: X.B pax ! 1573: Xwrites a diagnostic to standard error for each of the files and exits with ! 1574: Xa non-zero exit status. ! 1575: Xthe file names are compared before any of the ! 1576: X.BR \-i , ! 1577: X.BR \-s , ! 1578: Xor ! 1579: X.B \-y ! 1580: Xoptions are applied. ! 1581: X.TP 1i ! 1582: X.B \-o ! 1583: XRestore file ownership as specified in the archive. ! 1584: XThe invoking process must have appropriate privileges to accomplish this. ! 1585: X.TP 1i ! 1586: X.B \-p ! 1587: XPreserve the access time of the input files after they have been copied. ! 1588: X.TP 1i ! 1589: X.BI \-s " replstr" ! 1590: XFile names are modified according to the substitution expression using the ! 1591: Xsyntax of ! 1592: X.I "ed(1)" ! 1593: Xas shown: ! 1594: X.sp ! 1595: X.RS 2i ! 1596: X-s /\fIold\fR/\fInew\fR/\fB[\fRgp\fB]\fR ! 1597: X.RE ! 1598: X.RS 1i ! 1599: X.PP ! 1600: XAny non null character may be used as a delimiter (a / is used here as an ! 1601: Xexample). ! 1602: XMultiple ! 1603: X.B \-s ! 1604: Xexpressions may be specified; the expressions are applied in the order ! 1605: Xspecified terminating with the first successful substitution. ! 1606: XThe optional trailing ! 1607: X.B p ! 1608: Xcauses successful mappings to be listed on standard error. ! 1609: XThe optional trailing ! 1610: X.B g ! 1611: Xcauses the ! 1612: X.I old ! 1613: Xexpression to be replaced each time it occurs in the source string. ! 1614: XFiles that substitute to an empty string are ignored both on input and ! 1615: Xoutput. ! 1616: X.RE ! 1617: X.TP 1i ! 1618: X.BI \-t " device" ! 1619: XThe ! 1620: X.I device ! 1621: Xoption argument is an implementation-defined identifier that names the input ! 1622: Xor output archive device, overriding the default of standard input for ! 1623: X.B \-r ! 1624: Xand standard output for ! 1625: X.BR \-w . ! 1626: X.TP 1i ! 1627: X.B \-u ! 1628: XCopy each file only if it is newer than a pre-existing file with the same ! 1629: Xname. ! 1630: XThis implies ! 1631: X.BR \-a . ! 1632: X.TP 1i ! 1633: X.B \-v ! 1634: XList file names as they are encountered. ! 1635: XProduces a verbose table of contents listing on the standard output when both ! 1636: X.B \-r ! 1637: Xand ! 1638: X.B \-w ! 1639: Xare omitted, ! 1640: Xotherwise the file names are printed to standard error as they are ! 1641: Xencountered in the archive. ! 1642: X.TP 1i ! 1643: X.BI \-x " format" ! 1644: XSpecifies the output archive ! 1645: X.IR format . ! 1646: XThe input format, which must be one of the following, is automatically ! 1647: Xdetermined when the ! 1648: X.B \-r ! 1649: Xoption is used. ! 1650: XThe supported formats are: ! 1651: X.TP 1i ! 1652: X.I cpio ! 1653: XThe extended ! 1654: X.I CPIO ! 1655: Xinterchange format specified in ! 1656: X.B "Extended CPIO Format" in ! 1657: X.I "IEEE Std. 1003.1-1988." ! 1658: X.TP 1i ! 1659: X.I ustar ! 1660: XThe extended ! 1661: X.I TAR ! 1662: Xinterchange format specified in ! 1663: X.B "Extended TAR Format" in ! 1664: X.I "IEEE Std. 1003.1-1988." ! 1665: XThis is the default archive format. ! 1666: X.RE ! 1667: X.TP 1i ! 1668: X.B \-y ! 1669: XInteractively prompt for the disposition of each file. ! 1670: XSubstitutions specified by ! 1671: X.B \-s ! 1672: Xoptions (described above) ! 1673: Xare performed before prompting the user for disposition. ! 1674: X.B EOF ! 1675: Xor an input line starting with the character ! 1676: X.B q ! 1677: Xcaused ! 1678: X.I pax ! 1679: Xto exit. ! 1680: XOtherwise, an input line starting with anything other than ! 1681: X.B y ! 1682: Xcauses the file to be ignored. ! 1683: XThis option cannot be used in conjunction with the ! 1684: X.B \-i ! 1685: Xoption. ! 1686: X.PP ! 1687: XOnly the last of multiple ! 1688: X.B \-f ! 1689: Xor ! 1690: X.B \-t ! 1691: Xoptions take effect. ! 1692: X.PP ! 1693: XWhen writing to an archive, the ! 1694: Xstandard input is used as a list of pathnames if no ! 1695: X.I pathname ! 1696: Xoperands are specified. ! 1697: XThe format is one pathname per line. ! 1698: XOtherwise, the standard input is the archive file, ! 1699: Xwhich is formatted according to one of the specifications in ! 1700: X.B "Archive/Interchange File format" ! 1701: Xin ! 1702: X.IR "IEEE Std. 1003.1-1988" , ! 1703: Xor some other implementation-defined format. ! 1704: X.PP ! 1705: XThe user ID and group ID of the process, together with the appropriate ! 1706: Xprivileges, affect the ability of ! 1707: X.I pax ! 1708: Xto restore ownership and permissions attributes of the archived files. ! 1709: X(See ! 1710: X.I "format-reading utility" ! 1711: Xin ! 1712: X.B "Archive/Interchange File Format" ! 1713: Xin ! 1714: X.IR "IEEE Std. 1003.1-1988" ".)" ! 1715: X.PP ! 1716: XThe options ! 1717: X.BR \-a , ! 1718: X.BR \-c , ! 1719: X.BR \-d , ! 1720: X.BR \-i , ! 1721: X.BR \-l , ! 1722: X.BR \-p , ! 1723: X.BR \-t , ! 1724: X.BR \-u , ! 1725: Xand ! 1726: X.BR \-y ! 1727: Xare provided for functional compatibility with the historical ! 1728: X.I cpio ! 1729: Xand ! 1730: X.I tar ! 1731: Xutilities. ! 1732: XThe option defaults were chosen based on the most common usage of these ! 1733: Xoptions, therefore, some of the options have meanings different than ! 1734: Xthose of the historical commands. ! 1735: X.SS Operands ! 1736: XThe following operands are available: ! 1737: X.TP 1i ! 1738: X.I directory ! 1739: XThe destination directory pathname for copies when both the ! 1740: X.B \-r ! 1741: Xand ! 1742: X.B \-w ! 1743: Xoptions are specified. ! 1744: XThe directory must exist and be writable before the copy or and error ! 1745: Xresults. ! 1746: X.TP 1i ! 1747: X.I pathname ! 1748: XA file whose contents are used instead of the files named on the standard ! 1749: Xinput. ! 1750: XWhen a directory is named, all of its files and (recursively) ! 1751: Xsubdirectories ! 1752: Xare copied as well. ! 1753: X.TP 1i ! 1754: X.IR pattern ! 1755: XA ! 1756: X.I pattern ! 1757: Xis given in the standard shell pattern matching notation. ! 1758: XThe default if no ! 1759: X.I pattern ! 1760: Xis specified is ! 1761: X.BR * \, ! 1762: Xwhich selects all files. ! 1763: X.SH EXAMPLES ! 1764: XThe following command ! 1765: X.sp ! 1766: X.RS 1i ! 1767: Xpax \-w \-f /dev/rmt0 \. ! 1768: X.RE ! 1769: X.sp ! 1770: Xcopies the contents of the current directory to tape drive 0. ! 1771: X.PP ! 1772: XThe commands ! 1773: X.sp ! 1774: X.RS 1i ! 1775: X.RI mkdir " newdir" ! 1776: X.br ! 1777: X.RI cd " olddir" ! 1778: X.br ! 1779: X.RI "pax -rw . " newdir ! 1780: X.RE ! 1781: X.sp ! 1782: Xcopies the contents of ! 1783: X.I olddir ! 1784: Xto ! 1785: X.I newdir . ! 1786: X.PP ! 1787: XThe command ! 1788: X.sp ! 1789: X.RS 1i ! 1790: Xpax \-r \-s ',//*usr//*,,' -f pax.out ! 1791: X.RE ! 1792: X.sp ! 1793: Xreads the archive ! 1794: X.B pax.out ! 1795: Xwith all files rooted in "/usr" in the archive extracted ! 1796: Xrelative to the current directory. ! 1797: X.SH FILES ! 1798: X.TP 1i ! 1799: X/dev/tty ! 1800: Xused to prompt the user for information when the ! 1801: X.BR \-i " or " \-y ! 1802: Xoptions are specified. ! 1803: X.SH "SEE ALSO" ! 1804: Xcpio(1), find(1), tar(1), cpio(5), tar(5) ! 1805: X.SH DIAGNOSTICS ! 1806: X.I Pax ! 1807: Xwill terminate immediately, without processing any ! 1808: Xadditional files on the command line or in the archive. ! 1809: X.SH "EXIT CODES" ! 1810: X.I Pax ! 1811: Xwill exit with one of the following values: ! 1812: X.IP 0 .5i ! 1813: XAll files in the archive were processed successfully. ! 1814: X.IP ">0" .5i ! 1815: X.I Pax ! 1816: Xaborted due to errors encountered during operation. ! 1817: X.SH BUGS ! 1818: XSpecial permissions may be required to copy or extract special files. ! 1819: X.PP ! 1820: XDevice, user ID, and group ID numbers larger than 65535 cause additional ! 1821: Xheader records to be output. ! 1822: XThese records are ignored by some historical version of ! 1823: X.I "cpio(1)" ! 1824: Xand ! 1825: X.IR "tar(1)" . ! 1826: X.PP ! 1827: XThe archive formats described in ! 1828: X.B "Archive/Interchange File Format" ! 1829: Xhave certain restrictions that have ! 1830: Xbeen carried over from historical usage. ! 1831: XFor example, there are restrictions on the length of pathnames stored in ! 1832: Xthe archive. ! 1833: X.PP ! 1834: XWhen getting an "ls -l" style listing on ! 1835: X.I tar ! 1836: Xformat archives, link counts are listed as zero since the ! 1837: X.I ustar ! 1838: Xarchive format does not keep link count information. ! 1839: X.SH COPYRIGHT ! 1840: XCopyright (c) 1989 Mark H. Colburn. ! 1841: X.br ! 1842: XAll rights reserved. ! 1843: X.PP ! 1844: XRedistribution and use in source and binary forms are permitted ! 1845: Xprovided that the above copyright notice is duplicated in all such ! 1846: Xforms and that any documentation, advertising materials, and other ! 1847: Xmaterials related to such distribution and use acknowledge that the ! 1848: Xsoftware was developed by Mark H. Colburn and sponsored by The ! 1849: XUSENIX Association. ! 1850: X.PP ! 1851: XTHE SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 1852: XIMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 1853: XWARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 1854: X.SH AUTHOR ! 1855: XMark H. Colburn ! 1856: X.br ! 1857: XNAPS International ! 1858: X.br ! 1859: X117 Mackubin Street, Suite 1 ! 1860: X.br ! 1861: XSt. Paul, MN 55102 ! 1862: X.br ! 1863: [email protected] ! 1864: X.sp 2 ! 1865: XSponsored by ! 1866: X.B "The USENIX Association" ! 1867: Xfor public distribution. ! 1868: END_OF_pax.1 ! 1869: if test 13279 -ne `wc -c <pax.1`; then ! 1870: echo shar: \"pax.1\" unpacked with wrong size! ! 1871: fi ! 1872: # end of overwriting check ! 1873: fi ! 1874: echo shar: End of archive 4 \(of 6\). ! 1875: cp /dev/null ark4isdone ! 1876: MISSING="" ! 1877: for I in 1 2 3 4 5 6 ; do ! 1878: if test ! -f ark${I}isdone ; then ! 1879: MISSING="${MISSING} ${I}" ! 1880: fi ! 1881: done ! 1882: if test "${MISSING}" = "" ; then ! 1883: echo You have unpacked all 6 archives. ! 1884: rm -f ark[1-9]isdone ! 1885: else ! 1886: echo You still need to unpack the following archives: ! 1887: echo " " ${MISSING} ! 1888: fi ! 1889: ## End of shell archive. ! 1890: exit 0 ! 1891:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.