|
|
1.1 ! root 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.37 (Berkeley) 6/1/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: VOID ! 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.