update copyright date
[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 *
5 * Redistribution and use in source and binary forms are permitted
b36fc510
KB
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.
7172eb74
DF
16 */
17
b6b5501c 18#ifndef lint
b36fc510 19static char sccsid[] = "@(#)docmd.c 5.3 (Berkeley) %G%";
0718fb71 20#endif /* not lint */
b6b5501c
RC
21
22#include "defs.h"
0fccdfef 23#include <setjmp.h>
bbdda833 24#include <netdb.h>
b6b5501c 25
80babee1 26#ifndef RDIST
9b118173 27#define RDIST "/usr/ucb/rdist"
80babee1
RC
28#endif
29
0fccdfef 30FILE *lfp; /* log file for recording files updated */
4085f36f 31struct subcmd *subcmds; /* list of sub-commands for current cmd */
0fccdfef
RC
32jmp_buf env;
33
34int cleanup();
35int lostconn();
36
37/*
38 * Do the commands in cmds (initialized by yyparse).
39 */
78a18ca3
RC
40docmds(dhosts, argc, argv)
41 char **dhosts;
0fccdfef
RC
42 int argc;
43 char **argv;
44{
45 register struct cmd *c;
86d7a5c5
RC
46 register struct namelist *f;
47 register char **cpp;
0fccdfef
RC
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) {
e4b2c01a 56 if (dhosts != NULL && *dhosts != NULL) {
78a18ca3
RC
57 for (cpp = dhosts; *cpp; cpp++)
58 if (strcmp(c->c_name, *cpp) == 0)
59 goto fndhost;
60 continue;
61 }
62 fndhost:
86d7a5c5
RC
63 if (argc) {
64 for (cpp = argv; *cpp; cpp++) {
65 if (c->c_label != NULL &&
4085f36f 66 strcmp(c->c_label, *cpp) == 0) {
86d7a5c5
RC
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:
0fccdfef
RC
78 switch (c->c_type) {
79 case ARROW:
86d7a5c5 80 doarrow(cpp, c->c_files, c->c_name, c->c_cmds);
0fccdfef
RC
81 break;
82 case DCOLON:
86d7a5c5 83 dodcolon(cpp, c->c_files, c->c_name, c->c_cmds);
0fccdfef
RC
84 break;
85 default:
86 fatal("illegal command type %d\n", c->c_type);
87 }
88 }
89 closeconn();
90}
b6b5501c
RC
91
92/*
82572cb6 93 * Process commands for sending files to other machines.
b6b5501c 94 */
86d7a5c5
RC
95doarrow(filev, files, rhost, cmds)
96 char **filev;
0fccdfef 97 struct namelist *files;
9d560577 98 char *rhost;
0fccdfef 99 struct subcmd *cmds;
b6b5501c 100{
0fccdfef
RC
101 register struct namelist *f;
102 register struct subcmd *sc;
86d7a5c5 103 register char **cpp;
a3e6fd64 104 int n, ddir, opts = options;
b6b5501c
RC
105
106 if (debug)
9d560577 107 printf("doarrow(%x, %s, %x)\n", files, rhost, cmds);
b6b5501c 108
024fde5b
RC
109 if (files == NULL) {
110 error("no files to be updated\n");
111 return;
112 }
e8109cf8 113
4085f36f 114 subcmds = cmds;
0fccdfef 115 ddir = files->n_next != NULL; /* destination is a directory */
d0bd9bfc
RC
116 if (nflag)
117 printf("updating host %s\n", rhost);
118 else {
346dad94 119 if (setjmp(env))
0fccdfef
RC
120 goto done;
121 signal(SIGPIPE, lostconn);
9d560577 122 if (!makeconn(rhost))
0fccdfef
RC
123 return;
124 if ((lfp = fopen(tmpfile, "w")) == NULL) {
125 fatal("cannot open %s\n", tmpfile);
126 exit(1);
b6b5501c 127 }
0fccdfef
RC
128 }
129 for (f = files; f != NULL; f = f->n_next) {
86d7a5c5 130 if (filev) {
0fccdfef 131 for (cpp = filev; *cpp; cpp++)
86d7a5c5 132 if (strcmp(f->n_name, *cpp) == 0)
0fccdfef
RC
133 goto found;
134 if (!nflag)
135 (void) fclose(lfp);
136 continue;
b6b5501c 137 }
0fccdfef 138 found:
0fccdfef
RC
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);
a3e6fd64 146 opts = sc->sc_options;
b6b5501c 147 }
0fccdfef
RC
148 if (n == 0)
149 install(f->n_name, NULL, 0, options);
b6b5501c 150 }
0fccdfef
RC
151done:
152 if (!nflag) {
346dad94 153 (void) signal(SIGPIPE, cleanup);
0fccdfef
RC
154 (void) fclose(lfp);
155 lfp = NULL;
156 }
157 for (sc = cmds; sc != NULL; sc = sc->sc_next)
158 if (sc->sc_type == NOTIFY)
9d560577 159 notify(tmpfile, rhost, sc->sc_args, 0);
a3e6fd64 160 if (!nflag) {
b6b5501c 161 (void) unlink(tmpfile);
a3e6fd64
RC
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 }
b6b5501c
RC
170}
171
172/*
173 * Create a connection to the rdist server on the machine rhost.
174 */
175makeconn(rhost)
176 char *rhost;
177{
6e6d779a 178 register char *ruser, *cp;
0fccdfef 179 static char *cur_host = NULL;
bbdda833
RC
180 static int port = -1;
181 char tuser[20];
6e6d779a 182 int n;
b6b5501c 183 extern char user[];
80babee1 184 extern int userid;
b6b5501c 185
0fccdfef
RC
186 if (debug)
187 printf("makeconn(%s)\n", rhost);
188
346dad94
RC
189 if (cur_host != NULL && rem >= 0) {
190 if (strcmp(cur_host, rhost) == 0)
191 return(1);
192 closeconn();
346dad94 193 }
bbdda833
RC
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))
b6b5501c
RC
207 return(0);
208 } else
209 ruser = user;
0fccdfef
RC
210 if (!qflag)
211 printf("updating host %s\n", rhost);
80babee1 212 (void) sprintf(buf, "%s -Server%s", RDIST, qflag ? " -q" : "");
bbdda833
RC
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 }
b6b5501c
RC
220
221 if (debug) {
bbdda833 222 printf("port = %d, luser = %s, ruser = %s\n", ntohs(port), user, ruser);
b6b5501c
RC
223 printf("buf = %s\n", buf);
224 }
225
82572cb6 226 fflush(stdout);
80babee1 227 setreuid(userid, 0);
bbdda833 228 rem = rcmd(&rhost, port, user, ruser, buf, 0);
80babee1 229 setreuid(0, userid);
b6b5501c
RC
230 if (rem < 0)
231 return(0);
6e6d779a
RC
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');
0392d90c 245 if (*cp == '\0' && n == VERSION)
6e6d779a 246 return(1);
a3e6fd64
RC
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");
0392d90c 250 closeconn();
6e6d779a 251 return(0);
b6b5501c
RC
252}
253
0fccdfef
RC
254/*
255 * Signal end of previous connection.
256 */
257closeconn()
258{
9d560577
RC
259 if (debug)
260 printf("closeconn()\n");
261
0fccdfef
RC
262 if (rem >= 0) {
263 (void) write(rem, "\2\n", 2);
264 (void) close(rem);
265 rem = -1;
266 }
267}
268
269lostconn()
270{
346dad94
RC
271 if (iamremote)
272 cleanup();
273 log(lfp, "rdist: lost connection\n");
0fccdfef
RC
274 longjmp(env, 1);
275}
276
e8109cf8
RC
277okname(name)
278 register char *name;
b6b5501c 279{
e8109cf8
RC
280 register char *cp = name;
281 register int c;
b6b5501c 282
e8109cf8
RC
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);
292bad:
293 error("invalid user name %s\n", name);
294 return(0);
82572cb6
RC
295}
296
d6bccb44
RC
297time_t lastmod;
298FILE *tfp;
299extern char target[], *tp;
3024eb6f 300
82572cb6
RC
301/*
302 * Process commands for comparing files to time stamp files.
303 */
86d7a5c5
RC
304dodcolon(filev, files, stamp, cmds)
305 char **filev;
0fccdfef
RC
306 struct namelist *files;
307 char *stamp;
308 struct subcmd *cmds;
82572cb6 309{
0fccdfef
RC
310 register struct subcmd *sc;
311 register struct namelist *f;
82572cb6 312 register char **cpp;
f7770429
RC
313 struct timeval tv[2];
314 struct timezone tz;
82572cb6 315 struct stat stb;
82572cb6
RC
316
317 if (debug)
0fccdfef 318 printf("dodcolon()\n");
82572cb6 319
d6bccb44 320 if (files == NULL) {
024fde5b
RC
321 error("no files to be updated\n");
322 return;
323 }
0fccdfef
RC
324 if (stat(stamp, &stb) < 0) {
325 error("%s: %s\n", stamp, sys_errlist[errno]);
d6bccb44
RC
326 return;
327 }
328 if (debug)
0fccdfef 329 printf("%s: %d\n", stamp, stb.st_mtime);
3db8aa13 330
4085f36f 331 subcmds = cmds;
3db8aa13
RC
332 lastmod = stb.st_mtime;
333 if (nflag || (options & VERIFY))
334 tfp = NULL;
335 else {
336 if ((tfp = fopen(tmpfile, "w")) == NULL) {
0fccdfef 337 error("%s: %s\n", stamp, sys_errlist[errno]);
d6bccb44
RC
338 return;
339 }
3db8aa13
RC
340 (void) gettimeofday(&tv[0], &tz);
341 tv[1] = tv[0];
342 (void) utimes(stamp, tv);
343 }
f7770429 344
0fccdfef 345 for (f = files; f != NULL; f = f->n_next) {
86d7a5c5 346 if (filev) {
82572cb6 347 for (cpp = filev; *cpp; cpp++)
86d7a5c5 348 if (strcmp(f->n_name, *cpp) == 0)
82572cb6
RC
349 goto found;
350 continue;
351 }
352 found:
353 tp = NULL;
0fccdfef 354 cmptime(f->n_name);
82572cb6 355 }
f7770429 356
d6bccb44
RC
357 if (tfp != NULL)
358 (void) fclose(tfp);
0fccdfef
RC
359 for (sc = cmds; sc != NULL; sc = sc->sc_next)
360 if (sc->sc_type == NOTIFY)
361 notify(tmpfile, NULL, sc->sc_args, lastmod);
d6bccb44
RC
362 if (!nflag && !(options & VERIFY))
363 (void) unlink(tmpfile);
82572cb6
RC
364}
365
366/*
367 * Compare the mtime of file to the list of time stamps.
368 */
369cmptime(name)
370 char *name;
371{
82572cb6
RC
372 struct stat stb;
373
374 if (debug)
375 printf("cmptime(%s)\n", name);
376
4085f36f 377 if (except(name))
82572cb6
RC
378 return;
379
d6bccb44
RC
380 if (nflag) {
381 printf("comparing dates: %s\n", name);
382 return;
383 }
384
82572cb6
RC
385 /*
386 * first time cmptime() is called?
387 */
388 if (tp == NULL) {
e8109cf8
RC
389 if (exptilde(target, name) == NULL)
390 return;
82572cb6
RC
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
d6bccb44
RC
413 if (stb.st_mtime > lastmod)
414 log(tfp, "new: %s\n", name);
82572cb6
RC
415}
416
417rcmptime(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';
b6b5501c
RC
453}
454
455/*
456 * Notify the list of people the changes that were made.
f7770429
RC
457 * rhost == NULL if we are mailing a list of changes compared to at time
458 * stamp file.
b6b5501c 459 */
f7770429 460notify(file, rhost, to, lmod)
3024eb6f 461 char *file, *rhost;
0fccdfef 462 register struct namelist *to;
f7770429 463 time_t lmod;
b6b5501c
RC
464{
465 register int fd, len;
466 FILE *pf, *popen();
467 struct stat stb;
468
d6bccb44 469 if ((options & VERIFY) || to == NULL)
b6b5501c
RC
470 return;
471 if (!qflag) {
82572cb6 472 printf("notify ");
3024eb6f
RC
473 if (rhost)
474 printf("@%s ", rhost);
b6b5501c
RC
475 prnames(to);
476 }
477 if (nflag)
478 return;
479
82572cb6
RC
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);
b6b5501c
RC
491 return;
492 }
493 /*
494 * Create a pipe to mailling program.
495 */
496 pf = popen(MAILCMD, "w");
3024eb6f
RC
497 if (pf == NULL) {
498 error("notify: \"%s\" failed\n", MAILCMD);
499 (void) close(fd);
500 return;
501 }
b6b5501c
RC
502 /*
503 * Output the proper header information.
504 */
505 fprintf(pf, "From: rdist (Remote distribution program)\n");
506 fprintf(pf, "To:");
0fccdfef
RC
507 if (!any('@', to->n_name) && rhost != NULL)
508 fprintf(pf, " %s@%s", to->n_name, rhost);
f7770429 509 else
0fccdfef
RC
510 fprintf(pf, " %s", to->n_name);
511 to = to->n_next;
b6b5501c 512 while (to != NULL) {
0fccdfef
RC
513 if (!any('@', to->n_name) && rhost != NULL)
514 fprintf(pf, ", %s@%s", to->n_name, rhost);
82572cb6 515 else
0fccdfef
RC
516 fprintf(pf, ", %s", to->n_name);
517 to = to->n_next;
b6b5501c
RC
518 }
519 putc('\n', pf);
f7770429
RC
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));
b6b5501c
RC
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
b6b5501c 533/*
d6bccb44 534 * Return true if name is in the list.
b6b5501c 535 */
d6bccb44 536inlist(list, file)
0fccdfef 537 struct namelist *list;
b6b5501c
RC
538 char *file;
539{
0fccdfef 540 register struct namelist *nl;
b6b5501c 541
0fccdfef
RC
542 for (nl = list; nl != NULL; nl = nl->n_next)
543 if (!strcmp(file, nl->n_name))
e8109cf8 544 return(1);
b6b5501c
RC
545 return(0);
546}
547
e8109cf8 548/*
4085f36f 549 * Return TRUE if file is in the exception list.
e8109cf8 550 */
4085f36f
RC
551except(file)
552 char *file;
b6b5501c 553{
4085f36f
RC
554 register struct subcmd *sc;
555 register struct namelist *nl;
b6b5501c 556
e8109cf8 557 if (debug)
4085f36f 558 printf("except(%s)\n", file);
e8109cf8 559
4085f36f
RC
560 for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
561 if (sc->sc_type != EXCEPT && sc->sc_type != PATTERN)
e8109cf8 562 continue;
0fccdfef 563 for (nl = sc->sc_args; nl != NULL; nl = nl->n_next) {
4085f36f
RC
564 if (sc->sc_type == EXCEPT) {
565 if (!strcmp(file, nl->n_name))
566 return(1);
567 continue;
0fccdfef 568 }
4085f36f
RC
569 re_comp(nl->n_name);
570 if (re_exec(file) > 0)
571 return(1);
e8109cf8
RC
572 }
573 }
4085f36f 574 return(0);
b6b5501c
RC
575}
576
577char *
578colon(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}