date and time created 86/11/11 09:42:21 by minshall
[unix-history] / usr / src / usr.bin / rdist / docmd.c
CommitLineData
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
8static 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 19FILE *lfp; /* log file for recording files updated */
4085f36f 20struct subcmd *subcmds; /* list of sub-commands for current cmd */
0fccdfef
RC
21jmp_buf env;
22
23int cleanup();
24int lostconn();
25
26/*
27 * Do the commands in cmds (initialized by yyparse).
28 */
78a18ca3
RC
29docmds(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
84doarrow(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
140done:
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 */
164makeconn(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 */
246closeconn()
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
258lostconn()
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
266okname(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);
281bad:
282 error("invalid user name %s\n", name);
283 return(0);
82572cb6
RC
284}
285
d6bccb44
RC
286time_t lastmod;
287FILE *tfp;
288extern char target[], *tp;
3024eb6f 289
82572cb6
RC
290/*
291 * Process commands for comparing files to time stamp files.
292 */
86d7a5c5
RC
293dodcolon(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 */
358cmptime(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
406rcmptime(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 449notify(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 525inlist(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
540except(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
566char *
567colon(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}