xref: /netbsd-src/usr.bin/rdist/docmd.c (revision bdeefc61e50f9b72985eeb18bf7dffdc6c43a293)
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