1: /*
   2:  * afio.c
   3:  *
   4:  * Manipulate archives and files.
   5:  *
   6:  * Copyright (c) 1985 Lachman Associates, Inc..
   7:  *
   8:  * This software was written by Mark Brukhartz at Lachman Associates,
   9:  * Inc.. It may be distributed within the following restrictions:
  10:  *	(1) It may not be sold at a profit.
  11:  *	(2) This credit and notice must remain intact.
  12:  * This software may be distributed with other software by a commercial
  13:  * vendor, provided that it is included at no additional charge.
  14:  *
  15:  * Please report bugs to "..!ihnp4!laidbak!mdb".
  16:  *
  17:  * Options:
  18:  *  o Define INDEX to use index() in place of strchr() (v7, BSD).
  19:  *  o Define MEMCPY when an efficient memcpy() exists (SysV).
  20:  *  o Define MKDIR when a mkdir() system call is present (4.2BSD, SysVr3).
  21:  *  o Define NOVOID if your compiler doesn't like void casts.
  22:  *  o Define SYSTIME to use <sys/time.h> rather than <time.h> (4.2BSD).
  23:  *  o Define VOIDFIX to allow pointers to functions returning void (non-PCC).
  24:  *  o Define CTC3B2 to support AT&T 3B2 streaming cartridge tape.
  25:  */
  26: 
  27: static char *ident = "$Header: afio.c,v 1.68.1 96/3/21 13:07:11 mdb Exp $";
  28: 
  29: #include <stdio.h>
  30: #include <errno.h>
  31: #include <sys/signal.h>
  32: #include <sys/types.h>
  33: #include <sys/ioctl.h>
  34: #include <sys/stat.h>
  35: #include <pwd.h>
  36: #include <grp.h>
  37: #include <string.h>
  38: 
  39: #ifndef major
  40: #	include <sys/sysmacros.h>
  41: #endif	/* major */
  42: 
  43: #ifdef  SYSTIME
  44: #	include <sys/time.h>
  45: #else   /* SYSTIME */
  46: #	include <time.h>
  47: #endif	/* SYSTIME */
  48: 
  49: #ifdef  CTC3B2
  50: #	include <sys/vtoc.h>
  51: #	include <sys/ct.h>
  52: #endif	/* CTC3B2 */
  53: 
  54: /*
  55:  * Address link information base.
  56:  */
  57: #define linkhash(ino)   \
  58:     (linkbase + (ino) % nel(linkbase))
  59: 
  60: /*
  61:  * Mininum value.
  62:  */
  63: #define min(one, two)   \
  64:     (one < two ? one : two)
  65: 
  66: /*
  67:  * Number of array elements.
  68:  */
  69: #define nel(a)      \
  70:     (sizeof(a) / sizeof(*(a)))
  71: 
  72: /*
  73:  * Remove a file or directory.
  74:  */
  75: #define remove(name, asb) \
  76:     (((asb)->sb_mode & S_IFMT) == S_IFDIR ? rmdir(name) : unlink(name))
  77: 
  78: /*
  79:  * Swap bytes.
  80:  */
  81: #define swab(n)     \
  82:     ((((ushort)(n) >> 8) & 0xff) | (((ushort)(n) << 8) & 0xff00))
  83: 
  84: /*
  85:  * Cast and reduce to unsigned short.
  86:  */
  87: #define ush(n)      \
  88:     (((ushort) (n)) & 0177777)
  89: 
  90: /*
  91:  * Definitions.
  92:  */
  93: #define reg register    /* Convenience */
  94: #define uint    unsigned int    /* Not always in types.h */
  95: #define ushort  unsigned short  /* Not always in types.h */
  96: #define BLOCK   5120        /* Default archive block size */
  97: #define FSBUF   (8*1024)    /* Filesystem buffer size */
  98: #define H_COUNT 10      /* Number of items in ASCII header */
  99: #define H_PRINT "%06o%06o%06o%06o%06o%06o%06o%011lo%06o%011lo"
 100: #define H_SCAN  "%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6o%11lo"
 101: #define H_STRLEN 70     /* ASCII header string length */
 102: #define M_ASCII "070707"    /* ASCII magic number */
 103: #define M_BINARY 070707     /* Binary magic number */
 104: #define M_STRLEN 6      /* ASCII magic number length */
 105: #define NULLDEV -1      /* Null device code */
 106: #define NULLINO 0       /* Null inode number */
 107: #define PATHELEM 256        /* Pathname element count limit */
 108: #define PATHSIZE 1024       /* Pathname length limit */
 109: #define S_IFSHF 12      /* File type shift (shb in stat.h) */
 110: #define S_IPERM 07777       /* File permission bits (shb in stat.h) */
 111: #define S_IPEXE 07000       /* Special execution bits (shb in stat.h) */
 112: #define S_IPOPN 0777        /* Open access bits (shb in stat.h) */
 113: #define STDIN   0       /* Standard input file descriptor */
 114: #define STDOUT  1       /* Standard output file descriptor */
 115: #define TTY "/dev/tty"  /* For volume-change queries */
 116: 
 117: /*
 118:  * Some versions of the portable "C" compiler (PCC) can't handle
 119:  * pointers to functions returning void.
 120:  */
 121: #ifdef  VOIDFIX
 122: #	define    VOIDFN  void    /* Expect "void (*fnptr)()" to work */
 123: #else   /* VOIDFIX */
 124: #	define    VOIDFN  int /* Avoid PCC "void (*fnptr)()" bug */
 125: #endif	/* VOIDFIX */
 126: 
 127: /*
 128:  * Trailer pathnames. All must be of the same length.
 129:  */
 130: #define TRAILER "TRAILER!!!"    /* Archive trailer (cpio compatible) */
 131: #define TRAILZ  11      /* Trailer pathname length (including null) */
 132: 
 133: /*
 134:  * Open modes; there is no <fcntl.h> with v7 UNIX.
 135:  */
 136: #define O_RDONLY 0      /* Read-only */
 137: #define O_WRONLY 1      /* Write-only */
 138: #define O_RDWR  2       /* Read/write */
 139: 
 140: /*
 141:  * V7 and BSD UNIX use old-fashioned names for a couple of
 142:  * string functions.
 143:  */
 144: #ifdef  INDEX
 145: #	define    strchr  index   /* Forward character search */
 146: #	define    strrchr rindex  /* Reverse character search */
 147: #endif	/* INDEX */
 148: 
 149: /*
 150:  * Some compilers can't handle void casts.
 151:  */
 152: #ifdef  NOVOID
 153: #	define    VOID        /* Omit void casts */
 154: #else   /* NOVOID */
 155: #	define    VOID    (void)  /* Quiet lint about ignored return values */
 156: #endif	/* NOVOID */
 157: 
 158: /*
 159:  * Adb is more palatable when static functions and variables are
 160:  * declared as globals. Lint gives more useful information when
 161:  * statics are truly static.
 162:  */
 163: #ifdef  lint
 164: #	define    STATIC  static  /* Declare static variables for lint */
 165: #else   /* lint */
 166: #	define    STATIC      /* Make static variables global for adb */
 167: #endif	/* lint */
 168: 
 169: /*
 170:  * Simple types.
 171:  */
 172: typedef struct group    Group;  /* Structure for getgrgid(3) */
 173: typedef struct passwd   Passwd; /* Structure for getpwuid(3) */
 174: typedef struct tm   Time;   /* Structure for localtime(3) */
 175: 
 176: #ifdef  S_IFLNK
 177:     /*
 178: 	 * File status with symbolic links. Kludged to hold symbolic
 179: 	 * link pathname within structure.
 180: 	 */
 181:     typedef struct {
 182:         struct stat sb_stat;
 183:         char        sb_link[PATHSIZE];
 184:     } Stat;
 185: #	define    STAT(name, asb)     stat(name, &(asb)->sb_stat)
 186: #	define    FSTAT(fd, asb)      fstat(fd, &(asb)->sb_stat)
 187: #	define    LSTAT(name, asb)    lstat(name, &(asb)->sb_stat)
 188: #	define    sb_dev      sb_stat.st_dev
 189: #	define    sb_ino      sb_stat.st_ino
 190: #	define    sb_mode     sb_stat.st_mode
 191: #	define    sb_nlink    sb_stat.st_nlink
 192: #	define    sb_uid      sb_stat.st_uid
 193: #	define    sb_gid      sb_stat.st_gid
 194: #	define    sb_rdev     sb_stat.st_rdev
 195: #	define    sb_size     sb_stat.st_size
 196: #	define    sb_atime    sb_stat.st_atime
 197: #	define    sb_mtime    sb_stat.st_mtime
 198: #	define    sb_ctime    sb_stat.st_ctime
 199: #	define    sb_blksize  sb_stat.st_blksize
 200: #	define    sb_blocks   sb_stat.st_blocks
 201: #else   /* S_IFLNK */
 202:     /*
 203: 	 * File status without symbolic links.
 204: 	 */
 205:     typedef struct stat Stat;
 206: #	define    STAT(name, asb)     stat(name, asb)
 207: #	define    FSTAT(fd, asb)      fstat(fd, asb)
 208: #	define    LSTAT(name, asb)    stat(name, asb)
 209: #	define    sb_dev      st_dev
 210: #	define    sb_ino      st_ino
 211: #	define    sb_mode     st_mode
 212: #	define    sb_nlink    st_nlink
 213: #	define    sb_uid      st_uid
 214: #	define    sb_gid      st_gid
 215: #	define    sb_rdev     st_rdev
 216: #	define    sb_size     st_size
 217: #	define    sb_atime    st_atime
 218: #	define    sb_mtime    st_mtime
 219: #	define    sb_ctime    st_ctime
 220: #endif	/* S_IFLNK */
 221: 
 222: /*
 223:  * Binary archive header (obsolete).
 224:  */
 225: typedef struct {
 226:     short   b_dev;          /* Device code */
 227:     ushort  b_ino;          /* Inode number */
 228:     ushort  b_mode;         /* Type and permissions */
 229:     ushort  b_uid;          /* Owner */
 230:     ushort  b_gid;          /* Group */
 231:     short   b_nlink;        /* Number of links */
 232:     short   b_rdev;         /* Real device */
 233:     ushort  b_mtime[2];     /* Modification time (hi/lo) */
 234:     ushort  b_name;         /* Length of pathname (with null) */
 235:     ushort  b_size[2];      /* Length of data */
 236: } Binary;
 237: 
 238: /*
 239:  * Child process structure.
 240:  */
 241: typedef struct child {
 242:     struct child    *c_forw;    /* Forward link */
 243:     int     c_pid;      /* Process ID */
 244:     int     c_flags;    /* Flags (CF_) */
 245:     int     c_status;   /* Exit status */
 246: } Child;
 247: 
 248: /*
 249:  * Child process flags (c_flags).
 250:  */
 251: #define CF_EXIT (1<<0)          /* Exited */
 252: 
 253: /*
 254:  * Hard link sources. One or more are chained from each link
 255:  * structure.
 256:  */
 257: typedef struct name {
 258:     struct name *p_forw;    /* Forward chain (terminated) */
 259:     struct name *p_back;    /* Backward chain (circular) */
 260:     char        *p_name;    /* Pathname to link from */
 261: } Path;
 262: 
 263: /*
 264:  * File linking information. One entry exists for each unique
 265:  * file with with outstanding hard links.
 266:  */
 267: typedef struct link {
 268:     struct link *l_forw;    /* Forward chain (terminated) */
 269:     struct link *l_back;    /* Backward chain (terminated) */
 270:     dev_t       l_dev;      /* Device */
 271:     ino_t       l_ino;      /* Inode */
 272:     ushort      l_nlink;    /* Unresolved link count */
 273:     off_t       l_size;     /* Length */
 274:     Path        *l_path;    /* Pathname(s) to link from */
 275: } Link;
 276: 
 277: /*
 278:  * Pathnames to (or to not) be processed.
 279:  */
 280: typedef struct pattern {
 281:     struct pattern  *p_forw;    /* Forward chain */
 282:     char        *p_str;     /* String */
 283:     int     p_len;      /* Length of string */
 284:     int     p_not;      /* Reverse logic */
 285: } Pattern;
 286: 
 287: /*
 288:  * External functions.
 289:  */
 290: void    _exit();
 291: void    exit();
 292: void    free();
 293: char    *getenv();
 294: ushort  getgid();
 295: Group   *getgrgid();
 296: Passwd  *getpwuid();
 297: ushort  getuid();
 298: Time    *localtime();
 299: off_t   lseek();
 300: char    *malloc();
 301: VOIDFN  (*signal())();
 302: uint    sleep();
 303: char    *strcat();
 304: char    *strchr();
 305: char    *strcpy();
 306: char    *strncpy();
 307: char    *strrchr();
 308: time_t  time();
 309: ushort  umask();
 310: 
 311: /*
 312:  * Internal functions.
 313:  */
 314: VOIDFN  copyin();
 315: VOIDFN  copyout();
 316: int dirchg();
 317: int dirmake();
 318: int dirneed();
 319: void    fatal();
 320: VOIDFN  in();
 321: void    inalloc();
 322: int inascii();
 323: int inavail();
 324: int inbinary();
 325: int indata();
 326: int inentry();
 327: int infill();
 328: int inhead();
 329: int inread();
 330: int inskip();
 331: int inswab();
 332: int lineget();
 333: void    linkalso();
 334: Link    *linkfrom();
 335: void    linkleft();
 336: Link    *linkto();
 337: char    *memget();
 338: char    *memstr();
 339: int mkdir();
 340: void    nameadd();
 341: int namecmp();
 342: int nameopt();
 343: void    next();
 344: void    nextask();
 345: void    nextclos();
 346: int nextopen();
 347: int openi();
 348: int openo();
 349: int openq();
 350: int options();
 351: off_t   optsize();
 352: VOIDFN  out();
 353: void    outalloc();
 354: uint    outavail();
 355: int outdata();
 356: void    outeof();
 357: void    outflush();
 358: void    outhead();
 359: void    outpad();
 360: void    outwait();
 361: void    outwrite();
 362: VOIDFN  pass();
 363: void    passdata();
 364: int passitem();
 365: int pipechld();
 366: int pipeopen();
 367: void    pipewait();
 368: void    prsize();
 369: int rmdir();
 370: int swrite();
 371: char    *syserr();
 372: VOIDFN  toc();
 373: void    tocentry();
 374: void    tocmode();
 375: void    usage();
 376: int warn();
 377: int warnarch();
 378: int xfork();
 379: void    xpause();
 380: int xwait();
 381: 
 382: /*
 383:  * External variables.
 384:  */
 385: extern int  errno;      /* System error code */
 386: 
 387: /*
 388:  * Static variables.
 389:  */
 390: #ifdef  CTC3B2
 391: STATIC short    Cflag;      /* Enable 3B2 CTC streaming (kludge) */
 392: #endif	/* CTC3B2 */
 393: STATIC short    dflag;      /* Don't create missing directories */
 394: STATIC short    fflag;      /* Fork before writing to archive */
 395: STATIC short    gflag;      /* Change to input file directories */
 396: STATIC short    hflag;      /* Follow symbolic links */
 397: STATIC short    jflag;      /* Don't generate sparse filesystem blocks */
 398: STATIC short    kflag;      /* Skip initial junk to find a header */
 399: STATIC short    lflag;      /* Link rather than copying (when possible) */
 400: STATIC short    mflag;      /* Ignore archived timestamps */
 401: STATIC short    nflag;      /* Keep newer existing files */
 402: STATIC short    uflag;      /* Report files with unseen links */
 403: STATIC short    vflag;      /* Verbose */
 404: STATIC short    xflag;      /* Retain file ownership */
 405: STATIC short    zflag;      /* Print final statistics */
 406: STATIC uint arbsize = BLOCK;/* Archive block size */
 407: STATIC short    areof;      /* End of input volume reached */
 408: STATIC int  arfd;       /* Archive file descriptor */
 409: STATIC off_t    arleft;     /* Space remaining within current volume */
 410: STATIC char *arname;    /* Expanded archive name */
 411: STATIC uint arpad;      /* Final archive block padding boundary */
 412: STATIC char arspec[PATHSIZE];/* Specified archive name */
 413: STATIC off_t    aruntil;    /* Volume size limit */
 414: STATIC uint arvolume;   /* Volume number */
 415: STATIC uint buflen;     /* Archive buffer length */
 416: STATIC char *buffer;    /* Archive buffer */
 417: STATIC char *bufidx;    /* Archive buffer index */
 418: STATIC char *bufend;    /* End of data within archive buffer */
 419: STATIC Child    *children;  /* Child processes */
 420: STATIC ushort   gid;        /* Group ID */
 421: STATIC Link *linkbase[256]; /* Unresolved link information */
 422: STATIC ushort   mask;       /* File creation mask */
 423: STATIC char *myname;    /* Arg0 */
 424: STATIC char *optarg;    /* Option argument */
 425: STATIC int  optind;     /* Command line index */
 426: STATIC int  outpid;     /* Process ID of outstanding outflush() */
 427: STATIC Pattern  *pattern;   /* Pathname matching patterns */
 428: STATIC char pwd[PATHSIZE];  /* Working directory (with "-g") */
 429: STATIC int  pipepid;    /* Pipeline process ID */
 430: STATIC time_t   timenow;    /* Current time */
 431: STATIC time_t   timewait;   /* Time spent awaiting new media */
 432: STATIC off_t    total;      /* Total number of bytes transferred */
 433: STATIC int  ttyf;       /* For interactive queries (yuk) */
 434: STATIC ushort   uid;        /* User ID */
 435: 
 436: main(ac, av)
 437: int     ac;
 438: reg char    **av;
 439: {
 440:     reg int     c;
 441:     reg uint    group = 1;
 442:     reg VOIDFN  (*fn)() = NULL;
 443:     reg time_t  timedone;
 444:     auto char   remote[PATHSIZE];
 445: 
 446:     if (myname = strrchr(*av, '/'))
 447:         ++myname;
 448:     else
 449:         myname = *av;
 450:     mask = umask(0);
 451:     ttyf = openq();
 452:     uid = getuid();
 453:     gid = getgid();
 454:     if (uid == 0)
 455:         ++xflag;
 456:     VOID signal(SIGPIPE, SIG_IGN);
 457:     while (c = options(ac, av, "ioptIOVCb:c:de:fghjklmns:uvxXy:Y:z")) {
 458:         switch (c) {
 459:         case 'i':
 460:             if (fn)
 461:                 usage();
 462:             fn = in;
 463:             break;
 464:         case 'o':
 465:             if (fn)
 466:                 usage();
 467:             fn = out;
 468:             break;
 469:         case 'p':
 470:             if (fn)
 471:                 usage();
 472:             fn = pass;
 473:             break;
 474:         case 't':
 475:             if (fn)
 476:                 usage();
 477:             fn = toc;
 478:             break;
 479:         case 'I':
 480:             if (fn)
 481:                 usage();
 482:             fn = copyin;
 483:             break;
 484:         case 'O':
 485:             if (fn)
 486:                 usage();
 487:             fn = copyout;
 488:             break;
 489:         case 'V':
 490:             VOID printf("%s\n", ident);
 491:             exit(0);
 492: #ifdef  CTC3B2
 493:         case 'C':
 494:             ++Cflag;
 495:             arbsize = 31 * 512;
 496:             group = 10;
 497:             aruntil = 1469 * 31 * 512;
 498:             break;
 499: #endif	/* CTC3B2 */
 500:         case 'b':
 501:             if ((arbsize = (uint) optsize(optarg)) == 0)
 502:                 fatal(optarg, "Bad block size");
 503:             break;
 504:         case 'c':
 505:             if ((group = (uint) optsize(optarg)) == 0)
 506:                 fatal(optarg, "Bad buffer count");
 507:             break;
 508:         case 'd':
 509:             ++dflag;
 510:             break;
 511:         case 'e':
 512:             arpad = (uint) optsize(optarg);
 513:             break;
 514:         case 'f':
 515:             ++fflag;
 516:             break;
 517:         case 'g':
 518:             ++gflag;
 519:             break;
 520:         case 'h':
 521:             ++hflag;
 522:             break;
 523:         case 'j':
 524:             ++jflag;
 525:             break;
 526:         case 'k':
 527:             ++kflag;
 528:             break;
 529:         case 'l':
 530:             ++lflag;
 531:             break;
 532:         case 'm':
 533:             ++mflag;
 534:             break;
 535:         case 'n':
 536:             ++nflag;
 537:             break;
 538:         case 's':
 539:             aruntil = optsize(optarg);
 540:             break;
 541:         case 'u':
 542:             ++uflag;
 543:             break;
 544:         case 'v':
 545:             ++vflag;
 546:             break;
 547:         case 'x':
 548:             ++xflag;
 549:             break;
 550:         case 'X':
 551:             xflag = 0;
 552:             break;
 553:         case 'y':
 554:             nameadd(optarg, 0);
 555:             break;
 556:         case 'Y':
 557:             nameadd(optarg, 1);
 558:             break;
 559:         case 'z':
 560:             ++zflag;
 561:             break;
 562:         default:
 563:             usage();
 564:         }
 565:     }
 566:     if (fn == NULL || av[optind] == NULL)
 567:         usage();
 568:     buflen = arbsize * group;
 569:     if (arpad == 0)
 570:         arpad = arbsize;
 571:     if (fn != pass) {
 572:         reg char    *colon;
 573:         reg char    *equal;
 574:         reg int     isoutput = (fn == out || fn == copyout);
 575: 
 576:         arname = strcpy(arspec, av[optind++]);
 577:         if (colon = strchr(arspec, ':')) {
 578:             *colon++ = '\0';
 579:             if (equal = strchr(arspec, '='))
 580:                 *equal++ = '\0';
 581:             VOID sprintf(arname = remote,
 582:                 "!rsh %s %s -%c -b %u -c %u %s",
 583:                 arspec, equal ? equal : myname,
 584:                 isoutput ? 'O' : 'I', arbsize,
 585:                 group, colon);
 586:             if (equal)
 587:                 *--equal = '=';
 588:             *--colon = ':';
 589:         }
 590:         if (gflag && *arname != '/' && *arname != '!')
 591:             fatal(arspec, "Relative pathname");
 592:         if ((buffer = bufidx = bufend = malloc(buflen)) == NULL)
 593:             fatal(arspec, "Cannot allocate I/O buffer");
 594:         if (nextopen(isoutput ? O_WRONLY : O_RDONLY) < 0)
 595:             exit(1);
 596:     }
 597:     timenow = time((time_t *) NULL);
 598:     (*fn)(av + optind);
 599:     timedone = time((time_t *) NULL);
 600:     if (uflag)
 601:         linkleft();
 602:     if (zflag) {
 603:         reg FILE    *stream;
 604: 
 605:         stream = fn == toc || arfd == STDOUT ? stderr : stdout;
 606:         VOID fprintf(stream, "%s: ", myname);
 607:         prsize(stream, total);
 608:         VOID fprintf(stream, " bytes %s in %lu seconds\n",
 609:           fn == pass
 610:             ? "transferred"
 611:             : fn == out || fn == copyout
 612:               ? "written"
 613:               : "read",
 614:           timedone - timenow - timewait);
 615:     }
 616:     nextclos();
 617:     exit(0);
 618:     /* NOTREACHED */
 619: }
 620: 
 621: /*
 622:  * copyin()
 623:  *
 624:  * Copy directly from the archive to the standard output.
 625:  */
 626: STATIC VOIDFN
 627: copyin(av)
 628: reg char    **av;
 629: {
 630:     reg int     got;
 631:     reg uint    have;
 632: 
 633:     if (*av)
 634:         fatal(*av, "Extraneous argument");
 635:     while (!areof) {
 636:         VOID infill();
 637:         while (have = bufend - bufidx)
 638:             if ((got = write(STDOUT, bufidx, have)) < 0)
 639:                 fatal("<stdout>", syserr());
 640:             else if (got > 0)
 641:                 bufidx += got;
 642:             else
 643:                 return;
 644:     }
 645: }
 646: 
 647: /*
 648:  * copyout()
 649:  *
 650:  * Copy directly from the standard input to the archive.
 651:  */
 652: STATIC VOIDFN
 653: copyout(av)
 654: reg char    **av;
 655: {
 656:     reg int     got;
 657:     reg uint    want;
 658: 
 659:     if (*av)
 660:         fatal(*av, "Extraneous argument");
 661:     for (;;) {
 662:         while ((want = bufend - bufidx) == 0)
 663:             outflush();
 664:         if ((got = read(STDIN, bufidx, want)) < 0)
 665:             fatal("<stdin>", syserr());
 666:         else if (got == 0)
 667:             break;
 668:         else
 669:             bufidx += got;
 670:     }
 671:     outflush();
 672:     if (fflag)
 673:         outwait();
 674: }
 675: 
 676: /*
 677:  * dirchg()
 678:  *
 679:  * Change to the directory containing a given file.
 680:  */
 681: STATIC int
 682: dirchg(name, local)
 683: reg char    *name;
 684: reg char    *local;
 685: {
 686:     reg char    *last;
 687:     reg int     len;
 688:     auto char   dir[PATHSIZE];
 689: 
 690:     if (*name != '/')
 691:         return (warn(name, "Relative pathname"));
 692:     for (last = name + strlen(name); last[-1] != '/'; --last)
 693:         ;
 694:     len = last - name;
 695:     strncpy(dir, name, len)[len] = '\0';
 696:     VOID strcpy(local, *last ? last : ".");
 697:     if (strcmp(dir, pwd) == 0)
 698:         return (0);
 699:     if (chdir(dir) < 0)
 700:         return (warn(name, syserr()));
 701:     VOID strcpy(pwd, dir);
 702:     return (0);
 703: }
 704: 
 705: /*
 706:  * dirmake()
 707:  *
 708:  * Make a directory. Returns zero if successful, -1 otherwise.
 709:  */
 710: STATIC int
 711: dirmake(name, asb)
 712: reg char    *name;
 713: reg Stat    *asb;
 714: {
 715:     if (mkdir(name, asb->sb_mode & S_IPOPN) < 0)
 716:         return (-1);
 717:     if (asb->sb_mode & S_IPEXE)
 718:         VOID chmod(name, asb->sb_mode & S_IPERM);
 719:     if (xflag)
 720:         VOID chown(name,
 721:             uid == 0 ? ush(asb->sb_uid) : uid,
 722:             ush(asb->sb_gid));
 723:     return (0);
 724: }
 725: 
 726: /*
 727:  * dirneed()
 728:  *
 729:  * Recursively create missing directories (with the same permissions
 730:  * as their first existing parent). Temporarily modifies the 'name'
 731:  * argument string. Returns zero if successful, -1 otherwise.
 732:  */
 733: STATIC int
 734: dirneed(name)
 735: char        *name;
 736: {
 737:     reg char    *cp;
 738:     reg char    *last;
 739:     reg int     ok;
 740:     static Stat sb;
 741: 
 742:     last = NULL;
 743:     for (cp = name; *cp; )
 744:         if (*cp++ == '/')
 745:             last = cp;
 746:     if (last == NULL)
 747:         return (STAT(".", &sb));
 748:     *--last = '\0';
 749:     ok = STAT(*name ? name : "/", &sb) == 0
 750:         ? ((sb.sb_mode & S_IFMT) == S_IFDIR)
 751:         : (!dflag && dirneed(name) == 0 && dirmake(name, &sb) == 0);
 752:     *last = '/';
 753:     return (ok ? 0 : -1);
 754: }
 755: 
 756: /*
 757:  * fatal()
 758:  *
 759:  * Print fatal message and exit.
 760:  */
 761: STATIC void
 762: fatal(what, why)
 763: char        *what;
 764: char        *why;
 765: {
 766:     VOID fprintf(stderr,
 767:         "%s: \"%s\": %s\n",
 768:         myname, what, why);
 769:     exit(1);
 770: }
 771: 
 772: /*
 773:  * in()
 774:  *
 775:  * Read an archive.
 776:  */
 777: STATIC VOIDFN
 778: in(av)
 779: reg char    **av;
 780: {
 781:     auto Stat   sb;
 782:     auto char   name[PATHSIZE];
 783: 
 784:     if (*av)
 785:         fatal(*av, "Extraneous argument");
 786:     name[0] = '\0';
 787:     while (inhead(name, &sb) == 0) {
 788:         if (namecmp(name) < 0 || inentry(name, &sb) < 0)
 789:             if (inskip(sb.sb_size) < 0)
 790:                 VOID warn(name, "Skipped file data is corrupt");
 791:         if (vflag)
 792:             VOID fprintf(stderr, "%s\n", name);
 793:     }
 794: }
 795: 
 796: /*
 797:  * inalloc()
 798:  *
 799:  * Allocate input buffer space (which was previously indexed
 800:  * by inavail()).
 801:  */
 802: STATIC void
 803: inalloc(len)
 804: reg uint    len;
 805: {
 806:     bufidx += len;
 807:     total += len;
 808: }
 809: 
 810: /*
 811:  * inascii()
 812:  *
 813:  * Read an ASCII header. Returns zero if successful;
 814:  * -1 otherwise. Assumes that the entire magic number
 815:  * has been read.
 816:  */
 817: STATIC int
 818: inascii(magic, name, asb)
 819: reg char    *magic;
 820: reg char    *name;
 821: reg Stat    *asb;
 822: {
 823:     auto uint   namelen;
 824:     auto char   header[H_STRLEN + 1];
 825: 
 826:     if (strncmp(magic, M_ASCII, M_STRLEN) != 0)
 827:         return (-1);
 828:     if (inread(header, H_STRLEN) < 0)
 829:         return (warnarch("Corrupt ASCII header", (off_t) H_STRLEN));
 830:     header[H_STRLEN] = '\0';
 831:     if (sscanf(header, H_SCAN, &asb->sb_dev,
 832:         &asb->sb_ino, &asb->sb_mode, &asb->sb_uid,
 833:         &asb->sb_gid, &asb->sb_nlink, &asb->sb_rdev,
 834:         &asb->sb_mtime, &namelen, &asb->sb_size) != H_COUNT)
 835:         return (warnarch("Bad ASCII header", (off_t) H_STRLEN));
 836:     if (namelen == 0 || namelen >= PATHSIZE)
 837:         return (warnarch("Bad ASCII pathname length", (off_t) H_STRLEN));
 838:     if (inread(name, namelen) < 0)
 839:         return (warnarch("Corrupt ASCII pathname", (off_t) namelen));
 840:     if (name[namelen - 1] != '\0')
 841:         return (warnarch("Bad ASCII pathname", (off_t) namelen));
 842:     return (0);
 843: }
 844: 
 845: /*
 846:  * inavail()
 847:  *
 848:  * Index availible input data within the buffer. Stores a pointer
 849:  * to the data and its length in given locations. Returns zero with
 850:  * valid data, -1 if unreadable portions were replaced with nulls.
 851:  */
 852: STATIC int
 853: inavail(bufp, lenp)
 854: reg char    **bufp;
 855: uint        *lenp;
 856: {
 857:     reg uint    have;
 858:     reg int     corrupt = 0;
 859: 
 860:     while ((have = bufend - bufidx) == 0)
 861:         corrupt |= infill();
 862:     *bufp = bufidx;
 863:     *lenp = have;
 864:     return (corrupt);
 865: }
 866: 
 867: /*
 868:  * inbinary()
 869:  *
 870:  * Read a binary header. Returns the number of trailing alignment
 871:  * bytes to skip; -1 if unsuccessful.
 872:  */
 873: STATIC int
 874: inbinary(magic, name, asb)
 875: reg char    *magic;
 876: reg char    *name;
 877: reg Stat    *asb;
 878: {
 879:     reg uint    namefull;
 880:     auto Binary binary;
 881: 
 882:     if (*((ushort *) magic) != M_BINARY)
 883:         return (-1);
 884:     memcpy((char *) &binary,
 885:         magic + sizeof(ushort),
 886:         M_STRLEN - sizeof(ushort));
 887:     if (inread((char *) &binary + M_STRLEN - sizeof(ushort),
 888:         sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0)
 889:         return (warnarch("Corrupt binary header",
 890:             (off_t) sizeof(binary) - (M_STRLEN - sizeof(ushort))));
 891:     asb->sb_dev = binary.b_dev;
 892:     asb->sb_ino = binary.b_ino;
 893:     asb->sb_mode = binary.b_mode;
 894:     asb->sb_uid = binary.b_uid;
 895:     asb->sb_gid = binary.b_gid;
 896:     asb->sb_nlink = binary.b_nlink;
 897:     asb->sb_rdev = binary.b_rdev;
 898:     asb->sb_mtime = binary.b_mtime[0] << 16 | binary.b_mtime[1];
 899:     asb->sb_size = binary.b_size[0] << 16 | binary.b_size[1];
 900:     if (binary.b_name == 0 || binary.b_name >= PATHSIZE)
 901:         return (warnarch("Bad binary pathname length",
 902:             (off_t) sizeof(binary) - (M_STRLEN - sizeof(ushort))));
 903:     if (inread(name, namefull = binary.b_name + binary.b_name % 2) < 0)
 904:         return (warnarch("Corrupt binary pathname", (off_t) namefull));
 905:     if (name[binary.b_name - 1] != '\0')
 906:         return (warnarch("Bad binary pathname", (off_t) namefull));
 907:     return (asb->sb_size % 2);
 908: }
 909: 
 910: /*
 911:  * indata()
 912:  *
 913:  * Install data from an archive. Returns given file descriptor.
 914:  */
 915: STATIC int
 916: indata(fd, size, name)
 917: int     fd;
 918: reg off_t   size;
 919: char        *name;
 920: {
 921:     reg uint    chunk;
 922:     reg char    *oops;
 923:     reg int     sparse;
 924:     reg int     corrupt;
 925:     auto char   *buf;
 926:     auto uint   avail;
 927: 
 928:     corrupt = sparse = 0;
 929:     oops = NULL;
 930:     while (size) {
 931:         corrupt |= inavail(&buf, &avail);
 932:         size -= (chunk = size < avail ? (uint) size : avail);
 933:         if (oops == NULL && (sparse = swrite(fd, buf, chunk)) < 0)
 934:             oops = syserr();
 935:         inalloc(chunk);
 936:     }
 937:     if (corrupt)
 938:         VOID warn(name, "Corrupt archive data");
 939:     if (oops)
 940:         VOID warn(name, oops);
 941:     else if (sparse > 0
 942:       && (lseek(fd, (off_t) -1, 1) < 0
 943:         || write(fd, "", 1) != 1))
 944:         VOID warn(name, syserr());
 945:     return (fd);
 946: }
 947: 
 948: /*
 949:  * inentry()
 950:  *
 951:  * Install a single archive entry. Returns zero if successful, -1 otherwise.
 952:  */
 953: STATIC int
 954: inentry(name, asb)
 955: char        *name;
 956: reg Stat    *asb;
 957: {
 958:     reg Link    *linkp;
 959:     reg int     ifd;
 960:     reg int     ofd;
 961:     auto time_t tstamp[2];
 962: 
 963:     if ((ofd = openo(name, asb, linkp = linkfrom(asb), 0)) > 0)
 964:         if (asb->sb_size || linkp == NULL || linkp->l_size == 0)
 965:             VOID close(indata(ofd, asb->sb_size, name));
 966:         else if ((ifd = open(linkp->l_path->p_name, O_RDONLY)) < 0)
 967:             VOID warn(linkp->l_path->p_name, syserr());
 968:         else {
 969:             passdata(linkp->l_path->p_name, ifd, name, ofd);
 970:             VOID close(ifd);
 971:             VOID close(ofd);
 972:         }
 973:     else if (ofd < 0)
 974:         return (-1);
 975:     else if (inskip(asb->sb_size) < 0)
 976:         VOID warn(name, "Redundant file data is corrupt");
 977:     tstamp[0] = tstamp[1] = mflag ? timenow : asb->sb_mtime;
 978:     VOID utime(name, tstamp);
 979:     return (0);
 980: }
 981: 
 982: /*
 983:  * infill()
 984:  *
 985:  * Fill the archive buffer. Remembers mid-buffer read failures and
 986:  * reports them the next time through. Replaces unreadable data with
 987:  * null characters. Returns zero with valid data, -1 otherwise.
 988:  */
 989: STATIC int
 990: infill()
 991: {
 992:     reg int     got;
 993:     static int  failed;
 994: 
 995:     bufend = bufidx = buffer;
 996:     if (!failed) {
 997:         if (areof)
 998:             if (total == 0)
 999:                 fatal(arspec, "No input");
1000:             else
1001:                 next(O_RDONLY, "Input EOF");
1002:         if (aruntil && arleft < arbsize)
1003:             next(O_RDONLY, "Input limit reached");
1004:         while (!failed
1005:             && !areof
1006:             && (aruntil == 0 || arleft >= arbsize)
1007:             && buffer + buflen - bufend >= arbsize) {
1008:             if ((got = read(arfd, bufend, arbsize)) > 0) {
1009:                 bufend += got;
1010:                 arleft -= got;
1011:             } else if (got < 0)
1012:                 failed = warnarch(syserr(),
1013:                     (off_t) 0 - (bufend - bufidx));
1014:             else
1015:                 ++areof;
1016:         }
1017:     }
1018:     if (failed && bufend == buffer) {
1019:         failed = 0;
1020:         for (got = 0; got < arbsize; ++got)
1021:             *bufend++ = '\0';
1022:         return (-1);
1023:     }
1024:     return (0);
1025: }
1026: 
1027: /*
1028:  * inhead()
1029:  *
1030:  * Read a header. Quietly translates old-fashioned binary cpio headers
1031:  * (and arranges to skip the possible alignment byte). Returns zero if
1032:  * successful, -1 upon archive trailer.
1033:  */
1034: STATIC int
1035: inhead(name, asb)
1036: reg char    *name;
1037: reg Stat    *asb;
1038: {
1039:     reg off_t   skipped;
1040:     auto char   magic[M_STRLEN];
1041:     static int  align;
1042: 
1043:     if (align > 0)
1044:         VOID inskip((off_t) align);
1045:     align = 0;
1046:     for (;;) {
1047:         VOID inread(magic, M_STRLEN);
1048:         skipped = 0;
1049:         while ((align = inascii(magic, name, asb)) < 0
1050:             && (align = inbinary(magic, name, asb)) < 0
1051:             && (align = inswab(magic, name, asb)) < 0) {
1052:             if (++skipped == 1) {
1053:                 if (!kflag && total - sizeof(magic) == 0)
1054:                     fatal(arspec, "Unrecognizable archive");
1055:                 VOID warnarch("Bad magic number",
1056:                     (off_t) sizeof(magic));
1057:                 if (name[0])
1058:                     VOID warn(name, "May be corrupt");
1059:             }
1060:             memcpy(magic, magic + 1, sizeof(magic) - 1);
1061:             VOID inread(magic + sizeof(magic) - 1, 1);
1062:         }
1063:         if (skipped) {
1064:             VOID warnarch("Apparently resynchronized",
1065:                 (off_t) sizeof(magic));
1066:             VOID warn(name, "Continuing");
1067:         }
1068:         if (strcmp(name, TRAILER) == 0)
1069:             return (-1);
1070:         if (nameopt(name) >= 0)
1071:             break;
1072:         VOID inskip(asb->sb_size + align);
1073:     }
1074: #ifdef  S_IFLNK
1075:     if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
1076:         if (inread(asb->sb_link, (uint) asb->sb_size) < 0) {
1077:             VOID warn(name, "Corrupt symbolic link");
1078:             return (inhead(name, asb));
1079:         }
1080:         asb->sb_link[asb->sb_size] = '\0';
1081:         asb->sb_size = 0;
1082:     }
1083: #endif	/* S_IFLNK */
1084:     if (name[0] == '/')
1085:         if (name[1])
1086:             while (name[0] = name[1])
1087:                 ++name;
1088:         else
1089:             name[0] = '.';
1090:     asb->sb_atime = asb->sb_ctime = asb->sb_mtime;
1091:     return (0);
1092: }
1093: 
1094: /*
1095:  * inread()
1096:  *
1097:  * Read a given number of characters from the input archive. Returns
1098:  * zero with valid data, -1 if unreadable portions were replaced by
1099:  * null characters.
1100:  */
1101: STATIC int
1102: inread(dst, len)
1103: reg char    *dst;
1104: uint        len;
1105: {
1106:     reg uint    have;
1107:     reg uint    want;
1108:     reg int     corrupt = 0;
1109:     char        *endx = dst + len;
1110: 
1111:     while (want = endx - dst) {
1112:         while ((have = bufend - bufidx) == 0)
1113:             corrupt |= infill();
1114:         if (have > want)
1115:             have = want;
1116:         memcpy(dst, bufidx, have);
1117:         bufidx += have;
1118:         dst += have;
1119:         total += have;
1120:     }
1121:     return (corrupt);
1122: }
1123: 
1124: /*
1125:  * inskip()
1126:  *
1127:  * Skip input archive data. Returns zero under normal circumstances,
1128:  * -1 if unreadable data is encountered.
1129:  */
1130: STATIC int
1131: inskip(len)
1132: reg off_t   len;
1133: {
1134:     reg uint    chunk;
1135:     reg int     corrupt = 0;
1136: 
1137:     while (len) {
1138:         while ((chunk = bufend - bufidx) == 0)
1139:             corrupt |= infill();
1140:         if (chunk > len)
1141:             chunk = len;
1142:         bufidx += chunk;
1143:         len -= chunk;
1144:         total += chunk;
1145:     }
1146:     return (corrupt);
1147: }
1148: 
1149: /*
1150:  * inswab()
1151:  *
1152:  * Read a reversed byte order binary header. Returns the number
1153:  * of trailing alignment bytes to skip; -1 if unsuccessful.
1154:  */
1155: STATIC int
1156: inswab(magic, name, asb)
1157: reg char    *magic;
1158: reg char    *name;
1159: reg Stat    *asb;
1160: {
1161:     reg ushort  namesize;
1162:     reg uint    namefull;
1163:     auto Binary binary;
1164: 
1165:     if (*((ushort *) magic) != swab(M_BINARY))
1166:         return (-1);
1167:     memcpy((char *) &binary,
1168:         magic + sizeof(ushort),
1169:         M_STRLEN - sizeof(ushort));
1170:     if (inread((char *) &binary + M_STRLEN - sizeof(ushort),
1171:         sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0)
1172:         return (warnarch("Corrupt swapped header",
1173:             (off_t) sizeof(binary) - (M_STRLEN - sizeof(ushort))));
1174:     asb->sb_dev = (dev_t) swab(binary.b_dev);
1175:     asb->sb_ino = (ino_t) swab(binary.b_ino);
1176:     asb->sb_mode = swab(binary.b_mode);
1177:     asb->sb_uid = swab(binary.b_uid);
1178:     asb->sb_gid = swab(binary.b_gid);
1179:     asb->sb_nlink = swab(binary.b_nlink);
1180:     asb->sb_rdev = (dev_t) swab(binary.b_rdev);
1181:     asb->sb_mtime = swab(binary.b_mtime[0]) << 16 | swab(binary.b_mtime[1]);
1182:     asb->sb_size = swab(binary.b_size[0]) << 16 | swab(binary.b_size[1]);
1183:     if ((namesize = swab(binary.b_name)) == 0 || namesize >= PATHSIZE)
1184:         return (warnarch("Bad swapped pathname length",
1185:             (off_t) sizeof(binary) - (M_STRLEN - sizeof(ushort))));
1186:     if (inread(name, namefull = namesize + namesize % 2) < 0)
1187:         return (warnarch("Corrupt swapped pathname", (off_t) namefull));
1188:     if (name[namesize - 1] != '\0')
1189:         return (warnarch("Bad swapped pathname", (off_t) namefull));
1190:     return (asb->sb_size % 2);
1191: }
1192: 
1193: /*
1194:  * lineget()
1195:  *
1196:  * Get a line from a given stream. Returns 0 if successful, -1 at EOF.
1197:  */
1198: STATIC int
1199: lineget(stream, buf)
1200: reg FILE    *stream;
1201: reg char    *buf;
1202: {
1203:     reg int     c;
1204: 
1205:     for (;;) {
1206:         if ((c = getc(stream)) == EOF)
1207:             return (-1);
1208:         if (c == '\n')
1209:             break;
1210:         *buf++ = c;
1211:     }
1212:     *buf = '\0';
1213:     return (0);
1214: }
1215: 
1216: /*
1217:  * linkalso()
1218:  *
1219:  * Add a destination pathname to an existing chain. Assumes that
1220:  * at least one element is present.
1221:  */
1222: STATIC void
1223: linkalso(linkp, name)
1224: reg Link    *linkp;
1225: char        *name;
1226: {
1227:     reg Path    *path;
1228: 
1229:     if ((path = (Path *) memget(sizeof(Path))) == NULL
1230:         || (path->p_name = memstr(name)) == NULL)
1231:         return;
1232:     path->p_forw = NULL;
1233:     path->p_back = linkp->l_path->p_back;
1234:     path->p_back->p_forw = path;
1235:     linkp->l_path->p_back = path;
1236: }
1237: 
1238: /*
1239:  * linkfrom()
1240:  *
1241:  * Find a file to link from. Returns a pointer to a link
1242:  * structure, or NULL if unsuccessful.
1243:  */
1244: STATIC Link *
1245: linkfrom(asb)
1246: reg Stat    *asb;
1247: {
1248:     reg Link    *linkp;
1249:     reg Link    *linknext;
1250:     reg Path    *path;
1251:     reg Path    *pathnext;
1252:     reg Link    **abase;
1253: 
1254:     for (linkp = *(abase = linkhash(asb->sb_ino)); linkp; linkp = linknext)
1255:         if (linkp->l_nlink == 0) {
1256:             for (path = linkp->l_path; path; path = pathnext) {
1257:                 pathnext = path->p_forw;
1258:                 free(path->p_name);
1259:             }
1260:             free((char *) linkp->l_path);
1261:             if (linknext = linkp->l_forw)
1262:                 linknext->l_back = linkp->l_back;
1263:             if (linkp->l_back)
1264:                 linkp->l_back->l_forw = linkp->l_forw;
1265:             else
1266:                 *abase = linkp->l_forw;
1267:             free((char *) linkp);
1268:         } else if (linkp->l_ino == asb->sb_ino
1269:             && linkp->l_dev == asb->sb_dev) {
1270:             --linkp->l_nlink;
1271:             return (linkp);
1272:         } else
1273:             linknext = linkp->l_forw;
1274:     return (NULL);
1275: }
1276: 
1277: /*
1278:  * linkleft()
1279:  *
1280:  * Complain about files with unseen links.
1281:  */
1282: STATIC void
1283: linkleft()
1284: {
1285:     reg Link    *lp;
1286:     reg Link    **base;
1287: 
1288:     for (base = linkbase; base < linkbase + nel(linkbase); ++base)
1289:         for (lp = *base; lp; lp = lp->l_forw)
1290:             if (lp->l_nlink)
1291:                 VOID warn(lp->l_path->p_name, "Unseen link(s)");
1292: }
1293: 
1294: /*
1295:  * linkto()
1296:  *
1297:  * Remember a file with outstanding links. Returns a
1298:  * pointer to the associated link structure, or NULL
1299:  * when linking is not possible.
1300:  */
1301: STATIC Link *
1302: linkto(name, asb)
1303: char        *name;
1304: reg Stat    *asb;
1305: {
1306:     reg Link    *linkp;
1307:     reg Path    *path;
1308:     reg Link    **abase;
1309: 
1310:     if ((asb->sb_mode & S_IFMT) == S_IFDIR
1311:         || (linkp = (Link *) memget(sizeof(Link))) == NULL
1312:         || (path = (Path *) memget(sizeof(Path))) == NULL
1313:         || (path->p_name = memstr(name)) == NULL)
1314:         return (NULL);
1315:     linkp->l_dev = asb->sb_dev;
1316:     linkp->l_ino = asb->sb_ino;
1317:     linkp->l_nlink = asb->sb_nlink - 1;
1318:     linkp->l_size = asb->sb_size;
1319:     linkp->l_path = path;
1320:     path->p_forw = NULL;
1321:     path->p_back = path;
1322:     if (linkp->l_forw = *(abase = linkhash(asb->sb_ino)))
1323:         linkp->l_forw->l_back = linkp;
1324:     linkp->l_back = NULL;
1325:     return (*abase = linkp);
1326: }
1327: 
1328: #ifndef MEMCPY
1329: 
1330: /*
1331:  * memcpy()
1332:  *
1333:  * A simple block move.
1334:  */
1335: STATIC void
1336: memcpy(to, from, len)
1337: reg char    *to;
1338: reg char    *from;
1339: uint        len;
1340: {
1341:     reg char    *toend;
1342: 
1343:     for (toend = to + len; to < toend; *to++ = *from++)
1344:         ;
1345: }
1346: 
1347: #endif	/* MEMCPY */
1348: 
1349: /*
1350:  * memget()
1351:  *
1352:  * Allocate memory.
1353:  */
1354: STATIC char *
1355: memget(len)
1356: uint        len;
1357: {
1358:     reg char    *mem;
1359:     static short    outofmem;
1360: 
1361:     if ((mem = malloc(len)) == NULL && !outofmem)
1362:         outofmem = warn("memget()", "Out of memory");
1363:     return (mem);
1364: }
1365: 
1366: /*
1367:  * memstr()
1368:  *
1369:  * Duplicate a string into dynamic memory.
1370:  */
1371: STATIC char *
1372: memstr(str)
1373: reg char    *str;
1374: {
1375:     reg char    *mem;
1376: 
1377:     if (mem = memget((uint) strlen(str) + 1))
1378:         VOID strcpy(mem, str);
1379:     return (mem);
1380: }
1381: 
1382: #ifndef MKDIR
1383: 
1384: /*
1385:  * mkdir()
1386:  *
1387:  * Make a directory via "/bin/mkdir". Sets errno to a
1388:  * questionably sane value upon failure.
1389:  */
1390: STATIC int
1391: mkdir(name, mode)
1392: reg char    *name;
1393: reg ushort  mode;
1394: {
1395:     reg int     pid;
1396: 
1397:     if ((pid = xfork("mkdir()")) == 0) {
1398:         VOID close(fileno(stdin));
1399:         VOID close(fileno(stdout));
1400:         VOID close(fileno(stderr));
1401:         VOID open("/dev/null", O_RDWR);
1402:         VOID dup(fileno(stdin));
1403:         VOID dup(fileno(stdin));
1404:         VOID umask(~mode);
1405:         VOID execl("/bin/mkdir", "mkdir", name, (char *) NULL);
1406:         exit(1);
1407:     }
1408:     if (xwait(pid, "mkdir()") == 0)
1409:         return (0);
1410:     errno = EACCES;
1411:     return (-1);
1412: }
1413: 
1414: #endif	/* MKDIR */
1415: 
1416: /*
1417:  * nameadd()
1418:  *
1419:  * Add a name to the pattern list.
1420:  */
1421: STATIC void
1422: nameadd(name, not)
1423: reg char    *name;
1424: int     not;
1425: {
1426:     reg Pattern *px;
1427: 
1428:     px = (Pattern *) memget(sizeof(Pattern));
1429:     px->p_forw = pattern;
1430:     px->p_str = name;
1431:     px->p_len = strlen(name);
1432:     px->p_not = not;
1433:     pattern = px;
1434: }
1435: 
1436: /*
1437:  * namecmp()
1438:  *
1439:  * Compare a pathname with the pattern list. Returns 0 for
1440:  * a match, -1 otherwise.
1441:  */
1442: STATIC int
1443: namecmp(name)
1444: reg char    *name;
1445: {
1446:     reg Pattern *px;
1447:     reg int     positive;
1448:     reg int     match;
1449: 
1450:     positive = match = 0;
1451:     for (px = pattern; px; px = px->p_forw) {
1452:         if (!px->p_not)
1453:             ++positive;
1454:         if (strncmp(name, px->p_str, px->p_len) == 0
1455:           && (name[px->p_len] == '/' || name[px->p_len] == '\0')) {
1456:             if (px->p_not)
1457:                 return (-1);
1458:             ++match;
1459:         }
1460:     }
1461:     return (match || !positive ? 0 : -1);
1462: }
1463: 
1464: /*
1465:  * nameopt()
1466:  *
1467:  * Optimize a pathname. Confused by "<symlink>/.." twistiness.
1468:  * Returns the number of final pathname elements (zero for "/"
1469:  * or ".") or -1 if unsuccessful.
1470:  */
1471: STATIC int
1472: nameopt(begin)
1473: char    *begin;
1474: {
1475:     reg char    *name;
1476:     reg char    *item;
1477:     reg int     idx;
1478:     int     absolute;
1479:     auto char   *element[PATHELEM];
1480: 
1481:     absolute = (*(name = begin) == '/');
1482:     idx = 0;
1483:     for (;;) {
1484:         if (idx == PATHELEM)
1485:             return (warn(begin, "Too many elements"));
1486:         while (*name == '/')
1487:             ++name;
1488:         if (*name == '\0')
1489:             break;
1490:         element[idx] = item = name;
1491:         while (*name && *name != '/')
1492:             ++name;
1493:         if (*name)
1494:             *name++ = '\0';
1495:         if (strcmp(item, "..") == 0)
1496:             if (idx == 0)
1497:                 if (absolute)
1498:                     ;
1499:                 else
1500:                     ++idx;
1501:             else if (strcmp(element[idx - 1], "..") == 0)
1502:                 ++idx;
1503:             else
1504:                 --idx;
1505:         else if (strcmp(item, ".") != 0)
1506:             ++idx;
1507:     }
1508:     if (idx == 0)
1509:         element[idx++] = absolute ? "" : ".";
1510:     element[idx] = NULL;
1511:     name = begin;
1512:     if (absolute)
1513:         *name++ = '/';
1514:     for (idx = 0; item = element[idx]; ++idx, *name++ = '/')
1515:         while (*item)
1516:             *name++ = *item++;
1517:     *--name = '\0';
1518:     return (idx);
1519: }
1520: 
1521: /*
1522:  * next()
1523:  *
1524:  * Advance to the next archive volume.
1525:  */
1526: STATIC void
1527: next(mode, why)
1528: reg int     mode;
1529: reg char    *why;
1530: {
1531:     reg time_t  began;
1532:     auto char   msg[200];
1533:     auto char   answer[20];
1534: 
1535:     began = time((time_t *) NULL);
1536:     nextclos();
1537:     VOID warnarch(why, (off_t) 0);
1538:     if (arfd == STDIN || arfd == STDOUT)
1539:         exit(1);
1540:     VOID sprintf(msg, "\
1541: %s: Ready for volume %u on \"%s\"\n\
1542: %s: Type \"go\" when ready to proceed (or \"quit\" to abort): \07",
1543:         myname, arvolume + 1, arspec, myname);
1544:     for (;;) {
1545:         nextask(msg, answer, sizeof(answer));
1546:         if (strcmp(answer, "quit") == 0)
1547:             fatal(arspec, "Aborted");
1548:         if (strcmp(answer, "go") == 0 && nextopen(mode) == 0)
1549:             break;
1550:     }
1551:     VOID warnarch("Continuing", (off_t) 0);
1552:     timewait += time((time_t *) NULL) - began;
1553: }
1554: 
1555: /*
1556:  * nextask()
1557:  *
1558:  * Ask a question and get a response. Ignores spaces and tabs.
1559:  */
1560: STATIC void
1561: nextask(msg, answer, limit)
1562: reg char    *msg;
1563: reg char    *answer;
1564: reg int     limit;
1565: {
1566:     reg int     idx;
1567:     reg int     got;
1568:     auto char   c;
1569: 
1570:     if (ttyf < 0)
1571:         fatal(TTY, "Unavailable");
1572:     VOID write(ttyf, msg, (uint) strlen(msg));
1573:     idx = 0;
1574:     while ((got = read(ttyf, &c, 1)) == 1)
1575:         if (c == '\04' || c == '\n')
1576:             break;
1577:         else if (c == ' ' || c == '\t')
1578:             continue;
1579:         else if (idx < limit - 1)
1580:             answer[idx++] = c;
1581:     if (got < 0)
1582:         fatal(TTY, syserr());
1583:     answer[idx] = '\0';
1584: }
1585: 
1586: /*
1587:  * nextclos()
1588:  *
1589:  * Close an archive.
1590:  */
1591: STATIC void
1592: nextclos()
1593: {
1594:     if (arfd != STDIN && arfd != STDOUT)
1595:         VOID close(arfd);
1596:     areof = 0;
1597:     if (arname && *arname == '!')
1598:         pipewait();
1599: }
1600: 
1601: /*
1602:  * nextopen()
1603:  *
1604:  * Open an archive. Returns 0 if successful, -1 otherwise.
1605:  */
1606: STATIC int
1607: nextopen(mode)
1608: int     mode;
1609: {
1610:     if (*arname == '!')
1611:         arfd = pipeopen(mode);
1612:     else if (strcmp(arname, "-") == 0)
1613:         arfd = mode ? STDOUT : STDIN;
1614:     else {
1615: #ifdef  CTC3B2
1616:         if (Cflag) {
1617:             reg int     oops;
1618:             reg int     fd;
1619: 
1620:             oops = ((fd = open(arname, O_RDWR | O_CTSPECIAL)) < 0
1621:                 || ioctl(fd, STREAMON) < 0);
1622:             VOID close(fd);
1623:             if (oops)
1624:                 return (warnarch(syserr(), (off_t) 0));
1625:         }
1626: #endif	/* CTC3B2 */
1627:         arfd = mode ? creat(arname, 0666 & ~mask) : open(arname, mode);
1628:     }
1629:     if (arfd < 0)
1630:         return (warnarch(syserr(), (off_t) 0));
1631:     arleft = aruntil;
1632:     ++arvolume;
1633:     return (0);
1634: }
1635: 
1636: /*
1637:  * openi()
1638:  *
1639:  * Open the next input file. Returns a file descriptor, 0 if no data
1640:  * exists, or -1 at EOF. This kludge works because standard input is
1641:  * in use, preventing open() from returning zero.
1642:  */
1643: STATIC int
1644: openi(name, asb)
1645: char        *name;
1646: reg Stat    *asb;
1647: {
1648:     reg int     fd;
1649:     auto char   local[PATHSIZE];
1650: 
1651:     for (;;) {
1652:         if (lineget(stdin, name) < 0)
1653:             return (-1);
1654:         if (nameopt(name) < 0)
1655:             continue;
1656:         if (!gflag)
1657:             VOID strcpy(local, name);
1658:         else if (dirchg(name, local) < 0)
1659:             continue;
1660:         if ((hflag ? STAT(local, asb) : LSTAT(local, asb)) < 0) {
1661:             VOID warn(name, syserr());
1662:             continue;
1663:         }
1664:         switch (asb->sb_mode & S_IFMT) {
1665:         case S_IFDIR:
1666:             asb->sb_nlink = 1;
1667:             asb->sb_size = 0;
1668:             return (0);
1669: #ifdef  S_IFLNK
1670:         case S_IFLNK:
1671:             if ((asb->sb_size = readlink(local,
1672:                 asb->sb_link, sizeof(asb->sb_link) - 1)) < 0) {
1673:                 VOID warn(name, syserr());
1674:                 continue;
1675:             }
1676:             asb->sb_link[asb->sb_size] = '\0';
1677:             return (0);
1678: #endif	/* S_IFLNK */
1679:         case S_IFREG:
1680:             if (asb->sb_size == 0)
1681:                 return (0);
1682:             if ((fd = open(local, O_RDONLY)) >= 0)
1683:                 return (fd);
1684:             VOID warn(name, syserr());
1685:             break;
1686:         default:
1687:             asb->sb_size = 0;
1688:             return (0);
1689:         }
1690:     }
1691: }
1692: 
1693: /*
1694:  * openo()
1695:  *
1696:  * Open an output file. Returns the output file descriptor,
1697:  * 0 if no data is required or -1 if unsuccessful. Note that
1698:  * UNIX open() will never return 0 because the standard input
1699:  * is in use.
1700:  */
1701: STATIC int
1702: openo(name, asb, linkp, ispass)
1703: char        *name;
1704: reg Stat    *asb;
1705: Link        *linkp;
1706: reg int     ispass;
1707: {
1708:     reg int     exists;
1709:     reg int     fd;
1710:     reg ushort  perm;
1711:     ushort      operm;
1712:     Path        *path;
1713:     auto Stat   osb;
1714: #ifdef  S_IFLNK
1715:     reg int     ssize;
1716:     auto char   sname[PATHSIZE];
1717: #endif	/* S_IFLNK */
1718: 
1719:     if (exists = (LSTAT(name, &osb) == 0))
1720:         if (ispass
1721:             && osb.sb_ino == asb->sb_ino
1722:             && osb.sb_dev == asb->sb_dev)
1723:             return (warn(name, "Same file"));
1724:         else if ((osb.sb_mode & S_IFMT) == (asb->sb_mode & S_IFMT))
1725:             operm = osb.sb_mode & (xflag ? S_IPERM : S_IPOPN);
1726:         else if (remove(name, &osb) < 0)
1727:             return (warn(name, syserr()));
1728:         else
1729:             exists = 0;
1730:     if (linkp) {
1731:         if (exists)
1732:             if (asb->sb_ino == osb.sb_ino
1733:                 && asb->sb_dev == osb.sb_dev)
1734:                 return (0);
1735:             else if (unlink(name) < 0)
1736:                 return (warn(name, syserr()));
1737:             else
1738:                 exists = 0;
1739:         for (path = linkp->l_path; path; path = path->p_forw)
1740:             if (link(path->p_name, name) == 0
1741:               || (errno == ENOENT
1742:                 && dirneed(name) == 0
1743:                 && link(path->p_name, name) == 0))
1744:                 return (0);
1745:             else if (errno != EXDEV)
1746:                 return (warn(name, syserr()));
1747:         VOID warn(name, "Link broken");
1748:         linkalso(linkp, name);
1749:     }
1750:     perm = asb->sb_mode & (xflag ? S_IPERM : S_IPOPN);
1751:     switch (asb->sb_mode & S_IFMT) {
1752:     case S_IFBLK:
1753:     case S_IFCHR:
1754:         fd = 0;
1755:         if (exists)
1756:             if (asb->sb_rdev == osb.sb_rdev)
1757:                 if (perm != operm && chmod(name, perm) < 0)
1758:                     return (warn(name, syserr()));
1759:                 else
1760:                     break;
1761:             else if (remove(name, &osb) < 0)
1762:                 return (warn(name, syserr()));
1763:             else
1764:                 exists = 0;
1765:         if (mknod(name, asb->sb_mode, asb->sb_rdev) < 0
1766:           && (errno != ENOENT
1767:             || dirneed(name) < 0
1768:             || mknod(name, asb->sb_mode, asb->sb_rdev) < 0))
1769:             return (warn(name, syserr()));
1770:         break;
1771:     case S_IFDIR:
1772:         if (exists)
1773:             if (perm != operm && chmod(name, perm) < 0)
1774:                 return (warn(name, syserr()));
1775:             else
1776:                 ;
1777:         else if (dirneed(name) < 0 || dirmake(name, asb) < 0)
1778:             return (warn(name, syserr()));
1779:         return (0);
1780: #ifdef  S_IFIFO
1781:     case S_IFIFO:
1782:         fd = 0;
1783:         if (exists)
1784:             if (perm != operm && chmod(name, perm) < 0)
1785:                 return (warn(name, syserr()));
1786:             else
1787:                 ;
1788:         else if (mknod(name, asb->sb_mode, (dev_t) 0) < 0
1789:           && (errno != ENOENT
1790:             || dirneed(name) < 0
1791:             || mknod(name, asb->sb_mode, (dev_t) 0) < 0))
1792:             return (warn(name, syserr()));
1793:         break;
1794: #endif	/* S_IFIFO */
1795: #ifdef  S_IFLNK
1796:     case S_IFLNK:
1797:         if (exists)
1798:             if ((ssize = readlink(name, sname, sizeof(sname))) < 0)
1799:                 return (warn(name, syserr()));
1800:             else if (strncmp(sname, asb->sb_link, ssize) == 0)
1801:                 return (0);
1802:             else if (remove(name, &osb) < 0)
1803:                 return (warn(name, syserr()));
1804:             else
1805:                 exists = 0;
1806:         if (symlink(asb->sb_link, name) < 0
1807:           && (errno != ENOENT
1808:             || dirneed(name) < 0
1809:             || symlink(asb->sb_link, name) < 0))
1810:             return (warn(name, syserr()));
1811:         return (0); /* Can't chown()/chmod() a symbolic link */
1812: #endif	/* S_IFLNK */
1813:     case S_IFREG:
1814:         if (exists)
1815:             if (nflag && osb.sb_mtime > asb->sb_mtime)
1816:                 return (warn(name, "Newer file exists"));
1817:             else if (unlink(name) < 0)
1818:                 return (warn(name, syserr()));
1819:             else
1820:                 exists = 0;
1821:         if ((fd = creat(name, perm)) < 0
1822:           && (errno != ENOENT
1823:             || dirneed(name) < 0
1824:             || (fd = creat(name, perm)) < 0))
1825:             return (warn(name, syserr()));
1826:         break;
1827:     default:
1828:         return (warn(name, "Unknown filetype"));
1829:     }
1830:     if (xflag
1831:       && (!exists
1832:         || asb->sb_uid != osb.sb_uid
1833:         || asb->sb_gid != osb.sb_gid))
1834:         VOID chown(name,
1835:             uid == 0 ? ush(asb->sb_uid) : uid,
1836:             ush(asb->sb_gid));
1837:     if (linkp == NULL && asb->sb_nlink > 1)
1838:         VOID linkto(name, asb);
1839:     return (fd);
1840: }
1841: 
1842: /*
1843:  * openq()
1844:  *
1845:  * Open the terminal for interactive queries (sigh). Assumes that
1846:  * background processes ignore interrupts and that the open() or
1847:  * the isatty() will fail for processes which are not attached to
1848:  * terminals. Returns a file descriptor (-1 if unsuccessful).
1849:  */
1850: STATIC int
1851: openq()
1852: {
1853:     reg int     fd;
1854:     reg VOIDFN  (*intr)();
1855: 
1856:     if ((intr = signal(SIGINT, SIG_IGN)) == SIG_IGN)
1857:         return (-1);
1858:     VOID signal(SIGINT, intr);
1859:     if ((fd = open(TTY, O_RDWR)) < 0)
1860:         return (-1);
1861:     if (isatty(fd))
1862:         return (fd);
1863:     VOID close(fd);
1864:     return (-1);
1865: }
1866: 
1867: /*
1868:  * options()
1869:  *
1870:  * Decode most reasonable forms of UNIX option syntax. Takes main()-
1871:  * style argument indices (argc/argv) and a string of valid option
1872:  * letters. Letters denoting options with arguments must be followed
1873:  * by colons. With valid options, returns the option letter and points
1874:  * "optarg" at the associated argument (if any). Returns '?' for bad
1875:  * options and missing arguments. Returns zero when no options remain,
1876:  * leaving "optind" indexing the first remaining argument.
1877:  */
1878: STATIC int
1879: options(ac, av, proto)
1880: int     ac;
1881: register char   **av;
1882: char        *proto;
1883: {
1884:     register int    c;
1885:     register char   *idx;
1886:     static int  optsub;
1887: 
1888:     if (optind == 0) {
1889:         optind = 1;
1890:         optsub = 0;
1891:     }
1892:     optarg = NULL;
1893:     if (optind >= ac)
1894:         return (0);
1895:     if (optsub == 0 && (av[optind][0] != '-' || av[optind][1] == '\0'))
1896:         return (0);
1897:     switch (c = av[optind][++optsub]) {
1898:     case '\0':
1899:         ++optind;
1900:         optsub = 0;
1901:         return (options(ac, av, proto));
1902:     case '-':
1903:         ++optind;
1904:         optsub = 0;
1905:         return (0);
1906:     case ':':
1907:         return ('?');
1908:     }
1909:     if ((idx = strchr(proto, c)) == NULL)
1910:         return ('?');
1911:     if (idx[1] != ':')
1912:         return (c);
1913:     optarg = &av[optind][++optsub];
1914:     ++optind;
1915:     optsub = 0;
1916:     if (*optarg)
1917:         return (c);
1918:     if (optind >= ac)
1919:         return ('?');
1920:     optarg = av[optind++];
1921:     return (c);
1922: }
1923: 
1924: /*
1925:  * optsize()
1926:  *
1927:  * Interpret a "size" argument. Recognizes suffices for blocks
1928:  * (512-byte), kilobytes and megabytes and blocksize. Returns
1929:  * the size in bytes.
1930:  */
1931: STATIC off_t
1932: optsize(str)
1933: char        *str;
1934: {
1935:     reg char    *idx;
1936:     reg off_t   number;
1937:     reg off_t   result;
1938: 
1939:     result = 0;
1940:     idx = str;
1941:     for (;;) {
1942:         number = 0;
1943:         while (*idx >= '0' && *idx <= '9')
1944:             number = number * 10 + *idx++ - '0';
1945:         switch (*idx++) {
1946:         case 'b':
1947:             result += number * 512;
1948:             continue;
1949:         case 'k':
1950:             result += number * 1024;
1951:             continue;
1952:         case 'm':
1953:             result += number * 1024 * 1024;
1954:             continue;
1955:         case 'x':
1956:             result += number * arbsize;
1957:             continue;
1958:         case '+':
1959:             result += number;
1960:             continue;
1961:         case '\0':
1962:             result += number;
1963:             break;
1964:         default:
1965:             break;
1966:         }
1967:         break;
1968:     }
1969:     if (*--idx)
1970:         fatal(str, "Unrecognizable value");
1971:     return (result);
1972: }
1973: 
1974: /*
1975:  * out()
1976:  *
1977:  * Write an archive.
1978:  */
1979: STATIC VOIDFN
1980: out(av)
1981: char        **av;
1982: {
1983:     reg int     fd;
1984:     auto Stat   sb;
1985:     auto char   name[PATHSIZE];
1986: 
1987:     if (*av)
1988:         fatal(*av, "Extraneous argument");
1989:     while ((fd = openi(name, &sb)) >= 0) {
1990:         if (!lflag && sb.sb_nlink > 1)
1991:             if (linkfrom(&sb))
1992:                 sb.sb_size = 0;
1993:             else
1994:                 VOID linkto(name, &sb);
1995:         outhead(name, &sb);
1996:         if (fd)
1997:             VOID close(outdata(fd, name, sb.sb_size));
1998:         if (vflag)
1999:             VOID fprintf(stderr, "%s\n", name);
2000:     }
2001:     outeof(TRAILER, TRAILZ);
2002: }
2003: 
2004: /*
2005:  * outalloc()
2006:  *
2007:  * Allocate buffer space previously referenced by outavail().
2008:  */
2009: STATIC void
2010: outalloc(len)
2011: reg uint    len;
2012: {
2013:     bufidx += len;
2014:     total += len;
2015: }
2016: 
2017: /*
2018:  * outavail()
2019:  *
2020:  * Index buffer space for archive output. Stores a buffer pointer
2021:  * at a given location. Returns the number of bytes available.
2022:  */
2023: STATIC uint
2024: outavail(bufp)
2025: reg char    **bufp;
2026: {
2027:     reg uint    have;
2028: 
2029:     while ((have = bufend - bufidx) == 0)
2030:         outflush();
2031:     *bufp = bufidx;
2032:     return (have);
2033: }
2034: 
2035: /*
2036:  * outdata()
2037:  *
2038:  * Write archive data. Continues after file read errors, padding with
2039:  * null characters if neccessary. Always returns the given input file
2040:  * descriptor.
2041:  */
2042: STATIC int
2043: outdata(fd, name, size)
2044: int     fd;
2045: char        *name;
2046: reg off_t   size;
2047: {
2048:     reg uint    chunk;
2049:     reg int     got;
2050:     reg int     oops;
2051:     reg uint    avail;
2052:     auto char   *buf;
2053: 
2054:     oops = got = 0;
2055:     while (size) {
2056:         avail = outavail(&buf);
2057:         size -= (chunk = size < avail ? (uint) size : avail);
2058:         if (oops == 0 && (got = read(fd, buf, chunk)) < 0) {
2059:             oops = warn(name, syserr());
2060:             got = 0;
2061:         }
2062:         if (got < chunk) {
2063:             if (oops == NULL)
2064:                 oops = warn(name, "Early EOF");
2065:             while (got < chunk)
2066:                 buf[got++] = '\0';
2067:         }
2068:         outalloc(chunk);
2069:     }
2070:     return (fd);
2071: }
2072: 
2073: /*
2074:  * outeof()
2075:  *
2076:  * Write an archive trailer.
2077:  */
2078: STATIC void
2079: outeof(name, namelen)
2080: char        *name;
2081: reg uint    namelen;
2082: {
2083:     reg off_t   pad;
2084:     auto char   header[M_STRLEN + H_STRLEN + 1];
2085: 
2086:     if (pad = (total + M_STRLEN + H_STRLEN + namelen) % arpad)
2087:         pad = arpad - pad;
2088:     VOID strcpy(header, M_ASCII);
2089:     VOID sprintf(header + M_STRLEN, H_PRINT, 0, 0,
2090:         0, 0, 0, 1, 0, (time_t) 0, namelen, pad);
2091:     outwrite(header, M_STRLEN + H_STRLEN);
2092:     outwrite(name, namelen);
2093:     outpad(pad);
2094:     outflush();
2095:     if (fflag)
2096:         outwait();
2097: }
2098: 
2099: /*
2100:  * outflush()
2101:  *
2102:  * Flush the output buffer. Optionally fork()s to allow the
2103:  * parent to refill the buffer while the child waits for the
2104:  * write() to complete.
2105:  */
2106: STATIC void
2107: outflush()
2108: {
2109:     reg char    *buf;
2110:     reg int     got;
2111:     reg uint    len;
2112: 
2113:     if (aruntil && arleft == 0)
2114:         next(O_WRONLY, "Output limit reached");
2115:     if (fflag) {
2116:         outwait();
2117:         if ((outpid = xfork("outflush()")) == 0)
2118:             VOID nice(-40);
2119:     }
2120:     if (!fflag || outpid == 0) {
2121:         for (buf = buffer; len = bufidx - buf; ) {
2122:             if ((got = write(arfd, buf,
2123:                 *arname == '!' ? len : min(len, arbsize))) > 0) {
2124:                 buf += got;
2125:                 arleft -= got;
2126:             } else if (fflag) {
2127:                 VOID warn(arspec, got < 0
2128:                     ? syserr()
2129:                     : "Apparently full");
2130:                 _exit(1);
2131:             } else if (got < 0)
2132:                 fatal(arspec, syserr());
2133:             else
2134:                 next(O_WRONLY, "Apparently full");
2135:         }
2136:     }
2137:     if (fflag) {
2138:         if (outpid == 0)
2139:             _exit(0);
2140:         else
2141:             arleft -= bufidx - buffer;
2142:     }
2143:     bufend = (bufidx = buffer) + (aruntil ? min(buflen, arleft) : buflen);
2144: }
2145: 
2146: /*
2147:  * outhead()
2148:  *
2149:  * Write an archive header.
2150:  */
2151: STATIC void
2152: outhead(name, asb)
2153: reg char    *name;
2154: reg Stat    *asb;
2155: {
2156:     reg uint    namelen;
2157:     auto char   header[M_STRLEN + H_STRLEN + 1];
2158: 
2159:     if (name[0] == '/')
2160:         if (name[1])
2161:             ++name;
2162:         else
2163:             name = ".";
2164:     namelen = (uint) strlen(name) + 1;
2165:     VOID strcpy(header, M_ASCII);
2166:     VOID sprintf(header + M_STRLEN, H_PRINT, ush(asb->sb_dev),
2167:         ush(asb->sb_ino), ush(asb->sb_mode), ush(asb->sb_uid),
2168:         ush(asb->sb_gid), ush(asb->sb_nlink), ush(asb->sb_rdev),
2169:         mflag ? timenow : asb->sb_mtime, namelen, asb->sb_size);
2170:     outwrite(header, M_STRLEN + H_STRLEN);
2171:     outwrite(name, namelen);
2172: #ifdef  S_IFLNK
2173:     if ((asb->sb_mode & S_IFMT) == S_IFLNK)
2174:         outwrite(asb->sb_link, (uint) asb->sb_size);
2175: #endif	/* S_IFLNK */
2176: }
2177: 
2178: /*
2179:  * outpad()
2180:  *
2181:  * Pad the archive.
2182:  */
2183: STATIC void
2184: outpad(pad)
2185: reg off_t   pad;
2186: {
2187:     reg int     idx;
2188:     reg int     len;
2189: 
2190:     while (pad) {
2191:         if ((len = bufend - bufidx) > pad)
2192:             len = pad;
2193:         for (idx = 0; idx < len; ++idx)
2194:             *bufidx++ = '\0';
2195:         total += len;
2196:         outflush();
2197:         pad -= len;
2198:     }
2199: }
2200: 
2201: /*
2202:  * outwait()
2203:  *
2204:  * Wait for the last background outflush() process (if any). The child
2205:  * exit value is zero if successful, 255 if a write() returned zero or
2206:  * the value of errno if a write() was unsuccessful.
2207:  */
2208: STATIC void
2209: outwait()
2210: {
2211:     auto int    status;
2212: 
2213:     if (outpid == 0)
2214:         return;
2215:     status = xwait(outpid, "outwait()");
2216:     outpid = 0;
2217:     if (status)
2218:         fatal(arspec, "Child error");
2219: }
2220: 
2221: /*
2222:  * outwrite()
2223:  *
2224:  * Write archive data.
2225:  */
2226: STATIC void
2227: outwrite(idx, len)
2228: reg char    *idx;
2229: uint        len;
2230: {
2231:     reg uint    have;
2232:     reg uint    want;
2233:     reg char    *endx = idx + len;
2234: 
2235:     while (want = endx - idx) {
2236:         while ((have = bufend - bufidx) == 0)
2237:             outflush();
2238:         if (have > want)
2239:             have = want;
2240:         memcpy(bufidx, idx, have);
2241:         bufidx += have;
2242:         idx += have;
2243:         total += have;
2244:     }
2245: }
2246: 
2247: /*
2248:  * pass()
2249:  *
2250:  * Copy within the filesystem.
2251:  */
2252: STATIC VOIDFN
2253: pass(av)
2254: reg char    **av;
2255: {
2256:     reg int     fd;
2257:     reg char    **avx;
2258:     auto Stat   sb;
2259:     auto char   name[PATHSIZE];
2260: 
2261:     for (avx = av; *avx; ++avx) {
2262:         if (gflag && **avx != '/')
2263:             fatal(*avx, "Relative pathname");
2264:         if (STAT(*avx, &sb) < 0)
2265:             fatal(*avx, syserr());
2266:         if ((sb.sb_mode & S_IFMT) != S_IFDIR)
2267:             fatal(*avx, "Not a directory");
2268:     }
2269:     while ((fd = openi(name, &sb)) >= 0) {
2270:         if (passitem(name, &sb, fd, av))
2271:             VOID close(fd);
2272:         if (vflag)
2273:             VOID fprintf(stderr, "%s\n", name);
2274:     }
2275: }
2276: 
2277: /*
2278:  * passdata()
2279:  *
2280:  * Copy data to one file. Doesn't believe in input file
2281:  * descriptor zero (see description of kludge in openi()
2282:  * comments). Closes the provided output file descriptor.
2283:  */
2284: STATIC void
2285: passdata(from, ifd, to, ofd)
2286: char        *from;
2287: reg int     ifd;
2288: char        *to;
2289: reg int     ofd;
2290: {
2291:     reg int     got;
2292:     reg int     sparse;
2293:     auto char   block[FSBUF];
2294: 
2295:     if (ifd) {
2296:         VOID lseek(ifd, (off_t) 0, 0);
2297:         sparse = 0;
2298:         while ((got = read(ifd, block, sizeof(block))) > 0
2299:             && (sparse = swrite(ofd, block, (uint) got)) >= 0)
2300:             total += got;
2301:         if (got)
2302:             VOID warn(got < 0 ? from : to, syserr());
2303:         else if (sparse > 0
2304:           && (lseek(ofd, (off_t) -sparse, 1) < 0
2305:             || write(ofd, block, (uint) sparse) != sparse))
2306:             VOID warn(to, syserr());
2307:     }
2308:     VOID close(ofd);
2309: }
2310: 
2311: /*
2312:  * passitem()
2313:  *
2314:  * Copy one file. Returns given input file descriptor.
2315:  */
2316: STATIC int
2317: passitem(from, asb, ifd, dir)
2318: char        *from;
2319: Stat        *asb;
2320: reg int     ifd;
2321: reg char    **dir;
2322: {
2323:     reg int     ofd;
2324:     auto time_t tstamp[2];
2325:     auto char   to[PATHSIZE];
2326: 
2327:     while (*dir) {
2328:         if (nameopt(strcat(strcat(strcpy(to, *dir++), "/"), from)) < 0)
2329:             continue;
2330:         if ((ofd = openo(to, asb,
2331:             lflag ? linkto(from, asb) : linkfrom(asb), 1)) < 0)
2332:             continue;
2333:         if (ofd > 0)
2334:             passdata(from, ifd, to, ofd);
2335:         tstamp[0] = tstamp[1] = mflag ? timenow : asb->sb_mtime;
2336:         VOID utime(to, tstamp);
2337:     }
2338:     return (ifd);
2339: }
2340: 
2341: /*
2342:  * pipechld()
2343:  *
2344:  * Child portion of pipeline fork.
2345:  */
2346: STATIC int
2347: pipechld(mode, pfd)
2348: int     mode;
2349: reg int     *pfd;
2350: {
2351:     reg char    **av;
2352:     auto char   *arg[32];
2353: 
2354:     av = arg;
2355:     if ((*av = getenv("SHELL")) && **av)
2356:         ++av;
2357:     else
2358:         *av++ = "/bin/sh";
2359:     *av++ = "-c";
2360:     *av++ = arname + 1;
2361:     *av = NULL;
2362:     if (mode) {
2363:         VOID close(pfd[1]);
2364:         VOID close(STDIN);
2365:         VOID dup(pfd[0]);
2366:         VOID close(pfd[0]);
2367:         VOID close(STDOUT);
2368:         VOID open("/dev/null", O_WRONLY);
2369:     } else {
2370:         VOID close(STDIN);
2371:         VOID open("/dev/null", O_RDONLY);
2372:         VOID close(pfd[0]);
2373:         VOID close(STDOUT);
2374:         VOID dup(pfd[1]);
2375:         VOID close(pfd[1]);
2376:     }
2377:     if (ttyf >= 0)
2378:         VOID close(ttyf);
2379:     VOID execvp(arg[0], arg);
2380:     VOID warn(arg[0], syserr());
2381:     _exit(1);
2382: }
2383: 
2384: /*
2385:  * pipeopen()
2386:  *
2387:  * Open an archive via a pipeline. Returns a file
2388:  * descriptor, or -1 if unsuccessful.
2389:  */
2390: STATIC int
2391: pipeopen(mode)
2392: reg int     mode;
2393: {
2394:     auto int    pfd[2];
2395: 
2396:     if (pipe(pfd) < 0)
2397:         return (-1);
2398:     if ((pipepid = xfork("pipeopen()")) == 0)
2399:         pipechld(mode, pfd);
2400:     if (mode) {
2401:         VOID close(pfd[0]);
2402:         return (pfd[1]);
2403:     } else {
2404:         VOID close(pfd[1]);
2405:         return (pfd[0]);
2406:     }
2407: }
2408: 
2409: /*
2410:  * pipewait()
2411:  *
2412:  * Await a pipeline.
2413:  */
2414: STATIC void
2415: pipewait()
2416: {
2417:     reg int     status;
2418: 
2419:     if (pipepid == 0)
2420:         return;
2421:     status = xwait(pipepid, "pipewait()");
2422:     pipepid = 0;
2423:     if (status)
2424:         fatal(arspec, "Pipeline error");
2425: }
2426: 
2427: /*
2428:  * prsize()
2429:  *
2430:  * Print a file offset.
2431:  */
2432: STATIC void
2433: prsize(stream, size)
2434: FILE        *stream;
2435: reg off_t   size;
2436: {
2437:     reg off_t   n;
2438: 
2439:     if (n = (size / (1024 * 1024))) {
2440:         VOID fprintf(stream, "%ldm+", n);
2441:         size -= n * 1024 * 1024;
2442:     }
2443:     if (n = (size / 1024)) {
2444:         VOID fprintf(stream, "%ldk+", n);
2445:         size -= n * 1024;
2446:     }
2447:     VOID fprintf(stream, "%ld", size);
2448: }
2449: 
2450: #ifndef MKDIR
2451: 
2452: /*
2453:  * rmdir()
2454:  *
2455:  * Remove a directory via "/bin/rmdir". Sets errno to a
2456:  * questionably sane value upon failure.
2457:  */
2458: STATIC int
2459: rmdir(name)
2460: reg char    *name;
2461: {
2462:     reg int     pid;
2463: 
2464:     if ((pid = xfork("rmdir()")) == 0) {
2465:         VOID close(fileno(stdin));
2466:         VOID close(fileno(stdout));
2467:         VOID close(fileno(stderr));
2468:         VOID open("/dev/null", O_RDWR);
2469:         VOID dup(fileno(stdin));
2470:         VOID dup(fileno(stdin));
2471:         VOID execl("/bin/rmdir", "rmdir", name, (char *) NULL);
2472:         exit(1);
2473:     }
2474:     if (xwait(pid, "rmdir()") == 0)
2475:         return (0);
2476:     errno = EACCES;
2477:     return (-1);
2478: }
2479: 
2480: #endif	/* MKDIR */
2481: 
2482: /*
2483:  * swrite()
2484:  *
2485:  * Write a filesystem block. Seeks past sparse blocks. Returns
2486:  * 0 if the block was written, the given length for a sparse
2487:  * block or -1 if unsuccessful.
2488:  */
2489: STATIC int
2490: swrite(fd, buf, len)
2491: int     fd;
2492: char        *buf;
2493: uint        len;
2494: {
2495:     reg char    *bidx;
2496:     reg char    *bend;
2497: 
2498:     if (jflag)
2499:         return (write(fd, buf, len) == len ? 0 : -1);
2500:     bend = (bidx = buf) + len;
2501:     while (bidx < bend)
2502:         if (*bidx++)
2503:             return (write(fd, buf, len) == len ? 0 : -1);
2504:     return (lseek(fd, (off_t) len, 1) < 0 ? -1 : len);
2505: }
2506: 
2507: /*
2508:  * syserr()
2509:  *
2510:  * Return pointer to appropriate system error message.
2511:  */
2512: char *
2513: syserr()
2514: {
2515: 
2516:     return (strerror(errno));
2517: }
2518: 
2519: /*
2520:  * toc()
2521:  *
2522:  * Print archive table of contents.
2523:  */
2524: STATIC VOIDFN
2525: toc(av)
2526: reg char    **av;
2527: {
2528:     auto Stat   sb;
2529:     auto char   name[PATHSIZE];
2530: 
2531:     if (*av)
2532:         fatal(*av, "Extraneous argument");
2533:     name[0] = '\0';
2534:     while (inhead(name, &sb) == 0) {
2535:         if (namecmp(name) == 0)
2536:             tocentry(name, &sb);
2537:         if (inskip(sb.sb_size) < 0)
2538:             VOID warn(name, "File data is corrupt");
2539:     }
2540: }
2541: 
2542: /*
2543:  * tocentry()
2544:  *
2545:  * Print a single table-of-contents entry.
2546:  */
2547: STATIC void
2548: tocentry(name, asb)
2549: char        *name;
2550: reg Stat    *asb;
2551: {
2552:     reg Time    *atm;
2553:     reg Link    *from;
2554:     reg Passwd  *pwp;
2555:     reg Group   *grp;
2556:     static char *month[] = {
2557:         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2558:         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
2559:     };
2560: 
2561:     if (vflag) {
2562:         tocmode(asb->sb_mode);
2563:         VOID printf(" %2d", asb->sb_nlink);
2564:         atm = localtime(&asb->sb_mtime);
2565:         if (pwp = getpwuid(ush(asb->sb_uid)))
2566:             VOID printf(" %-8s", pwp->pw_name);
2567:         else
2568:             VOID printf(" %-8u", ush(asb->sb_uid));
2569:         if (grp = getgrgid(ush(asb->sb_gid)))
2570:             VOID printf(" %-8s", grp->gr_name);
2571:         else
2572:             VOID printf(" %-8u", ush(asb->sb_gid));
2573:         switch (asb->sb_mode & S_IFMT) {
2574:         case S_IFBLK:
2575:         case S_IFCHR:
2576:             VOID printf(" %3d, %3d",
2577:                 major(asb->sb_rdev), minor(asb->sb_rdev));
2578:             break;
2579:         case S_IFREG:
2580:             VOID printf(" %8ld", asb->sb_size);
2581:             break;
2582:         default:
2583:             VOID printf("         ");
2584:         }
2585:         VOID printf(" %3s %2d %02d:%02d:%02d %4d ",
2586:             month[atm->tm_mon], atm->tm_mday, atm->tm_hour,
2587:             atm->tm_min, atm->tm_sec, atm->tm_year + 1900);
2588:     }
2589:     VOID printf("%s", name);
2590:     if (vflag || lflag) {
2591:         if (asb->sb_nlink > 1)
2592:             if (from = linkfrom(asb))
2593:                 VOID printf(" -> %s",
2594:                     from->l_path->p_name);
2595:             else
2596:                 VOID linkto(name, asb);
2597: #ifdef  S_IFLNK
2598:         if ((asb->sb_mode & S_IFMT) == S_IFLNK)
2599:             VOID printf(" S-> %s", asb->sb_link);
2600: #endif	/* S_IFLNK */
2601:     }
2602:     putchar('\n');
2603: }
2604: 
2605: /*
2606:  * tocmode()
2607:  *
2608:  * Fancy file mode display.
2609:  */
2610: STATIC void
2611: tocmode(mode)
2612: reg ushort  mode;
2613: {
2614:     switch (mode & S_IFMT) {
2615:         case S_IFREG: putchar('-'); break;
2616:         case S_IFDIR: putchar('d'); break;
2617: #ifdef  S_IFLNK
2618:         case S_IFLNK: putchar('l'); break;
2619: #endif	/* S_IFLNK */
2620:         case S_IFBLK: putchar('b'); break;
2621:         case S_IFCHR: putchar('c'); break;
2622: #ifdef  S_IFIFO
2623:         case S_IFIFO: putchar('p'); break;
2624: #endif	/* S_IFIFO */
2625:         default:
2626:             VOID printf("[%o]", mode >> S_IFSHF);
2627:     }
2628:     putchar(mode & 0400 ? 'r' : '-');
2629:     putchar(mode & 0200 ? 'w' : '-');
2630:     putchar(mode & 0100
2631:         ? mode & 04000 ? 's' : 'x'
2632:         : mode & 04000 ? 'S' : '-');
2633:     putchar(mode & 0040 ? 'r' : '-');
2634:     putchar(mode & 0020 ? 'w' : '-');
2635:     putchar(mode & 0010
2636:         ? mode & 02000 ? 's' : 'x'
2637:         : mode & 02000 ? 'S' : '-');
2638:     putchar(mode & 0004 ? 'r' : '-');
2639:     putchar(mode & 0002 ? 'w' : '-');
2640:     putchar(mode & 0001
2641:         ? mode & 01000 ? 't' : 'x'
2642:         : mode & 01000 ? 'T' : '-');
2643: }
2644: 
2645: /*
2646:  * usage()
2647:  *
2648:  * Print a helpful message and exit.
2649:  */
2650: STATIC void
2651: usage()
2652: {
2653:     VOID fprintf(stderr, "\
2654: Usage:	%s -o [ -fghlmuvz ] [ -(bces) n ] archive\n\
2655: 	%s -i [ -djkmnuvxz ] [ -(bcs) n ] [ -y prefix ] archive\n\
2656: 	%s -t [ -kuvz ] [ -(bcs) n ] [ -y prefix ] archive\n\
2657: 	%s -p [ -dghjlmnuvxz ] dir [ ... ]\n",
2658:         myname, myname, myname, myname);
2659:     exit(1);
2660: }
2661: 
2662: /*
2663:  * warn()
2664:  *
2665:  * Print a warning message. Always returns -1.
2666:  */
2667: STATIC int
2668: warn(what, why)
2669: char    *what;
2670: char    *why;
2671: {
2672:     VOID fprintf(stderr,
2673:         "%s: \"%s\": %s\n",
2674:         myname, what, why);
2675:     return (-1);
2676: }
2677: 
2678: /*
2679:  * warnarch()
2680:  *
2681:  * Print an archive-related warning message, including
2682:  * an adjusted file offset. Always returns -1.
2683:  */
2684: STATIC int
2685: warnarch(msg, adjust)
2686: char    *msg;
2687: off_t   adjust;
2688: {
2689:     VOID fprintf(stderr, "%s: \"%s\" [offset ", myname, arspec);
2690:     prsize(stderr, total - adjust);
2691:     VOID fprintf(stderr, "]: %s\n", msg);
2692:     return (-1);
2693: }
2694: 
2695: /*
2696:  * xfork()
2697:  *
2698:  * Create a child.
2699:  */
2700: STATIC int
2701: xfork(what)
2702: reg char    *what;
2703: {
2704:     reg int     pid;
2705:     reg Child   *cp;
2706:     reg int     idx;
2707:     static uint delay[] = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 };
2708: 
2709:     for (idx = 0; (pid = fork()) < 0; ++idx) {
2710:         if (idx == sizeof(delay))
2711:             fatal(arspec, syserr());
2712:         VOID warn(what, "Trouble forking...");
2713:         sleep(delay[idx]);
2714:     }
2715:     if (idx)
2716:         VOID warn(what, "...successful fork");
2717:     cp = (Child *) memget(sizeof(*cp));
2718:     cp->c_pid = pid;
2719:     cp->c_flags = 0;
2720:     cp->c_status = 0;
2721:     cp->c_forw = children;
2722:     children = cp;
2723:     return (pid);
2724: }
2725: 
2726: /*
2727:  * xpause()
2728:  *
2729:  * Await a child.
2730:  */
2731: STATIC void
2732: xpause()
2733: {
2734:     reg Child   *cp;
2735:     reg int     pid;
2736:     auto int    status;
2737: 
2738:     do {
2739:         while ((pid = wait(&status)) < 0)
2740:             ;
2741:         for (cp = children; cp && cp->c_pid != pid; cp = cp->c_forw)
2742:             ;
2743:     } while (cp == NULL);
2744:     cp->c_flags |= CF_EXIT;
2745:     cp->c_status = status;
2746: }
2747: 
2748: /*
2749:  * xwait()
2750:  *
2751:  * Find the status of a child.
2752:  */
2753: STATIC int
2754: xwait(pid, what)
2755: reg int     pid;
2756: char        *what;
2757: {
2758:     reg int     status;
2759:     reg Child   *cp;
2760:     reg Child   **acp;
2761:     auto char   why[100];
2762: 
2763:     for (acp = &children; cp = *acp; acp = &cp->c_forw)
2764:         if (cp->c_pid == pid)
2765:             break;
2766:     if (cp == NULL)
2767:         fatal(what, "Lost child");
2768:     while ((cp->c_flags & CF_EXIT) == 0)
2769:         xpause();
2770:     status = cp->c_status;
2771:     *acp = cp->c_forw;
2772:     free((char *) cp);
2773:     if (status == 0)
2774:         return (0);
2775:     if (status & 0377)
2776:         VOID sprintf(why, "Killed by signal %d%s",
2777:             status & 0177, status & 0200 ? " -- core dumped" : "");
2778:     else
2779:         VOID sprintf(why, "Exit %d", (status >> 8) & 0377);
2780:     return (warn(what, why));
2781: }

