First stable version.
authorRalph Campbell <ralph@ucbvax.Berkeley.EDU>
Wed, 28 Sep 1983 06:39:44 +0000 (22:39 -0800)
committerRalph Campbell <ralph@ucbvax.Berkeley.EDU>
Wed, 28 Sep 1983 06:39:44 +0000 (22:39 -0800)
SCCS-vsn: usr.bin/rdist/defs.h 4.2
SCCS-vsn: usr.bin/rdist/Makefile 4.2
SCCS-vsn: usr.bin/rdist/docmd.c 4.2
SCCS-vsn: usr.bin/rdist/expand.c 4.2
SCCS-vsn: usr.bin/rdist/gram.y 4.2
SCCS-vsn: usr.bin/rdist/main.c 4.2
SCCS-vsn: usr.bin/rdist/server.c 4.2
SCCS-vsn: usr.bin/rdist/lookup.c 4.2

usr/src/usr.bin/rdist/Makefile
usr/src/usr.bin/rdist/defs.h
usr/src/usr.bin/rdist/docmd.c
usr/src/usr.bin/rdist/expand.c
usr/src/usr.bin/rdist/gram.y
usr/src/usr.bin/rdist/lookup.c
usr/src/usr.bin/rdist/main.c
usr/src/usr.bin/rdist/server.c

index a4850c5..b905201 100644 (file)
@@ -1,8 +1,8 @@
 #      Makefile        4.1     83/09/07
 
 DESTDIR=
 #      Makefile        4.1     83/09/07
 
 DESTDIR=
-SRCS = main.c gram.y docmd.c expand.c server.c
-OBJS = main.o gram.o docmd.o expand.o server.o
+SRCS = docmd.c expand.c gram.y lookup.c main.c server.c
+OBJS = docmd.o expand.o gram.o lookup.o main.o server.o
 LINT = lint -ps
 CFLAGS=
 
 LINT = lint -ps
 CFLAGS=
 
@@ -17,8 +17,8 @@ clean:
 install:
        install -s rdist ${DESTDIR}/usr/ucb/rdist
 
 install:
        install -s rdist ${DESTDIR}/usr/ucb/rdist
 
-lint:  main.c gram.c docmd.c expand.c server.c
-       ${LINT} main.c gram.c docmd.c expand.c server.c
+lint:  docmd.c expand.c gram.c lookup.c main.c server.c
+       ${LINT} docmd.c expand.c gram.c lookup.c main.c server.c
 
 print: ${SRCS}
        lpr -p ${SRCS} defs.h
 
 print: ${SRCS}
        lpr -p ${SRCS} defs.h
index 0ab56e9..342835c 100644 (file)
@@ -1,4 +1,4 @@
-/*     defs.h  4.1     83/09/07        */
+/*     defs.h  4.2     83/09/27        */
 
 #include <stdio.h>
 #include <ctype.h>
 
 #include <stdio.h>
 #include <ctype.h>
 
        /* defines for yacc */
 #define EQUAL 1
 
        /* defines for yacc */
 #define EQUAL 1
-#define ARROW 2
-#define LP 3
-#define RP 4
-#define NAME 5
-#define INSTALL 6
-#define VERIFY 7
-#define NOTIFY 8
-#define EXCEPT 9
+#define LP 2
+#define RP 3
+#define ARROW 4
+#define DCOLON 5
+#define NAME 6
+#define INSTALL 7
+#define VERIFY 8
+#define NOTIFY 9
+#define EXCEPT 10
+
+#define VAR 11
+
+       /* lexical definitions */
+#define        QUOTE   0200            /* used internally for quoted characters */
+#define        TRIM    0177            /* Mask to strip quote bit */
 
        /* table sizes */
 #define HASHSIZE 1021
 #define INMAX 3500
 
        /* table sizes */
 #define HASHSIZE 1021
 #define INMAX 3500
+#define NCARGS 10240
+#define GAVSIZ NCARGS / 6
+#define NSTAMPS 15
+
 
 #define ALLOC(x) (struct x *) malloc(sizeof(struct x))
 
 
 #define ALLOC(x) (struct x *) malloc(sizeof(struct x))
 
@@ -49,7 +60,7 @@ extern int rem;                       /* remote file descriptor */
 extern int iamremote;          /* acting as remote server */
 extern int filec;              /* number of files to update */
 extern char **filev;           /* list of files/directories to update */
 extern int iamremote;          /* acting as remote server */
 extern int filec;              /* number of files to update */
 extern char **filev;           /* list of files/directories to update */
-extern char *tmpfile;          /* file name for logging changes */
+extern char tmpfile[];         /* file name for logging changes */
 extern char host[];            /* host name of master copy */
 extern char *rhost;            /* host name of remote being updated */
 extern struct block *except;   /* list of files to exclude */
 extern char host[];            /* host name of master copy */
 extern char *rhost;            /* host name of remote being updated */
 extern struct block *except;   /* list of files to exclude */
@@ -58,5 +69,7 @@ extern int errno;             /* system error number */
 extern char *sys_errlist[];
 
 struct block *lookup();
 extern char *sys_errlist[];
 
 struct block *lookup();
+struct block *makeblock();
 struct block *expand();
 char *rindex();
 struct block *expand();
 char *rindex();
+char *index();
index 248ce8e..d4c0615 100644 (file)
@@ -1,5 +1,5 @@
 #ifndef lint
 #ifndef lint
-static char *sccsid = "@(#)docmd.c     4.1 (Berkeley) 83/09/07";
+static char *sccsid = "@(#)docmd.c     4.2 (Berkeley) 83/09/27";
 #endif
 
 #include "defs.h"
 #endif
 
 #include "defs.h"
@@ -7,62 +7,70 @@ static        char *sccsid = "@(#)docmd.c     4.1 (Berkeley) 83/09/07";
 FILE   *lfp;           /* log file for recording files updated */
 
 /*
 FILE   *lfp;           /* log file for recording files updated */
 
 /*
- * Routines to process commands.
+ * Process commands for sending files to other machines.
  */
  */
-docmd(files, hosts, cmds)
+dohcmds(files, hosts, cmds)
        struct block *files, *hosts, *cmds;
 {
        register struct block *h, *f, *c;
        register char *cp, **cpp;
        struct block *files, *hosts, *cmds;
 {
        register struct block *h, *f, *c;
        register char *cp, **cpp;
-       int n;
+       int n, ddir;
 
        if (debug)
 
        if (debug)
-               printf("docmd()\n");
+               printf("dohcmds(%x, %x, %x)\n", files, hosts, cmds);
 
 
-       files = expand(files);
-       hosts = expand(hosts);
+       files = expand(files, 0);
+       hosts = expand(hosts, 1);
        if (files == NULL)
                fatal("no files to be updated\n");
        if (hosts == NULL)
                fatal("empty list of hosts to be updated\n");
        except = cmds;
        if (files == NULL)
                fatal("no files to be updated\n");
        if (hosts == NULL)
                fatal("empty list of hosts to be updated\n");
        except = cmds;
+       ddir = files->b_next != NULL;
 
        for (h = hosts; h != NULL; h = h->b_next) {
 
        for (h = hosts; h != NULL; h = h->b_next) {
+               if (!qflag)
+                       printf("updating host %s\n", h->b_name);
                if (!nflag) {
                if (!nflag) {
+                       if (!makeconn(h->b_name))
+                               continue;
                        if ((lfp = fopen(tmpfile, "w")) == NULL) {
                                fatal("cannot open %s\n", tmpfile);
                                exit(1);
                        }
                        if ((lfp = fopen(tmpfile, "w")) == NULL) {
                                fatal("cannot open %s\n", tmpfile);
                                exit(1);
                        }
-                       if (!makeconn(h->b_name))
-                               continue;
                }
                for (f = files; f != NULL; f = f->b_next) {
                        if (filec) {
                                for (cpp = filev; *cpp; cpp++)
                                        if (!strcmp(f->b_name, *cpp))
                                                goto found;
                }
                for (f = files; f != NULL; f = f->b_next) {
                        if (filec) {
                                for (cpp = filev; *cpp; cpp++)
                                        if (!strcmp(f->b_name, *cpp))
                                                goto found;
+                               if (!nflag) {
+                                       (void) fclose(lfp);
+                               }
                                continue;
                        }
                found:
                        n = 0;
                        for (c = cmds; c != NULL; c = c->b_next)
                                if (c->b_type == INSTALL) {
                                continue;
                        }
                found:
                        n = 0;
                        for (c = cmds; c != NULL; c = c->b_next)
                                if (c->b_type == INSTALL) {
-                                       install(f->b_name, c->b_name, 0);
+                                       install(f->b_name, c->b_name, ddir, 0);
                                        n++;
                                } else if (c->b_type == VERIFY) {
                                        n++;
                                } else if (c->b_type == VERIFY) {
-                                       install(f->b_name, c->b_name, 1);
+                                       install(f->b_name, c->b_name, ddir, 1);
                                        n++;
                                }
                        if (n == 0)
                                        n++;
                                }
                        if (n == 0)
-                               install(f->b_name, f->b_name, 0);
+                               install(f->b_name, f->b_name, 0, 0);
                }
                if (!nflag) {
                }
                if (!nflag) {
-                       (void) fclose(lfp);
+                       /* signal end of connection */
+                       (void) write(rem, "\2\n", 2);
                        (void) close(rem);
                        (void) close(rem);
+                       (void) fclose(lfp);
                }
                for (c = cmds; c != NULL; c = c->b_next)
                        if (c->b_type == NOTIFY)
                }
                for (c = cmds; c != NULL; c = c->b_next)
                        if (c->b_type == NOTIFY)
-                               notify(h->b_name, c->b_args);
+                               notify(tmpfile, h->b_name, c->b_args);
        }
        if (!nflag)
                (void) unlink(tmpfile);
        }
        if (!nflag)
                (void) unlink(tmpfile);
@@ -79,7 +87,7 @@ makeconn(rhost)
 
        (void) sprintf(buf, "/usr/local/rdist -Server%s%s%s%s%s",
                vflag ? " -v" : "", qflag ? " -q" : "", nflag ? " -n" : "",
 
        (void) sprintf(buf, "/usr/local/rdist -Server%s%s%s%s%s",
                vflag ? " -v" : "", qflag ? " -q" : "", nflag ? " -n" : "",
-               yflag ? " -y" : "", debug ? " -d" : "");
+               yflag ? " -y" : "", debug ? " -D" : "");
 
        ruser = rindex(rhost, '.');
        if (ruser != NULL) {
 
        ruser = rindex(rhost, '.');
        if (ruser != NULL) {
@@ -95,6 +103,7 @@ makeconn(rhost)
                printf("buf = %s\n", buf);
        }
 
                printf("buf = %s\n", buf);
        }
 
+       fflush(stdout);
        rem = rcmd(&rhost, IPPORT_CMDSERVER, user, ruser, buf, 0);
        if (rem < 0)
                return(0);
        rem = rcmd(&rhost, IPPORT_CMDSERVER, user, ruser, buf, 0);
        if (rem < 0)
                return(0);
@@ -103,38 +112,204 @@ makeconn(rhost)
        return(1);
 }
 
        return(1);
 }
 
