# 2.11BSD#431 - /usr/src/local/afio/afio.c

##### Functions

    copyin            X
    copyout           X
    dirchg            X
    dirmake           X
    dirneed           X
    fatal             X
    in                X
    inalloc           X
    inascii           X
    inavail           X
    inbinary          X
    indata            X
    inentry           X
    infill            X
    inhead            X
    inread            X
    inskip            X
    inswab            X
    lineget           X
    linkalso          X
    linkfrom          X
    linkleft          X
    linkto            X
    main              X
    memcpy            X
    memget            X
    memstr            X
    mkdir             X
    nameadd           X
    namecmp           X
    nameopt           X
    next              X
    nextask           X
    nextclos          X
    nextopen          X
    openi             X
    openo             X
    openq             X
    options           X
    optsize           X
    out               X
    outalloc          X
    outavail          X
    outdata           X
    outeof            X
    outflush          X
    outhead           X
    outpad            X
    outwait           X
    outwrite          X
    pass              X
    passdata          X
    passitem          X
    pipechld          X
    pipeopen          X
    pipewait          X
    prsize            X
    rmdir             X
    swrite            X
    syserr            X
    toc               X
    tocentry          X
    tocmode           X
    usage             X
    warn              X
    warnarch          X
    xfork             X
    xpause            X
    xwait             X

##### Variables

    STATIC            X
    VOIDFN            X

##### Macros

    BLOCK             X
    CF_EXIT           X
    FSBUF             X
    FSTAT             X
    H_COUNT           X
    H_PRINT           X
    H_SCAN            X
    H_STRLEN          X
    LSTAT             X
    M_ASCII           X
    M_BINARY          X
    M_STRLEN          X
    NULLDEV           X
    NULLINO           X
    O_RDONLY          X
    O_RDWR            X
    O_WRONLY          X
    PATHELEM          X
    PATHSIZE          X
    STAT              X
    STATIC            X
    STDIN             X
    STDOUT            X
    S_IFSHF           X
    S_IPERM           X
    S_IPEXE           X
    S_IPOPN           X
    TRAILER           X
    TRAILZ            X
    TTY               X
    VOID              X
    VOIDFN            X
    linkhash          X
    min               X
    nel               X
    reg               X
    remove            X
    sb_atime          X
    sb_blksize        X
    sb_blocks         X
    sb_ctime          X
    sb_dev            X
    sb_gid            X
    sb_ino            X
    sb_mode           X
    sb_mtime          X
    sb_nlink          X
    sb_rdev           X
    sb_size           X
    sb_uid            X
    strchr            X
    strrchr           X
    swab              X
    uint              X
    ush               X
    ushort            X

##### struct's

    child             X
    link              X
    name              X
    pattern           X

##### typedef's

    Child             X
    Group             X
    Link              X
    Passwd            X
    Path              X
    Pattern           X
    Stat              X
    Time              X

       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

- in line 314, 482

copyout defined in line 652; used 4 times

- in line 315, 487, 574, 611

dirchg defined in line 681; used 2 times

- in line 316, 1658

dirmake defined in line 710; used 3 times

- in line 317, 751, 1777

dirneed defined in line 733; used 8 times

- in line 318, 751, 1742, 1767, 1777, 1790, 1808, 1823

fatal defined in line 761; used 26 times

- in line 319, 502-506(2), 591-593(2), 634-639(2), 660-665(2), 785, 999, 1054, 1547, 1571, 1582, 1970, 1988, 2132, 2218, 2263-2267(3), 2424, 2532, 2711, 2767

in defined in line 777; used 2 times

- in line 320, 462

inalloc defined in line 802; used 2 times

- in line 321, 935

inascii defined in line 817; used 2 times

- in line 322, 1049

inavail defined in line 852; used 2 times

- in line 323, 931

inbinary defined in line 873; used 2 times

- in line 324, 1050

indata defined in line 915; used 2 times

- in line 325, 965

inentry defined in line 953; used 2 times

- in line 326, 788

infill defined in line 989; used 5 times

- in line 327, 636, 861, 1113, 1139

inhead defined in line 1034; used 4 times

- in line 328, 787, 1078, 2534

inread defined in line 1101; used 10 times

- in line 329, 828, 838, 887, 903, 1047, 1061, 1076, 1170, 1186

inskip defined in line 1130; used 6 times

- in line 330, 789, 975, 1044, 1072, 2537

inswab defined in line 1155; used 2 times

- in line 331, 1051

lineget defined in line 1198; used 2 times

- in line 332, 1652

linkalso defined in line 1222; used 2 times

- in line 333, 1748

linkfrom defined in line 1244; used 5 times

- in line 334, 963, 1991, 2331, 2592

