home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / named / ns_maint.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-24  |  13.2 KB  |  540 lines

  1. /*
  2.  * Copyright (c) 1986, 1988 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[] = "@(#)ns_maint.c    4.39 (Berkeley) 3/2/91";
  36. #endif /* not lint */
  37.  
  38. #include <sys/param.h>
  39. #include <sys/socket.h>
  40. #include <sys/time.h>
  41. #if defined(SYSV)
  42. #include <unistd.h>
  43. #endif SYSV
  44. #include <netinet/in.h>
  45. #include <stdio.h>
  46. #include <syslog.h>
  47. #include <signal.h>
  48. #include <errno.h>
  49. #include <arpa/nameser.h>
  50. #include <sys/wait.h>
  51. #include "ns.h"
  52. #include "db.h"
  53. #include "pathnames.h"
  54.  
  55. extern int errno;
  56. extern int maint_interval;
  57. extern int needzoneload;
  58. extern u_short ns_port;
  59. extern char *ctime();
  60.  
  61. int xfers_running;           /* number of xfers running */
  62. int xfers_deferred;           /* number of needed xfers not run yet */
  63. static int alarm_pending;
  64.  
  65.  
  66. /*
  67.  * Invoked at regular intervals by signal interrupt; refresh all secondary
  68.  * zones from primary name server and remove old cache entries.  Also,
  69.  * ifdef'd ALLOW_UPDATES, dump database if it has changed since last
  70.  * dump/bootup.
  71.  */
  72. ns_maint()
  73. {
  74.     register struct zoneinfo *zp;
  75.     struct itimerval ival;
  76.     time_t next_refresh = 0;
  77.     int zonenum;
  78.  
  79.     gettime(&tt);
  80.  
  81. #ifdef DEBUG
  82.     if (debug)
  83.         fprintf(ddt,"\nns_maint(); now %s", ctime(&tt.tv_sec));
  84. #endif
  85.  
  86.     xfers_deferred = 0;
  87.     alarm_pending = 0;
  88.     for (zp = zones, zonenum = 0; zp < &zones[nzones]; zp++, zonenum++) {
  89. #ifdef DEBUG
  90.         if (debug >= 2)
  91.             printzoneinfo(zonenum);
  92. #endif
  93.         if (tt.tv_sec >= zp->z_time && zp->z_refresh > 0) {
  94.             /*
  95.              * Set default time for next action first,
  96.              * so that it can be changed later if necessary.
  97.              */
  98.             zp->z_time = tt.tv_sec + zp->z_refresh;
  99.  
  100.             switch (zp->z_type) {
  101.  
  102.             case Z_CACHE:
  103.                 doachkpt();
  104.                 break;
  105.  
  106.             case Z_SECONDARY:
  107.                 if ((zp->z_state & Z_NEED_RELOAD) == 0) {
  108.                     if (zp->z_state & Z_XFER_RUNNING)
  109.                     abortxfer(zp);
  110.                     else if (xfers_running < MAX_XFERS_RUNNING)
  111.                     startxfer(zp);
  112.                     else {
  113.                     zp->z_state |= Z_NEED_XFER;
  114.                     ++xfers_deferred;
  115. #ifdef DEBUG
  116.                     if (debug > 1)
  117.                         fprintf(ddt,
  118.                         "xfer deferred for %s\n",
  119.                         zp->z_origin);
  120. #endif
  121.                     }
  122.                 }
  123.                 break;
  124. #ifdef ALLOW_UPDATES
  125.             case Z_PRIMARY:
  126.                 /*
  127.                  * Checkpoint the zone if it has changed
  128.                  * since we last checkpointed
  129.                  */
  130.                 if (zp->hasChanged)
  131.                     zonedump(zp);
  132.                 break;
  133. #endif ALLOW_UPDATES
  134.             }
  135.             gettime(&tt);
  136.         }
  137.     }
  138.     sched_maint();
  139. #ifdef DEBUG
  140.     if (debug)
  141.         fprintf(ddt,"exit ns_maint()\n");
  142. #endif
  143. }
  144.  
  145. /*
  146.  * Find when the next refresh needs to be and set
  147.  * interrupt time accordingly.
  148.  */
  149. sched_maint()
  150. {
  151.     register struct zoneinfo *zp;
  152.     struct itimerval ival;
  153.     time_t next_refresh = 0;
  154.     static time_t next_alarm;
  155.  
  156.     for (zp = zones; zp < &zones[nzones]; zp++)
  157.         if (zp->z_time != 0 &&
  158.             (next_refresh == 0 || next_refresh > zp->z_time))
  159.             next_refresh = zp->z_time;
  160.         /*
  161.      *  Schedule the next call to ns_maint.
  162.      *  Don't visit any sooner than maint_interval.
  163.      */
  164.     bzero((char *)&ival, sizeof (ival));
  165.     if (next_refresh != 0) {
  166.         if (next_refresh == next_alarm && alarm_pending) {
  167. #ifdef DEBUG
  168.             if (debug)
  169.                 fprintf(ddt,"sched_maint: no schedule change\n");
  170. #endif
  171.             return;
  172.         }
  173.         ival.it_value.tv_sec = next_refresh - tt.tv_sec;
  174.         if (ival.it_value.tv_sec < maint_interval)
  175.             ival.it_value.tv_sec = maint_interval;
  176.         next_alarm = next_refresh;
  177.         alarm_pending = 1;
  178.     }
  179.     (void) setitimer(ITIMER_REAL, &ival, (struct itimerval *)NULL);
  180. #ifdef DEBUG
  181.     if (debug)
  182.         fprintf(ddt,"sched_maint: Next interrupt in %d sec\n",
  183.             ival.it_value.tv_sec);
  184. #endif
  185. }
  186.  
  187. /*
  188.  * Start an asynchronous zone transfer for a zone.
  189.  * Depends on current time being in tt.
  190.  * The caller must call sched_maint after startxfer.
  191.  */
  192. startxfer(zp)
  193.     struct zoneinfo *zp;
  194. {
  195.     static char *argv[NSMAX + 20], argv_ns[NSMAX][MAXDNAME];
  196.     int cnt, argc = 0, argc_ns = 0, pid, omask;
  197.     char debug_str[10];
  198.     char serial_str[10];
  199.     char port_str[10];
  200.  
  201. #ifdef DEBUG
  202.     if (debug)
  203.         fprintf(ddt,"startxfer() %s\n", zp->z_origin);
  204. #endif
  205.  
  206.     argv[argc++] = "named-xfer";
  207.     argv[argc++] = "-z";
  208.     argv[argc++] = zp->z_origin;
  209.     argv[argc++] = "-f";
  210.     argv[argc++] = zp->z_source;
  211.     argv[argc++] = "-s";
  212.     sprintf(serial_str, "%d", zp->z_serial);
  213.     argv[argc++] = serial_str;
  214.     if (zp->z_state & Z_SYSLOGGED)
  215.         argv[argc++] = "-q";
  216.     argv[argc++] = "-P";
  217.     sprintf(port_str, "%d", ns_port);
  218.     argv[argc++] = port_str;
  219. #ifdef DEBUG
  220.     if (debug) {
  221.         argv[argc++] = "-d";
  222.         sprintf(debug_str, "%d", debug);
  223.         argv[argc++] = debug_str;
  224.         argv[argc++] = "-l";
  225.         argv[argc++] = "/usr/tmp/xfer.ddt";
  226.         if (debug > 5) {
  227.             argv[argc++] = "-t";
  228.             argv[argc++] = "/usr/tmp/xfer.trace";
  229.         }
  230.     }
  231. #endif
  232.     
  233.     /*
  234.      * Copy the server ip addresses into argv, after converting
  235.      * to ascii and saving the static inet_ntoa result
  236.      */
  237.     for (cnt = 0; cnt < zp->z_addrcnt; cnt++)
  238.         argv[argc++] = strcpy(argv_ns[argc_ns++],
  239.             inet_ntoa(zp->z_addr[cnt]));
  240.  
  241.     argv[argc] = 0;
  242.  
  243. #ifdef DEBUG
  244. #ifdef ECHOARGS
  245.     if (debug) {
  246.         int i;
  247.         for (i = 0; i < argc; i++) 
  248.             fprintf(ddt, "Arg %d=%s\n", i, argv[i]);
  249.         }
  250. #endif /* ECHOARGS */
  251. #endif /* DEBUG */
  252.  
  253. #ifdef SYSV
  254. #define vfork fork
  255. #else
  256.     gettime(&tt);
  257.     omask = sigblock(sigmask(SIGCHLD));
  258. #endif
  259.     if ((pid = vfork()) == -1) {
  260. #ifdef DEBUG
  261.         if (debug)
  262.             fprintf(ddt, "xfer [v]fork: %d\n", errno);
  263. #endif
  264.         syslog(LOG_ERR, "xfer [v]fork: %m");
  265. #ifndef SYSV
  266.         (void) sigsetmask(omask);
  267. #endif
  268.         zp->z_time = tt.tv_sec + 10;
  269.         return;
  270.     }
  271.  
  272.     if (pid) {
  273. #ifdef DEBUG
  274.         if (debug)
  275.             fprintf(ddt, "started xfer child %d\n", pid);
  276. #endif
  277.         zp->z_state &= ~Z_NEED_XFER;
  278.         zp->z_state |= Z_XFER_RUNNING;
  279.         zp->z_xferpid = pid;
  280.         xfers_running++;
  281.         zp->z_time = tt.tv_sec + MAX_XFER_TIME;
  282. #ifndef SYSV
  283.         (void) sigsetmask(omask);
  284. #endif
  285.     } else {
  286.         execve(_PATH_XFER, argv, NULL);
  287.         syslog(LOG_ERR, "can't exec %s: %m", _PATH_XFER);
  288.         _exit(XFER_FAIL);    /* avoid duplicate buffer flushes */
  289.     }
  290. }
  291.  
  292. #ifdef DEBUG
  293. printzoneinfo(zonenum)
  294. int zonenum;
  295. {
  296.     struct timeval  tt;
  297.     struct zoneinfo *zp = &zones[zonenum];
  298.     char *ZoneType;
  299.  
  300.     if (!debug)
  301.         return; /* Else fprintf to ddt will bomb */
  302.     fprintf(ddt, "printzoneinfo(%d):\n", zonenum);
  303.  
  304.     gettime(&tt);
  305.     switch (zp->z_type) {
  306.         case Z_PRIMARY: ZoneType = "Primary"; break;
  307.         case Z_SECONDARY: ZoneType = "Secondary"; break;
  308.         case Z_CACHE: ZoneType = "Cache"; break;
  309.         default: ZoneType = "Unknown";
  310.     }
  311.     if (zp->z_origin[0] == '\0')
  312.         fprintf(ddt,"origin ='.'");
  313.     else
  314.         fprintf(ddt,"origin ='%s'", zp->z_origin);
  315.     fprintf(ddt,", type = %s", ZoneType);
  316.     fprintf(ddt,", source = %s\n", zp->z_source);
  317.     fprintf(ddt,"z_refresh = %ld", zp->z_refresh);
  318.     fprintf(ddt,", retry = %ld", zp->z_retry);
  319.     fprintf(ddt,", expire = %ld", zp->z_expire);
  320.     fprintf(ddt,", minimum = %ld", zp->z_minimum);
  321.     fprintf(ddt,", serial = %ld\n", zp->z_serial);
  322.     fprintf(ddt,"z_time = %d", zp->z_time);
  323.     if (zp->z_time) {
  324.         fprintf(ddt,", now time : %d sec", tt.tv_sec);
  325.         fprintf(ddt,", time left: %d sec", zp->z_time - tt.tv_sec);
  326.     }
  327.     fprintf(ddt,"; state %x\n", zp->z_state);
  328. }
  329. #endif DEBUG
  330.  
  331. /*
  332.  * remove_zone (htp, zone) --
  333.  *     Delete all RR's in the zone "zone" under specified hash table.
  334.  */
  335. remove_zone(htp, zone)
  336.     register struct hashbuf *htp;
  337.     register int zone;
  338. {
  339.     register struct databuf *dp, *pdp;
  340.     register struct namebuf *np;
  341.     struct namebuf **npp, **nppend;
  342.  
  343.     nppend = htp->h_tab + htp->h_size;
  344.     for (npp = htp->h_tab; npp < nppend; npp++)
  345.         for (np = *npp; np != NULL; np = np->n_next) {
  346.         for (pdp = NULL, dp = np->n_data; dp != NULL; ) {
  347.             if (dp->d_zone == zone)
  348.                 dp = rm_datum(dp, np, pdp);
  349.             else {
  350.                 pdp = dp;
  351.                 dp = dp->d_next;
  352.             }
  353.         }
  354.         /* Call recursively to remove subdomains. */
  355.         if (np->n_hash)
  356.             remove_zone(np->n_hash, zone);
  357.         }
  358. }
  359.    
  360. /*
  361.  * Abort an xfer that has taken too long.
  362.  */
  363. abortxfer(zp)
  364.     register struct zoneinfo *zp;
  365. {
  366.  
  367.     kill(zp->z_xferpid, SIGKILL); /* don't trust it at all */
  368. #ifdef DEBUG
  369.     if (debug)
  370.       fprintf(ddt, "Killed child %d (zone %s) due to timeout\n",
  371.          zp->z_xferpid, zp->z_origin);
  372. #endif /* DEBUG */
  373.     zp->z_time = tt.tv_sec + zp->z_retry;
  374. }
  375.  
  376. #ifdef SYSV
  377. union wait {
  378.     unsigned short    w_termsig:7;    /* termination signal */
  379.     unsigned short    w_coredump:1;    /* core dump indicator */
  380.     unsigned short    w_retcode:8;    /* exit code if w_termsig==0 */
  381. };
  382. #endif
  383.  
  384. /*
  385.  * SIGCHLD signal handler: process exit of xfer's.
  386.  * (Note: also called when outgoing transfer completes.)
  387.  */
  388. SIG_FN
  389. endxfer()
  390. {
  391.         register struct zoneinfo *zp;   
  392.     int pid, xfers = 0;
  393.     union wait status;
  394.  
  395.     gettime(&tt);
  396. #if defined(SYSV)
  397.     { int stat;
  398.     pid = wait(&stat);
  399.     status.w_termsig = stat & 0x7f;
  400.     status.w_retcode = stat >> 8;
  401.     }
  402. #else /* SYSV */
  403.     while ((pid =
  404.         wait3((int *)&status, WNOHANG, (struct rusage *)NULL)) > 0) {
  405. #endif /* SYSV */
  406.         for (zp = zones; zp < &zones[nzones]; zp++)
  407.             if (zp->z_xferpid == pid) {
  408.             xfers++;
  409.             xfers_running--;
  410.             zp->z_xferpid = 0;
  411.             zp->z_state &= ~Z_XFER_RUNNING;
  412. #ifdef DEBUG
  413.             if (debug) 
  414.                 fprintf(ddt,
  415.         "\nendxfer: child %d zone %s returned status=%d termsig=%d\n", 
  416.                 pid, zp->z_origin, status.w_retcode,
  417.                 status.w_termsig);
  418. #endif
  419.             if (status.w_termsig != 0) {
  420.                 if (status.w_termsig != SIGKILL) {
  421.                     syslog(LOG_ERR,
  422.                        "named-xfer exited with signal %d\n",
  423.                        status.w_termsig);
  424. #ifdef DEBUG
  425.                     if (debug)
  426.                         fprintf(ddt,
  427.                      "\tchild termination with signal %d\n",
  428.                         status.w_termsig);
  429. #endif
  430.                 }
  431.                 zp->z_time = tt.tv_sec + zp->z_retry;
  432.             } else switch (status.w_retcode) {
  433.                 case XFER_UPTODATE:
  434.                     zp->z_state &= ~Z_SYSLOGGED;
  435.                     zp->z_lastupdate = tt.tv_sec;
  436.                     zp->z_time = tt.tv_sec + zp->z_refresh;
  437.                     /*
  438.                      * Restore z_auth in case expired,
  439.                      * but only if there were no errors
  440.                      * in the zone file.
  441.                      */
  442.                     if ((zp->z_state & Z_DB_BAD) == 0)
  443.                         zp->z_auth = 1;
  444.                     if (zp->z_source) {
  445. #if defined(SYSV)
  446.                         struct utimbuf t;
  447.  
  448.                         t.actime = tt.tv_sec;
  449.                         t.modtime = tt.tv_sec;
  450.                         (void) utime(zp->z_source, &t);
  451. #else
  452.                         struct timeval t[2];
  453.  
  454.                         t[0] = tt;
  455.                         t[1] = tt;
  456.                         (void) utimes(zp->z_source, t);
  457. #endif /* SYSV */
  458.                     }
  459.                     break;
  460.  
  461.                 case XFER_SUCCESS:
  462.                     zp->z_state |= Z_NEED_RELOAD;
  463.                     zp->z_state &= ~Z_SYSLOGGED;
  464.                     needzoneload++;
  465.                     break;
  466.  
  467.                 case XFER_TIMEOUT:
  468. #ifdef DEBUG
  469.                     if (debug) fprintf(ddt,
  470.             "zoneref: Masters for secondary zone %s unreachable\n",
  471.                         zp->z_origin);
  472. #endif
  473.                     if ((zp->z_state & Z_SYSLOGGED) == 0) {
  474.                         zp->z_state |= Z_SYSLOGGED;
  475.                         syslog(LOG_WARNING,
  476.               "zoneref: Masters for secondary zone %s unreachable",
  477.                             zp->z_origin);
  478.                     }
  479.                     zp->z_time = tt.tv_sec + zp->z_retry;
  480.                     break;
  481.  
  482.                 default:
  483.                     if ((zp->z_state & Z_SYSLOGGED) == 0) {
  484.                         zp->z_state |= Z_SYSLOGGED;
  485.                         syslog(LOG_ERR,
  486.                             "named-xfer exit code %d",
  487.                             status.w_retcode);
  488.                     }
  489.                     /* FALLTHROUGH */
  490.                 case XFER_FAIL:
  491.                     zp->z_state |= Z_SYSLOGGED;
  492.                     zp->z_time = tt.tv_sec + zp->z_retry;
  493.                     break;
  494.             }
  495.             break;
  496.         }
  497. #ifndef SYSV
  498.     }
  499. #endif /* SYSV */
  500.     if (xfers) {
  501.         for (zp = zones;
  502.             xfers_deferred != 0 && xfers_running < MAX_XFERS_RUNNING &&
  503.             zp < &zones[nzones]; zp++)
  504.             if (zp->z_state & Z_NEED_XFER) {
  505.                 xfers_deferred--;
  506.                 startxfer(zp);
  507.             }
  508.         sched_maint();
  509.     }
  510. #if defined(SYSV)
  511.     (void)signal(SIGCLD, endxfer);
  512. #endif
  513. }
  514.  
  515. /*
  516.  * Reload zones whose transfers have completed.
  517.  */
  518. loadxfer()
  519. {
  520.         register struct zoneinfo *zp;   
  521.  
  522.     gettime(&tt);
  523.     for (zp = zones; zp < &zones[nzones]; zp++)
  524.         if (zp->z_state & Z_NEED_RELOAD) {
  525. #ifdef DEBUG
  526.         if (debug)
  527.             fprintf(ddt, "loadxfer() '%s'\n",
  528.             zp->z_origin[0] ? zp->z_origin : ".");
  529. #endif
  530.         zp->z_state &= ~Z_NEED_RELOAD;
  531.         zp->z_auth = 0;
  532.         remove_zone(hashtab, zp - zones);
  533.         if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0)
  534.             zp->z_auth = 1;
  535.         if (zp->z_state & Z_TMP_FILE)
  536.             (void) unlink(zp->z_source);
  537.         }
  538.     sched_maint();
  539. }
  540.