+extern char target[], *tp;
+
 /*
  * Update the file(s) if they are different.
 /*
  * Update the file(s) if they are different.
+ * destdir = 1 if destination should be a directory
+ * (i.e., more than one source is being copied to the same destination).
  */
  */
-install(src, dest, verify)
+install(src, dest, destdir, verify)
        char *src, *dest;
        char *src, *dest;
-       int verify;
+       int destdir, verify;
 {
 {
-       register char *cp;
-       extern char *tp;
-       char lbuf[BUFSIZ];
+       if (exclude(src))
+               return;
 
 
-       if (!qflag)
+       if (nflag) {
                printf("%s %s %s\n", verify ? "verify" : "install", src, dest);
                printf("%s %s %s\n", verify ? "verify" : "install", src, dest);
-       if (nflag)
                return;
                return;
+       }
        /*
         * Pass the destination file/directory name to remote.
         */
        /*
         * Pass the destination file/directory name to remote.
         */
-       (void) sprintf(buf, "T%s\n", dest);
+       (void) sprintf(buf, "%c%s\n", destdir ? 'T' : 't', dest);
        if (debug)
                printf("buf = %s", buf);
        (void) write(rem, buf, strlen(buf));
        tp = NULL;
        if (debug)
                printf("buf = %s", buf);
        (void) write(rem, buf, strlen(buf));
        tp = NULL;
-       shexpand(lbuf, src);
-       sendf(lbuf, verify);
+       sendf(src, verify);
+}
+
+struct tstamp {
+       time_t  lastmod;
+       FILE    *tfp;
+} ts[NSTAMPS];
+
+int    nstamps;
+
+/*
+ * Process commands for comparing files to time stamp files.
+ */
+dofcmds(files, stamps, cmds)
+       struct block *files, *stamps, *cmds;
+{
+       register struct block *b;
+       register struct tstamp *t;
+       register char **cpp;
+       struct stat stb;
+       extern char *tmpinc;
+       int n;
+
+       if (debug)
+               printf("dofcmds()\n");
+
+       files = expand(files, 0);
+       stamps = expand(stamps, 1);
+       if (files == NULL)
+               fatal("no files to be updated\n");
+       if (stamps == NULL)
+               fatal("empty time stamp file list\n");
+       except = cmds;
+
+       t = ts;
+       nstamps = 0;
+       for (b = stamps; b != NULL; b = b->b_next) {
+               if (stat(b->b_name, &stb) < 0) {
+                       error("%s: %s\n", b->b_name, sys_errlist[errno]);
+                       continue;
+               }
+               if (++nstamps > NSTAMPS)
+                       fatal("too many time stamp files in one command\n");
+               if (debug)
+                       printf("%s: %d\n", b->b_name, stb.st_mtime);
+               t->lastmod = stb.st_mtime;
+               if (!nflag && !vflag) {
+                       if ((t->tfp = fopen(tmpfile, "w")) == NULL)
+                               error("%s: %s\n", b->b_name, sys_errlist[errno]);
+                       (*tmpinc)++;
+               } else
+                       t->tfp = NULL;
+               t++;
+       }
+       for (b = files; b != NULL; b = b->b_next) {
+               if (filec) {
+                       for (cpp = filev; *cpp; cpp++)
+                               if (!strcmp(b->b_name, *cpp))
+                                       goto found;
+                       continue;
+               }
+       found:
+               tp = NULL;
+               cmptime(b->b_name);
+       }
+       if (!nflag && !vflag)
+               for (t = ts; t < &ts[n]; t++)
+                       if (t->tfp != NULL)
+                               (void) fclose(t->tfp);
+       *tmpinc = 'A';
+       while (n--) {
+               for (b = cmds; b != NULL; b = b->b_next)
+                       if (b->b_type == NOTIFY)
+                               notify(tmpfile, NULL, b->b_args);
+               if (!nflag && !vflag)
+                       (void) unlink(tmpfile);
+               (*tmpinc)++;
+       }
+}
+
+/*
+ * Compare the mtime of file to the list of time stamps.
+ */
+cmptime(name)
+       char *name;
+{
+       register struct tstamp *t;
+       struct stat stb;
+
+       if (debug)
+               printf("cmptime(%s)\n", name);
+
+       if (exclude(name))
+               return;
+
+       /*
+        * first time cmptime() is called?
+        */
+       if (tp == NULL) {
+               exptilde(target, name);
+               tp = name = target;
+               while (*tp)
+                       tp++;
+       }
+       if (access(name, 4) < 0 || stat(name, &stb) < 0) {
+               error("%s: %s\n", name, sys_errlist[errno]);
+               return;
+       }
+
+       switch (stb.st_mode & S_IFMT) {
+       case S_IFREG:
+               break;
+
+       case S_IFDIR:
+               rcmptime(&stb);
+               return;
+
+       default:
+               error("%s: not a plain file\n", name);
+               return;
+       }
+
+       for (t = ts; t < &ts[nstamps]; t++) {
+               if (stb.st_mtime <= t->lastmod)
+                       return;
+               log(t->tfp, "updating: %s\n", name);
+       }
+}
+
+rcmptime(st)
+       struct stat *st;
+{
+       register DIR *d;
+       register struct direct *dp;
+       register char *cp;
+       char *otp;
+       int len;
+
+       if (debug)
+               printf("rcmptime(%x)\n", st);
+
+       if ((d = opendir(target)) == NULL) {
+               error("%s: %s\n", target, sys_errlist[errno]);
+               return;
+       }
+       otp = tp;
+       len = tp - target;
+       while (dp = readdir(d)) {
+               if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+                       continue;
+               if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
+                       error("%s/%s: Name too long\n", target, dp->d_name);
+                       continue;
+               }
+               tp = otp;
+               *tp++ = '/';
+               cp = dp->d_name;
+               while (*tp++ = *cp++)
+                       ;
+               tp--;
+               cmptime(target);
+       }
+       closedir(d);
+       tp = otp;
+       *tp = '\0';
 }
 
 /*
  * Notify the list of people the changes that were made.
  */
 }
 
 /*
  * Notify the list of people the changes that were made.
  */
