1*bdeefc61Schristos /* $NetBSD: docmd.c,v 1.30 2013/10/18 20:43:45 christos Exp $ */
23aab4f7dSthorpej
361f28255Scgd /*
4a5bfdf78Scgd * Copyright (c) 1983, 1993
5a5bfdf78Scgd * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * Redistribution and use in source and binary forms, with or without
861f28255Scgd * modification, are permitted provided that the following conditions
961f28255Scgd * are met:
1061f28255Scgd * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd * notice, this list of conditions and the following disclaimer.
1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd * notice, this list of conditions and the following disclaimer in the
1461f28255Scgd * documentation and/or other materials provided with the distribution.
1589aaa1bbSagc * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd * may be used to endorse or promote products derived from this software
1761f28255Scgd * without specific prior written permission.
1861f28255Scgd *
1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd * SUCH DAMAGE.
3061f28255Scgd */
3161f28255Scgd
323b3cf635Slukem #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
343aab4f7dSthorpej #if 0
353aab4f7dSthorpej static char sccsid[] = "@(#)docmd.c 8.1 (Berkeley) 6/9/93";
363aab4f7dSthorpej #else
37*bdeefc61Schristos __RCSID("$NetBSD: docmd.c,v 1.30 2013/10/18 20:43:45 christos Exp $");
383aab4f7dSthorpej #endif
3961f28255Scgd #endif /* not lint */
4061f28255Scgd
410026c9e9Smrg #include <sys/types.h>
420026c9e9Smrg #include <sys/ioctl.h>
430026c9e9Smrg
440026c9e9Smrg #include <errno.h>
4561f28255Scgd #include <netdb.h>
46cf0afdf8Sthorpej #include <regex.h>
470026c9e9Smrg #include <setjmp.h>
48b751ad2cSchristos #include <fcntl.h>
490026c9e9Smrg
500026c9e9Smrg #include "defs.h"
5161f28255Scgd
5261f28255Scgd FILE *lfp; /* log file for recording files updated */
5361f28255Scgd struct subcmd *subcmds; /* list of sub-commands for current cmd */
5461f28255Scgd jmp_buf env;
5561f28255Scgd
562cb3df57Schristos static int remerr = -1; /* Remote stderr */
572cb3df57Schristos
58a9b4ca62Swiz static int makeconn(char *);
59a9b4ca62Swiz static int okname(char *);
60a9b4ca62Swiz static void closeconn(void);
61a9b4ca62Swiz static void cmptime(char *);
62a9b4ca62Swiz static void doarrow(char **,
63a9b4ca62Swiz struct namelist *, char *, struct subcmd *);
64a9b4ca62Swiz static void dodcolon(char **,
65a9b4ca62Swiz struct namelist *, char *, struct subcmd *);
66a9b4ca62Swiz static void notify(char *, char *, struct namelist *, time_t);
67a9b4ca62Swiz static void rcmptime(struct stat *);
6861f28255Scgd
6961f28255Scgd /*
7061f28255Scgd * Do the commands in cmds (initialized by yyparse).
7161f28255Scgd */
72a5bfdf78Scgd void
docmds(char ** dhosts,int argc,char ** argv)73a9b4ca62Swiz docmds(char **dhosts, int argc, char **argv)
7461f28255Scgd {
753b3cf635Slukem struct cmd *c;
763b3cf635Slukem struct namelist *f;
773b3cf635Slukem char **cpp;
7861f28255Scgd extern struct cmd *cmds;
7961f28255Scgd
8061f28255Scgd signal(SIGHUP, cleanup);
8161f28255Scgd signal(SIGINT, cleanup);
8261f28255Scgd signal(SIGQUIT, cleanup);
8361f28255Scgd signal(SIGTERM, cleanup);
8461f28255Scgd
8561f28255Scgd for (c = cmds; c != NULL; c = c->c_next) {
8661f28255Scgd if (dhosts != NULL && *dhosts != NULL) {
8761f28255Scgd for (cpp = dhosts; *cpp; cpp++)
8861f28255Scgd if (strcmp(c->c_name, *cpp) == 0)
8961f28255Scgd goto fndhost;
9061f28255Scgd continue;
9161f28255Scgd }
9261f28255Scgd fndhost:
9361f28255Scgd if (argc) {
9461f28255Scgd for (cpp = argv; *cpp; cpp++) {
9561f28255Scgd if (c->c_label != NULL &&
9661f28255Scgd strcmp(c->c_label, *cpp) == 0) {
9761f28255Scgd cpp = NULL;
9861f28255Scgd goto found;
9961f28255Scgd }
10061f28255Scgd for (f = c->c_files; f != NULL; f = f->n_next)
10161f28255Scgd if (strcmp(f->n_name, *cpp) == 0)
10261f28255Scgd goto found;
10361f28255Scgd }
10461f28255Scgd continue;
10561f28255Scgd } else
10661f28255Scgd cpp = NULL;
10761f28255Scgd found:
10861f28255Scgd switch (c->c_type) {
10961f28255Scgd case ARROW:
11061f28255Scgd doarrow(cpp, c->c_files, c->c_name, c->c_cmds);
11161f28255Scgd break;
11261f28255Scgd case DCOLON:
11361f28255Scgd dodcolon(cpp, c->c_files, c->c_name, c->c_cmds);
11461f28255Scgd break;
11561f28255Scgd default:
11661f28255Scgd fatal("illegal command type %d\n", c->c_type);
11761f28255Scgd }
11861f28255Scgd }
11961f28255Scgd closeconn();
12061f28255Scgd }
12161f28255Scgd
12261f28255Scgd /*
12361f28255Scgd * Process commands for sending files to other machines.
12461f28255Scgd */
125a5bfdf78Scgd static void
doarrow(char ** filev,struct namelist * xfiles,char * rhost,struct subcmd * xcmds)126*bdeefc61Schristos doarrow(char **filev, struct namelist *xfiles, char *rhost,
127*bdeefc61Schristos struct subcmd *xcmds)
12861f28255Scgd {
1293b3cf635Slukem struct namelist *f;
1303b3cf635Slukem struct subcmd *sc;
1313b3cf635Slukem char **cpp;
1327d2ef9d9Schristos int n;
1337d2ef9d9Schristos int volatile ddir;
1347d2ef9d9Schristos int volatile opts;
135c3e578cfSchristos struct namelist * volatile files = xfiles;
136*bdeefc61Schristos struct subcmd * volatile cmds = xcmds;
13761f28255Scgd
1387d2ef9d9Schristos opts = options;
13961f28255Scgd if (debug)
1403b3cf635Slukem printf("doarrow(%lx, %s, %lx)\n",
1413b3cf635Slukem (long)files, rhost, (long)cmds);
14261f28255Scgd
14361f28255Scgd if (files == NULL) {
14461f28255Scgd error("no files to be updated\n");
14561f28255Scgd return;
14661f28255Scgd }
14761f28255Scgd
14861f28255Scgd subcmds = cmds;
14961f28255Scgd ddir = files->n_next != NULL; /* destination is a directory */
15061f28255Scgd if (nflag)
15161f28255Scgd printf("updating host %s\n", rhost);
15261f28255Scgd else {
15361f28255Scgd if (setjmp(env))
15461f28255Scgd goto done;
15561f28255Scgd signal(SIGPIPE, lostconn);
15661f28255Scgd if (!makeconn(rhost))
15761f28255Scgd return;
15861f28255Scgd if ((lfp = fopen(tempfile, "w")) == NULL) {
15961f28255Scgd fatal("cannot open %s\n", tempfile);
16061f28255Scgd exit(1);
16161f28255Scgd }
16261f28255Scgd }
16361f28255Scgd for (f = files; f != NULL; f = f->n_next) {
16461f28255Scgd if (filev) {
16561f28255Scgd for (cpp = filev; *cpp; cpp++)
16661f28255Scgd if (strcmp(f->n_name, *cpp) == 0)
16761f28255Scgd goto found;
1682cb3df57Schristos if (!nflag && lfp)
16961f28255Scgd (void) fclose(lfp);
17061f28255Scgd continue;
17161f28255Scgd }
17261f28255Scgd found:
17361f28255Scgd n = 0;
17461f28255Scgd for (sc = cmds; sc != NULL; sc = sc->sc_next) {
17561f28255Scgd if (sc->sc_type != INSTALL)
17661f28255Scgd continue;
17761f28255Scgd n++;
17861f28255Scgd install(f->n_name, sc->sc_name,
17961f28255Scgd sc->sc_name == NULL ? 0 : ddir, sc->sc_options);
18061f28255Scgd opts = sc->sc_options;
18161f28255Scgd }
18261f28255Scgd if (n == 0)
18361f28255Scgd install(f->n_name, NULL, 0, options);
18461f28255Scgd }
18561f28255Scgd done:
18661f28255Scgd if (!nflag) {
18761f28255Scgd (void) signal(SIGPIPE, cleanup);
1882cb3df57Schristos if (lfp)
18961f28255Scgd (void) fclose(lfp);
19061f28255Scgd lfp = NULL;
19161f28255Scgd }
19261f28255Scgd for (sc = cmds; sc != NULL; sc = sc->sc_next)
19361f28255Scgd if (sc->sc_type == NOTIFY)
19461f28255Scgd notify(tempfile, rhost, sc->sc_args, 0);
19561f28255Scgd if (!nflag) {
19661f28255Scgd for (; ihead != NULL; ihead = ihead->nextp) {
19761f28255Scgd free(ihead);
19861f28255Scgd if ((opts & IGNLNKS) || ihead->count == 0)
19961f28255Scgd continue;
2002cb3df57Schristos if (lfp)
201f393397bSthorpej dolog(lfp, "%s: Warning: missing links\n",
20261f28255Scgd ihead->pathname);
20361f28255Scgd }
20461f28255Scgd }
20561f28255Scgd }
20661f28255Scgd
20761f28255Scgd /*
20861f28255Scgd * Create a connection to the rdist server on the machine rhost.
20961f28255Scgd */
210a5bfdf78Scgd static int
makeconn(char * rhost)211a9b4ca62Swiz makeconn(char *rhost)
21261f28255Scgd {
2133b3cf635Slukem char *ruser, *cp;
21461f28255Scgd static char *cur_host = NULL;
21561f28255Scgd static int port = -1;
21661f28255Scgd char tuser[20];
21761f28255Scgd int n;
21861f28255Scgd extern char user[];
21961f28255Scgd
22061f28255Scgd if (debug)
22161f28255Scgd printf("makeconn(%s)\n", rhost);
22261f28255Scgd
22361f28255Scgd if (cur_host != NULL && rem >= 0) {
22461f28255Scgd if (strcmp(cur_host, rhost) == 0)
22561f28255Scgd return(1);
22661f28255Scgd closeconn();
22761f28255Scgd }
22861f28255Scgd cur_host = rhost;
2293b3cf635Slukem cp = strchr(rhost, '@');
23061f28255Scgd if (cp != NULL) {
23161f28255Scgd char c = *cp;
23261f28255Scgd
23361f28255Scgd *cp = '\0';
234417386ecSitojun if (strlcpy(tuser, rhost, sizeof(tuser)) >= sizeof(tuser)) {
235417386ecSitojun *cp = c;
236417386ecSitojun return(0);
237417386ecSitojun }
23861f28255Scgd *cp = c;
23961f28255Scgd rhost = cp + 1;
24061f28255Scgd ruser = tuser;
24161f28255Scgd if (*ruser == '\0')
24261f28255Scgd ruser = user;
24361f28255Scgd else if (!okname(ruser))
24461f28255Scgd return(0);
24561f28255Scgd } else
24661f28255Scgd ruser = user;
24761f28255Scgd if (!qflag)
24861f28255Scgd printf("updating host %s\n", rhost);
249cf0afdf8Sthorpej (void) snprintf(buf, sizeof(buf), "%s -Server%s", _PATH_RDIST,
250336eeb5fSthorpej qflag ? " -q" : "");
25161f28255Scgd if (port < 0) {
25261f28255Scgd struct servent *sp;
25361f28255Scgd
25461f28255Scgd if ((sp = getservbyname("shell", "tcp")) == NULL)
25561f28255Scgd fatal("shell/tcp: unknown service");
25661f28255Scgd port = sp->s_port;
25761f28255Scgd }
25861f28255Scgd
25961f28255Scgd if (debug) {
26061f28255Scgd printf("port = %d, luser = %s, ruser = %s\n", ntohs(port), user, ruser);
26161f28255Scgd printf("buf = %s\n", buf);
26261f28255Scgd }
26361f28255Scgd
26461f28255Scgd fflush(stdout);
265d0ffbae0Scgd seteuid(0);
2662cb3df57Schristos rem = rcmd(&rhost, port, user, ruser, buf, &remerr);
267d0ffbae0Scgd seteuid(userid);
26861f28255Scgd if (rem < 0)
26961f28255Scgd return(0);
27061f28255Scgd cp = buf;
27161f28255Scgd if (read(rem, cp, 1) != 1)
272a5bfdf78Scgd lostconn(0);
27361f28255Scgd if (*cp == 'V') {
27461f28255Scgd do {
27561f28255Scgd if (read(rem, cp, 1) != 1)
276a5bfdf78Scgd lostconn(0);
27761f28255Scgd } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
27861f28255Scgd *--cp = '\0';
27961f28255Scgd cp = buf;
28061f28255Scgd n = 0;
28161f28255Scgd while (*cp >= '0' && *cp <= '9')
28261f28255Scgd n = (n * 10) + (*cp++ - '0');
28361f28255Scgd if (*cp == '\0' && n == VERSION)
28461f28255Scgd return(1);
28561f28255Scgd error("connection failed: version numbers don't match (local %d, remote %d)\n", VERSION, n);
286a5bfdf78Scgd } else {
28761f28255Scgd error("connection failed: version numbers don't match\n");
288a5bfdf78Scgd error("got unexpected input:");
289a5bfdf78Scgd do {
290a5bfdf78Scgd error("%c", *cp);
291a5bfdf78Scgd } while (*cp != '\n' && read(rem, cp, 1) == 1);
292a5bfdf78Scgd }
29361f28255Scgd closeconn();
29461f28255Scgd return(0);
29561f28255Scgd }
29661f28255Scgd
29761f28255Scgd /*
29861f28255Scgd * Signal end of previous connection.
29961f28255Scgd */
300a5bfdf78Scgd static void
closeconn(void)301a9b4ca62Swiz closeconn(void)
30261f28255Scgd {
30361f28255Scgd if (debug)
30461f28255Scgd printf("closeconn()\n");
30561f28255Scgd
30661f28255Scgd if (rem >= 0) {
307c08b0cf3Smrg if (write(rem, "\2\n", 2) < 0 && debug)
308c08b0cf3Smrg printf("write failed on fd %d: %s\n", rem,
309c08b0cf3Smrg strerror(errno));
31061f28255Scgd (void) close(rem);
3112cb3df57Schristos (void) close(remerr);
31261f28255Scgd rem = -1;
3132cb3df57Schristos remerr = -1;
31461f28255Scgd }
31561f28255Scgd }
31661f28255Scgd
31761f28255Scgd void
3187d2ef9d9Schristos /*ARGSUSED*/
lostconn(int signo __unused)3197d2ef9d9Schristos lostconn(int signo __unused)
32061f28255Scgd {
3214538623fSlukem char lcbuf[BUFSIZ];
3222cb3df57Schristos int nr = -1;
3232cb3df57Schristos
3242cb3df57Schristos if (remerr != -1)
3252cb3df57Schristos if (ioctl(remerr, FIONREAD, &nr) != -1) {
3264538623fSlukem if (nr >= (int)sizeof(lcbuf))
3274538623fSlukem nr = sizeof(lcbuf) - 1;
3284538623fSlukem if ((nr = read(remerr, lcbuf, nr)) > 0) {
3294538623fSlukem lcbuf[nr] = '\0';
3304538623fSlukem if (lcbuf[nr - 1] == '\n')
3314538623fSlukem lcbuf[--nr] = '\0';
3322cb3df57Schristos }
3332cb3df57Schristos }
3342cb3df57Schristos
3352cb3df57Schristos if (nr <= 0)
3364538623fSlukem (void) strlcpy(lcbuf, "lost connection", sizeof(lcbuf));
3372cb3df57Schristos
33861f28255Scgd if (iamremote)
339a5bfdf78Scgd cleanup(0);
3402cb3df57Schristos if (lfp)
3414538623fSlukem dolog(lfp, "rdist: %s\n", lcbuf);
3422cb3df57Schristos else
3434538623fSlukem error("%s\n", lcbuf);
34461f28255Scgd longjmp(env, 1);
34561f28255Scgd }
34661f28255Scgd
347a5bfdf78Scgd static int
okname(char * name)348a9b4ca62Swiz okname(char *name)
34961f28255Scgd {
3503b3cf635Slukem char *cp = name;
3513b3cf635Slukem int c;
35261f28255Scgd
35361f28255Scgd do {
35461f28255Scgd c = *cp;
35561f28255Scgd if (c & 0200)
35661f28255Scgd goto bad;
35761f28255Scgd if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
35861f28255Scgd goto bad;
35961f28255Scgd cp++;
36061f28255Scgd } while (*cp);
36161f28255Scgd return(1);
36261f28255Scgd bad:
36361f28255Scgd error("invalid user name %s\n", name);
36461f28255Scgd return(0);
36561f28255Scgd }
36661f28255Scgd
36761f28255Scgd time_t lastmod;
36861f28255Scgd FILE *tfp;
36961f28255Scgd extern char target[], *tp;
37061f28255Scgd
37161f28255Scgd /*
37261f28255Scgd * Process commands for comparing files to time stamp files.
37361f28255Scgd */
374a5bfdf78Scgd static void
dodcolon(char ** filev,struct namelist * files,char * stamp,struct subcmd * cmds)375a9b4ca62Swiz dodcolon(char **filev, struct namelist *files, char *stamp, struct subcmd *cmds)
37661f28255Scgd {
3773b3cf635Slukem struct subcmd *sc;
3783b3cf635Slukem struct namelist *f;
3793b3cf635Slukem char **cpp;
38061f28255Scgd struct timeval tv[2];
38161f28255Scgd struct stat stb;
38261f28255Scgd
38361f28255Scgd if (debug)
38461f28255Scgd printf("dodcolon()\n");
38561f28255Scgd
38661f28255Scgd if (files == NULL) {
38761f28255Scgd error("no files to be updated\n");
38861f28255Scgd return;
38961f28255Scgd }
39061f28255Scgd if (stat(stamp, &stb) < 0) {
39161f28255Scgd error("%s: %s\n", stamp, strerror(errno));
39261f28255Scgd return;
39361f28255Scgd }
39461f28255Scgd if (debug)
395538e6929Smrg printf("%s: %lu\n", stamp, (u_long)stb.st_mtime);
39661f28255Scgd
39761f28255Scgd subcmds = cmds;
39861f28255Scgd lastmod = stb.st_mtime;
39961f28255Scgd if (nflag || (options & VERIFY))
40061f28255Scgd tfp = NULL;
40161f28255Scgd else {
40261f28255Scgd if ((tfp = fopen(tempfile, "w")) == NULL) {
403b5d63942Smycroft error("%s: %s\n", tempfile, strerror(errno));
40461f28255Scgd return;
40561f28255Scgd }
406b5d63942Smycroft (void) gettimeofday(&tv[0], (struct timezone *)0);
40761f28255Scgd tv[1] = tv[0];
40861f28255Scgd (void) utimes(stamp, tv);
40961f28255Scgd }
41061f28255Scgd
41161f28255Scgd for (f = files; f != NULL; f = f->n_next) {
41261f28255Scgd if (filev) {
41361f28255Scgd for (cpp = filev; *cpp; cpp++)
41461f28255Scgd if (strcmp(f->n_name, *cpp) == 0)
41561f28255Scgd goto found;
41661f28255Scgd continue;
41761f28255Scgd }
41861f28255Scgd found:
41961f28255Scgd tp = NULL;
42061f28255Scgd cmptime(f->n_name);
42161f28255Scgd }
42261f28255Scgd
42361f28255Scgd if (tfp != NULL)
42461f28255Scgd (void) fclose(tfp);
42561f28255Scgd for (sc = cmds; sc != NULL; sc = sc->sc_next)
42661f28255Scgd if (sc->sc_type == NOTIFY)
42761f28255Scgd notify(tempfile, NULL, sc->sc_args, lastmod);
42861f28255Scgd }
42961f28255Scgd
43061f28255Scgd /*
43161f28255Scgd * Compare the mtime of file to the list of time stamps.
43261f28255Scgd */
433a5bfdf78Scgd static void
cmptime(char * name)434a9b4ca62Swiz cmptime(char *name)
43561f28255Scgd {
43661f28255Scgd struct stat stb;
43761f28255Scgd
43861f28255Scgd if (debug)
43961f28255Scgd printf("cmptime(%s)\n", name);
44061f28255Scgd
44161f28255Scgd if (except(name))
44261f28255Scgd return;
44361f28255Scgd
44461f28255Scgd if (nflag) {
44561f28255Scgd printf("comparing dates: %s\n", name);
44661f28255Scgd return;
44761f28255Scgd }
44861f28255Scgd
44961f28255Scgd /*
45061f28255Scgd * first time cmptime() is called?
45161f28255Scgd */
45261f28255Scgd if (tp == NULL) {
45361f28255Scgd if (exptilde(target, name) == NULL)
45461f28255Scgd return;
45561f28255Scgd tp = name = target;
45661f28255Scgd while (*tp)
45761f28255Scgd tp++;
45861f28255Scgd }
45961f28255Scgd if (access(name, 4) < 0 || stat(name, &stb) < 0) {
46061f28255Scgd error("%s: %s\n", name, strerror(errno));
46161f28255Scgd return;
46261f28255Scgd }
46361f28255Scgd
46461f28255Scgd switch (stb.st_mode & S_IFMT) {
46561f28255Scgd case S_IFREG:
46661f28255Scgd break;
46761f28255Scgd
46861f28255Scgd case S_IFDIR:
46961f28255Scgd rcmptime(&stb);
47061f28255Scgd return;
47161f28255Scgd
47261f28255Scgd default:
47361f28255Scgd error("%s: not a plain file\n", name);
47461f28255Scgd return;
47561f28255Scgd }
47661f28255Scgd
47761f28255Scgd if (stb.st_mtime > lastmod)
478f393397bSthorpej dolog(tfp, "new: %s\n", name);
47961f28255Scgd }
48061f28255Scgd
481a5bfdf78Scgd static void
rcmptime(struct stat * st)482a9b4ca62Swiz rcmptime(struct stat *st)
48361f28255Scgd {
4843b3cf635Slukem DIR *d;
485b751ad2cSchristos struct dirent *dp;
4863b3cf635Slukem char *cp;
48761f28255Scgd char *otp;
48861f28255Scgd int len;
48961f28255Scgd
49061f28255Scgd if (debug)
4913b3cf635Slukem printf("rcmptime(%lx)\n", (long)st);
49261f28255Scgd
49361f28255Scgd if ((d = opendir(target)) == NULL) {
49461f28255Scgd error("%s: %s\n", target, strerror(errno));
49561f28255Scgd return;
49661f28255Scgd }
49761f28255Scgd otp = tp;
49861f28255Scgd len = tp - target;
4993b3cf635Slukem while ((dp = readdir(d)) != NULL) {
50061f28255Scgd if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
50161f28255Scgd continue;
50261f28255Scgd if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
50361f28255Scgd error("%s/%s: Name too long\n", target, dp->d_name);
50461f28255Scgd continue;
50561f28255Scgd }
50661f28255Scgd tp = otp;
50761f28255Scgd *tp++ = '/';
50861f28255Scgd cp = dp->d_name;
5093b3cf635Slukem while ((*tp++ = *cp++) != 0)
51061f28255Scgd ;
51161f28255Scgd tp--;
51261f28255Scgd cmptime(target);
51361f28255Scgd }
51461f28255Scgd closedir(d);
51561f28255Scgd tp = otp;
51661f28255Scgd *tp = '\0';
51761f28255Scgd }
51861f28255Scgd
51961f28255Scgd /*
52061f28255Scgd * Notify the list of people the changes that were made.
52161f28255Scgd * rhost == NULL if we are mailing a list of changes compared to at time
52261f28255Scgd * stamp file.
52361f28255Scgd */
524a5bfdf78Scgd static void
notify(char * file,char * rhost,struct namelist * to,time_t lmod)525a9b4ca62Swiz notify(char *file, char *rhost, struct namelist *to, time_t lmod)
52661f28255Scgd {
5273b3cf635Slukem int fd, len;
52861f28255Scgd struct stat stb;
529a5bfdf78Scgd FILE *pf;
5302841b777Sginsbach char *cp, *nrhost = rhost;
53161f28255Scgd
53261f28255Scgd if ((options & VERIFY) || to == NULL)
53361f28255Scgd return;
5342841b777Sginsbach
5352841b777Sginsbach /* strip any leading user@ prefix from rhost */
5362841b777Sginsbach if (rhost && (cp = strchr(rhost, '@')) != NULL)
5372841b777Sginsbach nrhost = cp + 1;
5382841b777Sginsbach
53961f28255Scgd if (!qflag) {
54061f28255Scgd printf("notify ");
54161f28255Scgd if (rhost)
5422841b777Sginsbach printf("@%s ", nrhost);
54361f28255Scgd prnames(to);
54461f28255Scgd }
54561f28255Scgd if (nflag)
54661f28255Scgd return;
54761f28255Scgd
54861f28255Scgd if ((fd = open(file, 0)) < 0) {
54961f28255Scgd error("%s: %s\n", file, strerror(errno));
55061f28255Scgd return;
55161f28255Scgd }
55261f28255Scgd if (fstat(fd, &stb) < 0) {
55361f28255Scgd error("%s: %s\n", file, strerror(errno));
55461f28255Scgd (void) close(fd);
55561f28255Scgd return;
55661f28255Scgd }
55761f28255Scgd if (stb.st_size == 0) {
55861f28255Scgd (void) close(fd);
55961f28255Scgd return;
56061f28255Scgd }
56161f28255Scgd /*
56261f28255Scgd * Create a pipe to mailling program.
56361f28255Scgd */
564cf0afdf8Sthorpej (void)snprintf(buf, sizeof(buf), "%s -oi -t", _PATH_SENDMAIL);
56561f28255Scgd pf = popen(buf, "w");
56661f28255Scgd if (pf == NULL) {
56761f28255Scgd error("notify: \"%s\" failed\n", _PATH_SENDMAIL);
56861f28255Scgd (void) close(fd);
56961f28255Scgd return;
57061f28255Scgd }
57161f28255Scgd /*
57261f28255Scgd * Output the proper header information.
57361f28255Scgd */
57461f28255Scgd fprintf(pf, "From: rdist (Remote distribution program)\n");
57561f28255Scgd fprintf(pf, "To:");
57661f28255Scgd if (!any('@', to->n_name) && rhost != NULL)
5772841b777Sginsbach fprintf(pf, " %s@%s", to->n_name, nrhost);
57861f28255Scgd else
57961f28255Scgd fprintf(pf, " %s", to->n_name);
58061f28255Scgd to = to->n_next;
58161f28255Scgd while (to != NULL) {
58261f28255Scgd if (!any('@', to->n_name) && rhost != NULL)
5832841b777Sginsbach fprintf(pf, ", %s@%s", to->n_name, nrhost);
58461f28255Scgd else
58561f28255Scgd fprintf(pf, ", %s", to->n_name);
58661f28255Scgd to = to->n_next;
58761f28255Scgd }
58861f28255Scgd putc('\n', pf);
58961f28255Scgd if (rhost != NULL)
59061f28255Scgd fprintf(pf, "Subject: files updated by rdist from %s to %s\n",
59161f28255Scgd host, rhost);
59261f28255Scgd else
59361f28255Scgd fprintf(pf, "Subject: files updated after %s\n", ctime(&lmod));
59461f28255Scgd putc('\n', pf);
59561f28255Scgd
59661f28255Scgd while ((len = read(fd, buf, BUFSIZ)) > 0)
597c08b0cf3Smrg if (fwrite(buf, 1, len, pf) < 1)
598c08b0cf3Smrg error("%s: %s\n", file, strerror(errno));
59961f28255Scgd (void) close(fd);
60061f28255Scgd (void) pclose(pf);
60161f28255Scgd }
60261f28255Scgd
60361f28255Scgd /*
60461f28255Scgd * Return true if name is in the list.
60561f28255Scgd */
606a5bfdf78Scgd int
inlist(struct namelist * list,char * file)607a9b4ca62Swiz inlist(struct namelist *list, char *file)
60861f28255Scgd {
6093b3cf635Slukem struct namelist *nl;
61061f28255Scgd
61161f28255Scgd for (nl = list; nl != NULL; nl = nl->n_next)
61261f28255Scgd if (!strcmp(file, nl->n_name))
61361f28255Scgd return(1);
61461f28255Scgd return(0);
61561f28255Scgd }
61661f28255Scgd
61761f28255Scgd /*
61861f28255Scgd * Return TRUE if file is in the exception list.
61961f28255Scgd */
620a5bfdf78Scgd int
except(char * file)621a9b4ca62Swiz except(char *file)
62261f28255Scgd {
6233b3cf635Slukem struct subcmd *sc;
6243b3cf635Slukem struct namelist *nl;
625cf0afdf8Sthorpej int err;
626cf0afdf8Sthorpej regex_t s;
62761f28255Scgd
62861f28255Scgd if (debug)
62961f28255Scgd printf("except(%s)\n", file);
63061f28255Scgd
63161f28255Scgd for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
63261f28255Scgd if (sc->sc_type != EXCEPT && sc->sc_type != PATTERN)
63361f28255Scgd continue;
63461f28255Scgd for (nl = sc->sc_args; nl != NULL; nl = nl->n_next) {
63561f28255Scgd if (sc->sc_type == EXCEPT) {
63661f28255Scgd if (!strcmp(file, nl->n_name))
63761f28255Scgd return(1);
63861f28255Scgd continue;
63961f28255Scgd }
640cf0afdf8Sthorpej if ((err = regcomp(&s, nl->n_name, 0)) != 0) {
641cf0afdf8Sthorpej char ebuf[BUFSIZ];
642cf0afdf8Sthorpej (void) regerror(err, &s, ebuf, sizeof(ebuf));
643cf0afdf8Sthorpej error("%s: %s\n", nl->n_name, ebuf);
644cf0afdf8Sthorpej }
645d54b3d99Sexplorer if (regexec(&s, file, 0, NULL, 0) == 0) {
646d54b3d99Sexplorer regfree(&s);
64761f28255Scgd return(1);
64861f28255Scgd }
649d54b3d99Sexplorer regfree(&s);
650d54b3d99Sexplorer }
65161f28255Scgd }
65261f28255Scgd return(0);
65361f28255Scgd }
65461f28255Scgd
65561f28255Scgd char *
colon(char * cp)656a9b4ca62Swiz colon(char *cp)
65761f28255Scgd {
65861f28255Scgd
65961f28255Scgd while (*cp) {
66061f28255Scgd if (*cp == ':')
66161f28255Scgd return(cp);
66261f28255Scgd if (*cp == '/')
66361f28255Scgd return(0);
66461f28255Scgd cp++;
66561f28255Scgd }
66661f28255Scgd return(0);
66761f28255Scgd }
668