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