Annotation of src/usr.bin/oldrdist/docmd.c, Revision 1.4
1.4 ! millert 1: /* $OpenBSD: docmd.c,v 1.3 1996/06/26 05:37:38 deraadt Exp $ */
1.3 deraadt 2:
1.1 dm 3: /*
4: * Copyright (c) 1983, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #ifndef lint
37: /* from: static char sccsid[] = "@(#)docmd.c 8.1 (Berkeley) 6/9/93"; */
1.4 ! millert 38: static char *rcsid = "$OpenBSD: docmd.c,v 1.3 1996/06/26 05:37:38 deraadt Exp $";
1.1 dm 39: #endif /* not lint */
40:
41: #include "defs.h"
42: #include <setjmp.h>
43: #include <netdb.h>
44:
45: FILE *lfp; /* log file for recording files updated */
46: struct subcmd *subcmds; /* list of sub-commands for current cmd */
47: jmp_buf env;
48:
49: static int makeconn __P((char *));
50: static int okname __P((char *));
51: static void closeconn __P((void));
52: static void cmptime __P((char *));
53: static void doarrow __P((char **,
54: struct namelist *, char *, struct subcmd *));
55: static void dodcolon __P((char **,
56: struct namelist *, char *, struct subcmd *));
57: static void notify __P((char *, char *, struct namelist *, time_t));
58: static void rcmptime __P((struct stat *));
59:
60: /*
61: * Do the commands in cmds (initialized by yyparse).
62: */
63: void
64: docmds(dhosts, argc, argv)
65: char **dhosts;
66: int argc;
67: char **argv;
68: {
69: register struct cmd *c;
70: register struct namelist *f;
71: register char **cpp;
72: extern struct cmd *cmds;
73:
74: signal(SIGHUP, cleanup);
75: signal(SIGINT, cleanup);
76: signal(SIGQUIT, cleanup);
77: signal(SIGTERM, cleanup);
78:
79: for (c = cmds; c != NULL; c = c->c_next) {
80: if (dhosts != NULL && *dhosts != NULL) {
81: for (cpp = dhosts; *cpp; cpp++)
82: if (strcmp(c->c_name, *cpp) == 0)
83: goto fndhost;
84: continue;
85: }
86: fndhost:
87: if (argc) {
88: for (cpp = argv; *cpp; cpp++) {
89: if (c->c_label != NULL &&
90: strcmp(c->c_label, *cpp) == 0) {
91: cpp = NULL;
92: goto found;
93: }
94: for (f = c->c_files; f != NULL; f = f->n_next)
95: if (strcmp(f->n_name, *cpp) == 0)
96: goto found;
97: }
98: continue;
99: } else
100: cpp = NULL;
101: found:
102: switch (c->c_type) {
103: case ARROW:
104: doarrow(cpp, c->c_files, c->c_name, c->c_cmds);
105: break;
106: case DCOLON:
107: dodcolon(cpp, c->c_files, c->c_name, c->c_cmds);
108: break;
109: default:
110: fatal("illegal command type %d\n", c->c_type);
111: }
112: }
113: closeconn();
114: }
115:
116: /*
117: * Process commands for sending files to other machines.
118: */
119: static void
120: doarrow(filev, files, rhost, cmds)
121: char **filev;
122: struct namelist *files;
123: char *rhost;
124: struct subcmd *cmds;
125: {
126: register struct namelist *f;
127: register struct subcmd *sc;
128: register char **cpp;
129: int n, ddir, opts = options;
130:
131: if (debug)
132: printf("doarrow(%x, %s, %x)\n", files, rhost, cmds);
133:
134: if (files == NULL) {
135: error("no files to be updated\n");
136: return;
137: }
138:
139: subcmds = cmds;
140: ddir = files->n_next != NULL; /* destination is a directory */
141: if (nflag)
142: printf("updating host %s\n", rhost);
143: else {
1.2 deraadt 144: int fd;
145:
1.1 dm 146: if (setjmp(env))
147: goto done;
148: signal(SIGPIPE, lostconn);
149: if (!makeconn(rhost))
150: return;
1.2 deraadt 151: if ((fd = open(tempfile, O_RDWR|O_EXCL|O_CREAT, 0666)) == -1 ||
152: (lfp = fdopen(fd, "w")) == NULL) {
153: if (fd != -1)
154: close(fd);
1.1 dm 155: fatal("cannot open %s\n", tempfile);
156: exit(1);
157: }
158: }
159: for (f = files; f != NULL; f = f->n_next) {
160: if (filev) {
161: for (cpp = filev; *cpp; cpp++)
162: if (strcmp(f->n_name, *cpp) == 0)
163: goto found;
1.4 ! millert 164: if (!nflag && lfp) {
1.1 dm 165: (void) fclose(lfp);
1.4 ! millert 166: lfp = NULL;
! 167: }
1.1 dm 168: continue;
169: }
170: found:
171: n = 0;
172: for (sc = cmds; sc != NULL; sc = sc->sc_next) {
173: if (sc->sc_type != INSTALL)
174: continue;
175: n++;
176: install(f->n_name, sc->sc_name,
177: sc->sc_name == NULL ? 0 : ddir, sc->sc_options);
178: opts = sc->sc_options;
179: }
180: if (n == 0)
181: install(f->n_name, NULL, 0, options);
182: }
183: done:
184: if (!nflag) {
185: (void) signal(SIGPIPE, cleanup);
1.4 ! millert 186: if (lfp)
! 187: (void) fclose(lfp);
1.1 dm 188: lfp = NULL;
189: }
190: for (sc = cmds; sc != NULL; sc = sc->sc_next)
191: if (sc->sc_type == NOTIFY)
192: notify(tempfile, rhost, sc->sc_args, 0);
193: if (!nflag) {
194: (void) unlink(tempfile);
195: for (; ihead != NULL; ihead = ihead->nextp) {
196: free(ihead);
197: if ((opts & IGNLNKS) || ihead->count == 0)
198: continue;
199: log(lfp, "%s: Warning: missing links\n",
200: ihead->pathname);
201: }
202: }
203: }
204:
205: /*
206: * Create a connection to the rdist server on the machine rhost.
207: */
208: static int
209: makeconn(rhost)
210: char *rhost;
211: {
212: register char *ruser, *cp;
213: static char *cur_host = NULL;
1.4 ! millert 214: #if defined(DIRECT_RCMD)
1.1 dm 215: static int port = -1;
1.4 ! millert 216: #endif /* DIRECT_RCMD */
1.1 dm 217: char tuser[20];
218: int n;
219: extern char user[];
220: extern int userid;
221:
222: if (debug)
223: printf("makeconn(%s)\n", rhost);
224:
225: if (cur_host != NULL && rem >= 0) {
226: if (strcmp(cur_host, rhost) == 0)
227: return(1);
228: closeconn();
229: }
230: cur_host = rhost;
1.4 ! millert 231: cp = strchr(rhost, '@');
1.1 dm 232: if (cp != NULL) {
233: char c = *cp;
234:
235: *cp = '\0';
236: strncpy(tuser, rhost, sizeof(tuser)-1);
237: *cp = c;
238: rhost = cp + 1;
239: ruser = tuser;
240: if (*ruser == '\0')
241: ruser = user;
242: else if (!okname(ruser))
243: return(0);
244: } else
245: ruser = user;
246: if (!qflag)
247: printf("updating host %s\n", rhost);
248: (void) sprintf(buf, "%s -Server%s", _PATH_RDIST, qflag ? " -q" : "");
1.4 ! millert 249: #if defined(DIRECT_RCMD)
1.1 dm 250: if (port < 0) {
251: struct servent *sp;
252:
253: if ((sp = getservbyname("shell", "tcp")) == NULL)
254: fatal("shell/tcp: unknown service");
255: port = sp->s_port;
256: }
1.4 ! millert 257: #endif /* !DIRECT_RCMD */
1.1 dm 258:
259: if (debug) {
1.4 ! millert 260: #if defined(DIRECT_RCMD)
1.1 dm 261: printf("port = %d, luser = %s, ruser = %s\n", ntohs(port), user, ruser);
1.4 ! millert 262: #else /* !DIRECT_RCMD */
! 263: printf("luser = %s, ruser = %s\n", user, ruser);
! 264: #endif /* !DIRECT_RCMD */
1.1 dm 265: printf("buf = %s\n", buf);
266: }
267:
268: fflush(stdout);
1.4 ! millert 269: #if defined(DIRECT_RCMD)
1.1 dm 270: seteuid(0);
271: rem = rcmd(&rhost, port, user, ruser, buf, 0);
272: seteuid(userid);
1.4 ! millert 273: #else /* !DIRECT_RCMD */
! 274: rem = rshrcmd(&rhost, -1, user, ruser, buf, 0);
! 275: #endif /* !DIRECT_RCMD */
1.1 dm 276: if (rem < 0)
277: return(0);
278: cp = buf;
279: if (read(rem, cp, 1) != 1)
280: lostconn(0);
281: if (*cp == 'V') {
282: do {
283: if (read(rem, cp, 1) != 1)
284: lostconn(0);
285: } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
286: *--cp = '\0';
287: cp = buf;
288: n = 0;
289: while (*cp >= '0' && *cp <= '9')
290: n = (n * 10) + (*cp++ - '0');
291: if (*cp == '\0' && n == VERSION)
292: return(1);
293: error("connection failed: version numbers don't match (local %d, remote %d)\n", VERSION, n);
294: } else {
295: error("connection failed: version numbers don't match\n");
296: error("got unexpected input:");
297: do {
298: error("%c", *cp);
299: } while (*cp != '\n' && read(rem, cp, 1) == 1);
300: }
301: closeconn();
302: return(0);
303: }
304:
305: /*
306: * Signal end of previous connection.
307: */
308: static void
309: closeconn()
310: {
311: if (debug)
312: printf("closeconn()\n");
313:
314: if (rem >= 0) {
1.4 ! millert 315: void (*osig)();
! 316: osig = signal(SIGPIPE, SIG_IGN);
1.1 dm 317: (void) write(rem, "\2\n", 2);
1.4 ! millert 318: (void) signal(SIGPIPE, osig);
1.1 dm 319: (void) close(rem);
320: rem = -1;
321: }
322: }
323:
324: void
325: lostconn(signo)
326: int signo;
327: {
328: if (iamremote)
329: cleanup(0);
330: log(lfp, "rdist: lost connection\n");
1.4 ! millert 331: if (rem >= 0) {
! 332: (void) close(rem);
! 333: rem = -1;
! 334: }
1.1 dm 335: longjmp(env, 1);
336: }
337:
338: static int
339: okname(name)
340: register char *name;
341: {
342: register char *cp = name;
343: register int c;
344:
345: do {
346: c = *cp;
347: if (c & 0200)
348: goto bad;
349: if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
350: goto bad;
351: cp++;
352: } while (*cp);
353: return(1);
354: bad:
355: error("invalid user name %s\n", name);
356: return(0);
357: }
358:
359: time_t lastmod;
360: FILE *tfp;
361: extern char target[], *tp;
362:
363: /*
364: * Process commands for comparing files to time stamp files.
365: */
366: static void
367: dodcolon(filev, files, stamp, cmds)
368: char **filev;
369: struct namelist *files;
370: char *stamp;
371: struct subcmd *cmds;
372: {
373: register struct subcmd *sc;
374: register struct namelist *f;
375: register char **cpp;
376: struct timeval tv[2];
377: struct timezone tz;
378: struct stat stb;
379:
380: if (debug)
381: printf("dodcolon()\n");
382:
383: if (files == NULL) {
384: error("no files to be updated\n");
385: return;
386: }
387: if (stat(stamp, &stb) < 0) {
388: error("%s: %s\n", stamp, strerror(errno));
389: return;
390: }
391: if (debug)
392: printf("%s: %ld\n", stamp, stb.st_mtime);
393:
394: subcmds = cmds;
395: lastmod = stb.st_mtime;
396: if (nflag || (options & VERIFY))
397: tfp = NULL;
398: else {
1.2 deraadt 399: int fd;
400:
401: if ((fd = open(tempfile, O_RDWR|O_EXCL|O_CREAT, 0666)) == -1 ||
402: (tfp = fdopen(fd, "w")) == NULL) {
403: if (fd != -1)
404: close(fd);
1.1 dm 405: error("%s: %s\n", stamp, strerror(errno));
406: return;
407: }
408: (void) gettimeofday(&tv[0], &tz);
409: tv[1] = tv[0];
410: (void) utimes(stamp, tv);
411: }
412:
413: for (f = files; f != NULL; f = f->n_next) {
414: if (filev) {
415: for (cpp = filev; *cpp; cpp++)
416: if (strcmp(f->n_name, *cpp) == 0)
417: goto found;
418: continue;
419: }
420: found:
421: tp = NULL;
422: cmptime(f->n_name);
423: }
424:
425: if (tfp != NULL)
426: (void) fclose(tfp);
427: for (sc = cmds; sc != NULL; sc = sc->sc_next)
428: if (sc->sc_type == NOTIFY)
429: notify(tempfile, NULL, sc->sc_args, lastmod);
430: if (!nflag && !(options & VERIFY))
431: (void) unlink(tempfile);
432: }
433:
434: /*
435: * Compare the mtime of file to the list of time stamps.
436: */
437: static void
438: cmptime(name)
439: char *name;
440: {
441: struct stat stb;
442:
443: if (debug)
444: printf("cmptime(%s)\n", name);
445:
446: if (except(name))
447: return;
448:
449: if (nflag) {
450: printf("comparing dates: %s\n", name);
451: return;
452: }
453:
454: /*
455: * first time cmptime() is called?
456: */
457: if (tp == NULL) {
458: if (exptilde(target, name) == NULL)
459: return;
460: tp = name = target;
461: while (*tp)
462: tp++;
463: }
464: if (access(name, 4) < 0 || stat(name, &stb) < 0) {
465: error("%s: %s\n", name, strerror(errno));
466: return;
467: }
468:
469: switch (stb.st_mode & S_IFMT) {
470: case S_IFREG:
471: break;
472:
473: case S_IFDIR:
474: rcmptime(&stb);
475: return;
476:
477: default:
478: error("%s: not a plain file\n", name);
479: return;
480: }
481:
482: if (stb.st_mtime > lastmod)
483: log(tfp, "new: %s\n", name);
484: }
485:
486: static void
487: rcmptime(st)
488: struct stat *st;
489: {
490: register DIR *d;
491: register struct direct *dp;
492: register char *cp;
493: char *otp;
494: int len;
495:
496: if (debug)
497: printf("rcmptime(%x)\n", st);
498:
499: if ((d = opendir(target)) == NULL) {
500: error("%s: %s\n", target, strerror(errno));
501: return;
502: }
503: otp = tp;
504: len = tp - target;
505: while (dp = readdir(d)) {
506: if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
507: continue;
508: if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
509: error("%s/%s: Name too long\n", target, dp->d_name);
510: continue;
511: }
512: tp = otp;
513: *tp++ = '/';
514: cp = dp->d_name;
515: while (*tp++ = *cp++)
516: ;
517: tp--;
518: cmptime(target);
519: }
520: closedir(d);
521: tp = otp;
522: *tp = '\0';
523: }
524:
525: /*
526: * Notify the list of people the changes that were made.
527: * rhost == NULL if we are mailing a list of changes compared to at time
528: * stamp file.
529: */
530: static void
531: notify(file, rhost, to, lmod)
532: char *file, *rhost;
533: register struct namelist *to;
534: time_t lmod;
535: {
536: register int fd, len;
537: struct stat stb;
538: FILE *pf;
539:
540: if ((options & VERIFY) || to == NULL)
541: return;
542: if (!qflag) {
543: printf("notify ");
544: if (rhost)
545: printf("@%s ", rhost);
546: prnames(to);
547: }
548: if (nflag)
549: return;
550:
551: if ((fd = open(file, 0)) < 0) {
552: error("%s: %s\n", file, strerror(errno));
553: return;
554: }
555: if (fstat(fd, &stb) < 0) {
556: error("%s: %s\n", file, strerror(errno));
557: (void) close(fd);
558: return;
559: }
560: if (stb.st_size == 0) {
561: (void) close(fd);
562: return;
563: }
564: /*
565: * Create a pipe to mailling program.
566: */
567: (void)sprintf(buf, "%s -oi -t", _PATH_SENDMAIL);
568: pf = popen(buf, "w");
569: if (pf == NULL) {
570: error("notify: \"%s\" failed\n", _PATH_SENDMAIL);
571: (void) close(fd);
572: return;
573: }
574: /*
575: * Output the proper header information.
576: */
577: fprintf(pf, "From: rdist (Remote distribution program)\n");
578: fprintf(pf, "To:");
579: if (!any('@', to->n_name) && rhost != NULL)
580: fprintf(pf, " %s@%s", to->n_name, rhost);
581: else
582: fprintf(pf, " %s", to->n_name);
583: to = to->n_next;
584: while (to != NULL) {
585: if (!any('@', to->n_name) && rhost != NULL)
586: fprintf(pf, ", %s@%s", to->n_name, rhost);
587: else
588: fprintf(pf, ", %s", to->n_name);
589: to = to->n_next;
590: }
591: putc('\n', pf);
592: if (rhost != NULL)
593: fprintf(pf, "Subject: files updated by rdist from %s to %s\n",
594: host, rhost);
595: else
596: fprintf(pf, "Subject: files updated after %s\n", ctime(&lmod));
597: putc('\n', pf);
598:
599: while ((len = read(fd, buf, BUFSIZ)) > 0)
600: (void) fwrite(buf, 1, len, pf);
601: (void) close(fd);
602: (void) pclose(pf);
603: }
604:
605: /*
606: * Return true if name is in the list.
607: */
608: int
609: inlist(list, file)
610: struct namelist *list;
611: char *file;
612: {
613: register struct namelist *nl;
614:
615: for (nl = list; nl != NULL; nl = nl->n_next)
616: if (!strcmp(file, nl->n_name))
617: return(1);
618: return(0);
619: }
620:
621: /*
622: * Return TRUE if file is in the exception list.
623: */
624: int
625: except(file)
626: char *file;
627: {
628: register struct subcmd *sc;
629: register struct namelist *nl;
630:
631: if (debug)
632: printf("except(%s)\n", file);
633:
634: for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
635: if (sc->sc_type != EXCEPT && sc->sc_type != PATTERN)
636: continue;
637: for (nl = sc->sc_args; nl != NULL; nl = nl->n_next) {
638: if (sc->sc_type == EXCEPT) {
639: if (!strcmp(file, nl->n_name))
640: return(1);
641: continue;
642: }
643: re_comp(nl->n_name);
644: if (re_exec(file) > 0)
645: return(1);
646: }
647: }
648: return(0);
649: }
650:
651: char *
652: colon(cp)
653: register char *cp;
654: {
655:
656: while (*cp) {
657: if (*cp == ':')
658: return(cp);
659: if (*cp == '/')
660: return(0);
661: cp++;
662: }
663: return(0);
664: }