Defined functions

copyin defined in line 626; used 2 times
copyout defined in line 652; used 4 times
dirchg defined in line 681; used 2 times
dirmake defined in line 710; used 3 times
dirneed defined in line 733; used 8 times
fatal defined in line 761; used 26 times
in defined in line 777; used 2 times
inalloc defined in line 802; used 2 times
inascii defined in line 817; used 2 times
inavail defined in line 852; used 2 times
inbinary defined in line 873; used 2 times
indata defined in line 915; used 2 times
inentry defined in line 953; used 2 times
infill defined in line 989; used 5 times
inhead defined in line 1034; used 4 times
inread defined in line 1101; used 10 times
inskip defined in line 1130; used 6 times
inswab defined in line 1155; used 2 times
lineget defined in line 1198; used 2 times
linkalso defined in line 1222; used 2 times
linkfrom defined in line 1244; used 5 times
linkleft defined in line 1282; used 2 times
linkto defined in line 1301; used 5 times
main defined in line 436; never used
memcpy defined in line 1335; used 5 times
memget defined in line 1354; used 7 times
memstr defined in line 1371; used 3 times
mkdir defined in line 1390; used 2 times
nameadd defined in line 1421; used 3 times
namecmp defined in line 1442; used 3 times
nameopt defined in line 1471; used 4 times
next defined in line 1526; used 5 times
nextask defined in line 1560; used 2 times
nextclos defined in line 1591; used 3 times
nextopen defined in line 1606; used 3 times
openi defined in line 1643; used 3 times
openo defined in line 1701; used 3 times
openq defined in line 1850; used 2 times
options defined in line 1878; used 3 times
optsize defined in line 1931; used 5 times
out defined in line 1979; used 4 times
outalloc defined in line 2009; used 2 times
outavail defined in line 2023; used 2 times
outdata defined in line 2042; used 2 times
outeof defined in line 2078; used 2 times
outflush defined in line 2106; used 7 times
outhead defined in line 2151; used 2 times
outpad defined in line 2183; used 2 times
outwait defined in line 2208; used 4 times
outwrite defined in line 2226; used 6 times
pass defined in line 2252; used 4 times
passdata defined in line 2284; used 3 times
passitem defined in line 2316; used 2 times
pipechld defined in line 2346; used 2 times
pipeopen defined in line 2390; used 2 times
pipewait defined in line 2414; used 2 times
prsize defined in line 2432; used 3 times
rmdir defined in line 2458; used 2 times
swrite defined in line 2489; used 3 times
syserr defined in line 2512; used 37 times
toc defined in line 2524; used 3 times
tocentry defined in line 2547; used 2 times
tocmode defined in line 2610; used 2 times
usage defined in line 2650; used 9 times
warn defined in line 2667; used 47 times
warnarch defined in line 2684; used 21 times
xfork defined in line 2700; used 5 times
xpause defined in line 2731; used 2 times
xwait defined in line 2753; used 5 times

