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