linkleft defined in line 1282; used 2 times

- in line 335, 601

linkto defined in line 1301; used 5 times

- in line 336, 1838, 1994, 2331, 2596

main defined in line 436; never used
memcpy defined in line 1335; used 5 times

- in line 884, 1060, 1116, 1167, 2240

memget defined in line 1354; used 7 times

- in line 337, 1229, 1311-1312(2), 1377, 1428, 2717

memstr defined in line 1371; used 3 times

- in line 338, 1230, 1313

mkdir defined in line 1390; used 2 times

- in line 339, 715

nameadd defined in line 1421; used 3 times

- in line 340, 554-557(2)

namecmp defined in line 1442; used 3 times

- in line 341, 788, 2535

nameopt defined in line 1471; used 4 times

- in line 342, 1070, 1654, 2328

next defined in line 1526; used 5 times

- in line 343, 1001-1003(2), 2114, 2134

nextask defined in line 1560; used 2 times

- in line 344, 1545

nextclos defined in line 1591; used 3 times

- in line 345, 616, 1536

nextopen defined in line 1606; used 3 times

- in line 346, 594, 1548

openi defined in line 1643; used 3 times

- in line 347, 1989, 2269

openo defined in line 1701; used 3 times

- in line 348, 963, 2330

openq defined in line 1850; used 2 times

- in line 349, 451

options defined in line 1878; used 3 times

- in line 350, 457, 1901

optsize defined in line 1931; used 5 times

- in line 351, 501-505(2), 512, 539

out defined in line 1979; used 4 times

- in line 352, 467, 574, 611

outalloc defined in line 2009; used 2 times

- in line 353, 2068

outavail defined in line 2023; used 2 times

- in line 354, 2056

outdata defined in line 2042; used 2 times

- in line 355, 1997

outeof defined in line 2078; used 2 times

- in line 356, 2001

outflush defined in line 2106; used 7 times

- in line 357, 663, 671, 2030, 2094, 2196, 2237

outhead defined in line 2151; used 2 times

- in line 358, 1995

outpad defined in line 2183; used 2 times

- in line 359, 2093

outwait defined in line 2208; used 4 times

- in line 360, 673, 2096, 2116

outwrite defined in line 2226; used 6 times

- in line 361, 2091-2092(2), 2170-2174(3)

pass defined in line 2252; used 4 times

- in line 362, 472, 571, 609

passdata defined in line 2284; used 3 times

- in line 363, 969, 2334

passitem defined in line 2316; used 2 times

- in line 364, 2270

pipechld defined in line 2346; used 2 times

- in line 365, 2399

pipeopen defined in line 2390; used 2 times

- in line 366, 1611

pipewait defined in line 2414; used 2 times

- in line 367, 1598

prsize defined in line 2432; used 3 times

- in line 368, 607, 2690

rmdir defined in line 2458; used 2 times

- in line 76, 369

swrite defined in line 2489; used 3 times

- in line 370, 933, 2299

syserr defined in line 2512; used 37 times

- in line 371, 639, 665, 700, 934, 944, 967, 1012, 1582, 1624, 1630, 1661, 1673, 1684, 1727, 1736, 1746, 1758-1762(2), 1769-1778(3), 1785, 1792, 1799-1803(2), 1810, 1818, 1825, 2059, 2128-2132(2), 2265, 2302-2306(2), 2380, 2711

toc defined in line 2524; used 3 times

- in line 372, 477, 605

tocentry defined in line 2547; used 2 times

- in line 373, 2536

tocmode defined in line 2610; used 2 times

- in line 374, 2562

usage defined in line 2650; used 9 times

- in line 375, 461-486(6), 563-567(2)

warn defined in line 2667; used 47 times

- in line 376, 691, 700, 790, 938-944(3), 967, 976, 1058, 1066, 1077, 1291, 1362, 1485, 1661, 1673, 1684, 1723-1727(2), 1736, 1746-1747(2), 1758-1762(2), 1769-1778(3), 1785, 1792, 1799-1803(2), 1810, 1816-1818(2), 1825-1828(2), 2059-2064(2), 2127, 2302-2306(2), 2380, 2538, 2712-2716(2), 2780

warnarch defined in line 2684; used 21 times

- in line 377, 829, 835-841(4), 889, 901-906(3), 1012, 1055, 1064, 1172, 1184-1189(3), 1537, 1551, 1624, 1630

xfork defined in line 2700; used 5 times

- in line 378, 1397, 2117, 2398, 2464

xpause defined in line 2731; used 2 times

- in line 379, 2769

xwait defined in line 2753; used 5 times

- in line 380, 1408, 2215, 2421, 2474

#### Defined variables

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

- in line 490

#### Defined struct's

