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