Defined variables

STATIC defined in line 2753; never used
VOIDFN defined in line 2524; never used
ident defined in line 27; used 1 times

Defined struct's

child defined in line 241; used 2 times
  • in line 242(2)
link defined in line 267; used 4 times
name defined in line 257; used 4 times
pattern defined in line 280; used 2 times
  • in line 281(2)

Defined typedef's

Child defined in line 246; used 6 times
Group defined in line 172; used 2 times
Link defined in line 275; used 18 times
Passwd defined in line 173; used 2 times
Path defined in line 261; used 10 times
Pattern defined in line 285; used 5 times
Stat defined in line 205; used 20 times
Time defined in line 174; used 2 times

Defined macros

BLOCK defined in line 96; used 1 times
CF_EXIT defined in line 251; used 2 times
FSBUF defined in line 97; used 1 times
FSTAT defined in line 207; never used
H_COUNT defined in line 98; used 1 times
H_PRINT defined in line 99; used 2 times
H_SCAN defined in line 100; used 1 times
H_STRLEN defined in line 101; used 11 times
LSTAT defined in line 208; used 2 times
M_ASCII defined in line 102; used 3 times
M_BINARY defined in line 103; used 2 times
M_STRLEN defined in line 104; used 20 times
NULLDEV defined in line 105; never used
NULLINO defined in line 106; never used
O_RDONLY defined in line 136; used 6 times
O_RDWR defined in line 138; used 4 times
O_WRONLY defined in line 137; used 4 times
PATHELEM defined in line 107; used 2 times
PATHSIZE defined in line 108; used 15 times
STAT defined in line 206; used 4 times
STATIC defined in line 166; used 100 times
STDIN defined in line 113; used 6 times
STDOUT defined in line 114; used 7 times
S_IFSHF defined in line 109; used 1 times
S_IPERM defined in line 110; used 3 times
S_IPEXE defined in line 111; used 1 times
S_IPOPN defined in line 112; used 3 times
TRAILER defined in line 130; used 2 times
TRAILZ defined in line 131; used 1 times
TTY defined in line 115; used 3 times
VOID defined in line 155; used 122 times
VOIDFN defined in line 124; used 13 times
linkhash defined in line 57; used 2 times
min defined in line 63; used 2 times
nel defined in line 69; used 2 times
reg defined in line 93; used 180 times
remove defined in line 75; used 3 times
sb_atime defined in line 217; used 1 times
sb_blksize defined in line 199; never used
sb_blocks defined in line 200; never used
sb_ctime defined in line 219; used 1 times
sb_dev defined in line 209; used 10 times
sb_gid defined in line 214; used 10 times
sb_ino defined in line 210; used 12 times
sb_mode defined in line 211; used 26 times
sb_mtime defined in line 218; used 10 times
sb_nlink defined in line 212; used 10 times
sb_rdev defined in line 215; used 10 times
sb_size defined in line 216; used 25 times
sb_uid defined in line 213; used 10 times
strchr defined in line 145; used 4 times
strrchr defined in line 146; used 2 times
swab defined in line 81; used 13 times
uint defined in line 94; used 48 times
ush defined in line 87; used 15 times
ushort defined in line 95; never used
Last modified: 1996-03-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 9487
Valid CSS Valid XHTML 1.0 Strict