From d1dee8e8e30711f345b766859f89eac8468f1cbe Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Thu, 20 Oct 1983 20:15:12 -0800 Subject: [PATCH] added -r option to remove extra files. SCCS-vsn: usr.bin/rdist/defs.h 4.5 SCCS-vsn: usr.bin/rdist/docmd.c 4.5 SCCS-vsn: usr.bin/rdist/expand.c 4.4 SCCS-vsn: usr.bin/rdist/gram.y 4.5 SCCS-vsn: usr.bin/rdist/main.c 4.6 SCCS-vsn: usr.bin/rdist/server.c 4.5 --- usr/src/usr.bin/rdist/defs.h | 46 ++--- usr/src/usr.bin/rdist/docmd.c | 23 ++- usr/src/usr.bin/rdist/expand.c | 18 +- usr/src/usr.bin/rdist/gram.y | 55 ++++-- usr/src/usr.bin/rdist/main.c | 6 +- usr/src/usr.bin/rdist/server.c | 316 ++++++++++++++++++++++++++++++++- 6 files changed, 403 insertions(+), 61 deletions(-) diff --git a/usr/src/usr.bin/rdist/defs.h b/usr/src/usr.bin/rdist/defs.h index 1ebeacb446..2ee3d1e33d 100644 --- a/usr/src/usr.bin/rdist/defs.h +++ b/usr/src/usr.bin/rdist/defs.h @@ -1,4 +1,4 @@ -/* defs.h 4.4 83/10/12 */ +/* defs.h 4.5 83/10/20 */ #include #include @@ -15,34 +15,38 @@ #define MAILCMD "/usr/lib/sendmail -oi -t" /* defines for yacc */ -#define EQUAL 1 -#define LP 2 -#define RP 3 -#define ARROW 4 -#define DCOLON 5 -#define NAME 6 -#define INSTALL 7 -#define NOTIFY 8 -#define EXCEPT 9 -#define OPTION 10 -#define VAR 11 +#define EQUAL 1 +#define LP 2 +#define RP 3 +#define SM 4 +#define ARROW 5 +#define DCOLON 6 +#define NAME 7 +#define INSTALL 8 +#define NOTIFY 9 +#define EXCEPT 10 +#define OPTION 11 +#define VAR 12 /* 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 -#define NCARGS 10240 -#define GAVSIZ NCARGS / 6 -#define NSTAMPS 15 +#define HASHSIZE 1021 +#define INMAX 3500 +#define NCARGS 10240 +#define GAVSIZ NCARGS / 6 +#define NSTAMPS 15 /* option flags */ -#define VERIFY 1 -#define WHOLE 2 -#define YOUNGER 4 -#define STRIP 8 +#define VERIFY 0x1 +#define WHOLE 0x2 +#define YOUNGER 0x4 +#define STRIP 0x8 +#define REMOVE 0x10 + +#define ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #define ALLOC(x) (struct x *) malloc(sizeof(struct x)) diff --git a/usr/src/usr.bin/rdist/docmd.c b/usr/src/usr.bin/rdist/docmd.c index 5c53133c91..f9c4b73959 100644 --- a/usr/src/usr.bin/rdist/docmd.c +++ b/usr/src/usr.bin/rdist/docmd.c @@ -1,5 +1,5 @@ #ifndef lint -static char *sccsid = "@(#)docmd.c 4.4 (Berkeley) 83/10/12"; +static char *sccsid = "@(#)docmd.c 4.5 (Berkeley) 83/10/20"; #endif #include "defs.h" @@ -51,11 +51,15 @@ dohcmds(files, hosts, cmds) } found: n = 0; - for (c = cmds; c != NULL; c = c->b_next) - if (c->b_type == INSTALL) { + for (c = cmds; c != NULL; c = c->b_next) { + if (c->b_type != INSTALL) + continue; + n++; + if (c->b_name == NULL) + install(f->b_name, f->b_name, 0, c->b_options); + else install(f->b_name, c->b_name, ddir, c->b_options); - n++; - } + } if (n == 0) install(f->b_name, f->b_name, 0, options); } @@ -123,9 +127,10 @@ install(src, dest, destdir, opts) return; if (nflag || debug) { - printf("%s%s%s %s %s\n", opts & VERIFY ? "verify":"install", + printf("%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install", opts & WHOLE ? " -w" : "", - opts & YOUNGER ? " -y" : "", src, dest); + opts & YOUNGER ? " -y" : "", + opts & REMOVE ? " -r" : "", src, dest); if (nflag) return; } @@ -139,6 +144,10 @@ install(src, dest, destdir, opts) if (!destdir && (opts & WHOLE)) opts |= STRIP; + if (opts & REMOVE) { + opts &= ~REMOVE; + rmchk(src, NULL, opts); + } sendf(src, NULL, opts); } diff --git a/usr/src/usr.bin/rdist/expand.c b/usr/src/usr.bin/rdist/expand.c index 62e4044386..fb4c75d62a 100644 --- a/usr/src/usr.bin/rdist/expand.c +++ b/usr/src/usr.bin/rdist/expand.c @@ -1,5 +1,5 @@ #ifndef lint -static char *sccsid = "@(#)expand.c 4.3 (Berkeley) 83/10/10"; +static char *sccsid = "@(#)expand.c 4.4 (Berkeley) 83/10/20"; #endif #include "defs.h" @@ -257,7 +257,7 @@ matchdir(pattern) } if (fstat(dirp->dd_fd, &stb) < 0) goto patherr1; - if ((stb.st_mode & S_IFMT) != S_IFDIR) { + if (!ISDIR(stb.st_mode)) { errno = ENOTDIR; goto patherr1; } @@ -440,8 +440,7 @@ slash: while (*s) addpath(*s++); addpath('/'); - if (stat(path, &stb) == 0 && - (stb.st_mode & S_IFMT) == S_IFDIR) + if (stat(path, &stb) == 0 && ISDIR(stb.st_mode)) if (*p == '\0') { Cat(path, ""); argcnt++; @@ -582,10 +581,9 @@ exptilde(buf, file) } for (s1 = buf; *s1++ = *s2++; ) ; - s1--; - if (s3 == NULL) - return(s1); - while (*s1++ = *s3++) - ; - return(s1 - 1); + s2 = --s1; + if (s3 != NULL) + while (*s1++ = *s3++) + ; + return(s2); } diff --git a/usr/src/usr.bin/rdist/gram.y b/usr/src/usr.bin/rdist/gram.y index af1372ade5..ee73c995b7 100644 --- a/usr/src/usr.bin/rdist/gram.y +++ b/usr/src/usr.bin/rdist/gram.y @@ -1,6 +1,6 @@ %{ #ifndef lint -static char *sccsid = "@(#)gram.y 4.4 (Berkeley) 83/10/12"; +static char *sccsid = "@(#)gram.y 4.5 (Berkeley) 83/10/20"; #endif #include "defs.h" @@ -13,20 +13,22 @@ struct block *lastc; %term EQUAL 1 %term LP 2 %term RP 3 -%term ARROW 4 -%term DCOLON 5 -%term NAME 6 -%term INSTALL 7 -%term NOTIFY 8 -%term EXCEPT 9 -%term OPTION 10 +%term SM 4 +%term ARROW 5 +%term DCOLON 6 +%term NAME 7 +%term INSTALL 8 +%term NOTIFY 9 +%term EXCEPT 10 +%term OPTION 11 %union { struct block *blk; int intval; } -%type NAME, INSTALL, NOTIFY, EXCEPT, namelist, names, cmdlist, cmd +%type NAME, INSTALL, NOTIFY, EXCEPT +%type namelist, names, opt_name, cmdlist, cmd %type OPTION, options %% @@ -84,25 +86,28 @@ cmdlist: /* VOID */ { } ; -cmd: INSTALL options NAME = { +cmd: INSTALL options opt_name SM = { register struct block *b; $1->b_options = $2 | options; - b = expand($3, 0); - if (b == NULL || b->b_next != NULL) - fatal("exactly one name allowed\n"); - $1->b_name = b->b_name; + if ($3 != NULL) { + b = expand($3, 0); + if (b->b_next != NULL) + fatal("exactly one name allowed\n"); + $1->b_name = b->b_name; + } $$ = $1; } - | NOTIFY namelist = { + | NOTIFY namelist SM = { $1->b_args = expand($2, 1); $$ = $1; } - | EXCEPT namelist = { + | EXCEPT namelist SM = { $1->b_args = expand($2, 0); $$ = $1; } ; + options: /* VOID */ = { $$ = 0; } @@ -111,6 +116,14 @@ options: /* VOID */ = { } ; +opt_name: /* VOID */ = { + $$ = NULL; + } + | NAME = { + $$ = $1; + } + ; + %% int yylineno = 1; @@ -148,6 +161,9 @@ again: case ')': /* RP */ return(RP); + case ';': /* SM */ + return(SM); + case '-': /* -> */ if ((c = getc(fin)) == '>') return(ARROW); @@ -179,7 +195,7 @@ again: } *cp1++ = c; c = getc(fin); - if (c == EOF || any(c, " \t()=\n")) { + if (c == EOF || any(c, " \t()=;\n")) { ungetc(c, fin); break; } @@ -187,6 +203,10 @@ again: *cp1 = '\0'; if (yytext[0] == '-' && yytext[2] == '\0') { switch (yytext[1]) { + case 'r': + yylval.intval = REMOVE; + return(OPTION); + case 'v': yylval.intval = VERIFY; return(OPTION); @@ -230,5 +250,6 @@ yyerror(s) { extern int yychar; + errs++; fprintf(stderr, "rdist: line %d: %s\n", yylineno, s); } diff --git a/usr/src/usr.bin/rdist/main.c b/usr/src/usr.bin/rdist/main.c index e5ecc33518..faa120b2e4 100644 --- a/usr/src/usr.bin/rdist/main.c +++ b/usr/src/usr.bin/rdist/main.c @@ -1,5 +1,5 @@ #ifndef lint -static char *sccsid = "@(#)main.c 4.5 (Berkeley) 83/10/12"; +static char *sccsid = "@(#)main.c 4.6 (Berkeley) 83/10/20"; #endif #include "defs.h" @@ -88,6 +88,10 @@ main(argc, argv) qflag++; break; + case 'r': + options |= REMOVE; + break; + case 'v': options |= VERIFY; break; diff --git a/usr/src/usr.bin/rdist/server.c b/usr/src/usr.bin/rdist/server.c index a78a3fda39..33a0acd60f 100644 --- a/usr/src/usr.bin/rdist/server.c +++ b/usr/src/usr.bin/rdist/server.c @@ -1,5 +1,5 @@ #ifndef lint -static char *sccsid = "@(#)server.c 4.4 (Berkeley) 83/10/12"; +static char *sccsid = "@(#)server.c 4.5 (Berkeley) 83/10/20"; #endif #include "defs.h" @@ -33,6 +33,7 @@ server() register char *cp; register struct block *bp, *last = NULL; static struct block cmdblk = { EXCEPT }; + int opts; sumask = umask(0); ga(); @@ -113,6 +114,19 @@ server() ga(); continue; + case 'C': /* Clean. Cleanup a directory */ + if (*cp < '0' || *cp > '7') { + error("bad options\n"); + continue; + } + opts = *cp++ - '0'; + if (*cp++ != ' ') { + error("options not delimited\n"); + continue; + } + clean(cp, opts, 1); + continue; + case 'Q': /* Query. Does directory exist? */ query(cp, 1); continue; @@ -327,8 +341,7 @@ update(lname, rname, opts, st) /* * Check to see if the file exists on the remote machine. */ - (void) sprintf(buf, "%c%s\n", - (st->st_mode & S_IFMT) == S_IFDIR ? 'Q' : 'q', rname); + (void) sprintf(buf, "%c%s\n", ISDIR(st->st_mode) ? 'Q' : 'q', rname); if (debug) printf("buf = %s", buf); (void) write(rem, buf, strlen(buf)); @@ -387,7 +400,7 @@ update(lname, rname, opts, st) if (st->st_mtime == mtime) return(0); if (st->st_mtime < mtime) { - log(lfp, "Warning: %s older than remote copy\n", lname); + log(lfp, "Warning: %s: remote copy is newer\n", lname); return(0); } } else if (st->st_mtime == mtime && st->st_size == size) @@ -528,7 +541,7 @@ recvf(cmd, isdir) return; } if (stat(target, &stb) == 0) { - if ((stb.st_mode & S_IFMT) != S_IFDIR) { + if (!ISDIR(stb.st_mode)) { errno = ENOTDIR; goto bad; } @@ -744,6 +757,299 @@ ok: return(0); } +/* + * Check for files on the machine being updated that are not on the master + * machine and remove them. + */ +rmchk(lname, rname, opts) + char *lname, *rname; + int opts; +{ + register char *cp; + struct stat stb; + + if (debug) + printf("rmchk(%s, %s, %x)\n", lname, + rname != NULL ? rname : "NULL", opts); + + if (exclude(lname)) + return; + + /* + * First time rmchk() is called? + */ + if (rname == NULL) { + rname = exptilde(target, lname); + if (rname == NULL) + return; + tp = lname = target; + while (*tp) + tp++; + /* + * If we are renaming a directory and we want to preserve + * the directory heirarchy (-w), we must strip off the first + * directory name and preserve the rest. + */ + if (opts & STRIP) { + opts &= ~STRIP; + rname = index(rname, '/'); + if (rname == NULL) + rname = tp; + else + rname++; + } else if (!(opts & WHOLE)) { + rname = rindex(lname, '/'); + if (rname == NULL) + rname = lname; + else + rname++; + } + } + if (debug) + printf("lname = %s, rname = %s\n", lname, rname); + if (access(lname, 4) < 0 || stat(lname, &stb) < 0) { + error("%s: %s\n", lname, sys_errlist[errno]); + return; + } + if (!ISDIR(stb.st_mode)) + return; + /* + * Tell the remote to clean the files from the last directory sent. + */ + (void) sprintf(buf, "C%o %s\n", opts & VERIFY, rname); + if (debug) + printf("buf = %s", buf); + (void) write(rem, buf, strlen(buf)); + if (response() < 0) + return; + catname = 0; + for (;;) { + cp = buf; + do { + if (read(rem, cp, 1) != 1) + lostconn(); + } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); + + if (debug) { + printf("readbuf = "); + fwrite(buf, 1, cp - buf, stdout); + } + switch (buf[0]) { + case 'Q': /* its a directory on the remote end */ + case 'q': /* its a regular file on the remote end */ + *--cp = '\0'; + (void) sprintf(tp, "/%s", buf + 1); + if (debug) + printf("check %s\n", target); + if (stat(target, &stb) < 0) + (void) write(rem, "N\n", 2); + else if (buf[0] == 'Q' && ISDIR(stb.st_mode)) { + if (catname >= sizeof(stp)) { + error("%s: too many directory levels\n", target); + break; + } + (void) write(rem, "Y\n", 2); + if (response() < 0) + break; + stp[catname++] = tp; + while (*tp) + tp++; + } else + (void) write(rem, "y\n", 2); + break; + + case 'E': + if (catname < 0) + fatal("too many 'E's\n"); + ga(); + if (catname == 0) + return; + tp = stp[--catname]; + *tp = '\0'; + break; + + case '\0': + *--cp = '\0'; + if (buf[1]) + log(lfp, "%s\n", buf + 1); + break; + + case '\1': + case '\2': + errs++; + if (buf[1] != '\n') { + if (!iamremote) { + fflush(stdout); + (void) write(2, buf + 1, cp - buf + 1); + } + if (lfp != NULL) + (void) fwrite(buf + 1, 1, cp - buf + 1, lfp); + } + if (buf[0] == '\2') + cleanup(); + break; + + default: + error("unknown response type %s\n", buf[0]); + } + } +} + +/* + * Check the directory for extraneous files and remove them. + */ +clean(lname, opts, first) + char *lname; + int opts, first; +{ + DIR *d; + struct direct *dp; + register char *cp; + struct stat stb; + char *ootp, *otp; + int len; + + if (first) { + ootp = tp; + if (catname) { + *tp++ = '/'; + cp = lname; + while (*tp++ = *cp++) + ; + tp--; + } + if (stat(target, &stb) < 0) { + if (errno == ENOENT) { + ga(); + goto done; + } + bad: + error("%s: %s\n", target, sys_errlist[errno]); + tp = otp; + *tp = '\0'; + return; + } + /* + * This should be a directory because its a directory on the + * master machine. If not, let install complain about it. + */ + if (!ISDIR(stb.st_mode)) { + ga(); + goto done; + } + } + if (access(target, 6) < 0 || (d = opendir(target)) == NULL) + goto bad; + ga(); + + 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--; + if (stat(target, &stb) < 0) { + error("%s: %s\n", target, sys_errlist[errno]); + continue; + } + (void) sprintf(buf, "%c%s\n", ISDIR(stb.st_mode) ? 'Q' : 'q', + dp->d_name); + (void) write(rem, buf, strlen(buf)); + cp = buf; + do { + if (read(rem, cp, 1) != 1) + lostconn(); + } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); + *--cp = '\0'; + cp = buf; + if (*cp != 'N') { + if (*cp == 'Y' && ISDIR(stb.st_mode)) + clean(dp->d_name, opts, 0); + continue; + } + if (!(opts & VERIFY)) + remove(&stb); + } + closedir(d); +done: + tp = (first) ? ootp : otp; + *tp = '\0'; + (void) write(rem, "E\n", 2); + (void) response(); +} + +remove(st) + struct stat *st; +{ + DIR *d; + struct direct *dp; + register char *cp; + struct stat stb; + char *otp; + int len; + + switch (st->st_mode & S_IFMT) { + case S_IFREG: + if (unlink(target) < 0) + goto bad; + goto removed; + + case S_IFDIR: + break; + + default: + error("%s: not a plain file\n", target); + return; + } + + if (access(target, 6) < 0 || (d = opendir(target)) == NULL) + goto bad; + + 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--; + if (stat(target, &stb) < 0) { + error("%s: %s\n", target, sys_errlist[errno]); + continue; + } + remove(&stb); + } + closedir(d); + tp = otp; + *tp = '\0'; + if (rmdir(target) < 0) { +bad: + error("%s: %s\n", target, sys_errlist[errno]); + return; + } +removed: + cp = buf; + *cp++ = '\0'; + (void) sprintf(cp, "removed %s\n", target); + (void) write(rem, buf, strlen(cp) + 1); +} + /*VARARGS2*/ log(fp, fmt, a1, a2, a3) FILE *fp; -- 2.20.1