From f79a3fd29dbdc3644041c7b35c090e1e76db78d3 Mon Sep 17 00:00:00 2001 From: "William F. Jolitz" Date: Mon, 10 Feb 1992 11:36:51 -0800 Subject: [PATCH] 386BSD 0.1 development Work on file usr/src/usr.bin/rdist/gram.y Work on file usr/src/usr.bin/rdist/Makefile Work on file usr/src/usr.bin/rdist/docmd.c Co-Authored-By: Lynne Greer Jolitz Synthesized-from: 386BSD-0.1 --- usr/src/usr.bin/rdist/Makefile | 11 + usr/src/usr.bin/rdist/docmd.c | 602 +++++++++++++++++++++++++++++++++ usr/src/usr.bin/rdist/gram.y | 507 +++++++++++++++++++++++++++ 3 files changed, 1120 insertions(+) create mode 100644 usr/src/usr.bin/rdist/Makefile create mode 100644 usr/src/usr.bin/rdist/docmd.c create mode 100644 usr/src/usr.bin/rdist/gram.y diff --git a/usr/src/usr.bin/rdist/Makefile b/usr/src/usr.bin/rdist/Makefile new file mode 100644 index 0000000000..28a99454cb --- /dev/null +++ b/usr/src/usr.bin/rdist/Makefile @@ -0,0 +1,11 @@ +# @(#)Makefile 5.11 (Berkeley) 3/12/91 + +PROG= rdist +CFLAGS+=-I${.CURDIR} +SRCS= docmd.c expand.c lookup.c main.c server.c +OBJS+= gram.o +BINOWN= root +BINMODE=4555 +CLEANFILES=y.tab.h + +.include diff --git a/usr/src/usr.bin/rdist/docmd.c b/usr/src/usr.bin/rdist/docmd.c new file mode 100644 index 0000000000..b99d12609f --- /dev/null +++ b/usr/src/usr.bin/rdist/docmd.c @@ -0,0 +1,602 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)docmd.c 5.8 (Berkeley) 3/1/91"; +#endif /* not lint */ + +#include "defs.h" +#include +#include + +FILE *lfp; /* log file for recording files updated */ +struct subcmd *subcmds; /* list of sub-commands for current cmd */ +jmp_buf env; + +void cleanup(), lostconn(); + +/* + * Do the commands in cmds (initialized by yyparse). + */ +docmds(dhosts, argc, argv) + char **dhosts; + int argc; + char **argv; +{ + register struct cmd *c; + register struct namelist *f; + register char **cpp; + extern struct cmd *cmds; + + 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; + } + 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; + } 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); + } + } + 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(tempfile, "w")) == NULL) { + fatal("cannot open %s\n", tempfile); + 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; + } + if (n == 0) + install(f->n_name, NULL, 0, options); + } +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(tempfile, rhost, sc->sc_args, 0); + if (!nflag) { + (void) unlink(tempfile); + for (; ihead != NULL; ihead = ihead->nextp) { + free(ihead); + if ((opts & IGNLNKS) || ihead->count == 0) + continue; + log(lfp, "%s: Warning: missing links\n", + ihead->pathname); + } + } +} + +/* + * Create a connection to the rdist server on the machine rhost. + */ +makeconn(rhost) + char *rhost; +{ + register char *ruser, *cp; + static char *cur_host = NULL; + static int port = -1; + char tuser[20]; + int n; + extern char user[]; + extern int userid; + + if (debug) + printf("makeconn(%s)\n", rhost); + + 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("port = %d, luser = %s, ruser = %s\n", ntohs(port), user, ruser); + printf("buf = %s\n", buf); + } + + fflush(stdout); + setreuid(userid, 0); + rem = rcmd(&rhost, port, user, ruser, buf, 0); + setreuid(0, userid); + if (rem < 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; + } +} + +void +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; + +/* + * Process commands for comparing files to time stamp files. + */ +dodcolon(filev, files, stamp, cmds) + char **filev; + struct namelist *files; + char *stamp; + struct subcmd *cmds; +{ + register struct subcmd *sc; + register struct namelist *f; + register char **cpp; + struct timeval tv[2]; + struct timezone tz; + struct stat stb; + + 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, strerror(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(tempfile, "w")) == NULL) { + error("%s: %s\n", stamp, strerror(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(tempfile, NULL, sc->sc_args, lastmod); + if (!nflag && !(options & VERIFY)) + (void) unlink(tempfile); +} + +/* + * 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; + } + + /* + * first time cmptime() is called? + */ + 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, strerror(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("rcmptime(%x)\n", st); + + if ((d = opendir(target)) == NULL) { + error("%s: %s\n", target, strerror(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(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 ((options & VERIFY) || to == NULL) + return; + if (!qflag) { + printf("notify "); + if (rhost) + printf("@%s ", rhost); + prnames(to); + } + if (nflag) + return; + + if ((fd = open(file, 0)) < 0) { + error("%s: %s\n", file, strerror(errno)); + return; + } + if (fstat(fd, &stb) < 0) { + error("%s: %s\n", file, strerror(errno)); + (void) close(fd); + return; + } + if (stb.st_size == 0) { + (void) close(fd); + return; + } + /* + * Create a pipe to mailling program. + */ + (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) { + 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); + 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) + (void) fwrite(buf, 1, len, pf); + (void) close(fd); + (void) pclose(pf); +} + +/* + * Return true if name is in the list. + */ +inlist(list, file) + struct namelist *list; + char *file; +{ + register struct namelist *nl; + + for (nl = list; nl != NULL; nl = nl->n_next) + if (!strcmp(file, nl->n_name)) + return(1); + return(0); +} + +/* + * Return TRUE if file is in the exception list. + */ +except(file) + char *file; +{ + register struct subcmd *sc; + register struct namelist *nl; + + 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; + } + if (regexec(file, regcomp(nl->n_name)) > 0) + return(1); + } + } + return(0); +} + +char * +colon(cp) + register char *cp; +{ + + while (*cp) { + if (*cp == ':') + return(cp); + if (*cp == '/') + return(0); + cp++; + } + return(0); +} diff --git a/usr/src/usr.bin/rdist/gram.y b/usr/src/usr.bin/rdist/gram.y new file mode 100644 index 0000000000..e9c87a14b8 --- /dev/null +++ b/usr/src/usr.bin/rdist/gram.y @@ -0,0 +1,507 @@ +%{ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)gram.y 5.6 (Berkeley) 6/1/90"; +#endif /* not lint */ + +#include "defs.h" + +struct cmd *cmds = NULL; +struct cmd *last_cmd; +struct namelist *last_n; +struct subcmd *last_sc; + +%} + +%term EQUAL 1 +%term LP 2 +%term RP 3 +%term SM 4 +%term ARROW 5 +%term COLON 6 +%term DCOLON 7 +%term NAME 8 +%term STRING 9 +%term INSTALL 10 +%term NOTIFY 11 +%term EXCEPT 12 +%term PATTERN 13 +%term SPECIAL 14 +%term OPTION 15 + +%union { + int intval; + char *string; + struct subcmd *subcmd; + struct namelist *namel; +} + +%type OPTION, options +%type NAME, STRING +%type INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd +%type namelist, names, opt_namelist + +%% + +file: /* VOID */ + | file command + ; + +command: NAME EQUAL namelist = { + (void) lookup($1, INSERT, $3); + } + | namelist ARROW namelist cmdlist = { + insert(NULL, $1, $3, $4); + } + | NAME COLON namelist ARROW namelist cmdlist = { + insert($1, $3, $5, $6); + } + | namelist DCOLON NAME cmdlist = { + append(NULL, $1, $3, $4); + } + | NAME COLON namelist DCOLON NAME cmdlist = { + append($1, $3, $5, $6); + } + | error + ; + +namelist: NAME = { + $$ = makenl($1); + } + | LP names RP = { + $$ = $2; + } + ; + +names: /* VOID */ { + $$ = last_n = NULL; + } + | names NAME = { + if (last_n == NULL) + $$ = last_n = makenl($2); + else { + last_n->n_next = makenl($2); + last_n = last_n->n_next; + $$ = $1; + } + } + ; + +cmdlist: /* VOID */ { + $$ = last_sc = NULL; + } + | cmdlist cmd = { + if (last_sc == NULL) + $$ = last_sc = $2; + else { + last_sc->sc_next = $2; + last_sc = $2; + $$ = $1; + } + } + ; + +cmd: INSTALL options opt_namelist SM = { + register struct namelist *nl; + + $1->sc_options = $2 | options; + if ($3 != NULL) { + nl = expand($3, E_VARS); + if (nl) { + if (nl->n_next != NULL) + yyerror("only one name allowed\n"); + $1->sc_name = nl->n_name; + free(nl); + } else + $1->sc_name = NULL; + } + $$ = $1; + } + | NOTIFY namelist SM = { + if ($2 != NULL) + $1->sc_args = expand($2, E_VARS); + $$ = $1; + } + | EXCEPT namelist SM = { + if ($2 != NULL) + $1->sc_args = expand($2, E_ALL); + $$ = $1; + } + | PATTERN namelist SM = { + struct namelist *nl; +#ifdef nope + char *cp, *re_comp(); + + for (nl = $2; nl != NULL; nl = nl->n_next) + if ((cp = re_comp(nl->n_name)) != NULL) + yyerror(cp); +#endif + $1->sc_args = expand($2, E_VARS); + $$ = $1; + } + | SPECIAL opt_namelist STRING SM = { + if ($2 != NULL) + $1->sc_args = expand($2, E_ALL); + $1->sc_name = $3; + $$ = $1; + } + ; + +options: /* VOID */ = { + $$ = 0; + } + | options OPTION = { + $$ |= $2; + } + ; + +opt_namelist: /* VOID */ = { + $$ = NULL; + } + | namelist = { + $$ = $1; + } + ; + +%% + +int yylineno = 1; +extern FILE *fin; + +yylex() +{ + static char yytext[INMAX]; + register int c; + register char *cp1, *cp2; + static char quotechars[] = "[]{}*?$"; + +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); + case '\n': + yylineno++; + case ' ': + case '\t': /* skip blanks */ + goto again; + + case '=': /* EQUAL */ + return(EQUAL); + + case '(': /* LP */ + return(LP); + + case ')': /* RP */ + return(RP); + + case ';': /* SM */ + return(SM); + + case '-': /* -> */ + if ((c = getc(fin)) == '>') + return(ARROW); + ungetc(c, fin); + c = '-'; + break; + + case '"': /* STRING */ + cp1 = yytext; + cp2 = &yytext[INMAX - 1]; + for (;;) { + if (cp1 >= cp2) { + yyerror("command string too long\n"); + break; + } + c = getc(fin); + if (c == EOF || c == '"') + break; + if (c == '\\') { + if ((c = getc(fin)) == EOF) { + *cp1++ = '\\'; + break; + } + } + if (c == '\n') { + yylineno++; + c = ' '; /* can't send '\n' */ + } + *cp1++ = c; + } + if (c != '"') + yyerror("missing closing '\"'\n"); + *cp1 = '\0'; + yylval.string = makestr(yytext); + return(STRING); + + case ':': /* : or :: */ + if ((c = getc(fin)) == ':') + return(DCOLON); + ungetc(c, fin); + return(COLON); + } + cp1 = yytext; + cp2 = &yytext[INMAX - 1]; + for (;;) { + if (cp1 >= cp2) { + yyerror("input line too long\n"); + break; + } + if (c == '\\') { + if ((c = getc(fin)) != EOF) { + if (any(c, quotechars)) + c |= QUOTE; + } else { + *cp1++ = '\\'; + break; + } + } + *cp1++ = c; + c = getc(fin); + if (c == EOF || any(c, " \"'\t()=;:\n")) { + ungetc(c, fin); + break; + } + } + *cp1 = '\0'; + if (yytext[0] == '-' && yytext[2] == '\0') { + switch (yytext[1]) { + case 'b': + yylval.intval = COMPARE; + return(OPTION); + + case 'R': + yylval.intval = REMOVE; + return(OPTION); + + case 'v': + yylval.intval = VERIFY; + return(OPTION); + + case 'w': + yylval.intval = WHOLE; + return(OPTION); + + case 'y': + yylval.intval = YOUNGER; + return(OPTION); + + case 'h': + yylval.intval = FOLLOW; + return(OPTION); + + case 'i': + yylval.intval = IGNLNKS; + return(OPTION); + } + } + if (!strcmp(yytext, "install")) + c = INSTALL; + else if (!strcmp(yytext, "notify")) + c = NOTIFY; + else if (!strcmp(yytext, "except")) + c = EXCEPT; + else if (!strcmp(yytext, "except_pat")) + c = PATTERN; + else if (!strcmp(yytext, "special")) + c = SPECIAL; + else { + yylval.string = makestr(yytext); + return(NAME); + } + yylval.subcmd = makesubcmd(c); + return(c); +} + +any(c, str) + register int c; + register char *str; +{ + while (*str) + if (c == *str++) + return(1); + return(0); +} + +/* + * Insert or append ARROW command to list of hosts to be updated. + */ +insert(label, files, hosts, subcmds) + char *label; + struct namelist *files, *hosts; + struct subcmd *subcmds; +{ + register struct cmd *c, *prev, *nc; + register struct namelist *h; + + files = expand(files, E_VARS|E_SHELL); + hosts = expand(hosts, E_ALL); + for (h = hosts; h != NULL; free(h), h = h->n_next) { + /* + * Search command list for an update to the same host. + */ + for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) { + if (strcmp(c->c_name, h->n_name) == 0) { + do { + prev = c; + c = c->c_next; + } while (c != NULL && + strcmp(c->c_name, h->n_name) == 0); + break; + } + } + /* + * Insert new command to update host. + */ + nc = ALLOC(cmd); + if (nc == NULL) + fatal("ran out of memory\n"); + nc->c_type = ARROW; + nc->c_name = h->n_name; + nc->c_label = label; + nc->c_files = files; + nc->c_cmds = subcmds; + nc->c_next = c; + if (prev == NULL) + cmds = nc; + else + prev->c_next = nc; + /* update last_cmd if appending nc to cmds */ + if (c == NULL) + last_cmd = nc; + } +} + +/* + * Append DCOLON command to the end of the command list since these are always + * executed in the order they appear in the distfile. + */ +append(label, files, stamp, subcmds) + char *label; + struct namelist *files; + char *stamp; + struct subcmd *subcmds; +{ + register struct cmd *c; + + c = ALLOC(cmd); + if (c == NULL) + fatal("ran out of memory\n"); + c->c_type = DCOLON; + c->c_name = stamp; + c->c_label = label; + c->c_files = expand(files, E_ALL); + c->c_cmds = subcmds; + c->c_next = NULL; + if (cmds == NULL) + cmds = last_cmd = c; + else { + last_cmd->c_next = c; + last_cmd = c; + } +} + +/* + * Error printing routine in parser. + */ +yyerror(s) + char *s; +{ + extern int yychar; + + nerrs++; + fflush(stdout); + fprintf(stderr, "rdist: line %d: %s\n", yylineno, s); +} + +/* + * Return a copy of the string. + */ +char * +makestr(str) + char *str; +{ + register char *cp, *s; + + str = cp = malloc(strlen(s = str) + 1); + if (cp == NULL) + fatal("ran out of memory\n"); + while (*cp++ = *s++) + ; + return(str); +} + +/* + * Allocate a namelist structure. + */ +struct namelist * +makenl(name) + char *name; +{ + register struct namelist *nl; + + nl = ALLOC(namelist); + if (nl == NULL) + fatal("ran out of memory\n"); + nl->n_name = name; + nl->n_next = NULL; + return(nl); +} + +/* + * Make a sub command for lists of variables, commands, etc. + */ +struct subcmd * +makesubcmd(type, name) + int type; + register char *name; +{ + register char *cp; + register struct subcmd *sc; + + sc = ALLOC(subcmd); + if (sc == NULL) + fatal("ran out of memory\n"); + sc->sc_type = type; + sc->sc_args = NULL; + sc->sc_next = NULL; + sc->sc_name = NULL; + return(sc); +} -- 2.20.1