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