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