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,v < prev    next >
Encoding:
Text File  |  1994-07-25  |  32.4 KB  |  1,611 lines

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