|
|
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.