X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/b6b5501c38d87f0639c0017f006f7ce504d46e7b..bf766a3770736e890c75df2a66b09b4a40baca69:/usr/src/usr.bin/rdist/docmd.c diff --git a/usr/src/usr.bin/rdist/docmd.c b/usr/src/usr.bin/rdist/docmd.c index 248ce8e416..448c707a59 100644 --- a/usr/src/usr.bin/rdist/docmd.c +++ b/usr/src/usr.bin/rdist/docmd.c @@ -1,71 +1,168 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + #ifndef lint -static char *sccsid = "@(#)docmd.c 4.1 (Berkeley) 83/09/07"; -#endif +static char sccsid[] = "@(#)docmd.c 5.4 (Berkeley) %G%"; +#endif /* not lint */ #include "defs.h" +#include +#include -FILE *lfp; /* log file for recording files updated */ +FILE *lfp; /* log file for recording files updated */ +struct subcmd *subcmds; /* list of sub-commands for current cmd */ +jmp_buf env; + +int cleanup(); +int lostconn(); /* - * Routines to process commands. + * Do the commands in cmds (initialized by yyparse). */ -docmd(files, hosts, cmds) - struct block *files, *hosts, *cmds; +docmds(dhosts, argc, argv) + char **dhosts; + int argc; + char **argv; { - register struct block *h, *f, *c; - register char *cp, **cpp; - int n; + register struct cmd *c; + register struct namelist *f; + register char **cpp; + extern struct cmd *cmds; - if (debug) - printf("docmd()\n"); - - files = expand(files); - hosts = expand(hosts); - if (files == NULL) - fatal("no files to be updated\n"); - if (hosts == NULL) - fatal("empty list of hosts to be updated\n"); - except = cmds; - - for (h = hosts; h != NULL; h = h->b_next) { - if (!nflag) { - if ((lfp = fopen(tmpfile, "w")) == NULL) { - fatal("cannot open %s\n", tmpfile); - exit(1); - } - if (!makeconn(h->b_name)) - continue; + signal(SIGHUP, cleanup); + signal(SIGINT, cleanup); + signal(SIGQUIT, cleanup); + signal(SIGTERM, cleanup); + + for (c = cmds; c != NULL; c = c->c_next) { + if (dhosts != NULL && *dhosts != NULL) { + for (cpp = dhosts; *cpp; cpp++) + if (strcmp(c->c_name, *cpp) == 0) + goto fndhost; + continue; } - for (f = files; f != NULL; f = f->b_next) { - if (filec) { - for (cpp = filev; *cpp; cpp++) - if (!strcmp(f->b_name, *cpp)) + fndhost: + if (argc) { + for (cpp = argv; *cpp; cpp++) { + if (c->c_label != NULL && + strcmp(c->c_label, *cpp) == 0) { + cpp = NULL; + goto found; + } + for (f = c->c_files; f != NULL; f = f->n_next) + if (strcmp(f->n_name, *cpp) == 0) goto found; - 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); - n++; - } else if (c->b_type == VERIFY) { - install(f->b_name, c->b_name, 1); - n++; - } - if (n == 0) - install(f->b_name, f->b_name, 0); + continue; + } else + cpp = NULL; + found: + switch (c->c_type) { + case ARROW: + doarrow(cpp, c->c_files, c->c_name, c->c_cmds); + break; + case DCOLON: + dodcolon(cpp, c->c_files, c->c_name, c->c_cmds); + break; + default: + fatal("illegal command type %d\n", c->c_type); } - if (!nflag) { - (void) fclose(lfp); - (void) close(rem); + } + closeconn(); +} + +/* + * Process commands for sending files to other machines. + */ +doarrow(filev, files, rhost, cmds) + char **filev; + struct namelist *files; + char *rhost; + struct subcmd *cmds; +{ + register struct namelist *f; + register struct subcmd *sc; + register char **cpp; + int n, ddir, opts = options; + + if (debug) + printf("doarrow(%x, %s, %x)\n", files, rhost, cmds); + + if (files == NULL) { + error("no files to be updated\n"); + return; + } + + subcmds = cmds; + ddir = files->n_next != NULL; /* destination is a directory */ + if (nflag) + printf("updating host %s\n", rhost); + else { + if (setjmp(env)) + goto done; + signal(SIGPIPE, lostconn); + if (!makeconn(rhost)) + return; + if ((lfp = fopen(tmpfile, "w")) == NULL) { + fatal("cannot open %s\n", tmpfile); + exit(1); + } + } + for (f = files; f != NULL; f = f->n_next) { + if (filev) { + for (cpp = filev; *cpp; cpp++) + if (strcmp(f->n_name, *cpp) == 0) + goto found; + if (!nflag) + (void) fclose(lfp); + continue; + } + found: + n = 0; + for (sc = cmds; sc != NULL; sc = sc->sc_next) { + if (sc->sc_type != INSTALL) + continue; + n++; + install(f->n_name, sc->sc_name, + sc->sc_name == NULL ? 0 : ddir, sc->sc_options); + opts = sc->sc_options; } - for (c = cmds; c != NULL; c = c->b_next) - if (c->b_type == NOTIFY) - notify(h->b_name, c->b_args); + if (n == 0) + install(f->n_name, NULL, 0, options); } - if (!nflag) +done: + if (!nflag) { + (void) signal(SIGPIPE, cleanup); + (void) fclose(lfp); + lfp = NULL; + } + for (sc = cmds; sc != NULL; sc = sc->sc_next) + if (sc->sc_type == NOTIFY) + notify(tmpfile, rhost, sc->sc_args, 0); + if (!nflag) { (void) unlink(tmpfile); + for (; ihead != NULL; ihead = ihead->nextp) { + free(ihead); + if ((opts & IGNLNKS) || ihead->count == 0) + continue; + log(lfp, "%s: Warning: missing links\n", + ihead->pathname); + } + } } /* @@ -74,103 +171,354 @@ docmd(files, hosts, cmds) makeconn(rhost) char *rhost; { - register char *ruser; + register char *ruser, *cp; + static char *cur_host = NULL; + static int port = -1; + char tuser[20]; + int n; extern char user[]; + extern int userid; - (void) sprintf(buf, "/usr/local/rdist -Server%s%s%s%s%s", - vflag ? " -v" : "", qflag ? " -q" : "", nflag ? " -n" : "", - yflag ? " -y" : "", debug ? " -d" : ""); + if (debug) + printf("makeconn(%s)\n", rhost); - ruser = rindex(rhost, '.'); - if (ruser != NULL) { - *ruser++ = '\0'; - if (!okname(ruser)) + if (cur_host != NULL && rem >= 0) { + if (strcmp(cur_host, rhost) == 0) + return(1); + closeconn(); + } + cur_host = rhost; + cp = index(rhost, '@'); + if (cp != NULL) { + char c = *cp; + + *cp = '\0'; + strncpy(tuser, rhost, sizeof(tuser)-1); + *cp = c; + rhost = cp + 1; + ruser = tuser; + if (*ruser == '\0') + ruser = user; + else if (!okname(ruser)) return(0); } else ruser = user; + if (!qflag) + printf("updating host %s\n", rhost); + (void) sprintf(buf, "%s -Server%s", _PATH_RDIST, qflag ? " -q" : ""); + if (port < 0) { + struct servent *sp; + + if ((sp = getservbyname("shell", "tcp")) == NULL) + fatal("shell/tcp: unknown service"); + port = sp->s_port; + } if (debug) { - printf("makeconn(%s)\n", rhost); - printf("luser = %s, ruser = %s\n", user, ruser); + printf("port = %d, luser = %s, ruser = %s\n", ntohs(port), user, ruser); printf("buf = %s\n", buf); } - rem = rcmd(&rhost, IPPORT_CMDSERVER, user, ruser, buf, 0); + fflush(stdout); + setreuid(userid, 0); + rem = rcmd(&rhost, port, user, ruser, buf, 0); + setreuid(0, userid); if (rem < 0) return(0); - if (response() < 0) - return(0); + cp = buf; + if (read(rem, cp, 1) != 1) + lostconn(); + if (*cp == 'V') { + do { + if (read(rem, cp, 1) != 1) + lostconn(); + } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); + *--cp = '\0'; + cp = buf; + n = 0; + while (*cp >= '0' && *cp <= '9') + n = (n * 10) + (*cp++ - '0'); + if (*cp == '\0' && n == VERSION) + return(1); + error("connection failed: version numbers don't match (local %d, remote %d)\n", VERSION, n); + } else + error("connection failed: version numbers don't match\n"); + closeconn(); + return(0); +} + +/* + * Signal end of previous connection. + */ +closeconn() +{ + if (debug) + printf("closeconn()\n"); + + if (rem >= 0) { + (void) write(rem, "\2\n", 2); + (void) close(rem); + rem = -1; + } +} + +lostconn() +{ + if (iamremote) + cleanup(); + log(lfp, "rdist: lost connection\n"); + longjmp(env, 1); +} + +okname(name) + register char *name; +{ + register char *cp = name; + register int c; + + do { + c = *cp; + if (c & 0200) + goto bad; + if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') + goto bad; + cp++; + } while (*cp); return(1); +bad: + error("invalid user name %s\n", name); + return(0); } +time_t lastmod; +FILE *tfp; +extern char target[], *tp; + /* - * Update the file(s) if they are different. + * Process commands for comparing files to time stamp files. */ -install(src, dest, verify) - char *src, *dest; - int verify; +dodcolon(filev, files, stamp, cmds) + char **filev; + struct namelist *files; + char *stamp; + struct subcmd *cmds; { - register char *cp; - extern char *tp; - char lbuf[BUFSIZ]; + register struct subcmd *sc; + register struct namelist *f; + register char **cpp; + struct timeval tv[2]; + struct timezone tz; + struct stat stb; - if (!qflag) - printf("%s %s %s\n", verify ? "verify" : "install", src, dest); - if (nflag) + if (debug) + printf("dodcolon()\n"); + + if (files == NULL) { + error("no files to be updated\n"); return; + } + if (stat(stamp, &stb) < 0) { + error("%s: %s\n", stamp, sys_errlist[errno]); + return; + } + if (debug) + printf("%s: %d\n", stamp, stb.st_mtime); + + subcmds = cmds; + lastmod = stb.st_mtime; + if (nflag || (options & VERIFY)) + tfp = NULL; + else { + if ((tfp = fopen(tmpfile, "w")) == NULL) { + error("%s: %s\n", stamp, sys_errlist[errno]); + return; + } + (void) gettimeofday(&tv[0], &tz); + tv[1] = tv[0]; + (void) utimes(stamp, tv); + } + + for (f = files; f != NULL; f = f->n_next) { + if (filev) { + for (cpp = filev; *cpp; cpp++) + if (strcmp(f->n_name, *cpp) == 0) + goto found; + continue; + } + found: + tp = NULL; + cmptime(f->n_name); + } + + if (tfp != NULL) + (void) fclose(tfp); + for (sc = cmds; sc != NULL; sc = sc->sc_next) + if (sc->sc_type == NOTIFY) + notify(tmpfile, NULL, sc->sc_args, lastmod); + if (!nflag && !(options & VERIFY)) + (void) unlink(tmpfile); +} + +/* + * Compare the mtime of file to the list of time stamps. + */ +cmptime(name) + char *name; +{ + struct stat stb; + + if (debug) + printf("cmptime(%s)\n", name); + + if (except(name)) + return; + + if (nflag) { + printf("comparing dates: %s\n", name); + return; + } + /* - * Pass the destination file/directory name to remote. + * first time cmptime() is called? */ - (void) sprintf(buf, "T%s\n", dest); + if (tp == NULL) { + if (exptilde(target, name) == NULL) + return; + 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; + } + + if (stb.st_mtime > lastmod) + log(tfp, "new: %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("buf = %s", buf); - (void) write(rem, buf, strlen(buf)); - tp = NULL; - shexpand(lbuf, src); - sendf(lbuf, verify); + 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. + * rhost == NULL if we are mailing a list of changes compared to at time + * stamp file. */ -notify(host, to) - char *host; - register struct block *to; +notify(file, rhost, to, lmod) + char *file, *rhost; + register struct namelist *to; + time_t lmod; { register int fd, len; FILE *pf, *popen(); struct stat stb; - if (vflag) + if ((options & VERIFY) || to == NULL) return; if (!qflag) { - printf("notify @%s ", host); + printf("notify "); + if (rhost) + printf("@%s ", rhost); 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; } /* * Create a pipe to mailling program. */ - pf = popen(MAILCMD, "w"); - if (pf == NULL) - fatal("notify: \"%s\" failed\n", MAILCMD); + (void)sprintf(buf, "%s -oi -t", _PATH_SENDMAIL); + pf = popen(buf, "w"); + if (pf == NULL) { + error("notify: \"%s\" failed\n", _PATH_SENDMAIL); + (void) close(fd); + return; + } /* * Output the proper header information. */ fprintf(pf, "From: rdist (Remote distribution program)\n"); fprintf(pf, "To:"); + if (!any('@', to->n_name) && rhost != NULL) + fprintf(pf, " %s@%s", to->n_name, rhost); + else + fprintf(pf, " %s", to->n_name); + to = to->n_next; while (to != NULL) { - fprintf(pf, " %s@%s", to->b_name, host); - to = to->b_next; + if (!any('@', to->n_name) && rhost != NULL) + fprintf(pf, ", %s@%s", to->n_name, rhost); + else + fprintf(pf, ", %s", to->n_name); + to = to->n_next; } putc('\n', pf); - fprintf(pf, "Subject: files updated by rdist\n"); + if (rhost != NULL) + fprintf(pf, "Subject: files updated by rdist from %s to %s\n", + host, rhost); + else + fprintf(pf, "Subject: files updated after %s\n", ctime(&lmod)); putc('\n', pf); while ((len = read(fd, buf, BUFSIZ)) > 0) @@ -179,43 +527,47 @@ notify(host, to) (void) pclose(pf); } -struct block *except; /* list of files to exclude */ - /* - * Return true if name is in list. + * Return true if name is in the list. */ -exclude(file) +inlist(list, file) + struct namelist *list; char *file; { - register struct block *b, *c; + register struct namelist *nl; - for (c = except; c != NULL; c = c->b_next) { - if (c->b_type != EXCEPT) - continue; - for (b = c->b_args; b != NULL; b = b->b_next) - if (!strcmp(file, b->b_name)) - return(1); - } + for (nl = list; nl != NULL; nl = nl->n_next) + if (!strcmp(file, nl->n_name)) + return(1); return(0); } -okname(name) - register char *name; +/* + * Return TRUE if file is in the exception list. + */ +except(file) + char *file; { - register char *cp = name; - register int c; + register struct subcmd *sc; + register struct namelist *nl; - do { - c = *cp; - if (c & 0200) - goto bad; - if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') - goto bad; - cp++; - } while (*cp); - return(1); -bad: - error("invalid user name %s\n", name); + if (debug) + printf("except(%s)\n", file); + + for (sc = subcmds; sc != NULL; sc = sc->sc_next) { + if (sc->sc_type != EXCEPT && sc->sc_type != PATTERN) + continue; + for (nl = sc->sc_args; nl != NULL; nl = nl->n_next) { + if (sc->sc_type == EXCEPT) { + if (!strcmp(file, nl->n_name)) + return(1); + continue; + } + re_comp(nl->n_name); + if (re_exec(file) > 0) + return(1); + } + } return(0); }