PageRenderTime 26ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/usr.bin/oldrdist/docmd.c

https://bitbucket.org/kmv/aeriebsd-src
C | 671 lines | 548 code | 56 blank | 67 comment | 199 complexity | 3af9411d9037d248a41a55e5c703193d MD5 | raw file
  1. /*
  2. * Copyright (c) 1983, 1993
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. #ifndef lint
  30. /* from: static char sccsid[] = "@(#)docmd.c 8.1 (Berkeley) 6/9/93"; */
  31. static const char rcsid[] = "$ABSD: docmd.c,v 1.1.1.1 2008/08/26 14:43:04 root Exp $";
  32. #endif /* not lint */
  33. #include "defs.h"
  34. #include <setjmp.h>
  35. #include <netdb.h>
  36. #include <regex.h>
  37. FILE *lfp; /* log file for recording files updated */
  38. struct subcmd *subcmds; /* list of sub-commands for current cmd */
  39. jmp_buf env;
  40. static int makeconn(char *);
  41. static int okname(char *);
  42. static void closeconn(void);
  43. static void cmptime(char *);
  44. static void doarrow(char **, struct namelist *, char *, struct subcmd *);
  45. static void dodcolon(char **, struct namelist *, char *, struct subcmd *);
  46. static void notify(char *, char *, struct namelist *, time_t);
  47. static void rcmptime(struct stat *);
  48. /*
  49. * Do the commands in cmds (initialized by yyparse).
  50. */
  51. void
  52. docmds(dhosts, argc, argv)
  53. char **dhosts;
  54. int argc;
  55. char **argv;
  56. {
  57. struct cmd *c;
  58. struct namelist *f;
  59. char **cpp;
  60. extern struct cmd *cmds;
  61. signal(SIGHUP, cleanup);
  62. signal(SIGINT, cleanup);
  63. signal(SIGQUIT, cleanup);
  64. signal(SIGTERM, cleanup);
  65. for (c = cmds; c != NULL; c = c->c_next) {
  66. if (dhosts != NULL && *dhosts != NULL) {
  67. for (cpp = dhosts; *cpp; cpp++)
  68. if (strcmp(c->c_name, *cpp) == 0)
  69. goto fndhost;
  70. continue;
  71. }
  72. fndhost:
  73. if (argc) {
  74. for (cpp = argv; *cpp; cpp++) {
  75. if (c->c_label != NULL &&
  76. strcmp(c->c_label, *cpp) == 0) {
  77. cpp = NULL;
  78. goto found;
  79. }
  80. for (f = c->c_files; f != NULL; f = f->n_next)
  81. if (strcmp(f->n_name, *cpp) == 0)
  82. goto found;
  83. }
  84. continue;
  85. } else
  86. cpp = NULL;
  87. found:
  88. switch (c->c_type) {
  89. case ARROW:
  90. doarrow(cpp, c->c_files, c->c_name, c->c_cmds);
  91. break;
  92. case DCOLON:
  93. dodcolon(cpp, c->c_files, c->c_name, c->c_cmds);
  94. break;
  95. default:
  96. fatal("illegal command type %d\n", c->c_type);
  97. }
  98. }
  99. closeconn();
  100. }
  101. /*
  102. * Process commands for sending files to other machines.
  103. */
  104. static void
  105. doarrow(filev, files, rhost, cmds)
  106. char **filev;
  107. struct namelist *files;
  108. char *rhost;
  109. struct subcmd *cmds;
  110. {
  111. struct namelist *f;
  112. struct subcmd *sc;
  113. char **cpp;
  114. int n, ddir, opts = options;
  115. if (debug)
  116. printf("doarrow(%lx, %s, %lx)\n", (long)files, rhost, (long)cmds);
  117. if (files == NULL) {
  118. error("no files to be updated\n");
  119. return;
  120. }
  121. subcmds = cmds;
  122. ddir = files->n_next != NULL; /* destination is a directory */
  123. if (nflag)
  124. printf("updating host %s\n", rhost);
  125. else {
  126. int fd;
  127. if (setjmp(env))
  128. goto done;
  129. signal(SIGPIPE, lostconn);
  130. if (!makeconn(rhost))
  131. return;
  132. if ((fd = open(tempfile, O_CREAT|O_EXCL|O_WRONLY, 0600)) < 0 ||
  133. (lfp = fdopen(fd, "w")) == NULL) {
  134. if (fd >= 0)
  135. (void) close(fd);
  136. fatal("cannot open %s\n", tempfile);
  137. exit(1);
  138. }
  139. }
  140. for (f = files; f != NULL; f = f->n_next) {
  141. if (filev) {
  142. for (cpp = filev; *cpp; cpp++)
  143. if (strcmp(f->n_name, *cpp) == 0)
  144. goto found;
  145. if (!nflag && lfp) {
  146. (void) fclose(lfp);
  147. lfp = NULL;
  148. }
  149. continue;
  150. }
  151. found:
  152. n = 0;
  153. for (sc = cmds; sc != NULL; sc = sc->sc_next) {
  154. if (sc->sc_type != INSTALL)
  155. continue;
  156. n++;
  157. install(f->n_name, sc->sc_name,
  158. sc->sc_name == NULL ? 0 : ddir, sc->sc_options);
  159. opts = sc->sc_options;
  160. }
  161. if (n == 0)
  162. install(f->n_name, NULL, 0, options);
  163. }
  164. done:
  165. if (!nflag) {
  166. (void) signal(SIGPIPE, cleanup);
  167. if (lfp)
  168. (void) fclose(lfp);
  169. lfp = NULL;
  170. }
  171. for (sc = cmds; sc != NULL; sc = sc->sc_next)
  172. if (sc->sc_type == NOTIFY)
  173. notify(tempfile, rhost, sc->sc_args, 0);
  174. if (!nflag) {
  175. struct linkbuf *nextihead;
  176. (void) unlink(tempfile);
  177. for (; ihead != NULL; ihead = nextihead) {
  178. nextihead = ihead->nextp;
  179. if ((opts & IGNLNKS) || ihead->count == 0)
  180. continue;
  181. logit(lfp, "%s: Warning: missing links\n",
  182. ihead->pathname);
  183. free(ihead);
  184. }
  185. }
  186. }
  187. /*
  188. * Create a connection to the rdist server on the machine rhost.
  189. */
  190. static int
  191. makeconn(rhost)
  192. char *rhost;
  193. {
  194. char *ruser, *cp;
  195. static char *cur_host = NULL;
  196. #if defined(DIRECT_RCMD)
  197. static int port = -1;
  198. #endif /* DIRECT_RCMD */
  199. char tuser[20];
  200. int n;
  201. extern char user[];
  202. #if defined(DIRECT_RCMD)
  203. extern uid_t userid;
  204. #endif
  205. if (debug)
  206. printf("makeconn(%s)\n", rhost);
  207. if (cur_host != NULL && rem >= 0) {
  208. if (strcmp(cur_host, rhost) == 0)
  209. return(1);
  210. closeconn();
  211. }
  212. cur_host = rhost;
  213. cp = strchr(rhost, '@');
  214. if (cp != NULL) {
  215. char c = *cp;
  216. *cp = '\0';
  217. strncpy(tuser, rhost, sizeof(tuser)-1);
  218. *cp = c;
  219. rhost = cp + 1;
  220. ruser = tuser;
  221. if (*ruser == '\0')
  222. ruser = user;
  223. else if (!okname(ruser))
  224. return(0);
  225. } else
  226. ruser = user;
  227. if (!qflag)
  228. printf("updating host %s\n", rhost);
  229. (void) snprintf(buf, sizeof(buf), "%s -Server%s", _PATH_RDIST,
  230. qflag ? " -q" : "");
  231. #if defined(DIRECT_RCMD)
  232. if (port < 0) {
  233. struct servent *sp;
  234. if ((sp = getservbyname("shell", "tcp")) == NULL)
  235. fatal("shell/tcp: unknown service");
  236. port = sp->s_port;
  237. }
  238. #endif /* !DIRECT_RCMD */
  239. if (debug) {
  240. #if defined(DIRECT_RCMD)
  241. printf("port = %d, luser = %s, ruser = %s\n", ntohs(port), user, ruser);
  242. #else /* !DIRECT_RCMD */
  243. printf("luser = %s, ruser = %s\n", user, ruser);
  244. #endif /* !DIRECT_RCMD */
  245. printf("buf = %s\n", buf);
  246. }
  247. fflush(stdout);
  248. #if defined(DIRECT_RCMD)
  249. seteuid(0);
  250. rem = rcmd(&rhost, port, user, ruser, buf, 0);
  251. seteuid(userid);
  252. #else /* !DIRECT_RCMD */
  253. rem = rcmdsh(&rhost, -1, user, ruser, buf, NULL);
  254. #endif /* !DIRECT_RCMD */
  255. if (rem < 0)
  256. return(0);
  257. cp = buf;
  258. if (read(rem, cp, 1) != 1)
  259. lostconn(0);
  260. if (*cp == 'V') {
  261. do {
  262. if (read(rem, cp, 1) != 1)
  263. lostconn(0);
  264. } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
  265. *--cp = '\0';
  266. cp = buf;
  267. n = 0;
  268. while (*cp >= '0' && *cp <= '9')
  269. n = (n * 10) + (*cp++ - '0');
  270. if (*cp == '\0' && n == VERSION)
  271. return(1);
  272. error("connection failed: version numbers don't match (local %d, remote %d)\n", VERSION, n);
  273. } else {
  274. error("connection failed: version numbers don't match\n");
  275. error("got unexpected input:");
  276. do {
  277. error("%c", *cp);
  278. } while (*cp != '\n' && read(rem, cp, 1) == 1);
  279. }
  280. closeconn();
  281. return(0);
  282. }
  283. /*
  284. * Signal end of previous connection.
  285. */
  286. static void
  287. closeconn()
  288. {
  289. if (debug)
  290. printf("closeconn()\n");
  291. if (rem >= 0) {
  292. void (*osig)();
  293. osig = signal(SIGPIPE, SIG_IGN);
  294. (void) write(rem, "\2\n", 2);
  295. (void) signal(SIGPIPE, osig);
  296. (void) close(rem);
  297. rem = -1;
  298. }
  299. }
  300. void
  301. lostconn(signo)
  302. int signo;
  303. {
  304. if (iamremote)
  305. cleanup(0);
  306. logit(lfp, "rdist: lost connection\n");
  307. if (rem >= 0) {
  308. (void) close(rem);
  309. rem = -1;
  310. }
  311. longjmp(env, 1);
  312. }
  313. static int
  314. okname(name)
  315. char *name;
  316. {
  317. char *cp = name;
  318. int c;
  319. do {
  320. c = *cp;
  321. if (c & 0200)
  322. goto bad;
  323. if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
  324. goto bad;
  325. cp++;
  326. } while (*cp);
  327. return(1);
  328. bad:
  329. error("invalid user name %s\n", name);
  330. return(0);
  331. }
  332. time_t lastmod;
  333. FILE *tfp;
  334. extern char *tp;
  335. /*
  336. * Process commands for comparing files to time stamp files.
  337. */
  338. static void
  339. dodcolon(filev, files, stamp, cmds)
  340. char **filev;
  341. struct namelist *files;
  342. char *stamp;
  343. struct subcmd *cmds;
  344. {
  345. struct subcmd *sc;
  346. struct namelist *f;
  347. char **cpp;
  348. struct timeval tv[2];
  349. struct stat stb;
  350. if (debug)
  351. printf("dodcolon()\n");
  352. if (files == NULL) {
  353. error("no files to be updated\n");
  354. return;
  355. }
  356. if (stat(stamp, &stb) < 0) {
  357. error("%s: %s\n", stamp, strerror(errno));
  358. return;
  359. }
  360. if (debug)
  361. printf("%s: %lld\n", stamp, (long long)stb.st_mtime);
  362. subcmds = cmds;
  363. lastmod = stb.st_mtime;
  364. if (nflag || (options & VERIFY))
  365. tfp = NULL;
  366. else {
  367. int fd;
  368. if ((fd = open(tempfile, O_CREAT|O_EXCL|O_WRONLY, 0600)) < 0 ||
  369. (tfp = fdopen(fd, "w")) == NULL) {
  370. error("%s: %s\n", tempfile, strerror(errno));
  371. if (fd >= 0)
  372. (void) close(fd);
  373. return;
  374. }
  375. (void) gettimeofday(&tv[0], NULL);
  376. tv[1] = tv[0];
  377. (void) utimes(stamp, tv);
  378. }
  379. for (f = files; f != NULL; f = f->n_next) {
  380. if (filev) {
  381. for (cpp = filev; *cpp; cpp++)
  382. if (strcmp(f->n_name, *cpp) == 0)
  383. goto found;
  384. continue;
  385. }
  386. found:
  387. tp = NULL;
  388. cmptime(f->n_name);
  389. }
  390. if (tfp != NULL)
  391. (void) fclose(tfp);
  392. for (sc = cmds; sc != NULL; sc = sc->sc_next)
  393. if (sc->sc_type == NOTIFY)
  394. notify(tempfile, NULL, sc->sc_args, lastmod);
  395. if (!nflag && !(options & VERIFY))
  396. (void) unlink(tempfile);
  397. }
  398. /*
  399. * Compare the mtime of file to the list of time stamps.
  400. */
  401. static void
  402. cmptime(name)
  403. char *name;
  404. {
  405. struct stat stb;
  406. if (debug)
  407. printf("cmptime(%s)\n", name);
  408. if (except(name))
  409. return;
  410. if (nflag) {
  411. printf("comparing dates: %s\n", name);
  412. return;
  413. }
  414. /*
  415. * first time cmptime() is called?
  416. */
  417. if (tp == NULL) {
  418. if (exptilde(target, name, sizeof (target)) == NULL)
  419. return;
  420. tp = name = target;
  421. while (*tp)
  422. tp++;
  423. }
  424. if (access(name, 4) < 0 || stat(name, &stb) < 0) {
  425. error("%s: %s\n", name, strerror(errno));
  426. return;
  427. }
  428. switch (stb.st_mode & S_IFMT) {
  429. case S_IFREG:
  430. break;
  431. case S_IFDIR:
  432. rcmptime(&stb);
  433. return;
  434. default:
  435. error("%s: not a plain file\n", name);
  436. return;
  437. }
  438. if (stb.st_mtime > lastmod)
  439. logit(tfp, "new: %s\n", name);
  440. }
  441. static void
  442. rcmptime(st)
  443. struct stat *st;
  444. {
  445. DIR *d;
  446. struct direct *dp;
  447. char *cp;
  448. char *otp;
  449. int len;
  450. if (debug)
  451. printf("rcmptime(%lx)\n", (long)st);
  452. if ((d = opendir(target)) == NULL) {
  453. error("%s: %s\n", target, strerror(errno));
  454. return;
  455. }
  456. otp = tp;
  457. len = tp - target;
  458. while (dp = readdir(d)) {
  459. if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  460. continue;
  461. if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
  462. error("%s/%s: Name too long\n", target, dp->d_name);
  463. continue;
  464. }
  465. tp = otp;
  466. *tp++ = '/';
  467. cp = dp->d_name;
  468. while (*tp++ = *cp++)
  469. ;
  470. tp--;
  471. cmptime(target);
  472. }
  473. closedir(d);
  474. tp = otp;
  475. *tp = '\0';
  476. }
  477. /*
  478. * Notify the list of people the changes that were made.
  479. * rhost == NULL if we are mailing a list of changes compared to at time
  480. * stamp file.
  481. */
  482. static void
  483. notify(file, rhost, to, lmod)
  484. char *file, *rhost;
  485. struct namelist *to;
  486. time_t lmod;
  487. {
  488. int fd, len;
  489. struct stat stb;
  490. FILE *pf;
  491. if ((options & VERIFY) || to == NULL)
  492. return;
  493. if (!qflag) {
  494. printf("notify ");
  495. if (rhost)
  496. printf("@%s ", rhost);
  497. prnames(to);
  498. }
  499. if (nflag)
  500. return;
  501. if ((fd = open(file, O_RDONLY)) < 0) {
  502. error("%s: %s\n", file, strerror(errno));
  503. return;
  504. }
  505. if (fstat(fd, &stb) < 0) {
  506. error("%s: %s\n", file, strerror(errno));
  507. (void) close(fd);
  508. return;
  509. }
  510. if (stb.st_size == 0) {
  511. (void) close(fd);
  512. return;
  513. }
  514. /*
  515. * Create a pipe to a mail program.
  516. */
  517. (void) snprintf(buf, sizeof(buf), "%s -oi -t", _PATH_SENDMAIL);
  518. pf = popen(buf, "w");
  519. if (pf == NULL) {
  520. error("notify: \"%s\" failed\n", _PATH_SENDMAIL);
  521. (void) close(fd);
  522. return;
  523. }
  524. /*
  525. * Output the proper header information.
  526. */
  527. fprintf(pf, "Auto-Submitted: auto-generated\n");
  528. fprintf(pf, "From: rdist (Remote distribution program)\n");
  529. fprintf(pf, "To:");
  530. if (!any('@', to->n_name) && rhost != NULL)
  531. fprintf(pf, " %s@%s", to->n_name, rhost);
  532. else
  533. fprintf(pf, " %s", to->n_name);
  534. to = to->n_next;
  535. while (to != NULL) {
  536. if (!any('@', to->n_name) && rhost != NULL)
  537. fprintf(pf, ", %s@%s", to->n_name, rhost);
  538. else
  539. fprintf(pf, ", %s", to->n_name);
  540. to = to->n_next;
  541. }
  542. putc('\n', pf);
  543. if (rhost != NULL)
  544. fprintf(pf, "Subject: files updated by rdist from %s to %s\n",
  545. host, rhost);
  546. else
  547. fprintf(pf, "Subject: files updated after %s\n", ctime(&lmod));
  548. putc('\n', pf);
  549. while ((len = read(fd, buf, BUFSIZ)) > 0)
  550. (void) fwrite(buf, 1, len, pf);
  551. (void) close(fd);
  552. (void) pclose(pf);
  553. }
  554. /*
  555. * Return true if name is in the list.
  556. */
  557. int
  558. inlist(list, file)
  559. struct namelist *list;
  560. char *file;
  561. {
  562. struct namelist *nl;
  563. for (nl = list; nl != NULL; nl = nl->n_next)
  564. if (!strcmp(file, nl->n_name))
  565. return(1);
  566. return(0);
  567. }
  568. /*
  569. * Return TRUE if file is in the exception list.
  570. */
  571. int
  572. except(file)
  573. char *file;
  574. {
  575. struct subcmd *sc;
  576. struct namelist *nl;
  577. regex_t s;
  578. int err;
  579. if (debug)
  580. printf("except(%s)\n", file);
  581. for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
  582. if (sc->sc_type != EXCEPT && sc->sc_type != PATTERN)
  583. continue;
  584. for (nl = sc->sc_args; nl != NULL; nl = nl->n_next) {
  585. if (sc->sc_type == EXCEPT) {
  586. if (!strcmp(file, nl->n_name))
  587. return(1);
  588. continue;
  589. }
  590. if ((err = regcomp(&s, nl->n_name, 0)) != 0) {
  591. (void) regerror(err, &s, buf, sizeof(buf));
  592. error("%s: %s\n", nl->n_name, buf);
  593. }
  594. if (regexec(&s, file, 0, NULL, 0) == 0) {
  595. regfree(&s);
  596. return(1);
  597. }
  598. regfree(&s);
  599. }
  600. }
  601. return(0);
  602. }
  603. char *
  604. colon(cp)
  605. char *cp;
  606. {
  607. while (*cp) {
  608. if (*cp == ':')
  609. return(cp);
  610. if (*cp == '/')
  611. return(0);
  612. cp++;
  613. }
  614. return(0);
  615. }