home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume12 / afio / part01 / afio.c.P2 < prev    next >
Encoding:
Text File  |  1987-10-25  |  28.6 KB  |  1,511 lines

  1.  
  2. /*
  3.  * linkleft()
  4.  *
  5.  * Complain about files with unseen links.
  6.  */
  7. STATIC void
  8. linkleft()
  9. {
  10.     reg Link    *lp;
  11.     reg Link    **base;
  12.  
  13.     for (base = linkbase; base < linkbase + nel(linkbase); ++base)
  14.         for (lp = *base; lp; lp = lp->l_forw)
  15.             if (lp->l_nlink)
  16.                 VOID warn(lp->l_path->p_name, "Unseen link(s)");
  17. }
  18.  
  19. /*
  20.  * linkto()
  21.  *
  22.  * Remember a file with outstanding links. Returns a
  23.  * pointer to the associated link structure, or NULL
  24.  * when linking is not possible.
  25.  */
  26. STATIC Link *
  27. linkto(name, asb)
  28. char        *name;
  29. reg Stat    *asb;
  30. {
  31.     reg Link    *linkp;
  32.     reg Path    *path;
  33.     reg Link    **abase;
  34.  
  35.     if ((asb->sb_mode & S_IFMT) == S_IFDIR
  36.         || (linkp = (Link *) memget(sizeof(Link))) == NULL
  37.         || (path = (Path *) memget(sizeof(Path))) == NULL
  38.         || (path->p_name = memstr(name)) == NULL)
  39.         return (NULL);
  40.     linkp->l_dev = asb->sb_dev;
  41.     linkp->l_ino = asb->sb_ino;
  42.     linkp->l_nlink = asb->sb_nlink - 1;
  43.     linkp->l_size = asb->sb_size;
  44.     linkp->l_path = path;
  45.     path->p_forw = NULL;
  46.     path->p_back = path;
  47.     if (linkp->l_forw = *(abase = linkhash(asb->sb_ino)))
  48.         linkp->l_forw->l_back = linkp;
  49.     linkp->l_back = NULL;
  50.     return (*abase = linkp);
  51. }
  52.  
  53. #ifndef    MEMCPY
  54.  
  55. /*
  56.  * memcpy()
  57.  *
  58.  * A simple block move.
  59.  */
  60. STATIC void
  61. memcpy(to, from, len)
  62. reg char    *to;
  63. reg char    *from;
  64. uint        len;
  65. {
  66.     reg char    *toend;
  67.  
  68.     for (toend = to + len; to < toend; *to++ = *from++)
  69.         ;
  70. }
  71.  
  72. #endif    /* MEMCPY */
  73.  
  74. /*
  75.  * memget()
  76.  *
  77.  * Allocate memory.
  78.  */
  79. STATIC char *
  80. memget(len)
  81. uint        len;
  82. {
  83.     reg char    *mem;
  84.     static short    outofmem;
  85.  
  86.     if ((mem = malloc(len)) == NULL && !outofmem)
  87.         outofmem = warn("memget()", "Out of memory");
  88.     return (mem);
  89. }
  90.  
  91. /*
  92.  * memstr()
  93.  *
  94.  * Duplicate a string into dynamic memory.
  95.  */
  96. STATIC char *
  97. memstr(str)
  98. reg char    *str;
  99. {
  100.     reg char    *mem;
  101.  
  102.     if (mem = memget((uint) strlen(str) + 1))
  103.         VOID strcpy(mem, str);
  104.     return (mem);
  105. }
  106.  
  107. #ifndef    MKDIR
  108.  
  109. /*
  110.  * mkdir()
  111.  *
  112.  * Make a directory via "/bin/mkdir". Sets errno to a
  113.  * questionably sane value upon failure.
  114.  */
  115. STATIC int
  116. mkdir(name, mode)
  117. reg char    *name;
  118. reg ushort    mode;
  119. {
  120.     reg int        pid;
  121.  
  122.     if ((pid = xfork("mkdir()")) == 0) {
  123.         VOID close(fileno(stdin));
  124.         VOID close(fileno(stdout));
  125.         VOID close(fileno(stderr));
  126.         VOID open("/dev/null", O_RDWR);
  127.         VOID dup(fileno(stdin));
  128.         VOID dup(fileno(stdin));
  129.         VOID umask(~mode);
  130.         VOID execl("/bin/mkdir", "mkdir", name, (char *) NULL);
  131.         exit(1);
  132.     }
  133.     if (xwait(pid, "mkdir()") == 0)
  134.         return (0);
  135.     errno = EACCES;
  136.     return (-1);
  137. }
  138.  
  139. #endif    /* MKDIR */
  140.  
  141. /*
  142.  * nameadd()
  143.  *
  144.  * Add a name to the pattern list.
  145.  */
  146. STATIC void
  147. nameadd(name, not)
  148. reg char    *name;
  149. int        not;
  150. {
  151.     reg Pattern    *px;
  152.  
  153.     px = (Pattern *) memget(sizeof(Pattern));
  154.     px->p_forw = pattern;
  155.     px->p_str = name;
  156.     px->p_len = strlen(name);
  157.     px->p_not = not;
  158.     pattern = px;
  159. }
  160.  
  161. /*
  162.  * namecmp()
  163.  *
  164.  * Compare a pathname with the pattern list. Returns 0 for
  165.  * a match, -1 otherwise.
  166.  */
  167. STATIC int
  168. namecmp(name)
  169. reg char    *name;
  170. {
  171.     reg Pattern    *px;
  172.     reg int        positive;
  173.     reg int        match;
  174.  
  175.     positive = match = 0;
  176.     for (px = pattern; px; px = px->p_forw) {
  177.         if (!px->p_not)
  178.             ++positive;
  179.         if (strncmp(name, px->p_str, px->p_len) == 0
  180.           && (name[px->p_len] == '/' || name[px->p_len] == '\0')) {
  181.             if (px->p_not)
  182.                 return (-1);
  183.             ++match;
  184.         }
  185.     }
  186.     return (match || !positive ? 0 : -1);
  187. }
  188.  
  189. /*
  190.  * nameopt()
  191.  *
  192.  * Optimize a pathname. Confused by "<symlink>/.." twistiness.
  193.  * Returns the number of final pathname elements (zero for "/"
  194.  * or ".") or -1 if unsuccessful.
  195.  */
  196. STATIC int
  197. nameopt(begin)
  198. char    *begin;
  199. {
  200.     reg char    *name;
  201.     reg char    *item;
  202.     reg int        idx;
  203.     int        absolute;
  204.     auto char    *element[PATHELEM];
  205.  
  206.     absolute = (*(name = begin) == '/');
  207.     idx = 0;
  208.     for (;;) {
  209.         if (idx == PATHELEM)
  210.             return (warn(begin, "Too many elements"));
  211.         while (*name == '/')
  212.             ++name;
  213.         if (*name == '\0')
  214.             break;
  215.         element[idx] = item = name;
  216.         while (*name && *name != '/')
  217.             ++name;
  218.         if (*name)
  219.             *name++ = '\0';
  220.         if (strcmp(item, "..") == 0)
  221.             if (idx == 0)
  222.                 if (absolute)
  223.                     ;
  224.                 else
  225.                     ++idx;
  226.             else if (strcmp(element[idx - 1], "..") == 0)
  227.                 ++idx;
  228.             else
  229.                 --idx;
  230.         else if (strcmp(item, ".") != 0)
  231.             ++idx;
  232.     }
  233.     if (idx == 0)
  234.         element[idx++] = absolute ? "" : ".";
  235.     element[idx] = NULL;
  236.     name = begin;
  237.     if (absolute)
  238.         *name++ = '/';
  239.     for (idx = 0; item = element[idx]; ++idx, *name++ = '/')
  240.         while (*item)
  241.             *name++ = *item++;
  242.     *--name = '\0';
  243.     return (idx);
  244. }
  245.  
  246. /*
  247.  * next()
  248.  *
  249.  * Advance to the next archive volume.
  250.  */
  251. STATIC void
  252. next(mode, why)
  253. reg int        mode;
  254. reg char    *why;
  255. {
  256.     reg time_t    began;
  257.     auto char    msg[200];
  258.     auto char    answer[20];
  259.  
  260.     began = time((time_t *) NULL);
  261.     nextclos();
  262.     VOID warnarch(why, (off_t) 0);
  263.     if (arfd == STDIN || arfd == STDOUT)
  264.         exit(1);
  265.     VOID sprintf(msg, "\
  266. %s: Ready for volume %u on \"%s\"\n\
  267. %s: Type \"go\" when ready to proceed (or \"quit\" to abort): \07",
  268.         myname, arvolume + 1, arspec, myname);
  269.     for (;;) {
  270.         nextask(msg, answer, sizeof(answer));
  271.         if (strcmp(answer, "quit") == 0)
  272.             fatal(arspec, "Aborted");
  273.         if (strcmp(answer, "go") == 0 && nextopen(mode) == 0)
  274.             break;
  275.     }
  276.     VOID warnarch("Continuing", (off_t) 0);
  277.     timewait += time((time_t *) NULL) - began;
  278. }
  279.  
  280. /*
  281.  * nextask()
  282.  *
  283.  * Ask a question and get a response. Ignores spaces and tabs.
  284.  */
  285. STATIC void
  286. nextask(msg, answer, limit)
  287. reg char    *msg;
  288. reg char    *answer;
  289. reg int        limit;
  290. {
  291.     reg int        idx;
  292.     reg int        got;
  293.     auto char    c;
  294.  
  295.     if (ttyf < 0)
  296.         fatal(TTY, "Unavailable");
  297.     VOID write(ttyf, msg, (uint) strlen(msg));
  298.     idx = 0;
  299.     while ((got = read(ttyf, &c, 1)) == 1)
  300.         if (c == '\04' || c == '\n')
  301.             break;
  302.         else if (c == ' ' || c == '\t')
  303.             continue;
  304.         else if (idx < limit - 1)
  305.             answer[idx++] = c;
  306.     if (got < 0)
  307.         fatal(TTY, syserr());
  308.     answer[idx] = '\0';
  309. }
  310.  
  311. /*
  312.  * nextclos()
  313.  *
  314.  * Close an archive.
  315.  */
  316. STATIC void
  317. nextclos()
  318. {
  319.     if (arfd != STDIN && arfd != STDOUT)
  320.         VOID close(arfd);
  321.     areof = 0;
  322.     if (arname && *arname == '!')
  323.         pipewait();
  324. }
  325.  
  326. /*
  327.  * nextopen()
  328.  *
  329.  * Open an archive. Returns 0 if successful, -1 otherwise.
  330.  */
  331. STATIC int
  332. nextopen(mode)
  333. int        mode;
  334. {
  335.     if (*arname == '!')
  336.         arfd = pipeopen(mode);
  337.     else if (strcmp(arname, "-") == 0)
  338.         arfd = mode ? STDOUT : STDIN;
  339.     else {
  340. #ifdef    CTC3B2
  341.         if (Cflag) {
  342.             reg int        oops;
  343.             reg int        fd;
  344.  
  345.             oops = ((fd = open(arname, O_RDWR | O_CTSPECIAL)) < 0
  346.                 || ioctl(fd, STREAMON) < 0);
  347.             VOID close(fd);
  348.             if (oops)
  349.                 return (warnarch(syserr(), (off_t) 0));
  350.         }
  351. #endif    /* CTC3B2 */
  352.         arfd = mode ? creat(arname, 0666 & ~mask) : open(arname, mode);
  353.     }
  354.     if (arfd < 0)
  355.         return (warnarch(syserr(), (off_t) 0));
  356.     arleft = aruntil;
  357.     ++arvolume;
  358.     return (0);
  359. }
  360.  
  361. /*
  362.  * openi()
  363.  *
  364.  * Open the next input file. Returns a file descriptor, 0 if no data
  365.  * exists, or -1 at EOF. This kludge works because standard input is
  366.  * in use, preventing open() from returning zero.
  367.  */
  368. STATIC int
  369. openi(name, asb)
  370. char        *name;
  371. reg Stat    *asb;
  372. {
  373.     reg int        fd;
  374.     auto char    local[PATHSIZE];
  375.  
  376.     for (;;) {
  377.         if (lineget(stdin, name) < 0)
  378.             return (-1);
  379.         if (nameopt(name) < 0)
  380.             continue;
  381.         if (!gflag)
  382.             VOID strcpy(local, name);
  383.         else if (dirchg(name, local) < 0)
  384.             continue;
  385.         if ((hflag ? STAT(local, asb) : LSTAT(local, asb)) < 0) {
  386.             VOID warn(name, syserr());
  387.             continue;
  388.         }
  389.         switch (asb->sb_mode & S_IFMT) {
  390.         case S_IFDIR:
  391.             asb->sb_nlink = 1;
  392.             asb->sb_size = 0;
  393.             return (0);
  394. #ifdef    S_IFLNK
  395.         case S_IFLNK:
  396.             if ((asb->sb_size = readlink(local,
  397.                 asb->sb_link, sizeof(asb->sb_link) - 1)) < 0) {
  398.                 VOID warn(name, syserr());
  399.                 continue;
  400.             }
  401.             asb->sb_link[asb->sb_size] = '\0';
  402.             return (0);
  403. #endif    /* S_IFLNK */
  404.         case S_IFREG:
  405.             if (asb->sb_size == 0)
  406.                 return (0);
  407.             if ((fd = open(local, O_RDONLY)) >= 0)
  408.                 return (fd);
  409.             VOID warn(name, syserr());
  410.             break;
  411.         default:
  412.             asb->sb_size = 0;
  413.             return (0);
  414.         }
  415.     }
  416. }
  417.  
  418. /*
  419.  * openo()
  420.  *
  421.  * Open an output file. Returns the output file descriptor,
  422.  * 0 if no data is required or -1 if unsuccessful. Note that
  423.  * UNIX open() will never return 0 because the standard input
  424.  * is in use.
  425.  */
  426. STATIC int
  427. openo(name, asb, linkp, ispass)
  428. char        *name;
  429. reg Stat    *asb;
  430. Link        *linkp;
  431. reg int        ispass;
  432. {
  433.     reg int        exists;
  434.     reg int        fd;
  435.     reg ushort    perm;
  436.     ushort        operm;
  437.     Path        *path;
  438.     auto Stat    osb;
  439. #ifdef    S_IFLNK
  440.     reg int        ssize;
  441.     auto char    sname[PATHSIZE];
  442. #endif    /* S_IFLNK */
  443.  
  444.     if (exists = (LSTAT(name, &osb) == 0))
  445.         if (ispass
  446.             && osb.sb_ino == asb->sb_ino
  447.             && osb.sb_dev == asb->sb_dev)
  448.             return (warn(name, "Same file"));
  449.         else if ((osb.sb_mode & S_IFMT) == (asb->sb_mode & S_IFMT))
  450.             operm = osb.sb_mode & (xflag ? S_IPERM : S_IPOPN);
  451.         else if (remove(name, &osb) < 0)
  452.             return (warn(name, syserr()));
  453.         else
  454.             exists = 0;
  455.     if (linkp) {
  456.         if (exists)
  457.             if (asb->sb_ino == osb.sb_ino
  458.                 && asb->sb_dev == osb.sb_dev)
  459.                 return (0);
  460.             else if (unlink(name) < 0)
  461.                 return (warn(name, syserr()));
  462.             else
  463.                 exists = 0;
  464.         for (path = linkp->l_path; path; path = path->p_forw)
  465.             if (link(path->p_name, name) == 0
  466.               || (errno == ENOENT
  467.                 && dirneed(name) == 0
  468.                 && link(path->p_name, name) == 0))
  469.                 return (0);
  470.             else if (errno != EXDEV)
  471.                 return (warn(name, syserr()));
  472.         VOID warn(name, "Link broken");
  473.         linkalso(linkp, name);
  474.     }
  475.     perm = asb->sb_mode & (xflag ? S_IPERM : S_IPOPN);
  476.     switch (asb->sb_mode & S_IFMT) {
  477.     case S_IFBLK:
  478.     case S_IFCHR:
  479.         fd = 0;
  480.         if (exists)
  481.             if (asb->sb_rdev == osb.sb_rdev)
  482.                 if (perm != operm && chmod(name, perm) < 0)
  483.                     return (warn(name, syserr()));
  484.                 else
  485.                     break;
  486.             else if (remove(name, &osb) < 0)
  487.                 return (warn(name, syserr()));
  488.             else
  489.                 exists = 0;
  490.         if (mknod(name, asb->sb_mode, asb->sb_rdev) < 0
  491.           && (errno != ENOENT
  492.             || dirneed(name) < 0
  493.             || mknod(name, asb->sb_mode, asb->sb_rdev) < 0))
  494.             return (warn(name, syserr()));
  495.         break;
  496.     case S_IFDIR:
  497.         if (exists)
  498.             if (perm != operm && chmod(name, perm) < 0)
  499.                 return (warn(name, syserr()));
  500.             else
  501.                 ;
  502.         else if (dirneed(name) < 0 || dirmake(name, asb) < 0)
  503.             return (warn(name, syserr()));
  504.         return (0);
  505. #ifdef    S_IFIFO
  506.     case S_IFIFO:
  507.         fd = 0;
  508.         if (exists)
  509.             if (perm != operm && chmod(name, perm) < 0)
  510.                 return (warn(name, syserr()));
  511.             else
  512.                 ;
  513.         else if (mknod(name, asb->sb_mode, (dev_t) 0) < 0
  514.           && (errno != ENOENT
  515.             || dirneed(name) < 0
  516.             || mknod(name, asb->sb_mode, (dev_t) 0) < 0))
  517.             return (warn(name, syserr()));
  518.         break;
  519. #endif    /* S_IFIFO */
  520. #ifdef    S_IFLNK
  521.     case S_IFLNK:
  522.         if (exists)
  523.             if ((ssize = readlink(name, sname, sizeof(sname))) < 0)
  524.                 return (warn(name, syserr()));
  525.             else if (strncmp(sname, asb->sb_link, ssize) == 0)
  526.                 return (0);
  527.             else if (remove(name, &osb) < 0)
  528.                 return (warn(name, syserr()));
  529.             else
  530.                 exists = 0;
  531.         if (symlink(asb->sb_link, name) < 0
  532.           && (errno != ENOENT
  533.             || dirneed(name) < 0
  534.             || symlink(asb->sb_link, name) < 0))
  535.             return (warn(name, syserr()));
  536.         return (0);    /* Can't chown()/chmod() a symbolic link */
  537. #endif    /* S_IFLNK */
  538.     case S_IFREG:
  539.         if (exists)
  540.             if (nflag && osb.sb_mtime > asb->sb_mtime)
  541.                 return (warn(name, "Newer file exists"));
  542.             else if (unlink(name) < 0)
  543.                 return (warn(name, syserr()));
  544.             else
  545.                 exists = 0;
  546.         if ((fd = creat(name, perm)) < 0
  547.           && (errno != ENOENT
  548.             || dirneed(name) < 0
  549.             || (fd = creat(name, perm)) < 0))
  550.             return (warn(name, syserr()));
  551.         break;
  552.     default:
  553.         return (warn(name, "Unknown filetype"));
  554.     }
  555.     if (xflag
  556.       && (!exists
  557.         || asb->sb_uid != osb.sb_uid
  558.         || asb->sb_gid != osb.sb_gid))
  559.         VOID chown(name,
  560.             uid == 0 ? ush(asb->sb_uid) : uid,
  561.             ush(asb->sb_gid));
  562.     if (linkp == NULL && asb->sb_nlink > 1)
  563.         VOID linkto(name, asb);
  564.     return (fd);
  565. }
  566.  
  567. /*
  568.  * openq()
  569.  *
  570.  * Open the terminal for interactive queries (sigh). Assumes that
  571.  * background processes ignore interrupts and that the open() or
  572.  * the isatty() will fail for processes which are not attached to
  573.  * terminals. Returns a file descriptor (-1 if unsuccessful).
  574.  */
  575. STATIC int
  576. openq()
  577. {
  578.     reg int        fd;
  579.     reg VOIDFN    (*intr)();
  580.  
  581.     if ((intr = signal(SIGINT, SIG_IGN)) == SIG_IGN)
  582.         return (-1);
  583.     VOID signal(SIGINT, intr);
  584.     if ((fd = open(TTY, O_RDWR)) < 0)
  585.         return (-1);
  586.     if (isatty(fd))
  587.         return (fd);
  588.     VOID close(fd);
  589.     return (-1);
  590. }
  591.  
  592. /*
  593.  * options()
  594.  *
  595.  * Decode most reasonable forms of UNIX option syntax. Takes main()-
  596.  * style argument indices (argc/argv) and a string of valid option
  597.  * letters. Letters denoting options with arguments must be followed
  598.  * by colons. With valid options, returns the option letter and points
  599.  * "optarg" at the associated argument (if any). Returns '?' for bad
  600.  * options and missing arguments. Returns zero when no options remain,
  601.  * leaving "optind" indexing the first remaining argument.
  602.  */
  603. STATIC int
  604. options(ac, av, proto)
  605. int        ac;
  606. register char    **av;
  607. char        *proto;
  608. {
  609.     register int    c;
  610.     register char    *idx;
  611.     static int    optsub;
  612.  
  613.     if (optind == 0) {
  614.         optind = 1;
  615.         optsub = 0;
  616.     }
  617.     optarg = NULL;
  618.     if (optind >= ac)
  619.         return (0);
  620.     if (optsub == 0 && (av[optind][0] != '-' || av[optind][1] == '\0'))
  621.         return (0);
  622.     switch (c = av[optind][++optsub]) {
  623.     case '\0':
  624.         ++optind;
  625.         optsub = 0;
  626.         return (options(ac, av, proto));
  627.     case '-':
  628.         ++optind;
  629.         optsub = 0;
  630.         return (0);
  631.     case ':':
  632.         return ('?');
  633.     }
  634.     if ((idx = strchr(proto, c)) == NULL)
  635.         return ('?');
  636.     if (idx[1] != ':')
  637.         return (c);
  638.     optarg = &av[optind][++optsub];
  639.     ++optind;
  640.     optsub = 0;
  641.     if (*optarg)
  642.         return (c);
  643.     if (optind >= ac)
  644.         return ('?');
  645.     optarg = av[optind++];
  646.     return (c);
  647. }
  648.  
  649. /*
  650.  * optsize()
  651.  *
  652.  * Interpret a "size" argument. Recognizes suffices for blocks
  653.  * (512-byte), kilobytes and megabytes and blocksize. Returns
  654.  * the size in bytes.
  655.  */
  656. STATIC off_t
  657. optsize(str)
  658. char        *str;
  659. {
  660.     reg char    *idx;
  661.     reg off_t    number;
  662.     reg off_t    result;
  663.  
  664.     result = 0;
  665.     idx = str;
  666.     for (;;) {
  667.         number = 0;
  668.         while (*idx >= '0' && *idx <= '9')
  669.             number = number * 10 + *idx++ - '0';
  670.         switch (*idx++) {
  671.         case 'b':
  672.             result += number * 512;
  673.             continue;
  674.         case 'k':
  675.             result += number * 1024;
  676.             continue;
  677.         case 'm':
  678.             result += number * 1024 * 1024;
  679.             continue;
  680.         case 'x':
  681.             result += number * arbsize;
  682.             continue;
  683.         case '+':
  684.             result += number;
  685.             continue;
  686.         case '\0':
  687.             result += number;
  688.             break;
  689.         default:
  690.             break;
  691.         }
  692.         break;
  693.     }
  694.     if (*--idx)
  695.         fatal(str, "Unrecognizable value");
  696.     return (result);
  697. }
  698.  
  699. /*
  700.  * out()
  701.  *
  702.  * Write an archive.
  703.  */
  704. STATIC VOIDFN
  705. out(av)
  706. char        **av;
  707. {
  708.     reg int        fd;
  709.     auto Stat    sb;
  710.     auto char    name[PATHSIZE];
  711.  
  712.     if (*av)
  713.         fatal(*av, "Extraneous argument");
  714.     while ((fd = openi(name, &sb)) >= 0) {
  715.         if (!lflag && sb.sb_nlink > 1)
  716.             if (linkfrom(&sb))
  717.                 sb.sb_size = 0;
  718.             else
  719.                 VOID linkto(name, &sb);
  720.         outhead(name, &sb);
  721.         if (fd)
  722.             VOID close(outdata(fd, name, sb.sb_size));
  723.         if (vflag)
  724.             VOID fprintf(stderr, "%s\n", name);
  725.     }
  726.     outeof(TRAILER, TRAILZ);
  727. }
  728.  
  729. /*
  730.  * outalloc()
  731.  *
  732.  * Allocate buffer space previously referenced by outavail().
  733.  */
  734. STATIC void
  735. outalloc(len)
  736. reg uint    len;
  737. {
  738.     bufidx += len;
  739.     total += len;
  740. }
  741.  
  742. /*
  743.  * outavail()
  744.  *
  745.  * Index buffer space for archive output. Stores a buffer pointer
  746.  * at a given location. Returns the number of bytes available.
  747.  */
  748. STATIC uint
  749. outavail(bufp)
  750. reg char    **bufp;
  751. {
  752.     reg uint    have;
  753.  
  754.     while ((have = bufend - bufidx) == 0)
  755.         outflush();
  756.     *bufp = bufidx;
  757.     return (have);
  758. }
  759.  
  760. /*
  761.  * outdata()
  762.  *
  763.  * Write archive data. Continues after file read errors, padding with
  764.  * null characters if neccessary. Always returns the given input file
  765.  * descriptor.
  766.  */
  767. STATIC int
  768. outdata(fd, name, size)
  769. int        fd;
  770. char        *name;
  771. reg off_t    size;
  772. {
  773.     reg uint    chunk;
  774.     reg int        got;
  775.     reg int        oops;
  776.     reg uint    avail;
  777.     auto char    *buf;
  778.  
  779.     oops = got = 0;
  780.     while (size) {
  781.         avail = outavail(&buf);
  782.         size -= (chunk = size < avail ? (uint) size : avail);
  783.         if (oops == 0 && (got = read(fd, buf, chunk)) < 0) {
  784.             oops = warn(name, syserr());
  785.             got = 0;
  786.         }
  787.         if (got < chunk) {
  788.             if (oops == NULL)
  789.                 oops = warn(name, "Early EOF");
  790.             while (got < chunk)
  791.                 buf[got++] = '\0';
  792.         }
  793.         outalloc(chunk);
  794.     }
  795.     return (fd);
  796. }
  797.  
  798. /*
  799.  * outeof()
  800.  *
  801.  * Write an archive trailer.
  802.  */
  803. STATIC void
  804. outeof(name, namelen)
  805. char        *name;
  806. reg uint    namelen;
  807. {
  808.     reg off_t    pad;
  809.     auto char    header[M_STRLEN + H_STRLEN + 1];
  810.  
  811.     if (pad = (total + M_STRLEN + H_STRLEN + namelen) % arpad)
  812.         pad = arpad - pad;
  813.     VOID strcpy(header, M_ASCII);
  814.     VOID sprintf(header + M_STRLEN, H_PRINT, 0, 0,
  815.         0, 0, 0, 1, 0, (time_t) 0, namelen, pad);
  816.     outwrite(header, M_STRLEN + H_STRLEN);
  817.     outwrite(name, namelen);
  818.     outpad(pad);
  819.     outflush();
  820.     if (fflag)
  821.         outwait();
  822. }
  823.  
  824. /*
  825.  * outflush()
  826.  *
  827.  * Flush the output buffer. Optionally fork()s to allow the
  828.  * parent to refill the buffer while the child waits for the
  829.  * write() to complete.
  830.  */
  831. STATIC void
  832. outflush()
  833. {
  834.     reg char    *buf;
  835.     reg int        got;
  836.     reg uint    len;
  837.  
  838.     if (aruntil && arleft == 0)
  839.         next(O_WRONLY, "Output limit reached");
  840.     if (fflag) {
  841.         outwait();
  842.         if ((outpid = xfork("outflush()")) == 0)
  843.             VOID nice(-40);
  844.     }
  845.     if (!fflag || outpid == 0) {
  846.         for (buf = buffer; len = bufidx - buf; ) {
  847.             if ((got = write(arfd, buf,
  848.                 *arname == '!' ? len : min(len, arbsize))) > 0) {
  849.                 buf += got;
  850.                 arleft -= got;
  851.             } else if (fflag) {
  852.                 VOID warn(arspec, got < 0
  853.                     ? syserr()
  854.                     : "Apparently full");
  855.                 _exit(1);
  856.             } else if (got < 0)
  857.                 fatal(arspec, syserr());
  858.             else
  859.                 next(O_WRONLY, "Apparently full");
  860.         }
  861.     }
  862.     if (fflag) {
  863.         if (outpid == 0)
  864.             _exit(0);
  865.         else
  866.             arleft -= bufidx - buffer;
  867.     }
  868.     bufend = (bufidx = buffer) + (aruntil ? min(buflen, arleft) : buflen);
  869. }
  870.  
  871. /*
  872.  * outhead()
  873.  *
  874.  * Write an archive header.
  875.  */
  876. STATIC void
  877. outhead(name, asb)
  878. reg char    *name;
  879. reg Stat    *asb;
  880. {
  881.     reg uint    namelen;
  882.     auto char    header[M_STRLEN + H_STRLEN + 1];
  883.  
  884.     if (name[0] == '/')
  885.         if (name[1])
  886.             ++name;
  887.         else
  888.             name = ".";
  889.     namelen = (uint) strlen(name) + 1;
  890.     VOID strcpy(header, M_ASCII);
  891.     VOID sprintf(header + M_STRLEN, H_PRINT, ush(asb->sb_dev),
  892.         ush(asb->sb_ino), ush(asb->sb_mode), ush(asb->sb_uid),
  893.         ush(asb->sb_gid), ush(asb->sb_nlink), ush(asb->sb_rdev),
  894.         mflag ? timenow : asb->sb_mtime, namelen, asb->sb_size);
  895.     outwrite(header, M_STRLEN + H_STRLEN);
  896.     outwrite(name, namelen);
  897. #ifdef    S_IFLNK
  898.     if ((asb->sb_mode & S_IFMT) == S_IFLNK)
  899.         outwrite(asb->sb_link, (uint) asb->sb_size);
  900. #endif    /* S_IFLNK */
  901. }
  902.  
  903. /*
  904.  * outpad()
  905.  *
  906.  * Pad the archive.
  907.  */
  908. STATIC void
  909. outpad(pad)
  910. reg off_t    pad;
  911. {
  912.     reg int        idx;
  913.     reg int        len;
  914.  
  915.     while (pad) {
  916.         if ((len = bufend - bufidx) > pad)
  917.             len = pad;
  918.         for (idx = 0; idx < len; ++idx)
  919.             *bufidx++ = '\0';
  920.         total += len;
  921.         outflush();
  922.         pad -= len;
  923.     }
  924. }
  925.  
  926. /*
  927.  * outwait()
  928.  *
  929.  * Wait for the last background outflush() process (if any). The child
  930.  * exit value is zero if successful, 255 if a write() returned zero or
  931.  * the value of errno if a write() was unsuccessful.
  932.  */
  933. STATIC void
  934. outwait()
  935. {
  936.     auto int    status;
  937.  
  938.     if (outpid == 0)
  939.         return;
  940.     status = xwait(outpid, "outwait()");
  941.     outpid = 0;
  942.     if (status)
  943.         fatal(arspec, "Child error");
  944. }
  945.  
  946. /*
  947.  * outwrite()
  948.  *
  949.  * Write archive data.
  950.  */
  951. STATIC void
  952. outwrite(idx, len)
  953. reg char    *idx;
  954. uint        len;
  955. {
  956.     reg uint    have;
  957.     reg uint    want;
  958.     reg char    *endx = idx + len;
  959.  
  960.     while (want = endx - idx) {
  961.         while ((have = bufend - bufidx) == 0)
  962.             outflush();
  963.         if (have > want)
  964.             have = want;
  965.         memcpy(bufidx, idx, have);
  966.         bufidx += have;
  967.         idx += have;
  968.         total += have;
  969.     }
  970. }
  971.  
  972. /*
  973.  * pass()
  974.  *
  975.  * Copy within the filesystem.
  976.  */
  977. STATIC VOIDFN
  978. pass(av)
  979. reg char    **av;
  980. {
  981.     reg int        fd;
  982.     reg char    **avx;
  983.     auto Stat    sb;
  984.     auto char    name[PATHSIZE];
  985.  
  986.     for (avx = av; *avx; ++avx) {
  987.         if (gflag && **avx != '/')
  988.             fatal(*avx, "Relative pathname");
  989.         if (STAT(*avx, &sb) < 0)
  990.             fatal(*avx, syserr());
  991.         if ((sb.sb_mode & S_IFMT) != S_IFDIR)
  992.             fatal(*avx, "Not a directory");
  993.     }
  994.     while ((fd = openi(name, &sb)) >= 0) {
  995.         if (passitem(name, &sb, fd, av))
  996.             VOID close(fd);
  997.         if (vflag)
  998.             VOID fprintf(stderr, "%s\n", name);
  999.     }
  1000. }
  1001.  
  1002. /*
  1003.  * passdata()
  1004.  *
  1005.  * Copy data to one file. Doesn't believe in input file
  1006.  * descriptor zero (see description of kludge in openi()
  1007.  * comments). Closes the provided output file descriptor.
  1008.  */
  1009. STATIC void
  1010. passdata(from, ifd, to, ofd)
  1011. char        *from;
  1012. reg int        ifd;
  1013. char        *to;
  1014. reg int        ofd;
  1015. {
  1016.     reg int        got;
  1017.     reg int        sparse;
  1018.     auto char    block[FSBUF];
  1019.  
  1020.     if (ifd) {
  1021.         VOID lseek(ifd, (off_t) 0, 0);
  1022.         sparse = 0;
  1023.         while ((got = read(ifd, block, sizeof(block))) > 0
  1024.             && (sparse = swrite(ofd, block, (uint) got)) >= 0)
  1025.             total += got;
  1026.         if (got)
  1027.             VOID warn(got < 0 ? from : to, syserr());
  1028.         else if (sparse > 0
  1029.           && (lseek(ofd, (off_t) -sparse, 1) < 0
  1030.             || write(ofd, block, (uint) sparse) != sparse))
  1031.             VOID warn(to, syserr());
  1032.     }
  1033.     VOID close(ofd);
  1034. }
  1035.  
  1036. /*
  1037.  * passitem()
  1038.  *
  1039.  * Copy one file. Returns given input file descriptor.
  1040.  */
  1041. STATIC int
  1042. passitem(from, asb, ifd, dir)
  1043. char        *from;
  1044. Stat        *asb;
  1045. reg int        ifd;
  1046. reg char    **dir;
  1047. {
  1048.     reg int        ofd;
  1049.     auto time_t    tstamp[2];
  1050.     auto char    to[PATHSIZE];
  1051.  
  1052.     while (*dir) {
  1053.         if (nameopt(strcat(strcat(strcpy(to, *dir++), "/"), from)) < 0)
  1054.             continue;
  1055.         if ((ofd = openo(to, asb,
  1056.             lflag ? linkto(from, asb) : linkfrom(asb), 1)) < 0)
  1057.             continue;
  1058.         if (ofd > 0)
  1059.             passdata(from, ifd, to, ofd);
  1060.         tstamp[0] = tstamp[1] = mflag ? timenow : asb->sb_mtime;
  1061.         VOID utime(to, tstamp);
  1062.     }
  1063.     return (ifd);
  1064. }
  1065.  
  1066. /*
  1067.  * pipechld()
  1068.  *
  1069.  * Child portion of pipeline fork.
  1070.  */
  1071. STATIC int
  1072. pipechld(mode, pfd)
  1073. int        mode;
  1074. reg int        *pfd;
  1075. {
  1076.     reg char    **av;
  1077.     auto char    *arg[32];
  1078.  
  1079.     av = arg;
  1080.     if ((*av = getenv("SHELL")) && **av)
  1081.         ++av;
  1082.     else
  1083.         *av++ = "/bin/sh";
  1084.     *av++ = "-c";
  1085.     *av++ = arname + 1;
  1086.     *av = NULL;
  1087.     if (mode) {
  1088.         VOID close(pfd[1]);
  1089.         VOID close(STDIN);
  1090.         VOID dup(pfd[0]);
  1091.         VOID close(pfd[0]);
  1092.         VOID close(STDOUT);
  1093.         VOID open("/dev/null", O_WRONLY);
  1094.     } else {
  1095.         VOID close(STDIN);
  1096.         VOID open("/dev/null", O_RDONLY);
  1097.         VOID close(pfd[0]);
  1098.         VOID close(STDOUT);
  1099.         VOID dup(pfd[1]);
  1100.         VOID close(pfd[1]);
  1101.     }
  1102.     if (ttyf >= 0)
  1103.         VOID close(ttyf);
  1104.     VOID execvp(arg[0], arg);
  1105.     VOID warn(arg[0], syserr());
  1106.     _exit(1);
  1107. }
  1108.  
  1109. /*
  1110.  * pipeopen()
  1111.  *
  1112.  * Open an archive via a pipeline. Returns a file
  1113.  * descriptor, or -1 if unsuccessful.
  1114.  */
  1115. STATIC int
  1116. pipeopen(mode)
  1117. reg int        mode;
  1118. {
  1119.     auto int    pfd[2];
  1120.  
  1121.     if (pipe(pfd) < 0)
  1122.         return (-1);
  1123.     if ((pipepid = xfork("pipeopen()")) == 0)
  1124.         pipechld(mode, pfd);
  1125.     if (mode) {
  1126.         VOID close(pfd[0]);
  1127.         return (pfd[1]);
  1128.     } else {
  1129.         VOID close(pfd[1]);
  1130.         return (pfd[0]);
  1131.     }
  1132. }
  1133.  
  1134. /*
  1135.  * pipewait()
  1136.  *
  1137.  * Await a pipeline.
  1138.  */
  1139. STATIC void
  1140. pipewait()
  1141. {
  1142.     reg int        status;
  1143.  
  1144.     if (pipepid == 0)
  1145.         return;
  1146.     status = xwait(pipepid, "pipewait()");
  1147.     pipepid = 0;
  1148.     if (status)
  1149.         fatal(arspec, "Pipeline error");
  1150. }
  1151.  
  1152. /*
  1153.  * prsize()
  1154.  *
  1155.  * Print a file offset.
  1156.  */
  1157. STATIC void
  1158. prsize(stream, size)
  1159. FILE        *stream;
  1160. reg off_t    size;
  1161. {
  1162.     reg off_t    n;
  1163.  
  1164.     if (n = (size / (1024 * 1024))) {
  1165.         VOID fprintf(stream, "%ldm+", n);
  1166.         size -= n * 1024 * 1024;
  1167.     }
  1168.     if (n = (size / 1024)) {
  1169.         VOID fprintf(stream, "%ldk+", n);
  1170.         size -= n * 1024;
  1171.     }
  1172.     VOID fprintf(stream, "%ld", size);
  1173. }
  1174.  
  1175. #ifndef    MKDIR
  1176.  
  1177. /*
  1178.  * rmdir()
  1179.  *
  1180.  * Remove a directory via "/bin/rmdir". Sets errno to a
  1181.  * questionably sane value upon failure.
  1182.  */
  1183. STATIC int
  1184. rmdir(name)
  1185. reg char    *name;
  1186. {
  1187.     reg int        pid;
  1188.  
  1189.     if ((pid = xfork("rmdir()")) == 0) {
  1190.         VOID close(fileno(stdin));
  1191.         VOID close(fileno(stdout));
  1192.         VOID close(fileno(stderr));
  1193.         VOID open("/dev/null", O_RDWR);
  1194.         VOID dup(fileno(stdin));
  1195.         VOID dup(fileno(stdin));
  1196.         VOID execl("/bin/rmdir", "rmdir", name, (char *) NULL);
  1197.         exit(1);
  1198.     }
  1199.     if (xwait(pid, "rmdir()") == 0)
  1200.         return (0);
  1201.     errno = EACCES;
  1202.     return (-1);
  1203. }
  1204.  
  1205. #endif    /* MKDIR */
  1206.  
  1207. /*
  1208.  * swrite()
  1209.  *
  1210.  * Write a filesystem block. Seeks past sparse blocks. Returns
  1211.  * 0 if the block was written, the given length for a sparse
  1212.  * block or -1 if unsuccessful.
  1213.  */
  1214. STATIC int
  1215. swrite(fd, buf, len)
  1216. int        fd;
  1217. char        *buf;
  1218. uint        len;
  1219. {
  1220.     reg char    *bidx;
  1221.     reg char    *bend;
  1222.  
  1223.     if (jflag)
  1224.         return (write(fd, buf, len) == len ? 0 : -1);
  1225.     bend = (bidx = buf) + len;
  1226.     while (bidx < bend)
  1227.         if (*bidx++)
  1228.             return (write(fd, buf, len) == len ? 0 : -1);
  1229.     return (lseek(fd, (off_t) len, 1) < 0 ? -1 : len);
  1230. }
  1231.  
  1232. /*
  1233.  * syserr()
  1234.  *
  1235.  * Return pointer to appropriate system error message.
  1236.  */
  1237. STATIC char *
  1238. syserr()
  1239. {
  1240.     static char    msg[40];
  1241.  
  1242.     if (errno > 0 && errno < sys_nerr)
  1243.         return (sys_errlist[errno]);
  1244.     VOID sprintf(msg, "Unknown error (errno %d)", errno);
  1245.     return (msg);
  1246. }
  1247.  
  1248. /*
  1249.  * toc()
  1250.  *
  1251.  * Print archive table of contents.
  1252.  */
  1253. STATIC VOIDFN
  1254. toc(av)
  1255. reg char    **av;
  1256. {
  1257.     auto Stat    sb;
  1258.     auto char    name[PATHSIZE];
  1259.  
  1260.     if (*av)
  1261.         fatal(*av, "Extraneous argument");
  1262.     name[0] = '\0';
  1263.     while (inhead(name, &sb) == 0) {
  1264.         if (namecmp(name) == 0)
  1265.             tocentry(name, &sb);
  1266.         if (inskip(sb.sb_size) < 0)
  1267.             VOID warn(name, "File data is corrupt");
  1268.     }
  1269. }
  1270.  
  1271. /*
  1272.  * tocentry()
  1273.  *
  1274.  * Print a single table-of-contents entry.
  1275.  */
  1276. STATIC void
  1277. tocentry(name, asb)
  1278. char        *name;
  1279. reg Stat    *asb;
  1280. {
  1281.     reg Time    *atm;
  1282.     reg Link    *from;
  1283.     reg Passwd    *pwp;
  1284.     reg Group    *grp;
  1285.     static char    *month[] = {
  1286.         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1287.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  1288.     };
  1289.  
  1290.     if (vflag) {
  1291.         tocmode(asb->sb_mode);
  1292.         VOID printf(" %2d", asb->sb_nlink);
  1293.         atm = localtime(&asb->sb_mtime);
  1294.         if (pwp = getpwuid(ush(asb->sb_uid)))
  1295.             VOID printf(" %-8s", pwp->pw_name);
  1296.         else
  1297.             VOID printf(" %-8u", ush(asb->sb_uid));
  1298.         if (grp = getgrgid(ush(asb->sb_gid)))
  1299.             VOID printf(" %-8s", grp->gr_name);
  1300.         else
  1301.             VOID printf(" %-8u", ush(asb->sb_gid));
  1302.         switch (asb->sb_mode & S_IFMT) {
  1303.         case S_IFBLK:
  1304.         case S_IFCHR:
  1305.             VOID printf(" %3d, %3d",
  1306.                 major(asb->sb_rdev), minor(asb->sb_rdev));
  1307.             break;
  1308.         case S_IFREG:
  1309.             VOID printf(" %8ld", asb->sb_size);
  1310.             break;
  1311.         default:
  1312.             VOID printf("         ");
  1313.         }
  1314.         VOID printf(" %3s %2d %02d:%02d:%02d %4d ",
  1315.             month[atm->tm_mon], atm->tm_mday, atm->tm_hour,
  1316.             atm->tm_min, atm->tm_sec, atm->tm_year + 1900);
  1317.     }
  1318.     VOID printf("%s", name);
  1319.     if (vflag || lflag) {
  1320.         if (asb->sb_nlink > 1)
  1321.             if (from = linkfrom(asb))
  1322.                 VOID printf(" -> %s",
  1323.                     from->l_path->p_name);
  1324.             else
  1325.                 VOID linkto(name, asb);
  1326. #ifdef    S_IFLNK
  1327.         if ((asb->sb_mode & S_IFMT) == S_IFLNK)
  1328.             VOID printf(" S-> %s", asb->sb_link);
  1329. #endif    /* S_IFLNK */
  1330.     }
  1331.     putchar('\n');
  1332. }
  1333.  
  1334. /*
  1335.  * tocmode()
  1336.  *
  1337.  * Fancy file mode display.
  1338.  */
  1339. STATIC void
  1340. tocmode(mode)
  1341. reg ushort    mode;
  1342. {
  1343.     switch (mode & S_IFMT) {
  1344.         case S_IFREG: putchar('-'); break;
  1345.         case S_IFDIR: putchar('d'); break;
  1346. #ifdef    S_IFLNK
  1347.         case S_IFLNK: putchar('l'); break;
  1348. #endif    /* S_IFLNK */
  1349.         case S_IFBLK: putchar('b'); break;
  1350.         case S_IFCHR: putchar('c'); break;
  1351. #ifdef    S_IFIFO
  1352.         case S_IFIFO: putchar('p'); break;
  1353. #endif    /* S_IFIFO */
  1354.         default:
  1355.             VOID printf("[%o]", mode >> S_IFSHF);
  1356.     }
  1357.     putchar(mode & 0400 ? 'r' : '-');
  1358.     putchar(mode & 0200 ? 'w' : '-');
  1359.     putchar(mode & 0100
  1360.         ? mode & 04000 ? 's' : 'x'
  1361.         : mode & 04000 ? 'S' : '-');
  1362.     putchar(mode & 0040 ? 'r' : '-');
  1363.     putchar(mode & 0020 ? 'w' : '-');
  1364.     putchar(mode & 0010
  1365.         ? mode & 02000 ? 's' : 'x'
  1366.         : mode & 02000 ? 'S' : '-');
  1367.     putchar(mode & 0004 ? 'r' : '-');
  1368.     putchar(mode & 0002 ? 'w' : '-');
  1369.     putchar(mode & 0001
  1370.         ? mode & 01000 ? 't' : 'x'
  1371.         : mode & 01000 ? 'T' : '-');
  1372. }
  1373.  
  1374. /*
  1375.  * usage()
  1376.  *
  1377.  * Print a helpful message and exit.
  1378.  */
  1379. STATIC void
  1380. usage()
  1381. {
  1382.     VOID fprintf(stderr, "\
  1383. Usage:    %s -o [ -fghlmuvz ] [ -(bces) n ] archive\n\
  1384.     %s -i [ -djkmnuvxz ] [ -(bcs) n ] [ -y prefix ] archive\n\
  1385.     %s -t [ -kuvz ] [ -(bcs) n ] [ -y prefix ] archive\n\
  1386.     %s -p [ -dghjlmnuvxz ] dir [ ... ]\n",
  1387.         myname, myname, myname, myname);
  1388.     exit(1);
  1389. }
  1390.  
  1391. /*
  1392.  * warn()
  1393.  *
  1394.  * Print a warning message. Always returns -1.
  1395.  */
  1396. STATIC int
  1397. warn(what, why)
  1398. char    *what;
  1399. char    *why;
  1400. {
  1401.     VOID fprintf(stderr,
  1402.         "%s: \"%s\": %s\n",
  1403.         myname, what, why);
  1404.     return (-1);
  1405. }
  1406.  
  1407. /*
  1408.  * warnarch()
  1409.  *
  1410.  * Print an archive-related warning message, including
  1411.  * an adjusted file offset. Always returns -1.
  1412.  */
  1413. STATIC int
  1414. warnarch(msg, adjust)
  1415. char    *msg;
  1416. off_t    adjust;
  1417. {
  1418.     VOID fprintf(stderr, "%s: \"%s\" [offset ", myname, arspec);
  1419.     prsize(stderr, total - adjust);
  1420.     VOID fprintf(stderr, "]: %s\n", msg);
  1421.     return (-1);
  1422. }
  1423.  
  1424. /*
  1425.  * xfork()
  1426.  *
  1427.  * Create a child.
  1428.  */
  1429. STATIC int
  1430. xfork(what)
  1431. reg char    *what;
  1432. {
  1433.     reg int        pid;
  1434.     reg Child    *cp;
  1435.     reg int        idx;
  1436.     static uint    delay[] = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 };
  1437.  
  1438.     for (idx = 0; (pid = fork()) < 0; ++idx) {
  1439.         if (idx == sizeof(delay))
  1440.             fatal(arspec, syserr());
  1441.         VOID warn(what, "Trouble forking...");
  1442.         sleep(delay[idx]);
  1443.     }
  1444.     if (idx)
  1445.         VOID warn(what, "...successful fork");
  1446.     cp = (Child *) memget(sizeof(*cp));
  1447.     cp->c_pid = pid;
  1448.     cp->c_flags = 0;
  1449.     cp->c_status = 0;
  1450.     cp->c_forw = children;
  1451.     children = cp;
  1452.     return (pid);
  1453. }
  1454.  
  1455. /*
  1456.  * xpause()
  1457.  *
  1458.  * Await a child.
  1459.  */
  1460. STATIC void
  1461. xpause()
  1462. {
  1463.     reg Child    *cp;
  1464.     reg int        pid;
  1465.     auto int    status;
  1466.  
  1467.     do {
  1468.         while ((pid = wait(&status)) < 0)
  1469.             ;
  1470.         for (cp = children; cp && cp->c_pid != pid; cp = cp->c_forw)
  1471.             ;
  1472.     } while (cp == NULL);
  1473.     cp->c_flags |= CF_EXIT;
  1474.     cp->c_status = status;
  1475. }
  1476.  
  1477. /*
  1478.  * xwait()
  1479.  *
  1480.  * Find the status of a child.
  1481.  */
  1482. STATIC int
  1483. xwait(pid, what)
  1484. reg int        pid;
  1485. char        *what;
  1486. {
  1487.     reg int        status;
  1488.     reg Child    *cp;
  1489.     reg Child    **acp;
  1490.     auto char    why[100];
  1491.  
  1492.     for (acp = &children; cp = *acp; acp = &cp->c_forw)
  1493.         if (cp->c_pid == pid)
  1494.             break;
  1495.     if (cp == NULL)
  1496.         fatal(what, "Lost child");
  1497.     while ((cp->c_flags & CF_EXIT) == 0)
  1498.         xpause();
  1499.     status = cp->c_status;
  1500.     *acp = cp->c_forw;
  1501.     free((char *) cp);
  1502.     if (status == 0)
  1503.         return (0);
  1504.     if (status & 0377)
  1505.         VOID sprintf(why, "Killed by signal %d%s",
  1506.             status & 0177, status & 0200 ? " -- core dumped" : "");
  1507.     else
  1508.         VOID sprintf(why, "Exit %d", (status >> 8) & 0377);
  1509.     return (warn(what, why));
  1510. }
  1511.