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