-notify(host, to)
-       char *host;
+notify(file, host, to)
+       char *file, *host;
        register struct block *to;
 {
        register int fd, len;
        register struct block *to;
 {
        register int fd, len;
@@ -144,14 +319,25 @@ notify(host, to)
        if (vflag)
                return;
        if (!qflag) {
        if (vflag)
                return;
        if (!qflag) {
-               printf("notify @%s ", host);
+               printf("notify ");
+               if (host)
+                       printf("@%s ", host);
                prnames(to);
        }
        if (nflag)
                return;
 
                prnames(to);
        }
        if (nflag)
                return;
 
-       if ((fd = open(tmpfile, 0)) < 0) {
-               error("%s: %s\n", tmpfile, sys_errlist[errno]);
+       if ((fd = open(file, 0)) < 0) {
+               error("%s: %s\n", file, sys_errlist[errno]);
+               return;
+       }
+       if (fstat(fd, &stb) < 0) {
+               error("%s: %s\n", file, sys_errlist[errno]);
+               (void) close(fd);
+               return;
+       }
+       if (stb.st_size == 0) {
+               (void) close(fd);
                return;
        }
        /*
                return;
        }
        /*
@@ -166,7 +352,10 @@ notify(host, to)
        fprintf(pf, "From: rdist (Remote distribution program)\n");
        fprintf(pf, "To:");
        while (to != NULL) {
        fprintf(pf, "From: rdist (Remote distribution program)\n");
        fprintf(pf, "To:");
        while (to != NULL) {
-               fprintf(pf, " %s@%s", to->b_name, host);
+               if (!any('@', to->b_name))
+                       fprintf(pf, " %s@%s", to->b_name, host);
+               else
+                       fprintf(pf, " %s", to->b_name);
                to = to->b_next;
        }
        putc('\n', pf);
                to = to->b_next;
        }
        putc('\n', pf);
index 37189e1..a5e42a3 100644 (file)
@@ -1,69 +1,38 @@
 #ifndef lint
 #ifndef lint
-static char *sccsid = "@(#)expand.c    4.1 (Berkeley) 83/09/07";
+static char *sccsid = "@(#)expand.c    4.2 (Berkeley) 83/09/27";
 #endif
 
 #include "defs.h"
 
 #endif
 
 #include "defs.h"
 
-static struct block *hashtab[HASHSIZE];
-static int nhashed = 0;
+char   shchars[] = "{[*?";
 
 
-/*
- * Lookup name in the table and return a pointer to it.
- * if insert, insert or replace name with value.
- */
-
-struct block *
-lookup(name, insert, value)
-       char *name;
-       int insert;
-       struct block *value;
-{
-       register unsigned n;
-       register char *cp;
-       register struct block *b;
-
-       if (debug)
-               printf("lookup(%s, %d, %x)\n", name, insert, value);
-
-       n = 0;
-       for (cp = name; *cp; )
-               n += *cp++;
-       n %= HASHSIZE;
+int    argc;
+char   **argv;
+char   *path, *pathp, *lastpathp;
+int    nleft;
 
 
-       for (b = hashtab[n]; b != NULL; b = b->b_next) {
-               if (strcmp(name, b->b_name))
-                       continue;
-               if (insert) {
-                       warn("%s redefined\n", name);
-                       b->b_args = value->b_args;
-                       free(value->b_name);
-                       free(value);
-               }
-               return(b);
-       }
-
-       if (!insert)
-               fatal("%s not defined", name);
-
-       value->b_next = hashtab[n];
-       hashtab[n] = value;
-       return(value);
-}
+int    argcnt;
+int    expany;         /* any expansions done? */
+char   *entp;
+char   **sortbase;
 
 char   *index();
 
 /*
 
 char   *index();
 
 /*
- * Take a list of names and expand any macros found.
+ * Take a list of names and expand any macros, etc.
  */
 struct block *
  */
 struct block *
-expand(list)
+expand(list, noshexp)
        struct block *list;
        struct block *list;
+       int noshexp;
 {
        register struct block *prev, *bp, *tp;
        register char *cp, *s;
        register int n;
        char *var, *tail;
        int c;
 {
        register struct block *prev, *bp, *tp;
        register char *cp, *s;
        register int n;
        char *var, *tail;
        int c;
+       char pathbuf[BUFSIZ];
+       char *argvbuf[GAVSIZ];
 
        for (prev = NULL, bp = list; bp != NULL; prev = bp, bp = bp->b_next) {
        again:
 
        for (prev = NULL, bp = list; bp != NULL; prev = bp, bp = bp->b_next) {
        again:
@@ -85,7 +54,7 @@ expand(list)
                        c = *tail;
                        *tail = '\0';
                }
                        c = *tail;
                        *tail = '\0';
                }
-               tp = lookup(cp, 0, NULL);
+               tp = lookup(cp, NULL, 0);
                if ((tp = tp->b_args) != NULL) {
                        struct block *first = tp;
 
                if ((tp = tp->b_args) != NULL) {
                        struct block *first = tp;
 
@@ -107,7 +76,7 @@ expand(list)
                        goto again;
                } else {
                        if (prev == NULL)
                        goto again;
                } else {
                        if (prev == NULL)
-                               list = tp = list->b_next;
+                               list = tp = bp->b_next;
                        else
                                prev->b_next = tp = bp->b_next;
                        free(bp->b_name);
                        else
                                prev->b_next = tp = bp->b_next;
                        free(bp->b_name);
@@ -119,6 +88,40 @@ expand(list)
                        break;
                }
        }
                        break;
                }
        }
+
+       if (noshexp)
+               return(list);
+
+       path = pathp = pathbuf;
+       *pathp = '\0';
+       lastpathp = &path[sizeof pathbuf - 2];
+       argc = 0;
+       argv = sortbase = argvbuf;
+       *argv = 0;
+       nleft = NCARGS - 4;
+       argcnt = 0;
+       for (bp = list; bp != NULL; bp = bp->b_next)
+               expsh(bp->b_name);
+       for (bp = list; bp != NULL; bp = tp) {
+               tp = bp->b_next;
+               free(bp->b_name);
+               free(bp);
+       }
+       prev = NULL;
+       for (n = 0; n < argc; n++) {
+               bp = ALLOC(block);
+               if (bp == NULL)
+                       fatal("ran out of memory\n");
+               bp->b_type = NAME;
+               bp->b_next = bp->b_args = NULL;
+               bp->b_name = argv[n];
+               if (prev == NULL)
+                       list = prev = bp;
+               else {
+                       prev->b_next = bp;
+                       prev = bp;
+               }
+       }
        return(list);
 }
 
        return(list);
 }
 
@@ -146,9 +149,387 @@ makestr(bp, head, tail)
 /*
  * If there are any Shell meta characters in the name,
  * expand into a list, after searching directory
 /*
  * If there are any Shell meta characters in the name,
  * expand into a list, after searching directory
- * For now, only do ~name.
  */
  */
-shexpand(buf, file)
+expsh(s)
+       register char *s;
+{
+       register int i;
+       register int oargc = argc;
+
+       if (!strcmp(s, "{") || !strcmp(s, "{}")) {
+               Cat(s, "");
+               sort();
+               return;
+       }
+
+       pathp = path;
+       *pathp = 0;
+       expany = 0;
+       expstr(s);
+       if (argc != oargc)
+               sort();
+}
+
+/*
+ * Bubble sort any new entries
+ */
+sort()
+{
+       register char **p1, **p2, *c;
+       char **ap = &argv[argc];
+
+       p1 = sortbase;
+       while (p1 < ap-1) {
+               p2 = p1;
+               while (++p2 < ap)
+                       if (strcmp(*p1, *p2) > 0)
+                               c = *p1, *p1 = *p2, *p2 = c;
+               p1++;
+       }
+       sortbase = ap;
+}
+
+expstr(s)
+       char *s;
+{
+       register char *cp;
+       register char *spathp, *oldcp;
+       struct stat stb;
+
+       spathp = pathp;
+       cp = s;
+       while (!any(*cp, shchars)) {
+               if (*cp == '\0') {
+                       if (!expany)
+                               Cat(path, "");
+                       else if (stat(path, &stb) >= 0) {
+                               Cat(path, "");
+                               argcnt++;
+                       }
+                       goto endit;
+               }
+               addpath(*cp++);
+       }
+       oldcp = cp;
+       while (cp > s && *cp != '/')
+               cp--, pathp--;
+       if (*cp == '/')
+               cp++, pathp++;
+       *pathp = '\0';
+       if (*oldcp == '{') {
+               execbrc(cp, NULL);
+               return;
+       }
+       matchdir(cp);
+endit:
+       pathp = spathp;
+       *pathp = '\0';
+}
+
+matchdir(pattern)
+       char *pattern;
+{
+       struct stat stb;
+       register struct direct *dp;
+       DIR *dirp;
+       register int cnt;
+
+       dirp = opendir(path);
+       if (dirp == NULL) {
+               if (expany)
+                       return;
+               goto patherr2;
+       }
+       if (fstat(dirp->dd_fd, &stb) < 0)
+               goto patherr1;
+       if ((stb.st_mode & S_IFMT) != S_IFDIR) {
+               errno = ENOTDIR;
+               goto patherr1;
+       }
+       while ((dp = readdir(dirp)) != NULL)
+               if (match(dp->d_name, pattern)) {
+                       Cat(path, dp->d_name);
+                       argcnt++;
+               }
+       closedir(dirp);
+       return;
+
+patherr1:
+       closedir(dirp);
+patherr2:
+       fatal("%s: %s\n", path, sys_errlist[errno]);
+}
+
+execbrc(p, s)
+       char *p, *s;
+{
+       char restbuf[BUFSIZ + 2];
+       register char *pe, *pm, *pl;
+       int brclev = 0;
+       char *lm, savec, *spathp;
+
+       for (lm = restbuf; *p != '{'; *lm++ = *p++)
+               continue;
+       for (pe = ++p; *pe; pe++)
+               switch (*pe) {
+
+               case '{':
+                       brclev++;
+                       continue;
+
+               case '}':
+                       if (brclev == 0)
+                               goto pend;
+                       brclev--;
+                       continue;
+
+               case '[':
+                       for (pe++; *pe && *pe != ']'; pe++)
+                               continue;
+                       if (!*pe)
+                               fatal("Missing ]\n");
+                       continue;
+               }
+pend:
+       if (brclev || !*pe)
+               fatal("Missing }\n");
+       for (pl = pm = p; pm <= pe; pm++)
+               switch (*pm & (QUOTE|TRIM)) {
+
+               case '{':
+                       brclev++;
+                       continue;
+
+               case '}':
+                       if (brclev) {
+                               brclev--;
+                               continue;
+                       }
+                       goto doit;
+
+               case ',':
+                       if (brclev)
+                               continue;
+doit:
+                       savec = *pm;
+                       *pm = 0;
+                       strcpy(lm, pl);
+                       strcat(restbuf, pe + 1);
+                       *pm = savec;
+                       if (s == 0) {
+                               spathp = pathp;
+                               expstr(restbuf);
+                               pathp = spathp;
+                               *pathp = 0;
+                       } else if (amatch(s, restbuf))
+                               return (1);
+                       sort();
+                       pl = pm + 1;
+                       continue;
+
+               case '[':
+                       for (pm++; *pm && *pm != ']'; pm++)
+                               continue;
+                       if (!*pm)
+                               fatal("Missing ]\n");
+                       continue;
+               }
+       return (0);
+}
+
+match(s, p)
+       char *s, *p;
+{
+       register int c;
+       register char *sentp;
+       char sexpany = expany;
+
+       if (*s == '.' && *p != '.')
+               return (0);
+       sentp = entp;
+       entp = s;
+       c = amatch(s, p);
+       entp = sentp;
+       expany = sexpany;
+       return (c);
+}
+
+amatch(s, p)
+       register char *s, *p;
+{
+       register int scc;
+       int ok, lc;
+       char *spathp;
+       struct stat stb;
+       int c, cc;
+
+       expany = 1;
+       for (;;) {
+               scc = *s++ & TRIM;
+               switch (c = *p++) {
+
+               case '{':
+                       return (execbrc(p - 1, s - 1));
+
+               case '[':
+                       ok = 0;
+                       lc = 077777;
+                       while (cc = *p++) {
+                               if (cc == ']') {
+                                       if (ok)
+                                               break;
+                                       return (0);
+                               }
+                               if (cc == '-') {
+                                       if (lc <= scc && scc <= *p++)
+                                               ok++;
+                               } else
+                                       if (scc == (lc = cc))
+                                               ok++;
+                       }
+                       if (cc == 0)
+                               fatal("Missing ]\n");
+                       continue;
+
+               case '*':
+                       if (!*p)
+                               return (1);
+                       if (*p == '/') {
+                               p++;
+                               goto slash;
+                       }
+                       for (s--; *s; s++)
+                               if (amatch(s, p))
+                                       return (1);
+                       return (0);
+
+               case '\0':
+                       return (scc == '\0');
+
+               default:
+                       if (c != scc)
+                               return (0);
+                       continue;
+
+               case '?':
+                       if (scc == '\0')
+                               return (0);
+                       continue;
+
+               case '/':
+                       if (scc)
+                               return (0);
+slash:
+                       s = entp;
+                       spathp = pathp;
+                       while (*s)
+                               addpath(*s++);
+                       addpath('/');
+                       if (stat(path, &stb) == 0 &&
+                           (stb.st_mode & S_IFMT) == S_IFDIR)
+                               if (*p == '\0') {
+                                       Cat(path, "");
+                                       argcnt++;
+                               } else
+                                       expstr(p);
+                       pathp = spathp;
+                       *pathp = '\0';
+                       return (0);
+               }
+       }
+}
+
+smatch(s, p)
+       register char *s, *p;
+{
+       register int scc;
+       int ok, lc;
+       int c, cc;
+
+       for (;;) {
+               scc = *s++ & TRIM;
+               switch (c = *p++) {
+
+               case '[':
+                       ok = 0;
+                       lc = 077777;
+                       while (cc = *p++) {
+                               if (cc == ']') {
+                                       if (ok)
+                                               break;
+                                       return (0);
+                               }
+                               if (cc == '-') {
+                                       if (lc <= scc && scc <= *p++)
+                                               ok++;
+                               } else
+                                       if (scc == (lc = cc))
+                                               ok++;
+                       }
+                       if (cc == 0)
+                               fatal("Missing ]\n");
+                       continue;
+
+               case '*':
+                       if (!*p)
+                               return (1);
+                       for (s--; *s; s++)
+                               if (smatch(s, p))
+                                       return (1);
+                       return (0);
+
+               case '\0':
+                       return (scc == '\0');
+
+               default:
+                       if ((c & TRIM) != scc)
+                               return (0);
+                       continue;
+
+               case '?':
+                       if (scc == 0)
+                               return (0);
+                       continue;
+
+               }
+       }
+}
+
+Cat(s1, s2)
+       register char *s1, *s2;
+{
+       int len = strlen(s1) + strlen(s2) + 1;
+       register char *s, *ep;
+
+       nleft -= len;
+       if (nleft <= 0 || ++argc >= GAVSIZ)
+               fatal("Arguments too long\n");
+       argv[argc] = 0;
+       argv[argc - 1] = s = (char *) malloc(len);
+       if (s == NULL)
+               fatal("ran out of memory\n");
+       while (*s++ = *s1++ & TRIM)
+               ;
+       s--;
+       while (*s++ = *s2++ & TRIM)
+               ;
+}
+
+addpath(c)
+       char c;
+{
+
+       if (pathp >= lastpathp)
+               fatal("Pathname too long\n");
+       *pathp++ = c;
+       *pathp = '\0';
+}
+
+/*
+ * Expand file names beginning with `~' into the
+ * user's home directory path name.
+ */
+exptilde(buf, file)
        char buf[];
        register char *file;
 {
        char buf[];
        register char *file;
 {
@@ -171,10 +552,9 @@ shexpand(buf, file)
                        *s3 = '\0';
                else
                        s3 = NULL;
                        *s3 = '\0';
                else
                        s3 = NULL;
-               setpwent();
                pw = getpwnam(file);
                if (pw == NULL) {
                pw = getpwnam(file);
                if (pw == NULL) {
-                       error("unknown user %s\n", file);
+                       fatal("unknown user %s\n", file);
                        if (s3 != NULL)
                                *s3 = '/';
                        return;
                        if (s3 != NULL)
                                *s3 = '/';
                        return;
index c9f12c3..34a7c08 100644 (file)
@@ -1,23 +1,25 @@
 %{
 #ifndef lint
 %{
 #ifndef lint
-static char *sccsid = "@(#)gram.y      4.1 (Berkeley) 83/09/07";
+static char *sccsid = "@(#)gram.y      4.2 (Berkeley) 83/09/27";
 #endif
 
 #include "defs.h"
 
 #endif
 
 #include "defs.h"
 
-struct block *last;
+struct block *lastn;
+struct block *lastc;
 
 %}
 
 %term EQUAL 1
 
 %}
 
 %term EQUAL 1
-%term ARROW 2
-%term LP 3
-%term RP 4
-%term NAME 5
-%term INSTALL 6
-%term VERIFY 7
-%term NOTIFY 8
-%term EXCEPT 9
+%term LP 2
+%term RP 3
+%term ARROW 4
+%term DCOLON 5
+%term NAME 6
+%term INSTALL 7
+%term VERIFY 8
+%term NOTIFY 9
+%term EXCEPT 10
 
 %union
        {
 
 %union
        {
@@ -34,10 +36,13 @@ file:                 /* VOID */
 
 command:         NAME EQUAL namelist = {
                        $1->b_args = $3;
 
 command:         NAME EQUAL namelist = {
                        $1->b_args = $3;
-                       (void) lookup($1->b_name, 1, $1);
+                       (void) lookup($1->b_name, $1, 1);
                }
                | namelist ARROW namelist cmdlist = {
                }
                | namelist ARROW namelist cmdlist = {
-                       docmd($1, $3, $4);
+                       dohcmds($1, $3, $4);
+               }
+               | namelist DCOLON namelist cmdlist = {
+                       dofcmds($1, $3, $4);
                }
                | error
                ;
                }
                | error
                ;
@@ -51,49 +56,53 @@ namelist:     NAME = {
                ;
 
 names:           /* VOID */ {
                ;
 
 names:           /* VOID */ {
-                       $$ = last = NULL;
+                       $$ = lastn = NULL;
                }
                | names NAME = {
                }
                | names NAME = {
-                       if (last == NULL)
-                               $$ = last = $2;
+                       if (lastn == NULL)
+                               $$ = lastn = $2;
                        else {
                        else {
-                               last->b_next = $2;
-                               last = $2;
+                               lastn->b_next = $2;
+                               lastn = $2;
                                $$ = $1;
                        }
                }
                ;
 
 cmdlist:         /* VOID */ {
                                $$ = $1;
                        }
                }
                ;
 
 cmdlist:         /* VOID */ {
-                       $$ = last = NULL;
+                       $$ = lastc = NULL;
                }
                | cmdlist cmd = {
                }
                | cmdlist cmd = {
-                       if (last == NULL)
-                               $$ = last = $2;
+                       if (lastc == NULL)
+                               $$ = lastc = $2;
                        else {
                        else {
-                               last->b_next = $2;
-                               last = $2;
+                               lastc->b_next = $2;
+                               lastc = $2;
                                $$ = $1;
                        }
                }
                ;
 
 cmd:             INSTALL NAME = {
                                $$ = $1;
                        }
                }
                ;
 
 cmd:             INSTALL NAME = {
-                       $1->b_name = $2->b_name;
+                       register struct block *b;
+
+               inst_name:
+                       b = expand($2, 0);
+                       if (b == NULL || b->b_next != NULL)
+                               fatal("exactly one name allowed\n");
+                       $1->b_name = b->b_name;
                        free($2);
                        $$ = $1;
                }
                | VERIFY NAME = {
                        free($2);
                        $$ = $1;
                }
                | VERIFY NAME = {
-                       $1->b_name = $2->b_name;
-                       free($2);
-                       $$ = $1;
+                       goto inst_name;
                }
                | NOTIFY namelist = {
                }
                | NOTIFY namelist = {
-                       $1->b_args = $2;
+                       $1->b_args = expand($2, 1);
                        $$ = $1;
                }
                | EXCEPT namelist = {
                        $$ = $1;
                }
                | EXCEPT namelist = {
-                       $1->b_args = expand($2);
+                       $1->b_args = expand($2, 0);
                        $$ = $1;
                }
                ;
                        $$ = $1;
                }
                ;
@@ -109,82 +118,85 @@ yylex()
        register int c;
        register char *cp1, *cp2;
        register struct block *bp;
        register int c;
        register char *cp1, *cp2;
        register struct block *bp;
+       static char quotechars[] = "[]{}*?";
        
        
-       for (;;) {
-               switch (c = getc(fin)) {
-               case EOF:  /* end of file */
+again:
+       switch (c = getc(fin)) {
+       case EOF:  /* end of file */
+               return(0);
+
+       case '#':  /* start of comment */
+               while ((c = getc(fin)) != EOF && c != '\n')
+                       ;
+               if (c == EOF)
                        return(0);
                        return(0);
-
-               case '#':  /* start of comment */
-                       while ((c = getc(fin)) != EOF && c != '\n')
-                               ;
-                       if (c == EOF)
-                               return(0);
-               case '\n':
-                       yylineno++;
-               case ' ':
-               case '\t':  /* skip blanks */
-                       continue;
-
-               case '=':  /* EQUAL */
-                       return(EQUAL);
-
-               case '(':  /* LP */
-                       return(LP);
-
-               case ')':  /* RP */
-                       return(RP);
-
-               case '-':  /* -> */
-                       if ((c = getc(fin)) == '>')
-                               return(ARROW);
-                       ungetc(c, fin);
-                       c = '-';
-               }
-               /*
-                * Start of a name.
-                */
-               cp1 = yytext;
-               cp2 = &yytext[INMAX - 1];
-               for (;;) {
-                       if (cp1 >= cp2) {
-                               fatal("input line too long\n");
-                               break;
-                       }
-                       *cp1++ = c;
-                       c = getc(fin);
-                       if (c == EOF || any(c, " \t()=\n")) {
-                               ungetc(c, fin);
+       case '\n':
+               yylineno++;
+       case ' ':
+       case '\t':  /* skip blanks */
+               goto again;
+
+       case '=':  /* EQUAL */
+               return(EQUAL);
+
+       case '(':  /* LP */
+               return(LP);
+
+       case ')':  /* RP */
+               return(RP);
+
+       case '-':  /* -> */
+               if ((c = getc(fin)) == '>')
+                       return(ARROW);
+               ungetc(c, fin);
+               c = '-';
+               break;
+
+       case ':':  /* :: */
+               if ((c = getc(fin)) == ':')
+                       return(DCOLON);
+               ungetc(c, fin);
+               c = ':';
+       }
+       /*
+        * Start of a name.
+        */
+       cp1 = yytext;
+       cp2 = &yytext[INMAX - 1];
+       for (;;) {
+               if (cp1 >= cp2) {
+                       fatal("input line too long\n");
+                       break;
+               }
+               if (c == '\\') {
+                       if ((c = getc(fin)) != EOF) {
+                               if (any(c, quotechars))
+                                       c |= QUOTE;
+                       } else {
+                               *cp1++ = '\\';
                                break;
                        }
                }
                                break;
                        }
                }
-               *cp1 = '\0';
-               yylval.blk = bp = ALLOC(block);
-               if (bp == NULL)
-                       fatal("ran out of memory\n");
-               if (!strcmp(yytext, "install"))
-                       c = INSTALL;
-               else if (!strcmp(yytext, "verify"))
-                       c = VERIFY;
-               else if (!strcmp(yytext, "notify"))
-                       c = NOTIFY;
-               else if (!strcmp(yytext, "except"))
-                       c = EXCEPT;
-               else
-                       c = NAME;
-               bp->b_type = c;
-               bp->b_next = bp->b_args = NULL;
-               if (c == NAME) {
-                       c = strlen(yytext) + 1;
-                       bp->b_name = cp1 = (char *) malloc(c);
-                       if (cp1 == NULL)
-                               fatal("ran out of memory\n");
-                       for (cp2 = yytext; *cp1++ = *cp2++; )
-                               ;
-               } else
-                       bp->b_name = NULL;
-               return(bp->b_type);
+               *cp1++ = c;
+               c = getc(fin);
+               if (c == EOF || any(c, " \t()=\n")) {
+                       ungetc(c, fin);
+                       break;
+               }
        }
        }
+       *cp1 = '\0';
+       if (!strcmp(yytext, "install"))
+               c = INSTALL;
+       else if (!strcmp(yytext, "verify"))
+               c = VERIFY;
+       else if (!strcmp(yytext, "notify"))
+               c = NOTIFY;
+       else if (!strcmp(yytext, "except"))
+               c = EXCEPT;
+       else
+               c = NAME;
+       yylval.blk = bp = makeblock(c, yytext);
+       return(c);
 }
 
 any(c, str)
 }
 
 any(c, str)
index 08840e5..6a5836c 100644 (file)
@@ -1,5 +1,5 @@
 #ifndef lint
 #ifndef lint
-static char *sccsid = "@(#)lookup.c    4.1 (Berkeley) 83/09/27";
+static char *sccsid = "@(#)lookup.c    4.2 (Berkeley) 83/09/27";
 #endif
 
 #include "defs.h"
 #endif
 
 #include "defs.h"
index 80c52ae..6399478 100644 (file)
@@ -1,5 +1,5 @@
 #ifndef lint
 #ifndef lint
-static char *sccsid = "@(#)main.c      4.1 (Berkeley) 83/09/07";
+static char *sccsid = "@(#)main.c      4.2 (Berkeley) 83/09/27";
 #endif
 
 #include "defs.h"
 #endif
 
 #include "defs.h"
@@ -9,7 +9,9 @@ static  char *sccsid = "@(#)main.c      4.1 (Berkeley) 83/09/07";
  */
 
 char   *distfile = "distfile";
  */
 
 char   *distfile = "distfile";
-char   *tmpfile = "/tmp/rdistXXXXXX";
+char   tmpfile[] = "/tmp/rdistAXXXXXX";
+char   *tmpname = &tmpfile[5];
+char   *tmpinc = &tmpfile[10];
 
 int    debug;          /* debugging flag */
 int    nflag;          /* NOP flag, just print commands without executing */
 
 int    debug;          /* debugging flag */
 int    nflag;          /* NOP flag, just print commands without executing */
@@ -27,7 +29,8 @@ int   errs;           /* number of errors while sending/receiving */
 char   user[10];       /* user's name */
 char   homedir[128];   /* user's home directory */
 int    userid;         /* user's user ID */
 char   user[10];       /* user's name */
 char   homedir[128];   /* user's home directory */
 int    userid;         /* user's user ID */
-int    usergid;        /* user's group ID */
+int    groupid;        /* user's group ID */
+int    iamupdate;
 
 int    cleanup();
 int    lostconn();
 
 int    cleanup();
 int    lostconn();
@@ -39,16 +42,22 @@ main(argc, argv)
        register char *arg;
        register struct passwd *pw;
 
        register char *arg;
        register struct passwd *pw;
 
-       setpwent();
+       arg = rindex(argv[0], '/');
+       if (arg == NULL)
+               arg = argv[0];
+       else
+               arg++;
+       if (!strcmp(arg, "update"))
+               iamupdate++;
+
        pw = getpwuid(userid = getuid());
        pw = getpwuid(userid = getuid());
-       endpwent();
        if (pw == NULL) {
        if (pw == NULL) {
-               fprintf(stderr, "rdist: Who are you?\n");
+               fprintf(stderr, "%s: Who are you?\n", argv[0]);
                exit(1);
        }
        strcpy(user, pw->pw_name);
        strcpy(homedir, pw->pw_dir);
                exit(1);
        }
        strcpy(user, pw->pw_name);
        strcpy(homedir, pw->pw_dir);
-       usergid = pw->pw_gid;
+       groupid = pw->pw_gid;
        gethostname(host, sizeof(host));
 
        while (--argc > 0) {
        gethostname(host, sizeof(host));
 
        while (--argc > 0) {
@@ -67,6 +76,12 @@ main(argc, argv)
                                break;
 
                        case 'd':
                                break;
 
                        case 'd':
+                               if (--argc <= 0)
+                                       usage();
+                               define(*++argv);
+                               break;
+
+                       case 'D':
                                debug++;
                                break;
 
                                debug++;
                                break;
 
@@ -90,31 +105,102 @@ main(argc, argv)
                                usage();
                        }
        }
                                usage();
                        }
        }
+
+       mktemp(tmpfile);
        signal(SIGPIPE, lostconn);
        if (iamremote) {
                server();
                exit(errs);
        }
        signal(SIGPIPE, lostconn);
        if (iamremote) {
                server();
                exit(errs);
        }
-       filec = argc;
-       filev = argv;
 
 
-       if (fin == NULL && (fin = fopen(distfile, "r")) == NULL) {
-               perror(distfile);
-               exit(1);
-       }
-       mktemp(tmpfile);
        signal(SIGHUP, cleanup);
        signal(SIGINT, cleanup);
        signal(SIGQUIT, cleanup);
        signal(SIGTERM, cleanup);
 
        signal(SIGHUP, cleanup);
        signal(SIGINT, cleanup);
        signal(SIGQUIT, cleanup);
        signal(SIGTERM, cleanup);
 
-       yyparse();
+       if (iamupdate)
+               doupdate(argc, argv);
+       else {
+               filec = argc;
+               filev = argv;
+               if (fin == NULL && (fin = fopen(distfile, "r")) == NULL) {
+                       perror(distfile);
+                       exit(1);
+               }
+               yyparse();
+       }
+
        exit(errs);
 }
 
 usage()
 {
        exit(errs);
 }
 
 usage()
 {
-       printf("Usage: rdist [-f distfile] [-n] [-q] [-y] [-d] [file ...]\n");
+       printf("Usage: rdist [-f distfile] [-d var=value] [-nqyD] [file ...]\n");
+       exit(1);
+}
+
+/*
+ * rcp like interface for distributing files.
+ */
+doupdate(nargs, args)
+       int nargs;
+       char *args[];
+{
+       struct block *bp, *files, *hosts, *cmds, *prev;
+       int i, firsttime = 1;
+       char *pos, dest[BUFSIZ];
+
+       if (nargs < 2)
+               upusage();
+
+       prev = NULL;
+       bp = files = ALLOC(block);
+       for (i = 0; i < nargs - 1; bp = ALLOC(block), i++) {
+               bp->b_type = NAME;
+               bp->b_name = args[i];
+               if (prev != NULL)
+                       prev->b_next = bp;
+               bp->b_next = bp->b_args = NULL;
+               prev = bp;
+       }
+
+       hosts = ALLOC(block);
+       hosts->b_type = NAME;
+       hosts->b_name = args[i];
+       hosts->b_name = args[i];
+       hosts->b_next = hosts->b_args = NULL;
+       if ((pos = index(hosts->b_name, ':')) != NULL) {
+               *pos++ = '\0';
+               strcpy(dest, pos);
+       } else
+               dest[0] = '\0';
+
+       hosts = expand(hosts, 0);
+
+       if (dest[0] == '\0')
+               cmds = NULL;
+       else {
+               cmds = ALLOC(block);
+               if (vflag)
+                       cmds->b_type = VERIFY;
+               else
+                       cmds->b_type = INSTALL;
+               cmds->b_name = dest;
+               cmds->b_next = cmds->b_args = NULL;
+       }
+
+       if (debug) {
+               printf("doupdate()\nfiles = ");
+               prnames(files);
+               printf("hosts = ");
+               prnames(hosts);
+       }
+       dohcmds(files, hosts, cmds);
+}
+
+upusage()
+{
+       printf("Usage: update [-nqyD] source [...] machine[:dest]\n");
        exit(1);
 }
 
        exit(1);
 }
 
index da9f0c7..efb827e 100644 (file)
@@ -1,16 +1,21 @@
 #ifndef lint
 #ifndef lint
-static char *sccsid = "@(#)server.c    4.1 (Berkeley) 83/09/07";
+static char *sccsid = "@(#)server.c    4.2 (Berkeley) 83/09/27";
 #endif
 
 #include "defs.h"
 
 #define        ga()    (void) write(rem, "", 1)
 
 #endif
 
 #include "defs.h"
 
 #define        ga()    (void) write(rem, "", 1)
 
-char   buf[BUFSIZ];            /* gerneral purpose buffer */
+char   buf[BUFSIZ];            /* general purpose buffer */
 char   target[BUFSIZ];         /* target/source directory name */
 char   *tp;                    /* pointer to end of target name */
 int    catname;                /* cat name to target name */
 
 char   target[BUFSIZ];         /* target/source directory name */
 char   *tp;                    /* pointer to end of target name */
 int    catname;                /* cat name to target name */
 
+static struct passwd *p = NULL;
+static struct group *g = NULL;
+
+extern FILE *lfp;              /* log file for mailing changes */
+
 /*
  * Server routine to read requests and process them.
  * Commands are:
 /*
  * Server routine to read requests and process them.
  * Commands are:
@@ -40,7 +45,7 @@ server()
                do {
                        if (read(rem, cp, 1) != 1)
                                lostconn();
                do {
                        if (read(rem, cp, 1) != 1)
                                lostconn();
-               } while (*cp++ != '\n');
+               } while (*cp++ != '\n' && cp < &cmdbuf[BUFSIZ]);
                *--cp = '\0';
                cp = cmdbuf;
                switch (*cp++) {
                *--cp = '\0';
                cp = cmdbuf;
                switch (*cp++) {
@@ -66,8 +71,13 @@ server()
                        continue;
 
                case 'T':  /* init target file/directory name */
                        continue;
 
                case 'T':  /* init target file/directory name */
+                       catname = 1;    /* target should be directory */
+                       goto dotarget;
+
+               case 't':  /* init target file/directory name */
                        catname = 0;
                        catname = 0;
-                       shexpand(target, cp);
+               dotarget:
+                       exptilde(target, cp);
                        tp = target;
                        while (*tp)
                                tp++;
                        tp = target;
                        while (*tp)
                                tp++;
@@ -93,13 +103,17 @@ server()
 
                case 'E':  /* End. (of directory) */
                        *tp = '\0';
 
                case 'E':  /* End. (of directory) */
                        *tp = '\0';
-                       cp = rindex(target, '/');
-                       if (cp == NULL || --catname < 0) {
+                       if (--catname < 0) {
                                error("too many 'E's\n");
                                continue;
                        }
                                error("too many 'E's\n");
                                continue;
                        }
-                       *cp = '\0';
-                       tp = cp;
+                       cp = rindex(target, '/');
+                       if (cp == NULL)
+                               tp = NULL;
+                       else {
+                               *cp = '\0';
+                               tp = cp;
+                       }
                        ga();
                        continue;
 
                        ga();
                        continue;
 
@@ -111,6 +125,13 @@ server()
                        query(cp);
                        continue;
 
                        query(cp);
                        continue;
 
+               case '\1':
+                       errs++;
+                       continue;
+
+               case '\2':
+                       return;
+
                default:
                        error("unknown command type %s\n", cp);
                case '\0':
                default:
                        error("unknown command type %s\n", cp);
                case '\0':
@@ -127,10 +148,8 @@ sendf(name, verify)
        int verify;
 {
        register char *last;
        int verify;
 {
        register char *last;
-       struct passwd *p;
-       struct group *g;
        struct stat stb;
        struct stat stb;
-       int sizerr, f;
+       int sizerr, f, u;
        off_t i;
 
        if (debug)
        off_t i;
 
        if (debug)
@@ -139,6 +158,15 @@ sendf(name, verify)
        if (exclude(name))
                return;
 
        if (exclude(name))
                return;
 
+       /*
+        * first time sendf() is called?
+        */
+       if (tp == NULL) {
+               exptilde(target, name);
+               tp = name = target;
+               while (*tp)
+                       tp++;
+       }
        if (access(name, 4) < 0 || stat(name, &stb) < 0) {
                error("%s: %s\n", name, sys_errlist[errno]);
                return;
        if (access(name, 4) < 0 || stat(name, &stb) < 0) {
                error("%s: %s\n", name, sys_errlist[errno]);
                return;
@@ -148,21 +176,19 @@ sendf(name, verify)
                last = name;
        else
                last++;
                last = name;
        else
                last++;
-       if (!update(last, &stb))
+       if ((u = update(last, &stb)) == 0)
                return;
 
                return;
 
-       setpwent();
-       if ((p = getpwuid(stb.st_uid)) == NULL) {
-               error("no password entry for uid %d\n", stb.st_uid);
-               return;
-       }
-       endpwent();
-       setgrent();
-       if ((g = getgrgid(stb.st_gid)) == NULL) {
-               error("no name for group %d\n", stb.st_gid);
-               return;
-       }
-       endgrent();
+       if (p == NULL || p->pw_uid != stb.st_uid)
+               if ((p = getpwuid(stb.st_uid)) == NULL) {
+                       error("no password entry for uid %d\n", stb.st_uid);
+                       return;
+               }
+       if (g == NULL || g->gr_gid != stb.st_gid)
+               if ((g = getgrgid(stb.st_gid)) == NULL) {
+                       error("no name for group %d\n", stb.st_gid);
+                       return;
+               }
 
        switch (stb.st_mode & S_IFMT) {
        case S_IFREG:
 
        switch (stb.st_mode & S_IFMT) {
        case S_IFREG:
@@ -177,15 +203,15 @@ sendf(name, verify)
                return;
        }
 
                return;
        }
 
-       if ((f = open(name, 0)) < 0) {
-               error("%s: %s\n", name, sys_errlist[errno]);
-               return;
-       }
-       log("updating: %s\n", name);
+       log(lfp, "%s: %s\n", u == 2 ? "updating" : "installing", name);
 
        if (verify || vflag)
                return;
 
 
        if (verify || vflag)
                return;
 
+       if ((f = open(name, 0)) < 0) {
+               error("%s: %s\n", name, sys_errlist[errno]);
+               return;
+       }
        (void) sprintf(buf, "R%04o %D %D %s %s %s\n", stb.st_mode & 07777,
                stb.st_size, stb.st_mtime, p->pw_name, g->gr_name, last);
        if (debug)
        (void) sprintf(buf, "R%04o %D %D %s %s %s\n", stb.st_mode & 07777,
                stb.st_size, stb.st_mtime, p->pw_name, g->gr_name, last);
        if (debug)
@@ -222,6 +248,7 @@ rsendf(name, verify, st, owner, group)
        struct direct *dp;
        register char *last;
        char *otp;
        struct direct *dp;
        register char *last;
        char *otp;
+       int len;
 
        if (debug)
                printf("rsendf(%s, %d, %x, %s, %s)\n", name, verify, st,
 
        if (debug)
                printf("rsendf(%s, %d, %x, %s, %s)\n", name, verify, st,
@@ -245,23 +272,12 @@ rsendf(name, verify, st, owner, group)
                closedir(d);
                return;
        }
                closedir(d);
                return;
        }
-       /*
-        * first time rsendf() is called?
-        */
-       if (tp == NULL) {
-               tp = target;
-               last = name;
-               while (*tp++ = *last++)
-                       ;
-               tp--;
-       }
        otp = tp;
        otp = tp;
+       len = tp - target;
        while (dp = readdir(d)) {
        while (dp = readdir(d)) {
-               if (dp->d_ino == 0)
-                       continue;
                if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
                        continue;
                if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
                        continue;
-               if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
+               if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
                        error("%s/%s: Name too long\n", name, dp->d_name);
                        continue;
                }
                        error("%s/%s: Name too long\n", name, dp->d_name);
                        continue;
                }
@@ -282,6 +298,7 @@ rsendf(name, verify, st, owner, group)
 
 /*
  * Check to see if file needs to be updated on the remote machine.
 
 /*
  * Check to see if file needs to be updated on the remote machine.
+ * Returns 0 if no update, 1 if remote doesn't exist, and 2 if out of date.
  */
 update(name, st)
        char *name;
  */
 update(name, st)
        char *name;
@@ -305,7 +322,7 @@ update(name, st)
        do {
                if (read(rem, cp, 1) != 1)
                        lostconn();
        do {
                if (read(rem, cp, 1) != 1)
                        lostconn();
-       } while (*cp++ != '\n');
+       } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
        *--cp = '\0';
        cp = buf;
        if (debug)
        *--cp = '\0';
        cp = buf;
        if (debug)
@@ -315,11 +332,19 @@ update(name, st)
        case 'Y':
                break;
 
        case 'Y':
                break;
 
-       case 'N':  /* file doesn't exist so update it */
+       case 'N':  /* file doesn't exist so install it */
                return(1);
 
        case '\1':
                return(1);
 
        case '\1':
-               error("%s\n", cp);
+               errs++;
+               if (*cp != '\0') {
+                       if (!iamremote) {
+                               fflush(stdout);
+                               (void) write(2, cp, strlen(cp));
+                       }
+                       if (lfp != NULL)
+                               (void) fwrite(cp, 1, strlen(cp), lfp);
+               }
                return(0);
 
        default:
                return(0);
 
        default:
@@ -329,9 +354,8 @@ update(name, st)
 
        if (*cp == '\0') {
                if ((st->st_mode & S_IFMT) == S_IFDIR)
 
        if (*cp == '\0') {
                if ((st->st_mode & S_IFMT) == S_IFDIR)
-                       return(1);
-               error("file -> directory\n");
-               return(0);
+                       return(2);
+               return(1);
        }
 
        size = 0;
        }
 
        size = 0;
@@ -352,10 +376,9 @@ update(name, st)
         * File needs to be updated?
         */
        if (st->st_mtime == mtime && st->st_size == size ||
         * File needs to be updated?
         */
        if (st->st_mtime == mtime && st->st_size == size ||
-           yflag && st->st_mtime < mtime) {
+           yflag && st->st_mtime < mtime)
                return(0);
                return(0);
-       }
-       return(1);
+       return(2);
 }
 
 /*
 }
 
 /*
@@ -407,6 +430,7 @@ recvf(cmd, isdir)
        struct timeval tvp[2];
        char *owner, *group, *dir;
        char new[BUFSIZ];
        struct timeval tvp[2];
        char *owner, *group, *dir;
        char new[BUFSIZ];
+       extern char *tmpname;
 
        mode = 0;
        for (cp = cmd; cp < cmd+4; cp++) {
 
        mode = 0;
        for (cp = cmd; cp < cmd+4; cp++) {
@@ -451,6 +475,7 @@ recvf(cmd, isdir)
        }
        *cp++ = '\0';
 
        }
        *cp++ = '\0';
 
+       new[0] = '\0';
        if (isdir) {
                if (catname++) {
                        *tp++ = '/';
        if (isdir) {
                if (catname++) {
                        *tp++ = '/';
@@ -458,6 +483,10 @@ recvf(cmd, isdir)
                                ;
                        tp--;
                }
                                ;
                        tp--;
                }
+               if (vflag) {
+                       ga();
+                       return;
+               }
                if (stat(target, &stb) == 0) {
                        if ((stb.st_mode & S_IFMT) != S_IFDIR) {
                                errno = ENOTDIR;
                if (stat(target, &stb) == 0) {
                        if ((stb.st_mode & S_IFMT) != S_IFDIR) {
                                errno = ENOTDIR;
@@ -477,16 +506,15 @@ recvf(cmd, isdir)
                                dir = target;
                                *cp = '\0';
                        }
                                dir = target;
                                *cp = '\0';
                        }
-                       f = access(dir, 2);
+                       if (access(dir, 2) < 0)
+                               goto bad2;
                        if (cp != NULL)
                                *cp = '/';
                        if (cp != NULL)
                                *cp = '/';
-                       if (f < 0)
-                               goto bad;
                        if (mkdir(target, mode) < 0)
                                goto bad;
                        if (mkdir(target, mode) < 0)
                                goto bad;
+                       if (chog(target, owner, group, mode) < 0)
+                               return;
                }
                }
-               if (chog(target, owner, group) < 0)
-                       return;
                ga();
                return;
        }
                ga();
                return;
        }
@@ -522,17 +550,23 @@ recvf(cmd, isdir)
                dir = target;
                *cp = '\0';
        }
                dir = target;
                *cp = '\0';
        }
-       (void) sprintf(new, "%s/rdistXXXXXX", dir);
-       mktemp(new);
-       f = access(dir, 2);
+       if (access(dir, 2) < 0) {
+bad2:
+               error("%s: %s\n", dir, sys_errlist[errno]);
+               if (cp != NULL)
+                       *cp = '/';
+               return;
+       }
+       (void) sprintf(new, "%s/%s", dir, tmpname);
        if (cp != NULL)
                *cp = '/';
        if (cp != NULL)
                *cp = '/';
-       if (f < 0)
-               goto bad;
        if ((f = creat(new, mode)) < 0)
                goto bad1;
        if ((f = creat(new, mode)) < 0)
                goto bad1;
-       if (chog(new, owner, group) < 0)
+       if (chog(new, owner, group, mode) < 0) {
+               (void) close(f);
+               (void) unlink(new);
                return;
                return;
+       }
        ga();
 
        wrerr = 0;
        ga();
 
        wrerr = 0;
@@ -545,8 +579,11 @@ recvf(cmd, isdir)
                do {
                        int j = read(rem, cp, amt);
 
                do {
                        int j = read(rem, cp, amt);
 
-                       if (j <= 0)
+                       if (j <= 0) {
+                               (void) close(f);
+                               (void) unlink(new);
                                cleanup();
                                cleanup();
+                       }
                        amt -= j;
                        cp += j;
                } while (amt > 0);
                        amt -= j;
                        cp += j;
                } while (amt > 0);
@@ -561,6 +598,8 @@ recvf(cmd, isdir)
        (void) response();
        if (wrerr) {
                error("%s: %s\n", cp, sys_errlist[olderrno]);
        (void) response();
        if (wrerr) {
                error("%s: %s\n", cp, sys_errlist[olderrno]);
+               (void) close(f);
+               (void) unlink(new);
                return;
        }
 
                return;
        }
 
@@ -576,12 +615,16 @@ recvf(cmd, isdir)
        if (utimes(new, tvp) < 0) {
 bad1:
                error("%s: %s\n", new, sys_errlist[errno]);
        if (utimes(new, tvp) < 0) {
 bad1:
                error("%s: %s\n", new, sys_errlist[errno]);
+               if (new[0])
+                       (void) unlink(new);
                return;
        }
        
        if (rename(new, target) < 0) {
 bad:
                error("%s: %s\n", target, sys_errlist[errno]);
                return;
        }
        
        if (rename(new, target) < 0) {
 bad:
                error("%s: %s\n", target, sys_errlist[errno]);
+               if (new[0])
+                       (void) unlink(new);
                return;
        }
        ga();
                return;
        }
        ga();
@@ -590,38 +633,44 @@ bad:
 /*
  * Change owner and group of file.
  */
 /*
  * Change owner and group of file.
  */
-chog(file, owner, group)
+chog(file, owner, group, mode)
        char *file, *owner, *group;
        char *file, *owner, *group;
+       int mode;
 {
 {
-       extern int userid, usergid;
-       extern char *user;
-       struct passwd *p;
-       struct group *g;
+       extern int userid, groupid;
+       extern char user[];
        register int i;
        int uid, gid;
 
        uid = userid;
        if (userid == 0) {
        register int i;
        int uid, gid;
 
        uid = userid;
        if (userid == 0) {
-               p = getpwnam(owner);
-               if (p == NULL) {
-                       error("%s: unknown login name\n", owner);
-                       return(-1);
-               }
-               uid = p->pw_uid;
-       }
-       setgrent();
-       g = getgrnam(group);
-       if (g == NULL) {
-               error("%s: unknown group\n", group);
-               return(-1);
-       }
-       gid = g->gr_gid;
-       if (userid && usergid != gid) {
-               for (i = 0; g->gr_mem[i]; i++)
+               if (p == NULL || strcmp(owner, p->pw_name) != 0) {
+                       if ((p = getpwnam(owner)) == NULL) {
+                               if (mode & 04000) {
+                                       error("%s: unknown login name\n", owner);
+                                       return(-1);
+                               }
+                       } else
+                               uid = p->pw_uid;
+               } else
+                       uid = p->pw_uid;
+       }
+       gid = groupid;
+       if (g == NULL || strcmp(group, g->gr_name) != 0) {
+               if ((g = getgrnam(group)) == NULL) {
+                       if (mode & 02000) {
+                               error("%s: unknown group\n", group);
+                               return(-1);
+                       }
+               } else
+                       gid = g->gr_gid;
+       } else
+               gid = g->gr_gid;
+       if (userid && groupid != gid) {
+               for (i = 0; g->gr_mem[i] != NULL; i++)
                        if (!(strcmp(user, g->gr_mem[i])))
                                goto ok;
                        if (!(strcmp(user, g->gr_mem[i])))
                                goto ok;
-               error("You are not a member of the %s group\n", group);
-               return(-1);
+               gid = groupid;
        }
 ok:
        if (chown(file, uid, gid) < 0) {
        }
 ok:
        if (chown(file, uid, gid) < 0) {
@@ -631,10 +680,9 @@ ok:
        return(0);
 }
 
        return(0);
 }
 
-extern FILE *lfp;      /* log file for mailing changes */
-
 /*VARARGS*/
 /*VARARGS*/
-log(fmt, a1, a2, a3)
+log(fp, fmt, a1, a2, a3)
+       FILE *fp;
        char *fmt;
        int a1, a2, a3;
 {
        char *fmt;
        int a1, a2, a3;
 {
@@ -643,8 +691,8 @@ log(fmt, a1, a2, a3)
                printf(fmt, a1, a2, a3);
 
        /* Save changes (for mailing) if really updating files */
                printf(fmt, a1, a2, a3);
 
        /* Save changes (for mailing) if really updating files */
-       if (!vflag)
-               fprintf(lfp, fmt, a1, a2, a3);
+       if (!vflag && fp != NULL)
+               fprintf(fp, fmt, a1, a2, a3);
 }
 
 /*VARARGS*/
 }
 
 /*VARARGS*/
@@ -657,8 +705,10 @@ error(fmt, a1, a2, a3)
        (void) sprintf(buf+8, fmt, a1, a2, a3);
        (void) write(rem, buf, strlen(buf));
        if (buf[1] != '\0') {
        (void) sprintf(buf+8, fmt, a1, a2, a3);
        (void) write(rem, buf, strlen(buf));
        if (buf[1] != '\0') {
-               if (!iamremote)
+               if (!iamremote) {
+                       fflush(stdout);
                        (void) write(2, buf+1, strlen(buf+1));
                        (void) write(2, buf+1, strlen(buf+1));
+               }
                if (lfp != NULL)
                        (void) fwrite(buf+1, 1, strlen(buf+1), lfp);
        }
                if (lfp != NULL)
                        (void) fwrite(buf+1, 1, strlen(buf+1), lfp);
        }
@@ -674,8 +724,10 @@ fatal(fmt, a1, a2,a3)
        (void) sprintf(buf+8, fmt, a1, a2, a3);
        (void) write(rem, buf, strlen(buf));
        if (buf[1] != '\0') {
        (void) sprintf(buf+8, fmt, a1, a2, a3);
        (void) write(rem, buf, strlen(buf));
        if (buf[1] != '\0') {
-               if (!iamremote)
+               if (!iamremote) {
+                       fflush(stdout);
                        (void) write(2, buf+1, strlen(buf+1));
                        (void) write(2, buf+1, strlen(buf+1));
+               }
                if (lfp != NULL)
                        (void) fwrite(buf+1, 1, strlen(buf+1), lfp);
        }
                if (lfp != NULL)
                        (void) fwrite(buf+1, 1, strlen(buf+1), lfp);
        }
@@ -705,10 +757,12 @@ response()
                do {
                        if (read(rem, cp, 1) != 1)
                                lostconn();
                do {
                        if (read(rem, cp, 1) != 1)
                                lostconn();
-               } while (cp < &buf[BUFSIZ] && *cp++ != '\n');
-               if (buf[1] != '\0') {
-                       if (!iamremote)
+               } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
+               if (buf[0] != '\n') {
+                       if (!iamremote) {
+                               fflush(stdout);
                                (void) write(2, buf, cp - buf);
                                (void) write(2, buf, cp - buf);
+                       }
                        if (lfp != NULL)
                                (void) fwrite(buf, 1, cp - buf, lfp);
                }
                        if (lfp != NULL)
                                (void) fwrite(buf, 1, cp - buf, lfp);
                }