home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / rdist / server.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  30.9 KB  |  1,515 lines

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