child defined in line 241; used 2 times

- in line 242(2)

link defined in line 267; used 4 times

- in line 268-269(4)

name defined in line 257; used 4 times

- in line 258-259(4)

pattern defined in line 280; used 2 times

- in line 281(2)

#### Defined typedef's

Child defined in line 246; used 6 times

- in line 419, 2705, 2717, 2734, 2759-2760(2)

Group defined in line 172; used 2 times

- in line 295, 2555

Link defined in line 275; used 18 times

- in line 334-336(2), 421, 1224, 1244, 1301, 1705-958(2), 1248-1252(3), 1285-1286(2), 1306-1311(4), 2553

Passwd defined in line 173; used 2 times

- in line 296, 2554

Path defined in line 261; used 10 times

- in line 274, 1227-1229(3), 1250-1251(2), 1307-1312(3), 1712

Pattern defined in line 285; used 5 times

- in line 427, 1426-1428(3), 1446

Stat defined in line 205; used 20 times

- in line 713, 821, 877, 956, 1037, 1159, 1246, 1304, 1646, 1704, 2154, 2319, 2550-184(2), 740, 781, 1713, 1984, 2258, 2528

Time defined in line 174; used 2 times

- in line 298, 2552

#### Defined macros

BLOCK defined in line 96; used 1 times

- in line 406

CF_EXIT defined in line 251; used 2 times

- in line 2744, 2768

FSBUF defined in line 97; used 1 times

- in line 2293

FSTAT defined in line 207; never used
H_COUNT defined in line 98; used 1 times

- in line 834

H_PRINT defined in line 99; used 2 times

- in line 2089, 2166

H_SCAN defined in line 100; used 1 times

- in line 831

H_STRLEN defined in line 101; used 11 times

- in line 824-837(6), 2084-2091(3), 2157, 2170

LSTAT defined in line 208; used 2 times

- in line 1660, 1719

M_ASCII defined in line 102; used 3 times

- in line 826, 2088, 2165

M_BINARY defined in line 103; used 2 times

- in line 882, 1165

M_STRLEN defined in line 104; used 20 times

- in line 826, 886-890(4), 902, 1040, 1047, 1169-1173(4), 1185, 2084-2091(4), 2157, 2166-2170(2)

NULLDEV defined in line 105; never used
NULLINO defined in line 106; never used
O_RDONLY defined in line 136; used 6 times

- in line 594, 966, 1001-1003(2), 1682, 2371

O_RDWR defined in line 138; used 4 times

- in line 1401, 1620, 1859, 2468

O_WRONLY defined in line 137; used 4 times

- in line 594, 2114, 2134, 2368

PATHELEM defined in line 107; used 2 times

- in line 1479-1484(2)

PATHSIZE defined in line 108; used 15 times

- in line 183, 412, 428, 444, 688, 782, 836, 900, 1183, 1649, 1716, 1985, 2259, 2325, 2529

STAT defined in line 206; used 4 times

- in line 747-749(2), 1660, 2264

STATIC defined in line 166; used 100 times

- in line 391-434(43), 626, 652, 681, 710, 733, 761, 777, 802, 817, 852, 873, 915, 953, 989, 1101, 1130, 1155, 1198, 1222, 1244, 1282, 1335, 1354, 1371, 1390, 1421, 1442, 1471, 1526, 1560, 1591, 1643, 1701, 1850, 1931, 1979, 2009, 2023, 2042, 2078, 2106, 2183, 2208, 2252, 2284, 2316, 2346, 2390, 2414, 2458, 2489, 2547, 2610, 2650, 2684, 2700, 2731

STDIN defined in line 113; used 6 times

- in line 664, 1538, 1594, 1613, 2364, 2370

STDOUT defined in line 114; used 7 times

- in line 605, 638, 1538, 1594, 1613, 2367, 2373

S_IFSHF defined in line 109; used 1 times

- in line 2626

S_IPERM defined in line 110; used 3 times

- in line 718, 1725, 1750

S_IPEXE defined in line 111; used 1 times

- in line 717

S_IPOPN defined in line 112; used 3 times

- in line 715, 1725, 1750

TRAILER defined in line 130; used 2 times

- in line 1068, 2001

TRAILZ defined in line 131; used 1 times

- in line 2001

TTY defined in line 115; used 3 times

- in line 1571, 1582, 1859

VOID defined in line 155; used 122 times

