home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / rdist / docmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  12.5 KB  |  604 lines

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