home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-B.05 / NETKIT-B / NetKit-B-0.05 / rdist / docmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-08  |  13.3 KB  |  632 lines

  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. 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. /* from: static char sccsid[] = "@(#)docmd.c    8.1 (Berkeley) 6/9/93"; */
  36. static char *rcsid = "$Id: docmd.c,v 1.1 1994/08/08 10:23:59 florian Exp florian $";
  37. #endif /* not lint */
  38.  
  39. #include "defs.h"
  40. #include <setjmp.h>
  41. #include <netdb.h>
  42.  
  43. FILE    *lfp;            /* log file for recording files updated */
  44. struct    subcmd *subcmds;    /* list of sub-commands for current cmd */
  45. jmp_buf    env;
  46.  
  47. static int     makeconn __P((char *));
  48. static int     okname __P((char *));
  49. static void     closeconn __P((void));
  50. static void     cmptime __P((char *));
  51. static void     doarrow __P((char **,
  52.             struct namelist *, char *, struct subcmd *));
  53. static void     dodcolon __P((char **,
  54.             struct namelist *, char *, struct subcmd *));
  55. static void     notify __P((char *, char *, struct namelist *, time_t));
  56. static void     rcmptime __P((struct stat *));
  57.  
  58. /*
  59.  * Do the commands in cmds (initialized by yyparse).
  60.  */
  61. void
  62. docmds(dhosts, argc, argv)
  63.     char **dhosts;
  64.     int argc;
  65.     char **argv;
  66. {
  67.     register struct cmd *c;
  68.     register struct namelist *f;
  69.     register char **cpp;
  70.     extern struct cmd *cmds;
  71.  
  72.     signal(SIGHUP, cleanup);
  73.     signal(SIGINT, cleanup);
  74.     signal(SIGQUIT, cleanup);
  75.     signal(SIGTERM, cleanup);
  76.  
  77.     for (c = cmds; c != NULL; c = c->c_next) {
  78.         if (dhosts != NULL && *dhosts != NULL) {
  79.             for (cpp = dhosts; *cpp; cpp++)
  80.                 if (strcmp(c->c_name, *cpp) == 0)
  81.                     goto fndhost;
  82.             continue;
  83.         }
  84.     fndhost:
  85.         if (argc) {
  86.             for (cpp = argv; *cpp; cpp++) {
  87.                 if (c->c_label != NULL &&
  88.                     strcmp(c->c_label, *cpp) == 0) {
  89.                     cpp = NULL;
  90.                     goto found;
  91.                 }
  92.                 for (f = c->c_files; f != NULL; f = f->n_next)
  93.                     if (strcmp(f->n_name, *cpp) == 0)
  94.                         goto found;
  95.             }
  96.             continue;
  97.         } else
  98.             cpp = NULL;
  99.     found:
  100.         switch (c->c_type) {
  101.         case ARROW:
  102.             doarrow(cpp, c->c_files, c->c_name, c->c_cmds);
  103.             break;
  104.         case DCOLON:
  105.             dodcolon(cpp, c->c_files, c->c_name, c->c_cmds);
  106.             break;
  107.         default:
  108.             fatal("illegal command type %d\n", c->c_type);
  109.         }
  110.     }
  111.     closeconn();
  112. }
  113.  
  114. /*
  115.  * Process commands for sending files to other machines.
  116.  */
  117. static void
  118. doarrow(filev, files, rhost, cmds)
  119.     char **filev;
  120.     struct namelist *files;
  121.     char *rhost;
  122.     struct subcmd *cmds;
  123. {
  124.     register struct namelist *f;
  125.     register struct subcmd *sc;
  126.     register char **cpp;
  127.     int n, ddir, opts = options;
  128.  
  129.     if (debug)
  130.         printf("doarrow(%x, %s, %x)\n", files, rhost, cmds);
  131.  
  132.     if (files == NULL) {
  133.         error("no files to be updated\n");
  134.         return;
  135.     }
  136.  
  137.     subcmds = cmds;
  138.     ddir = files->n_next != NULL;    /* destination is a directory */
  139.     if (nflag)
  140.         printf("updating host %s\n", rhost);
  141.     else {
  142.         if (setjmp(env))
  143.             goto done;
  144.         signal(SIGPIPE, lostconn);
  145.         if (!makeconn(rhost))
  146.             return;
  147.         if ((lfp = fopen(tempfile, "w")) == NULL) {
  148.             fatal("cannot open %s\n", tempfile);
  149.             exit(1);
  150.         }
  151.     }
  152.     for (f = files; f != NULL; f = f->n_next) {
  153.         if (filev) {
  154.             for (cpp = filev; *cpp; cpp++)
  155.                 if (strcmp(f->n_name, *cpp) == 0)
  156.                     goto found;
  157.             if (!nflag)
  158.                 (void) fclose(lfp);
  159.             continue;
  160.         }
  161.     found:
  162.         n = 0;
  163.         for (sc = cmds; sc != NULL; sc = sc->sc_next) {
  164.             if (sc->sc_type != INSTALL)
  165.                 continue;
  166.             n++;
  167.             install(f->n_name, sc->sc_name,
  168.                 sc->sc_name == NULL ? 0 : ddir, sc->sc_options);
  169.             opts = sc->sc_options;
  170.         }
  171.         if (n == 0)
  172.             install(f->n_name, NULL, 0, options);
  173.     }
  174. done:
  175.     if (!nflag) {
  176.         (void) signal(SIGPIPE, cleanup);
  177.         (void) fclose(lfp);
  178.         lfp = NULL;
  179.     }
  180.     for (sc = cmds; sc != NULL; sc = sc->sc_next)
  181.         if (sc->sc_type == NOTIFY)
  182.             notify(tempfile, rhost, sc->sc_args, 0);
  183.     if (!nflag) {
  184.         struct linkbuf *tmp;
  185.         (void) unlink(tempfile);
  186.         for (; ihead != NULL; ihead = tmp) {
  187.             if (!(opts & IGNLNKS) && ihead->count != 0)
  188.                 log(lfp, "%s: Warning: missing links\n",
  189.                     ihead->pathname);
  190.             tmp = ihead->nextp;
  191.             free(ihead);
  192.         }
  193.     }
  194. }
  195.  
  196. /*
  197.  * Create a connection to the rdist server on the machine rhost.
  198.  */
  199. static int
  200. makeconn(rhost)
  201.     char *rhost;
  202. {
  203.     register char *ruser, *cp;
  204.     static char *cur_host = NULL;
  205.     static int port = -1;
  206.     char tuser[20];
  207.     int n;
  208.     extern char user[];
  209.     extern int userid;
  210.  
  211.     if (debug)
  212.         printf("makeconn(%s)\n", rhost);
  213.  
  214.     if (cur_host != NULL && rem >= 0) {
  215.         if (strcmp(cur_host, rhost) == 0)
  216.             return(1);
  217.         closeconn();
  218.     }
  219.     cur_host = rhost;
  220.     cp = index(rhost, '@');
  221.     if (cp != NULL) {
  222.         char c = *cp;
  223.  
  224.         *cp = '\0';
  225.         strncpy(tuser, rhost, sizeof(tuser)-1);
  226.         *cp = c;
  227.         rhost = cp + 1;
  228.         ruser = tuser;
  229.         if (*ruser == '\0')
  230.             ruser = user;
  231.         else if (!okname(ruser))
  232.             return(0);
  233.     } else
  234.         ruser = user;
  235.     if (!qflag)
  236.         printf("updating host %s\n", rhost);
  237.     (void) sprintf(buf, "%s -Server%s", _PATH_RDIST, qflag ? " -q" : "");
  238.     if (port < 0) {
  239.         struct servent *sp;
  240.  
  241.         if ((sp = getservbyname("shell", "tcp")) == NULL)
  242.             fatal("shell/tcp: unknown service");
  243.         port = sp->s_port;
  244.     }
  245.  
  246.     if (debug) {
  247.         printf("port = %d, luser = %s, ruser = %s\n", ntohs(port), user, ruser);
  248.         printf("buf = %s\n", buf);
  249.     }
  250.  
  251.     fflush(stdout);
  252.     seteuid(0);
  253.     rem = rcmd(&rhost, port, user, ruser, buf, 0);
  254.     seteuid(userid);
  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. /*
  285.  * Signal end of previous connection.
  286.  */
  287. static void
  288. closeconn()
  289. {
  290.     if (debug)
  291.         printf("closeconn()\n");
  292.  
  293.     if (rem >= 0) {
  294.         (void) write(rem, "\2\n", 2);
  295.         (void) close(rem);
  296.         rem = -1;
  297.     }
  298. }
  299.  
  300. void
  301. lostconn(signo)
  302.     int signo;
  303. {
  304.     if (iamremote)
  305.         cleanup(0);
  306.     log(lfp, "rdist: lost connection\n");
  307.     longjmp(env, 1);
  308. }
  309.  
  310. static int
  311. okname(name)
  312.     register char *name;
  313. {
  314.     register char *cp = name;
  315.     register int c;
  316.  
  317.     do {
  318.         c = *cp;
  319.         if (c & 0200)
  320.             goto bad;
  321.         if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
  322.             goto bad;
  323.         cp++;
  324.     } while (*cp);
  325.     return(1);
  326. bad:
  327.     error("invalid user name %s\n", name);
  328.     return(0);
  329. }
  330.  
  331. time_t    lastmod;
  332. FILE    *tfp;
  333. extern    char target[], *tp;
  334.  
  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.     register struct subcmd *sc;
  346.     register struct namelist *f;
  347.     register char **cpp;
  348.     struct timeval tv[2];
  349.     struct timezone tz;
  350.     struct stat stb;
  351.  
  352.     if (debug)
  353.         printf("dodcolon()\n");
  354.  
  355.     if (files == NULL) {
  356.         error("no files to be updated\n");
  357.         return;
  358.     }
  359.     if (stat(stamp, &stb) < 0) {
  360.         error("%s: %s\n", stamp, strerror(errno));
  361.         return;
  362.     }
  363.     if (debug)
  364.         printf("%s: %ld\n", stamp, stb.st_mtime);
  365.  
  366.     subcmds = cmds;
  367.     lastmod = stb.st_mtime;
  368.     if (nflag || (options & VERIFY))
  369.         tfp = NULL;
  370.     else {
  371.         if ((tfp = fopen(tempfile, "w")) == NULL) {
  372.             error("%s: %s\n", stamp, strerror(errno));
  373.             return;
  374.         }
  375.         (void) gettimeofday(&tv[0], &tz);
  376.         tv[1] = tv[0];
  377.         (void) utimes(stamp, tv);
  378.     }
  379.  
  380.     for (f = files; f != NULL; f = f->n_next) {
  381.         if (filev) {
  382.             for (cpp = filev; *cpp; cpp++)
  383.                 if (strcmp(f->n_name, *cpp) == 0)
  384.                     goto found;
  385.             continue;
  386.         }
  387.     found:
  388.         tp = NULL;
  389.         cmptime(f->n_name);
  390.     }
  391.  
  392.     if (tfp != NULL)
  393.         (void) fclose(tfp);
  394.     for (sc = cmds; sc != NULL; sc = sc->sc_next)
  395.         if (sc->sc_type == NOTIFY)
  396.             notify(tempfile, NULL, sc->sc_args, lastmod);
  397.     if (!nflag && !(options & VERIFY))
  398.         (void) unlink(tempfile);
  399. }
  400.  
  401. /*
  402.  * Compare the mtime of file to the list of time stamps.
  403.  */
  404. static void
  405. cmptime(name)
  406.     char *name;
  407. {
  408.     struct stat stb;
  409.  
  410.     if (debug)
  411.         printf("cmptime(%s)\n", name);
  412.  
  413.     if (except(name))
  414.         return;
  415.  
  416.     if (nflag) {
  417.         printf("comparing dates: %s\n", name);
  418.         return;
  419.     }
  420.  
  421.     /*
  422.      * first time cmptime() is called?
  423.      */
  424.     if (tp == NULL) {
  425.         if (exptilde(target, name) == NULL)
  426.             return;
  427.         tp = name = target;
  428.         while (*tp)
  429.             tp++;
  430.     }
  431.     if (access(name, 4) < 0 || stat(name, &stb) < 0) {
  432.         error("%s: %s\n", name, strerror(errno));
  433.         return;
  434.     }
  435.  
  436.     switch (stb.st_mode & S_IFMT) {
  437.     case S_IFREG:
  438.         break;
  439.  
  440.     case S_IFDIR:
  441.         rcmptime(&stb);
  442.         return;
  443.  
  444.     default:
  445.         error("%s: not a plain file\n", name);
  446.         return;
  447.     }
  448.  
  449.     if (stb.st_mtime > lastmod)
  450.         log(tfp, "new: %s\n", name);
  451. }
  452.  
  453. static void
  454. rcmptime(st)
  455.     struct stat *st;
  456. {
  457.     register DIR *d;
  458.     register struct direct *dp;
  459.     register char *cp;
  460.     char *otp;
  461.     int len;
  462.  
  463.     if (debug)
  464.         printf("rcmptime(%x)\n", st);
  465.  
  466.     if ((d = opendir(target)) == NULL) {
  467.         error("%s: %s\n", target, strerror(errno));
  468.         return;
  469.     }
  470.     otp = tp;
  471.     len = tp - target;
  472.     while (dp = readdir(d)) {
  473.         if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  474.             continue;
  475.         if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
  476.             error("%s/%s: Name too long\n", target, dp->d_name);
  477.             continue;
  478.         }
  479.         tp = otp;
  480.         *tp++ = '/';
  481.         cp = dp->d_name;
  482.         while (*tp++ = *cp++)
  483.             ;
  484.         tp--;
  485.         cmptime(target);
  486.     }
  487.     closedir(d);
  488.     tp = otp;
  489.     *tp = '\0';
  490. }
  491.  
  492. /*
  493.  * Notify the list of people the changes that were made.
  494.  * rhost == NULL if we are mailing a list of changes compared to at time
  495.  * stamp file.
  496.  */
  497. static void
  498. notify(file, rhost, to, lmod)
  499.     char *file, *rhost;
  500.     register struct namelist *to;
  501.     time_t lmod;
  502. {
  503.     register int fd, len;
  504.     struct stat stb;
  505.     FILE *pf;
  506.  
  507.     if ((options & VERIFY) || to == NULL)
  508.         return;
  509.     if (!qflag) {
  510.         printf("notify ");
  511.         if (rhost)
  512.             printf("@%s ", rhost);
  513.         prnames(to);
  514.     }
  515.     if (nflag)
  516.         return;
  517.  
  518.     if ((fd = open(file, 0)) < 0) {
  519.         error("%s: %s\n", file, strerror(errno));
  520.         return;
  521.     }
  522.     if (fstat(fd, &stb) < 0) {
  523.         error("%s: %s\n", file, strerror(errno));
  524.         (void) close(fd);
  525.         return;
  526.     }
  527.     if (stb.st_size == 0) {
  528.         (void) close(fd);
  529.         return;
  530.     }
  531.     /*
  532.      * Create a pipe to mailling program.
  533.      */
  534.     (void)sprintf(buf, "%s -oi -t", _PATH_SENDMAIL);
  535.     pf = popen(buf, "w");
  536.     if (pf == NULL) {
  537.         error("notify: \"%s\" failed\n", _PATH_SENDMAIL);
  538.         (void) close(fd);
  539.         return;
  540.     }
  541.     /*
  542.      * Output the proper header information.
  543.      */
  544.     fprintf(pf, "From: rdist (Remote distribution program)\n");
  545.     fprintf(pf, "To:");
  546.     if (!any('@', to->n_name) && rhost != NULL)
  547.         fprintf(pf, " %s@%s", to->n_name, rhost);
  548.     else
  549.         fprintf(pf, " %s", to->n_name);
  550.     to = to->n_next;
  551.     while (to != NULL) {
  552.         if (!any('@', to->n_name) && rhost != NULL)
  553.             fprintf(pf, ", %s@%s", to->n_name, rhost);
  554.         else
  555.             fprintf(pf, ", %s", to->n_name);
  556.         to = to->n_next;
  557.     }
  558.     putc('\n', pf);
  559.     if (rhost != NULL)
  560.         fprintf(pf, "Subject: files updated by rdist from %s to %s\n",
  561.             host, rhost);
  562.     else
  563.         fprintf(pf, "Subject: files updated after %s\n", ctime(&lmod));
  564.     putc('\n', pf);
  565.  
  566.     while ((len = read(fd, buf, BUFSIZ)) > 0)
  567.         (void) fwrite(buf, 1, len, pf);
  568.     (void) close(fd);
  569.     (void) pclose(pf);
  570. }
  571.  
  572. /*
  573.  * Return true if name is in the list.
  574.  */
  575. int
  576. inlist(list, file)
  577.     struct namelist *list;
  578.     char *file;
  579. {
  580.     register struct namelist *nl;
  581.  
  582.     for (nl = list; nl != NULL; nl = nl->n_next)
  583.         if (!strcmp(file, nl->n_name))
  584.             return(1);
  585.     return(0);
  586. }
  587.  
  588. /*
  589.  * Return TRUE if file is in the exception list.
  590.  */
  591. int
  592. except(file)
  593.     char *file;
  594. {
  595.     register struct    subcmd *sc;
  596.     register struct    namelist *nl;
  597.  
  598.     if (debug)
  599.         printf("except(%s)\n", file);
  600.  
  601.     for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
  602.         if (sc->sc_type != EXCEPT && sc->sc_type != PATTERN)
  603.             continue;
  604.         for (nl = sc->sc_args; nl != NULL; nl = nl->n_next) {
  605.             if (sc->sc_type == EXCEPT) {
  606.                 if (!strcmp(file, nl->n_name))
  607.                     return(1);
  608.                 continue;
  609.             }
  610.             re_comp(nl->n_name);
  611.             if (re_exec(file) > 0)
  612.                 return(1);
  613.         }
  614.     }
  615.     return(0);
  616. }
  617.  
  618. char *
  619. colon(cp)
  620.     register char *cp;
  621. {
  622.  
  623.     while (*cp) {
  624.         if (*cp == ':')
  625.             return(cp);
  626.         if (*cp == '/')
  627.             return(0);
  628.         cp++;
  629.     }
  630.     return(0);
  631. }
  632.