- in line 456, 490, 581, 606-608(2), 636, 696-701(2), 718-720(2), 766, 790-792(2), 938-944(3), 965-978(6), 1044-1047(2), 1055-1066(5), 1072-1077(2), 1291, 1378, 1398-1405(8), 1537-1540(2), 1551, 1572, 1595, 1622, 1657-1661(2), 1673, 1684, 1747, 1834-1838(2), 1858-1863(2), 1994-1999(3), 2088-2089(2), 2118, 2127, 2165-2166(2), 2271-2273(2), 2296, 2302-2308(3), 2336, 2363-2380(15), 2401-2404(2), 2440-2447(3), 2465-2471(7), 2538, 2563-2599(13), 2626, 2653, 2672, 2689-2691(2), 2712-2716(2), 2776-2779(2)

VOIDFN defined in line 124; used 13 times

- in line 314-320(3), 352, 362, 372, 442, 626, 652, 777, 1854, 1979, 2252

linkhash defined in line 57; used 2 times

- in line 1254, 1322

min defined in line 63; used 2 times

- in line 2123, 2143

nel defined in line 69; used 2 times

- in line 58, 1288

reg defined in line 93; used 180 times

- in line 438-443(5), 572-574(3), 603, 628-631(3), 654-657(3), 683-687(4), 712-713(2), 737-739(3), 779, 804, 819-821(3), 854-858(3), 875-879(4), 918-924(5), 956-960(4), 992, 1036-1039(3), 1103-1108(4), 1132-1135(3), 1157-1162(5), 1200-1203(3), 1224-1227(2), 1246-1252(6), 1285-1286(2), 1304-1308(4), 1337-1341(3), 1358, 1373-1375(2), 1392-1395(3), 1423-1426(2), 1444-1448(4), 1475-1477(3), 1528-1531(3), 1562-1567(5), 1617-1618(2), 1646-1648(2), 1704-1715(6), 1853-1854(2), 1935-1937(3), 1983, 2011, 2025-2027(2), 2046-2051(5), 2081-2083(2), 2109-2111(3), 2153-2156(3), 2185-2188(3), 2228-2233(4), 2254-2257(3), 2287-2292(4), 2320-2323(3), 2349-2351(2), 2392, 2417, 2435-2437(2), 2460-2462(2), 2495-2496(2), 2526, 2550-2555(5), 2612, 2702-2706(4), 2734-2735(2), 2755-2760(4)

remove defined in line 75; used 3 times

- in line 1726, 1761, 1802

sb_atime defined in line 217; used 1 times

- in line 1090

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

- in line 1090

sb_dev defined in line 209; used 10 times

- in line 831, 891, 1174, 1269, 1315, 1722(2), 1733(2), 2166

sb_gid defined in line 214; used 10 times

- in line 722, 833, 895, 1178, 1833-1836(3), 2168, 2569-2572(2)

sb_ino defined in line 210; used 12 times

- in line 832, 892, 1175, 1254, 1268, 1316, 1322, 1721(2), 1732(2), 2167

sb_mode defined in line 211; used 26 times

- in line 76, 715-718(3), 750, 832, 893, 1075, 1176, 1310, 1664, 1724-1725(3), 1750-1751(2), 1765-1768(2), 1788-1791(2), 2167, 2173, 2266, 2562, 2573, 2598

sb_mtime defined in line 218; used 10 times

- in line 834, 898, 977, 1090, 1181, 1815(2), 2169, 2335, 2564

sb_nlink defined in line 212; used 10 times

- in line 833, 896, 1179, 1317, 1666, 1837, 1990, 2168, 2563, 2591

sb_rdev defined in line 215; used 10 times

- in line 833, 897, 1180, 1756(2), 1765-1768(2), 2168, 2577(2)

sb_size defined in line 216; used 25 times

- in line 789, 834, 899, 907, 964-965(2), 975, 1072-1081(4), 1182, 1190, 1318, 1667-1680(4), 1687, 1992-1997(2), 2169-2174(2), 2537, 2580

sb_uid defined in line 213; used 10 times

- in line 721, 832, 894, 1177, 1832-1835(3), 2167, 2565-2568(2)

strchr defined in line 145; used 4 times

- in line 304, 577-579(2), 1909

strrchr defined in line 146; used 2 times

- in line 307, 446

swab defined in line 81; used 13 times

- in line 1165, 1174-1183(12)

uint defined in line 94; used 48 times

- in line 302, 354, 406-415(4), 441, 501-505(2), 512, 631, 657, 804, 823, 855-857(2), 879, 921-926(2), 932, 1076, 1104-1107(3), 1134, 1162, 1339, 1356, 1377, 1572, 2011, 2023-2027(2), 2048-2051(2), 2057, 2081, 2111, 2156, 2164, 2174, 2229-2232(3), 2299, 2305, 2493, 2707

ush defined in line 87; used 15 times

- in line 721-722(2), 1835-1836(2), 2166-2168(7), 2565-2572(4)

ushort defined in line 95; never used

Last modified: 1996-03-22 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 4844 |