home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-B.05 / NETKIT-B / NetKit-B-0.05 / rdist / server.c < prev   
Encoding:
C/C++ Source or Header  |  1994-07-25  |  32.2 KB  |  1,589 lines

  1. /*
  2.  * Copyright (c) 1983, 1993
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. /* from: static char sccsid[] = "@(#)server.c    8.1 (Berkeley) 6/9/93"; */
  36. static char *rcsid = "$Id: server.c,v 1.1 1994/07/25 12:51:09 florian Exp florian $";
  37. #endif /* not lint */
  38.  
  39. #include <sys/wait.h>
  40. #include "defs.h"
  41.  
  42. #define    ack()     (void) write(rem, "\0\n", 2)
  43. #define    err()     (void) write(rem, "\1\n", 2)
  44.  
  45. #include <signal.h>
  46.  
  47. struct    linkbuf *ihead;        /* list of files with more than one link */
  48. char    buf[BUFSIZ];        /* general purpose buffer */
  49. char    target[BUFSIZ];        /* target/source directory name */
  50. char    *tp;            /* pointer to end of target name */
  51. char    *Tdest;            /* pointer to last T dest*/
  52. int    catname;        /* cat name to target name */
  53. char    *stp[32];        /* stack of saved tp's for directories */
  54. int    oumask;            /* old umask for creating files */
  55.  
  56. extern    FILE *lfp;        /* log file for mailing changes */
  57.  
  58. static int    chkparent __P((char *));
  59. static void    clean __P((char *));
  60. static void    comment __P((char *));
  61. static void    dospecial __P((char *));
  62. static int    fchog __P((int, char *, char *, char *, int));
  63. static void    hardlink __P((char *));
  64. static void    note __P((const char *, ...));
  65. static void    query __P((char *));
  66. static void    recvf __P((char *, int));
  67. static void    removeit __P((struct stat *));
  68. static int    response __P((void));
  69. static void    rmchk __P((int));
  70. static struct linkbuf *
  71.             savelink __P((struct stat *));
  72. static void    sendf __P((char *, int));
  73. static int    update __P((char *, int, struct stat *));
  74.  
  75. /*
  76.  * Server routine to read requests and process them.
  77.  * Commands are:
  78.  *    Tname    - Transmit file if out of date
  79.  *    Vname    - Verify if file out of date or not
  80.  *    Qname    - Query if file exists. Return mtime & size if it does.
  81.  */
  82. void
  83. server()
  84. {
  85.     char cmdbuf[BUFSIZ];
  86.     register char *cp;
  87.  
  88.     signal(SIGHUP, cleanup);
  89.     signal(SIGINT, cleanup);
  90.     signal(SIGQUIT, cleanup);
  91.     signal(SIGTERM, cleanup);
  92.     signal(SIGPIPE, cleanup);
  93.  
  94.     rem = 0;
  95.     oumask = umask(0);
  96.     (void) sprintf(buf, "V%d\n", VERSION);
  97.     (void) write(rem, buf, strlen(buf));
  98.  
  99.     for (;;) {
  100.         cp = cmdbuf;
  101.         if (read(rem, cp, 1) <= 0)
  102.             return;
  103.         if (*cp++ == '\n') {
  104.             error("server: expected control record\n");
  105.             continue;
  106.         }
  107.         do {
  108.             if (read(rem, cp, 1) != 1)
  109.                 cleanup(0);
  110.         } while (*cp++ != '\n' && cp < &cmdbuf[BUFSIZ]);
  111.         *--cp = '\0';
  112.         cp = cmdbuf;
  113.         switch (*cp++) {
  114.         case 'T':  /* init target file/directory name */
  115.             catname = 1;    /* target should be directory */
  116.             goto dotarget;
  117.  
  118.         case 't':  /* init target file/directory name */
  119.             catname = 0;
  120.         dotarget:
  121.             if (exptilde(target, cp) == NULL)
  122.                 continue;
  123.             tp = target;
  124.             while (*tp)
  125.                 tp++;
  126.             ack();
  127.             continue;
  128.  
  129.         case 'R':  /* Transfer a regular file. */
  130.             recvf(cp, S_IFREG);
  131.             continue;
  132.  
  133.         case 'D':  /* Transfer a directory. */
  134.             recvf(cp, S_IFDIR);
  135.             continue;
  136.  
  137.         case 'K':  /* Transfer symbolic link. */
  138.             recvf(cp, S_IFLNK);
  139.             continue;
  140.  
  141.         case 'k':  /* Transfer hard link. */
  142.             hardlink(cp);
  143.             continue;
  144.  
  145.         case 'E':  /* End. (of directory) */
  146.             *tp = '\0';
  147.             if (catname <= 0) {
  148.                 error("server: too many 'E's\n");
  149.                 continue;
  150.             }
  151.             tp = stp[--catname];
  152.             *tp = '\0';
  153.             ack();
  154.             continue;
  155.  
  156.         case 'C':  /* Clean. Cleanup a directory */
  157.             clean(cp);
  158.             continue;
  159.  
  160.         case 'Q':  /* Query. Does the file/directory exist? */
  161.             query(cp);
  162.             continue;
  163.  
  164.         case 'S':  /* Special. Execute commands */
  165.             dospecial(cp);
  166.             continue;
  167.  
  168. #ifdef notdef
  169.         /*
  170.          * These entries are reserved but not currently used.
  171.          * The intent is to allow remote hosts to have master copies.
  172.          * Currently, only the host rdist runs on can have masters.
  173.          */
  174.         case 'X':  /* start a new list of files to exclude */
  175.             except = bp = NULL;
  176.         case 'x':  /* add name to list of files to exclude */
  177.             if (*cp == '\0') {
  178.                 ack();
  179.                 continue;
  180.             }
  181.             if (*cp == '~') {
  182.                 if (exptilde(buf, cp) == NULL)
  183.                     continue;
  184.                 cp = buf;
  185.             }
  186.             if (bp == NULL)
  187.                 except = bp = expand(makeblock(NAME, cp), E_VARS);
  188.             else
  189.                 bp->b_next = expand(makeblock(NAME, cp), E_VARS);
  190.             while (bp->b_next != NULL)
  191.                 bp = bp->b_next;
  192.             ack();
  193.             continue;
  194.  
  195.         case 'I':  /* Install. Transfer file if out of date. */
  196.             opts = 0;
  197.             while (*cp >= '0' && *cp <= '7')
  198.                 opts = (opts << 3) | (*cp++ - '0');
  199.             if (*cp++ != ' ') {
  200.                 error("server: options not delimited\n");
  201.                 return;
  202.             }
  203.             install(cp, opts);
  204.             continue;
  205.  
  206.         case 'L':  /* Log. save message in log file */
  207.             log(lfp, cp);
  208.             continue;
  209. #endif
  210.  
  211.         case '\1':
  212.             nerrs++;
  213.             continue;
  214.  
  215.         case '\2':
  216.             return;
  217.  
  218.         default:
  219.             error("server: unknown command '%s'\n", cp);
  220.         case '\0':
  221.             continue;
  222.         }
  223.     }
  224. }
  225.  
  226. /*
  227.  * Update the file(s) if they are different.
  228.  * destdir = 1 if destination should be a directory
  229.  * (i.e., more than one source is being copied to the same destination).
  230.  */
  231. void
  232. install(src, dest, destdir, opts)
  233.     char *src, *dest;
  234.     int destdir, opts;
  235. {
  236.     char *rname;
  237.     char destcopy[BUFSIZ];
  238.  
  239.     if (dest == NULL) {
  240.         opts &= ~WHOLE; /* WHOLE mode only useful if renaming */
  241.         dest = src;
  242.     }
  243.  
  244.     if (nflag || debug) {
  245.         printf("%s%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install",
  246.             opts & WHOLE ? " -w" : "",
  247.             opts & YOUNGER ? " -y" : "",
  248.             opts & COMPARE ? " -b" : "",
  249.             opts & REMOVE ? " -R" : "", src, dest);
  250.         if (nflag)
  251.             return;
  252.     }
  253.  
  254.     rname = exptilde(target, src);
  255.     if (rname == NULL)
  256.         return;
  257.     tp = target;
  258.     while (*tp)
  259.         tp++;
  260.     /*
  261.      * If we are renaming a directory and we want to preserve
  262.      * the directory heirarchy (-w), we must strip off the leading
  263.      * directory name and preserve the rest.
  264.      */
  265.     if (opts & WHOLE) {
  266.         while (*rname == '/')
  267.             rname++;
  268.         destdir = 1;
  269.     } else {
  270.         rname = rindex(target, '/');
  271.         if (rname == NULL)
  272.             rname = target;
  273.         else
  274.             rname++;
  275.     }
  276.     if (debug)
  277.         printf("target = %s, rname = %s\n", target, rname);
  278.     /*
  279.      * Pass the destination file/directory name to remote.
  280.      */
  281.     (void) sprintf(buf, "%c%s\n", destdir ? 'T' : 't', dest);
  282.     if (debug)
  283.         printf("buf = %s", buf);
  284.     (void) write(rem, buf, strlen(buf));
  285.     if (response() < 0)
  286.         return;
  287.  
  288.     if (destdir) {
  289.         strcpy(destcopy, dest);
  290.         Tdest = destcopy;
  291.     }
  292.     sendf(rname, opts);
  293.     Tdest = 0;
  294. }
  295.  
  296. #define protoname() (pw ? pw->pw_name : user)
  297. #define protogroup() (gr ? gr->gr_name : group)
  298. /*
  299.  * Transfer the file or directory in target[].
  300.  * rname is the name of the file on the remote host.
  301.  */
  302. static void
  303. sendf(rname, opts)
  304.     char *rname;
  305.     int opts;
  306. {
  307.     register struct subcmd *sc;
  308.     struct stat stb;
  309.     int sizerr, f, u, len;
  310.     off_t i;
  311.     DIR *d;
  312.     struct direct *dp;
  313.     char *otp, *cp;
  314.     extern struct subcmd *subcmds;
  315.     static char user[15], group[15];
  316.  
  317.     if (debug)
  318.         printf("sendf(%s, %x)\n", rname, opts);
  319.  
  320.     if (except(target))
  321.         return;
  322.     if ((opts & FOLLOW ? stat(target, &stb) : lstat(target, &stb)) < 0) {
  323.         error("%s: %s\n", target, strerror(errno));
  324.         return;
  325.     }
  326.     if ((u = update(rname, opts, &stb)) == 0) {
  327.         if ((stb.st_mode & S_IFMT) == S_IFREG && stb.st_nlink > 1)
  328.             (void) savelink(&stb);
  329.         return;
  330.     }
  331.  
  332.     if (pw == NULL || pw->pw_uid != stb.st_uid)
  333.         if ((pw = getpwuid(stb.st_uid)) == NULL) {
  334.             log(lfp, "%s: no password entry for uid %d \n",
  335.                 target, stb.st_uid);
  336.             pw = NULL;
  337.             (void)sprintf(user, ":%lu", stb.st_uid);
  338.         }
  339.     if (gr == NULL || gr->gr_gid != stb.st_gid)
  340.         if ((gr = getgrgid(stb.st_gid)) == NULL) {
  341.             log(lfp, "%s: no name for group %d\n",
  342.                 target, stb.st_gid);
  343.             gr = NULL;
  344.             (void)sprintf(group, ":%lu", stb.st_gid);
  345.         }
  346.     if (u == 1) {
  347.         if (opts & VERIFY) {
  348.             log(lfp, "need to install: %s\n", target);
  349.             goto dospecial;
  350.         }
  351.         log(lfp, "installing: %s\n", target);
  352.         opts &= ~(COMPARE|REMOVE);
  353.     }
  354.  
  355.     switch (stb.st_mode & S_IFMT) {
  356.     case S_IFDIR:
  357.         if ((d = opendir(target)) == NULL) {
  358.             error("%s: %s\n", target, strerror(errno));
  359.             return;
  360.         }
  361.         (void) sprintf(buf, "D%o %04o 0 0 %s %s %s\n", opts,
  362.             stb.st_mode & 07777, protoname(), protogroup(), rname);
  363.         if (debug)
  364.             printf("buf = %s", buf);
  365.         (void) write(rem, buf, strlen(buf));
  366.         if (response() < 0) {
  367.             closedir(d);
  368.             return;
  369.         }
  370.  
  371.         if (opts & REMOVE)
  372.             rmchk(opts);
  373.  
  374.         otp = tp;
  375.         len = tp - target;
  376.         while (dp = readdir(d)) {
  377.             if (!strcmp(dp->d_name, ".") ||
  378.                 !strcmp(dp->d_name, ".."))
  379.                 continue;
  380.             if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
  381.                 error("%s/%s: Name too long\n", target,
  382.                     dp->d_name);
  383.                 continue;
  384.             }
  385.             tp = otp;
  386.             *tp++ = '/';
  387.             cp = dp->d_name;
  388.             while (*tp++ = *cp++)
  389.                 ;
  390.             tp--;
  391.             sendf(dp->d_name, opts);
  392.         }
  393.         closedir(d);
  394.         (void) write(rem, "E\n", 2);
  395.         (void) response();
  396.         tp = otp;
  397.         *tp = '\0';
  398.         return;
  399.  
  400.     case S_IFLNK:
  401.         if (u != 1)
  402.             opts |= COMPARE;
  403.         if (stb.st_nlink > 1) {
  404.             struct linkbuf *lp;
  405.  
  406.             if ((lp = savelink(&stb)) != NULL) {
  407.                 /* install link */
  408.                 if (*lp->target == 0)
  409.                 (void) sprintf(buf, "k%o %s %s\n", opts,
  410.                     lp->pathname, rname);
  411.                 else
  412.                 (void) sprintf(buf, "k%o %s/%s %s\n", opts,
  413.                     lp->target, lp->pathname, rname);
  414.                 if (debug)
  415.                     printf("buf = %s", buf);
  416.                 (void) write(rem, buf, strlen(buf));
  417.                 (void) response();
  418.                 return;
  419.             }
  420.         }
  421.         (void) sprintf(buf, "K%o %o %d %ld %s %s %s\n", opts,
  422.             stb.st_mode & 07777, stb.st_size, stb.st_mtime,
  423.             protoname(), protogroup(), rname);
  424.         if (debug)
  425.             printf("buf = %s", buf);
  426.         (void) write(rem, buf, strlen(buf));
  427.         if (response() < 0)
  428.             return;
  429.         sizerr = (readlink(target, buf, BUFSIZ) != stb.st_size);
  430.         (void) write(rem, buf, stb.st_size);
  431.         if (debug)
  432.             printf("readlink = %.*s\n", (int)stb.st_size, buf);
  433.         goto done;
  434.  
  435.     case S_IFREG:
  436.         break;
  437.  
  438.     default:
  439.         error("%s: not a file or directory\n", target);
  440.         return;
  441.     }
  442.  
  443.     if (u == 2) {
  444.         if (opts & VERIFY) {
  445.             log(lfp, "need to update: %s\n", target);
  446.             goto dospecial;
  447.         }
  448.         log(lfp, "updating: %s\n", target);
  449.     }
  450.  
  451.     if (stb.st_nlink > 1) {
  452.         struct linkbuf *lp;
  453.  
  454.         if ((lp = savelink(&stb)) != NULL) {
  455.             /* install link */
  456.             if (*lp->target == 0)
  457.             (void) sprintf(buf, "k%o %s %s\n", opts,
  458.                 lp->pathname, rname);
  459.             else
  460.             (void) sprintf(buf, "k%o %s/%s %s\n", opts,
  461.                 lp->target, lp->pathname, rname);
  462.             if (debug)
  463.                 printf("buf = %s", buf);
  464.             (void) write(rem, buf, strlen(buf));
  465.             (void) response();
  466.             return;
  467.         }
  468.     }
  469.  
  470.     if ((f = open(target, O_RDONLY, 0)) < 0) {
  471.         error("%s: %s\n", target, strerror(errno));
  472.         return;
  473.     }
  474.     (void) sprintf(buf, "R%o %o %d %ld %s %s %s\n", opts,
  475.         stb.st_mode & 07777, stb.st_size, stb.st_mtime,
  476.         protoname(), protogroup(), rname);
  477.     if (debug)
  478.         printf("buf = %s", buf);
  479.     (void) write(rem, buf, strlen(buf));
  480.     if (response() < 0) {
  481.         (void) close(f);
  482.         return;
  483.     }
  484.     sizerr = 0;
  485.     for (i = 0; i < stb.st_size; i += BUFSIZ) {
  486.         int amt = BUFSIZ;
  487.         if (i + amt > stb.st_size)
  488.             amt = stb.st_size - i;
  489.         if (sizerr == 0 && read(f, buf, amt) != amt)
  490.             sizerr = 1;
  491.         (void) write(rem, buf, amt);
  492.     }
  493.     (void) close(f);
  494. done:
  495.     if (sizerr) {
  496.         error("%s: file changed size\n", target);
  497.         err();
  498.     } else
  499.         ack();
  500.     f = response();
  501.     if (f < 0 || f == 0 && (opts & COMPARE))
  502.         return;
  503. dospecial:
  504.     for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
  505.         if (sc->sc_type != SPECIAL)
  506.             continue;
  507.         if (sc->sc_args != NULL && !inlist(sc->sc_args, target))
  508.             continue;
  509.         log(lfp, "special \"%s\"\n", sc->sc_name);
  510.         if (opts & VERIFY)
  511.             continue;
  512.         (void) sprintf(buf, "SFILE=%s;%s\n", target, sc->sc_name);
  513.         if (debug)
  514.             printf("buf = %s", buf);
  515.         (void) write(rem, buf, strlen(buf));
  516.         while (response() > 0)
  517.             ;
  518.     }
  519. }
  520.  
  521. static struct linkbuf *
  522. savelink(stp)
  523.     struct stat *stp;
  524. {
  525.     struct linkbuf *lp;
  526.  
  527.     for (lp = ihead; lp != NULL; lp = lp->nextp)
  528.         if (lp->inum == stp->st_ino && lp->devnum == stp->st_dev) {
  529.             lp->count--;
  530.             return(lp);
  531.         }
  532.     lp = (struct linkbuf *) malloc(sizeof(*lp));
  533.     if (lp == NULL)
  534.         log(lfp, "out of memory, link information lost\n");
  535.     else {
  536.         lp->nextp = ihead;
  537.         ihead = lp;
  538.         lp->inum = stp->st_ino;
  539.         lp->devnum = stp->st_dev;
  540.         lp->count = stp->st_nlink - 1;
  541.         strcpy(lp->pathname, target);
  542.         if (Tdest)
  543.             strcpy(lp->target, Tdest);
  544.         else
  545.             *lp->target = 0;
  546.     }
  547.     return(NULL);
  548. }
  549.  
  550. /*
  551.  * Check to see if file needs to be updated on the remote machine.
  552.  * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date
  553.  * and 3 if comparing binaries to determine if out of date.
  554.  */
  555. static int
  556. update(rname, opts, stp)
  557.     char *rname;
  558.     int opts;
  559.     struct stat *stp;
  560. {
  561.     register char *cp, *s;
  562.     register off_t size;
  563.     register time_t mtime;
  564.  
  565.     if (debug) 
  566.         printf("update(%s, %x, %x)\n", rname, opts, stp);
  567.  
  568.     /*
  569.      * Check to see if the file exists on the remote machine.
  570.      */
  571.     (void) sprintf(buf, "Q%s\n", rname);
  572.     if (debug)
  573.         printf("buf = %s", buf);
  574.     (void) write(rem, buf, strlen(buf));
  575. again:
  576.     cp = s = buf;
  577.     do {
  578.         if (read(rem, cp, 1) != 1)
  579.             lostconn(0);
  580.     } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
  581.  
  582.     switch (*s++) {
  583.     case 'Y':
  584.         break;
  585.  
  586.     case 'N':  /* file doesn't exist so install it */
  587.         return(1);
  588.  
  589.     case '\1':
  590.         nerrs++;
  591.         if (*s != '\n') {
  592.             if (!iamremote) {
  593.                 fflush(stdout);
  594.                 (void) write(2, s, cp - s);
  595.             }
  596.             if (lfp != NULL)
  597.                 (void) fwrite(s, 1, cp - s, lfp);
  598.         }
  599.         return(0);
  600.  
  601.     case '\3':
  602.         *--cp = '\0';
  603.         if (lfp != NULL) 
  604.             log(lfp, "update: note: %s\n", s);
  605.         goto again;
  606.  
  607.     default:
  608.         *--cp = '\0';
  609.         error("update: unexpected response '%s'\n", s);
  610.         return(0);
  611.     }
  612.  
  613.     if (*s == '\n')
  614.         return(2);
  615.  
  616.     if (opts & COMPARE)
  617.         return(3);
  618.  
  619.     size = 0;
  620.     while (isdigit(*s))
  621.         size = size * 10 + (*s++ - '0');
  622.     if (*s++ != ' ') {
  623.         error("update: size not delimited\n");
  624.         return(0);
  625.     }
  626.     mtime = 0;
  627.     while (isdigit(*s))
  628.         mtime = mtime * 10 + (*s++ - '0');
  629.     if (*s != '\n') {
  630.         error("update: mtime not delimited\n");
  631.         return(0);
  632.     }
  633.     /*
  634.      * File needs to be updated?
  635.      */
  636.     if (opts & YOUNGER) {
  637.         if (stp->st_mtime == mtime)
  638.             return(0);
  639.         if (stp->st_mtime < mtime) {
  640.             log(lfp, "Warning: %s: remote copy is newer\n", target);
  641.             return(0);
  642.         }
  643.     } else if (stp->st_mtime == mtime && stp->st_size == size)
  644.         return(0);
  645.     return(2);
  646. }
  647.  
  648. /*
  649.  * Query. Check to see if file exists. Return one of the following:
  650.  *    N\n        - doesn't exist
  651.  *    Ysize mtime\n    - exists and its a regular file (size & mtime of file)
  652.  *    Y\n        - exists and its a directory or symbolic link
  653.  *    ^Aerror message\n
  654.  */
  655. static void
  656. query(name)
  657.     char *name;
  658. {
  659.     struct stat stb;
  660.  
  661.     if (catname)
  662.         (void) sprintf(tp, "/%s", name);
  663.  
  664.     if (lstat(target, &stb) < 0) {
  665.         if (errno == ENOENT)
  666.             (void) write(rem, "N\n", 2);
  667.         else
  668.             error("%s:%s: %s\n", host, target, strerror(errno));
  669.         *tp = '\0';
  670.         return;
  671.     }
  672.  
  673.     switch (stb.st_mode & S_IFMT) {
  674.     case S_IFREG:
  675.         (void) sprintf(buf, "Y%d %ld\n", stb.st_size,
  676.             stb.st_mtime);
  677.         (void) write(rem, buf, strlen(buf));
  678.         break;
  679.  
  680.     case S_IFLNK:
  681.     case S_IFDIR:
  682.         (void) write(rem, "Y\n", 2);
  683.         break;
  684.  
  685.     default:
  686.         error("%s: not a file or directory\n", name);
  687.         break;
  688.     }
  689.     *tp = '\0';
  690. }
  691.  
  692. static void
  693. recvf(cmd, type)
  694.     char *cmd;
  695.     int type;
  696. {
  697.     register char *cp;
  698.     int f, mode, opts, wrerr, olderrno;
  699.     off_t i, size;
  700.     time_t mtime;
  701.     struct stat stb;
  702.     struct timeval tvp[2];
  703.     char *owner, *group;
  704.     char new[BUFSIZ];
  705.     extern char *tempname;
  706.  
  707.     cp = cmd;
  708.     opts = 0;
  709.     while (*cp >= '0' && *cp <= '7')
  710.         opts = (opts << 3) | (*cp++ - '0');
  711.     if (*cp++ != ' ') {
  712.         error("recvf: options not delimited\n");
  713.         return;
  714.     }
  715.     mode = 0;
  716.     while (*cp >= '0' && *cp <= '7')
  717.         mode = (mode << 3) | (*cp++ - '0');
  718.     if (*cp++ != ' ') {
  719.         error("recvf: mode not delimited\n");
  720.         return;
  721.     }
  722.     size = 0;
  723.     while (isdigit(*cp))
  724.         size = size * 10 + (*cp++ - '0');
  725.     if (*cp++ != ' ') {
  726.         error("recvf: size not delimited\n");
  727.         return;
  728.     }
  729.     mtime = 0;
  730.     while (isdigit(*cp))
  731.         mtime = mtime * 10 + (*cp++ - '0');
  732.     if (*cp++ != ' ') {
  733.         error("recvf: mtime not delimited\n");
  734.         return;
  735.     }
  736.     owner = cp;
  737.     while (*cp && *cp != ' ')
  738.         cp++;
  739.     if (*cp != ' ') {
  740.         error("recvf: owner name not delimited\n");
  741.         return;
  742.     }
  743.     *cp++ = '\0';
  744.     group = cp;
  745.     while (*cp && *cp != ' ')
  746.         cp++;
  747.     if (*cp != ' ') {
  748.         error("recvf: group name not delimited\n");
  749.         return;
  750.     }
  751.     *cp++ = '\0';
  752.  
  753.     if (type == S_IFDIR) {
  754.         if (catname >= sizeof(stp)) {
  755.             error("%s:%s: too many directory levels\n",
  756.                 host, target);
  757.             return;
  758.         }
  759.         stp[catname] = tp;
  760.         if (catname++) {
  761.             *tp++ = '/';
  762.             while (*tp++ = *cp++)
  763.                 ;
  764.             tp--;
  765.         }
  766.         if (opts & VERIFY) {
  767.             ack();
  768.             return;
  769.         }
  770.         if (lstat(target, &stb) == 0) {
  771.             if (ISDIR(stb.st_mode)) {
  772.                 if ((stb.st_mode & 07777) == mode) {
  773.                     ack();
  774.                     return;
  775.                 }
  776.                 buf[0] = '\0';
  777.                 (void) sprintf(buf + 1,
  778.                     "%s: Warning: remote mode %o != local mode %o\n",
  779.                     target, stb.st_mode & 07777, mode);
  780.                 (void) write(rem, buf, strlen(buf + 1) + 1);
  781.                 return;
  782.             }
  783.             errno = ENOTDIR;
  784.         } else if (errno == ENOENT && (mkdir(target, mode) == 0 ||
  785.             chkparent(target) == 0 && mkdir(target, mode) == 0)) {
  786.             if (fchog(-1, target, owner, group, mode) == 0)
  787.                 ack();
  788.             return;
  789.         }
  790.         error("%s:%s: %s\n", host, target, strerror(errno));
  791.         tp = stp[--catname];
  792.         *tp = '\0';
  793.         return;
  794.     }
  795.  
  796.     if (catname)
  797.         (void) sprintf(tp, "/%s", cp);
  798.     cp = rindex(target, '/');
  799.     if (cp == NULL)
  800.         strcpy(new, tempname);
  801.     else if (cp == target)
  802.         (void) sprintf(new, "/%s", tempname);
  803.     else {
  804.         *cp = '\0';
  805.         (void) sprintf(new, "%s/%s", target, tempname);
  806.         *cp = '/';
  807.     }
  808.  
  809.     if (type == S_IFLNK) {
  810.         int j;
  811.  
  812.         ack();
  813.         cp = buf;
  814.         for (i = 0; i < size; i += j) {
  815.             if ((j = read(rem, cp, size - i)) <= 0)
  816.                 cleanup(0);
  817.             cp += j;
  818.         }
  819.         *cp = '\0';
  820.         if (response() < 0) {
  821.             err();
  822.             return;
  823.         }
  824.         if (symlink(buf, new) < 0) {
  825.             if (errno != ENOENT || chkparent(new) < 0 ||
  826.                 symlink(buf, new) < 0)
  827.                 goto badnew1;
  828.         }
  829.         mode &= 0777;
  830.         if (opts & COMPARE) {
  831.             char tbuf[BUFSIZ];
  832.  
  833.             if ((i = readlink(target, tbuf, BUFSIZ)) >= 0 &&
  834.                 i == size && strncmp(buf, tbuf, size) == 0) {
  835.                 (void) unlink(new);
  836.                 ack();
  837.                 return;
  838.             }
  839.             if (opts & VERIFY)
  840.                 goto differ;
  841.         }
  842.         goto fixup;
  843.     }
  844.  
  845.     if ((f = creat(new, mode)) < 0) {
  846.         if (errno != ENOENT || chkparent(new) < 0 ||
  847.             (f = creat(new, mode)) < 0)
  848.             goto badnew1;
  849.     }
  850.  
  851.     ack();
  852.     wrerr = 0;
  853.     for (i = 0; i < size; i += BUFSIZ) {
  854.         int amt = BUFSIZ;
  855.  
  856.         cp = buf;
  857.         if (i + amt > size)
  858.             amt = size - i;
  859.         do {
  860.             int j = read(rem, cp, amt);
  861.  
  862.             if (j <= 0) {
  863.                 (void) close(f);
  864.                 (void) unlink(new);
  865.                 cleanup(0);
  866.             }
  867.             amt -= j;
  868.             cp += j;
  869.         } while (amt > 0);
  870.         amt = BUFSIZ;
  871.         if (i + amt > size)
  872.             amt = size - i;
  873.         if (wrerr == 0 && write(f, buf, amt) != amt) {
  874.             olderrno = errno;
  875.             wrerr++;
  876.         }
  877.     }
  878.     if (response() < 0) {
  879.         err();
  880.         goto badnew2;
  881.     }
  882.     if (wrerr)
  883.         goto badnew1;
  884.     if (opts & COMPARE) {
  885.         FILE *f1, *f2;
  886.         int c;
  887.  
  888.         if ((f1 = fopen(target, "r")) == NULL)
  889.             goto badtarget;
  890.         if ((f2 = fopen(new, "r")) == NULL) {
  891. badnew1:        error("%s:%s: %s\n", host, new, strerror(errno));
  892.             goto badnew2;
  893.         }
  894.         while ((c = getc(f1)) == getc(f2))
  895.             if (c == EOF) {
  896.                 (void) fclose(f1);
  897.                 (void) fclose(f2);
  898.                 ack();
  899.                 goto badnew2;
  900.             }
  901.         (void) fclose(f1);
  902.         (void) fclose(f2);
  903.         if (opts & VERIFY) {
  904. differ:            buf[0] = '\0';
  905.             (void) sprintf(buf + 1, "need to update: %s\n",target);
  906.             (void) write(rem, buf, strlen(buf + 1) + 1);
  907.             goto badnew2;
  908.         }
  909.     }
  910.  
  911.     /*
  912.      * Set last modified time
  913.      */
  914.     tvp[0].tv_sec = time(0);
  915.     tvp[0].tv_usec = 0;
  916.     tvp[1].tv_sec = mtime;
  917.     tvp[1].tv_usec = 0;
  918.     if (utimes(new, tvp) < 0)
  919.         note("%s: utimes failed %s: %s\n", host, new, strerror(errno));
  920.  
  921.     if (fchog(f, new, owner, group, mode) < 0) {
  922. badnew2:    (void) close(f);
  923.         (void) unlink(new);
  924.         return;
  925.     }
  926.     (void) close(f);
  927.  
  928. fixup:    if (rename(new, target) < 0) {
  929. badtarget:    error("%s:%s: %s\n", host, target, strerror(errno));
  930.         (void) unlink(new);
  931.         return;
  932.     }
  933.  
  934.     if (opts & COMPARE) {
  935.         buf[0] = '\0';
  936.         (void) sprintf(buf + 1, "updated %s\n", target);
  937.         (void) write(rem, buf, strlen(buf + 1) + 1);
  938.     } else
  939.         ack();
  940. }
  941.  
  942. /*
  943.  * Creat a hard link to existing file.
  944.  */
  945. static void
  946. hardlink(cmd)
  947.     char *cmd;
  948. {
  949.     register char *cp;
  950.     struct stat stb;
  951.     char *oldname;
  952.     int opts, exists = 0;
  953.  
  954.     cp = cmd;
  955.     opts = 0;
  956.     while (*cp >= '0' && *cp <= '7')
  957.         opts = (opts << 3) | (*cp++ - '0');
  958.     if (*cp++ != ' ') {
  959.         error("hardlink: options not delimited\n");
  960.         return;
  961.     }
  962.     oldname = cp;
  963.     while (*cp && *cp != ' ')
  964.         cp++;
  965.     if (*cp != ' ') {
  966.         error("hardlink: oldname name not delimited\n");
  967.         return;
  968.     }
  969.     *cp++ = '\0';
  970.  
  971.     if (catname) {
  972.         (void) sprintf(tp, "/%s", cp);
  973.     }
  974.     if (lstat(target, &stb) == 0) {
  975.         int mode = stb.st_mode & S_IFMT;
  976.         if (mode != S_IFREG && mode != S_IFLNK) {
  977.             error("%s:%s: not a regular file\n", host, target);
  978.             return;
  979.         }
  980.         exists = 1;
  981.     }
  982.     if (chkparent(target) < 0 ) {
  983.         error("%s:%s: %s (no parent)\n",
  984.             host, target, strerror(errno));
  985.         return;
  986.     }
  987.     if (exists && (unlink(target) < 0)) {
  988.         error("%s:%s: %s (unlink)\n",
  989.             host, target, strerror(errno));
  990.         return;
  991.     }
  992.     if (link(oldname, target) < 0) {
  993.         error("%s:can't link %s to %s\n",
  994.             host, target, oldname);
  995.         return;
  996.     }
  997.     ack();
  998. }
  999.  
  1000. /*
  1001.  * Check to see if parent directory exists and create one if not.
  1002.  */
  1003. static int
  1004. chkparent(name)
  1005.     char *name;
  1006. {
  1007.     register char *cp;
  1008.     struct stat stb;
  1009.  
  1010.     cp = rindex(name, '/');
  1011.     if (cp == NULL || cp == name)
  1012.         return(0);
  1013.     *cp = '\0';
  1014.     if (lstat(name, &stb) < 0) {
  1015.         if (errno == ENOENT && chkparent(name) >= 0 &&
  1016.             mkdir(name, 0777 & ~oumask) >= 0) {
  1017.             *cp = '/';
  1018.             return(0);
  1019.         }
  1020.     } else if (ISDIR(stb.st_mode)) {
  1021.         *cp = '/';
  1022.         return(0);
  1023.     }
  1024.     *cp = '/';
  1025.     return(-1);
  1026. }
  1027.  
  1028. /*
  1029.  * Change owner, group and mode of file.
  1030.  */
  1031. static int
  1032. fchog(fd, file, owner, group, mode)
  1033.     int fd;
  1034.     char *file, *owner, *group;
  1035.     int mode;
  1036. {
  1037.     register int i;
  1038.     int uid, gid;
  1039.     extern char user[];
  1040.     extern int userid;
  1041.  
  1042.     uid = userid;
  1043.     if (userid == 0) {
  1044.         if (*owner == ':') {
  1045.             uid = atoi(owner + 1);
  1046.         } else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) {
  1047.             if ((pw = getpwnam(owner)) == NULL) {
  1048.                 if (mode & 04000) {
  1049.                     note("%s:%s: unknown login name, clearing setuid",
  1050.                         host, owner);
  1051.                     mode &= ~04000;
  1052.                     uid = 0;
  1053.                 }
  1054.             } else
  1055.                 uid = pw->pw_uid;
  1056.         } else
  1057.             uid = pw->pw_uid;
  1058.         if (*group == ':') {
  1059.             gid = atoi(group + 1);
  1060.             goto ok;
  1061.         }
  1062.     } else if ((mode & 04000) && strcmp(user, owner) != 0)
  1063.         mode &= ~04000;
  1064.     gid = -1;
  1065.     if (gr == NULL || strcmp(group, gr->gr_name) != 0) {
  1066.         if ((*group == ':' && (getgrgid(gid = atoi(group + 1)) == NULL))
  1067.            || ((gr = getgrnam(group)) == NULL)) {
  1068.             if (mode & 02000) {
  1069.                 note("%s:%s: unknown group", host, group);
  1070.                 mode &= ~02000;
  1071.             }
  1072.         } else
  1073.             gid = gr->gr_gid;
  1074.     } else
  1075.         gid = gr->gr_gid;
  1076.     if (userid && gid >= 0) {
  1077.         if (gr) for (i = 0; gr->gr_mem[i] != NULL; i++)
  1078.             if (!(strcmp(user, gr->gr_mem[i])))
  1079.                 goto ok;
  1080.         mode &= ~02000;
  1081.         gid = -1;
  1082.     }
  1083. ok:    if (fd != -1 && fchown(fd, uid, gid) < 0 || chown(file, uid, gid) < 0)
  1084.         note("%s: %s chown: %s", host, file, strerror(errno));
  1085.     else if (mode & 07000 &&
  1086.        (fd != -1 && fchmod(fd, mode) < 0 || chmod(file, mode) < 0))
  1087.         note("%s: %s chmod: %s", host, file, strerror(errno));
  1088.     return(0);
  1089. }
  1090.  
  1091. /*
  1092.  * Check for files on the machine being updated that are not on the master
  1093.  * machine and remove them.
  1094.  */
  1095. static void
  1096. rmchk(opts)
  1097.     int opts;
  1098. {
  1099.     register char *cp, *s;
  1100.     struct stat stb;
  1101.  
  1102.     if (debug)
  1103.         printf("rmchk()\n");
  1104.  
  1105.     /*
  1106.      * Tell the remote to clean the files from the last directory sent.
  1107.      */
  1108.     (void) sprintf(buf, "C%o\n", opts & VERIFY);
  1109.     if (debug)
  1110.         printf("buf = %s", buf);
  1111.     (void) write(rem, buf, strlen(buf));
  1112.     if (response() < 0)
  1113.         return;
  1114.     for (;;) {
  1115.         cp = s = buf;
  1116.         do {
  1117.             if (read(rem, cp, 1) != 1)
  1118.                 lostconn(0);
  1119.         } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
  1120.  
  1121.         switch (*s++) {
  1122.         case 'Q': /* Query if file should be removed */
  1123.             /*
  1124.              * Return the following codes to remove query.
  1125.              * N\n -- file exists - DON'T remove.
  1126.              * Y\n -- file doesn't exist - REMOVE.
  1127.              */
  1128.             *--cp = '\0';
  1129.             (void) sprintf(tp, "/%s", s);
  1130.             if (debug)
  1131.                 printf("check %s\n", target);
  1132.             if (except(target))
  1133.                 (void) write(rem, "N\n", 2);
  1134.             else if (lstat(target, &stb) < 0)
  1135.                 (void) write(rem, "Y\n", 2);
  1136.             else
  1137.                 (void) write(rem, "N\n", 2);
  1138.             break;
  1139.  
  1140.         case '\0':
  1141.             *--cp = '\0';
  1142.             if (*s != '\0')
  1143.                 log(lfp, "%s\n", s);
  1144.             break;
  1145.  
  1146.         case 'E':
  1147.             *tp = '\0';
  1148.             ack();
  1149.             return;
  1150.  
  1151.         case '\1':
  1152.         case '\2':
  1153.             nerrs++;
  1154.             if (*s != '\n') {
  1155.                 if (!iamremote) {
  1156.                     fflush(stdout);
  1157.                     (void) write(2, s, cp - s);
  1158.                 }
  1159.                 if (lfp != NULL)
  1160.                     (void) fwrite(s, 1, cp - s, lfp);
  1161.             }
  1162.             if (buf[0] == '\2')
  1163.                 lostconn(0);
  1164.             break;
  1165.  
  1166.         default:
  1167.             error("rmchk: unexpected response '%s'\n", buf);
  1168.             err();
  1169.         }
  1170.     }
  1171. }
  1172.  
  1173. /*
  1174.  * Check the current directory (initialized by the 'T' command to server())
  1175.  * for extraneous files and remove them.
  1176.  */
  1177. static void
  1178. clean(cp)
  1179.     register char *cp;
  1180. {
  1181.     DIR *d;
  1182.     register struct direct *dp;
  1183.     struct stat stb;
  1184.     char *otp;
  1185.     int len, opts;
  1186.  
  1187.     opts = 0;
  1188.     while (*cp >= '0' && *cp <= '7')
  1189.         opts = (opts << 3) | (*cp++ - '0');
  1190.     if (*cp != '\0') {
  1191.         error("clean: options not delimited\n");
  1192.         return;
  1193.     }
  1194.     if ((d = opendir(target)) == NULL) {
  1195.         error("%s:%s: %s\n", host, target, strerror(errno));
  1196.         return;
  1197.     }
  1198.     ack();
  1199.  
  1200.     otp = tp;
  1201.     len = tp - target;
  1202.     while (dp = readdir(d)) {
  1203.         if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  1204.             continue;
  1205.         if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
  1206.             error("%s:%s/%s: Name too long\n",
  1207.                 host, target, dp->d_name);
  1208.             continue;
  1209.         }
  1210.         tp = otp;
  1211.         *tp++ = '/';
  1212.         cp = dp->d_name;;
  1213.         while (*tp++ = *cp++)
  1214.             ;
  1215.         tp--;
  1216.         if (lstat(target, &stb) < 0) {
  1217.             error("%s:%s: %s\n", host, target, strerror(errno));
  1218.             continue;
  1219.         }
  1220.         (void) sprintf(buf, "Q%s\n", dp->d_name);
  1221.         (void) write(rem, buf, strlen(buf));
  1222.         cp = buf;
  1223.         do {
  1224.             if (read(rem, cp, 1) != 1)
  1225.                 cleanup(0);
  1226.         } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
  1227.         *--cp = '\0';
  1228.         cp = buf;
  1229.         if (*cp != 'Y')
  1230.             continue;
  1231.         if (opts & VERIFY) {
  1232.             cp = buf;
  1233.             *cp++ = '\0';
  1234.             (void) sprintf(cp, "need to remove: %s\n", target);
  1235.             (void) write(rem, buf, strlen(cp) + 1);
  1236.         } else
  1237.             removeit(&stb);
  1238.     }
  1239.     closedir(d);
  1240.     (void) write(rem, "E\n", 2);
  1241.     (void) response();
  1242.     tp = otp;
  1243.     *tp = '\0';
  1244. }
  1245.  
  1246. /*
  1247.  * Remove a file or directory (recursively) and send back an acknowledge
  1248.  * or an error message.
  1249.  */
  1250. static void
  1251. removeit(stp)
  1252.     struct stat *stp;
  1253. {
  1254.     DIR *d;
  1255.     struct direct *dp;
  1256.     register char *cp;
  1257.     struct stat stb;
  1258.     char *otp;
  1259.     int len;
  1260.  
  1261.     switch (stp->st_mode & S_IFMT) {
  1262.     case S_IFREG:
  1263.     case S_IFLNK:
  1264.         if (unlink(target) < 0)
  1265.             goto bad;
  1266.         goto removed;
  1267.  
  1268.     case S_IFDIR:
  1269.         break;
  1270.  
  1271.     default:
  1272.         error("%s:%s: not a plain file\n", host, target);
  1273.         return;
  1274.     }
  1275.  
  1276.     if ((d = opendir(target)) == NULL)
  1277.         goto bad;
  1278.  
  1279.     otp = tp;
  1280.     len = tp - target;
  1281.     while (dp = readdir(d)) {
  1282.         if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  1283.             continue;
  1284.         if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
  1285.             error("%s:%s/%s: Name too long\n",
  1286.                 host, target, dp->d_name);
  1287.             continue;
  1288.         }
  1289.         tp = otp;
  1290.         *tp++ = '/';
  1291.         cp = dp->d_name;;
  1292.         while (*tp++ = *cp++)
  1293.             ;
  1294.         tp--;
  1295.         if (lstat(target, &stb) < 0) {
  1296.             error("%s:%s: %s\n", host, target, strerror(errno));
  1297.             continue;
  1298.         }
  1299.         removeit(&stb);
  1300.     }
  1301.     closedir(d);
  1302.     tp = otp;
  1303.     *tp = '\0';
  1304.     if (rmdir(target) < 0) {
  1305. bad:
  1306.         error("%s:%s: %s\n", host, target, strerror(errno));
  1307.         return;
  1308.     }
  1309. removed:
  1310.     cp = buf;
  1311.     *cp++ = '\0';
  1312.     (void) sprintf(cp, "removed %s\n", target);
  1313.     (void) write(rem, buf, strlen(cp) + 1);
  1314. }
  1315.  
  1316. /*
  1317.  * Execute a shell command to handle special cases.
  1318.  */
  1319. static void
  1320. dospecial(cmd)
  1321.     char *cmd;
  1322. {
  1323.     int fd[2], status, pid, i;
  1324.     register char *cp, *s;
  1325.     char sbuf[BUFSIZ];
  1326.     extern int userid, groupid;
  1327.  
  1328.     if (pipe(fd) < 0) {
  1329.         error("%s\n", strerror(errno));
  1330.         return;
  1331.     }
  1332.     if ((pid = fork()) == 0) {
  1333.         /*
  1334.          * Return everything the shell commands print.
  1335.          */
  1336.         (void) close(0);
  1337.         (void) close(1);
  1338.         (void) close(2);
  1339.         (void) open(_PATH_DEVNULL, O_RDONLY);
  1340.         (void) dup(fd[1]);
  1341.         (void) dup(fd[1]);
  1342.         (void) close(fd[0]);
  1343.         (void) close(fd[1]);
  1344.         setgid(groupid);
  1345.         setuid(userid);
  1346.         execl(_PATH_BSHELL, "sh", "-c", cmd, 0);
  1347.         _exit(127);
  1348.     }
  1349.     (void) close(fd[1]);
  1350.     s = sbuf;
  1351.     *s++ = '\0';
  1352.     while ((i = read(fd[0], buf, sizeof(buf))) > 0) {
  1353.         cp = buf;
  1354.         do {
  1355.             *s++ = *cp++;
  1356.             if (cp[-1] != '\n') {
  1357.                 if (s < &sbuf[sizeof(sbuf)-1])
  1358.                     continue;
  1359.                 *s++ = '\n';
  1360.             }
  1361.             /*
  1362.              * Throw away blank lines.
  1363.              */
  1364.             if (s == &sbuf[2]) {
  1365.                 s--;
  1366.                 continue;
  1367.             }
  1368.             (void) write(rem, sbuf, s - sbuf);
  1369.             s = &sbuf[1];
  1370.         } while (--i);
  1371.     }
  1372.     if (s > &sbuf[1]) {
  1373.         *s++ = '\n';
  1374.         (void) write(rem, sbuf, s - sbuf);
  1375.     }
  1376.     while ((i = wait(&status)) != pid && i != -1)
  1377.         ;
  1378.     if (i == -1)
  1379.         status = -1;
  1380.     (void) close(fd[0]);
  1381.     if (status)
  1382.         error("shell returned %d\n", status);
  1383.     else
  1384.         ack();
  1385. }
  1386.  
  1387. #if __STDC__
  1388. #include <stdarg.h>
  1389. #else
  1390. #include <varargs.h>
  1391. #endif
  1392.  
  1393. void
  1394. #if __STDC__
  1395. log(FILE *fp, const char *fmt, ...)
  1396. #else
  1397. log(fp, fmt, va_alist)
  1398.     FILE *fp;
  1399.     char *fmt;
  1400.         va_dcl
  1401. #endif
  1402. {
  1403.     va_list ap;
  1404. #if __STDC__
  1405.     va_start(ap, fmt);
  1406. #else
  1407.     va_start(ap);
  1408. #endif
  1409.     /* Print changes locally if not quiet mode */
  1410.     if (!qflag)
  1411.         (void)vprintf(fmt, ap);
  1412.  
  1413.     /* Save changes (for mailing) if really updating files */
  1414.     if (!(options & VERIFY) && fp != NULL)
  1415.         (void)vfprintf(fp, fmt, ap);
  1416.     va_end(ap);
  1417. }
  1418.  
  1419. void
  1420. #if __STDC__
  1421. error(const char *fmt, ...)
  1422. #else
  1423. error(fmt, va_alist)
  1424.     char *fmt;
  1425.         va_dcl
  1426. #endif
  1427. {
  1428.     static FILE *fp;
  1429.     va_list ap;
  1430. #if __STDC__
  1431.     va_start(ap, fmt);
  1432. #else
  1433.     va_start(ap);
  1434. #endif
  1435.  
  1436.     ++nerrs;
  1437.     if (!fp && !(fp = fdopen(rem, "w")))
  1438.         return;
  1439.     if (iamremote) {
  1440.         (void)fprintf(fp, "%crdist: ", 0x01);
  1441.         (void)vfprintf(fp, fmt, ap);
  1442.         fflush(fp);
  1443.     }
  1444.     else {
  1445.         fflush(stdout);
  1446.         (void)fprintf(stderr, "rdist: ");
  1447.         (void)vfprintf(stderr, fmt, ap);
  1448.         fflush(stderr);
  1449.     }
  1450.     if (lfp != NULL) {
  1451.         (void)fprintf(lfp, "rdist: ");
  1452.         (void)vfprintf(lfp, fmt, ap);
  1453.         fflush(lfp);
  1454.     }
  1455.     va_end(ap);
  1456. }
  1457.  
  1458. void
  1459. #if __STDC__
  1460. fatal(const char *fmt, ...)
  1461. #else
  1462. fatal(fmt, va_alist)
  1463.     char *fmt;
  1464.         va_dcl
  1465. #endif
  1466. {
  1467.     static FILE *fp;
  1468.     va_list ap;
  1469. #if __STDC__
  1470.     va_start(ap, fmt);
  1471. #else
  1472.     va_start(ap);
  1473. #endif
  1474.  
  1475.     ++nerrs;
  1476.     if (!fp && !(fp = fdopen(rem, "w")))
  1477.         return;
  1478.     if (iamremote) {
  1479.         (void)fprintf(fp, "%crdist: ", 0x02);
  1480.         (void)vfprintf(fp, fmt, ap);
  1481.         fflush(fp);
  1482.     }
  1483.     else {
  1484.         fflush(stdout);
  1485.         (void)fprintf(stderr, "rdist: ");
  1486.         (void)vfprintf(stderr, fmt, ap);
  1487.         fflush(stderr);
  1488.     }
  1489.     if (lfp != NULL) {
  1490.         (void)fprintf(lfp, "rdist: ");
  1491.         (void)vfprintf(lfp, fmt, ap);
  1492.         fflush(lfp);
  1493.     }
  1494.     cleanup(0);
  1495. }
  1496.  
  1497. static int
  1498. response()
  1499. {
  1500.     char *cp, *s;
  1501.     char resp[BUFSIZ];
  1502.  
  1503.     if (debug)
  1504.         printf("response()\n");
  1505.  
  1506.     cp = s = resp;
  1507.     do {
  1508.         if (read(rem, cp, 1) != 1)
  1509.             lostconn(0);
  1510.     } while (*cp++ != '\n' && cp < &resp[BUFSIZ]);
  1511.  
  1512.     switch (*s++) {
  1513.     case '\0':
  1514.         *--cp = '\0';
  1515.         if (*s != '\0') {
  1516.             log(lfp, "%s\n", s);
  1517.             return(1);
  1518.         }
  1519.         return(0);
  1520.     case '\3':
  1521.         *--cp = '\0';
  1522.         log(lfp, "Note: %s\n",s);
  1523.         return(response());
  1524.  
  1525.     default:
  1526.         s--;
  1527.         /* fall into... */
  1528.     case '\1':
  1529.     case '\2':
  1530.         nerrs++;
  1531.         if (*s != '\n') {
  1532.             if (!iamremote) {
  1533.                 fflush(stdout);
  1534.                 (void) write(2, s, cp - s);
  1535.             }
  1536.             if (lfp != NULL)
  1537.                 (void) fwrite(s, 1, cp - s, lfp);
  1538.         }
  1539.         if (resp[0] == '\2')
  1540.             lostconn(0);
  1541.         return(-1);
  1542.     }
  1543. }
  1544.  
  1545. /*
  1546.  * Remove temporary files and do any cleanup operations before exiting.
  1547.  */
  1548. void
  1549. cleanup(signo)
  1550.     int signo;
  1551. {
  1552.     (void) unlink(tempfile);
  1553.     exit(1);
  1554. }
  1555.  
  1556. static void
  1557. #if __STDC__
  1558. note(const char *fmt, ...)
  1559. #else
  1560. note(fmt, va_alist)
  1561.     char *fmt;
  1562.         va_dcl
  1563. #endif
  1564. {
  1565.     static char buf[BUFSIZ];
  1566.     va_list ap;
  1567. #if __STDC__
  1568.     va_start(ap, fmt);
  1569. #else
  1570.     va_start(ap);
  1571. #endif
  1572.     (void)vsprintf(buf, fmt, ap);
  1573.     va_end(ap);
  1574.     comment(buf);
  1575. }
  1576.  
  1577. static void
  1578. comment(s)
  1579.     char *s;
  1580. {
  1581.     char c;
  1582.  
  1583.     c = '\3';
  1584.     write(rem, &c, 1);
  1585.     write(rem, s, strlen(s));
  1586.     c = '\n';
  1587.     write(rem, &c, 1);
  1588. }
  1589.