* Copyright (c) 1986, 1988 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)ns_maint.c 4.39 (Berkeley) 3/2/91";
#include <arpa/nameser.h>
extern int maint_interval
;
int xfers_running
; /* number of xfers running */
int xfers_deferred
; /* number of needed xfers not run yet */
static int alarm_pending
;
* Invoked at regular intervals by signal interrupt; refresh all secondary
* zones from primary name server and remove old cache entries. Also,
* ifdef'd ALLOW_UPDATES, dump database if it has changed since last
register struct zoneinfo
*zp
;
fprintf(ddt
,"\nns_maint(); now %s", ctime(&tt
.tv_sec
));
for (zp
= zones
, zonenum
= 0; zp
< &zones
[nzones
]; zp
++, zonenum
++) {
if (tt
.tv_sec
>= zp
->z_time
&& zp
->z_refresh
> 0) {
* Set default time for next action first,
* so that it can be changed later if necessary.
zp
->z_time
= tt
.tv_sec
+ zp
->z_refresh
;
if ((zp
->z_state
& Z_NEED_RELOAD
) == 0) {
if (zp
->z_state
& Z_XFER_RUNNING
)
else if (xfers_running
< MAX_XFERS_RUNNING
)
zp
->z_state
|= Z_NEED_XFER
;
"xfer deferred for %s\n",
* Checkpoint the zone if it has changed
* since we last checkpointed
fprintf(ddt
,"exit ns_maint()\n");
* Find when the next refresh needs to be and set
* interrupt time accordingly.
register struct zoneinfo
*zp
;
static time_t next_alarm
;
for (zp
= zones
; zp
< &zones
[nzones
]; zp
++)
(next_refresh
== 0 || next_refresh
> zp
->z_time
))
next_refresh
= zp
->z_time
;
* Schedule the next call to ns_maint.
* Don't visit any sooner than maint_interval.
bzero((char *)&ival
, sizeof (ival
));
if (next_refresh
== next_alarm
&& alarm_pending
) {
fprintf(ddt
,"sched_maint: no schedule change\n");
ival
.it_value
.tv_sec
= next_refresh
- tt
.tv_sec
;
if (ival
.it_value
.tv_sec
< maint_interval
)
ival
.it_value
.tv_sec
= maint_interval
;
next_alarm
= next_refresh
;
(void) setitimer(ITIMER_REAL
, &ival
, (struct itimerval
*)NULL
);
fprintf(ddt
,"sched_maint: Next interrupt in %d sec\n",
* Start an asynchronous zone transfer for a zone.
* Depends on current time being in tt.
* The caller must call sched_maint after startxfer.
static char *argv
[NSMAX
+ 20], argv_ns
[NSMAX
][MAXDNAME
];
int cnt
, argc
= 0, argc_ns
= 0, pid
, omask
;
fprintf(ddt
,"startxfer() %s\n", zp
->z_origin
);
argv
[argc
++] = "named-xfer";
argv
[argc
++] = zp
->z_origin
;
argv
[argc
++] = zp
->z_source
;
sprintf(serial_str
, "%d", zp
->z_serial
);
argv
[argc
++] = serial_str
;
if (zp
->z_state
& Z_SYSLOGGED
)
sprintf(port_str
, "%d", ns_port
);
sprintf(debug_str
, "%d", debug
);
argv
[argc
++] = debug_str
;
argv
[argc
++] = "/usr/tmp/xfer.ddt";
argv
[argc
++] = "/usr/tmp/xfer.trace";
* Copy the server ip addresses into argv, after converting
* to ascii and saving the static inet_ntoa result
for (cnt
= 0; cnt
< zp
->z_addrcnt
; cnt
++)
argv
[argc
++] = strcpy(argv_ns
[argc_ns
++],
inet_ntoa(zp
->z_addr
[cnt
]));
for (i
= 0; i
< argc
; i
++)
fprintf(ddt
, "Arg %d=%s\n", i
, argv
[i
]);
omask
= sigblock(sigmask(SIGCHLD
));
if ((pid
= vfork()) == -1) {
fprintf(ddt
, "xfer [v]fork: %d\n", errno
);
syslog(LOG_ERR
, "xfer [v]fork: %m");
(void) sigsetmask(omask
);
zp
->z_time
= tt
.tv_sec
+ 10;
fprintf(ddt
, "started xfer child %d\n", pid
);
zp
->z_state
&= ~Z_NEED_XFER
;
zp
->z_state
|= Z_XFER_RUNNING
;
zp
->z_time
= tt
.tv_sec
+ MAX_XFER_TIME
;
(void) sigsetmask(omask
);
execve(_PATH_XFER
, argv
, NULL
);
syslog(LOG_ERR
, "can't exec %s: %m", _PATH_XFER
);
_exit(XFER_FAIL
); /* avoid duplicate buffer flushes */
struct zoneinfo
*zp
= &zones
[zonenum
];
return; /* Else fprintf to ddt will bomb */
fprintf(ddt
, "printzoneinfo(%d):\n", zonenum
);
case Z_PRIMARY
: ZoneType
= "Primary"; break;
case Z_SECONDARY
: ZoneType
= "Secondary"; break;
case Z_CACHE
: ZoneType
= "Cache"; break;
default: ZoneType
= "Unknown";
if (zp
->z_origin
[0] == '\0')
fprintf(ddt
,"origin ='.'");
fprintf(ddt
,"origin ='%s'", zp
->z_origin
);
fprintf(ddt
,", type = %s", ZoneType
);
fprintf(ddt
,", source = %s\n", zp
->z_source
);
fprintf(ddt
,"z_refresh = %ld", zp
->z_refresh
);
fprintf(ddt
,", retry = %ld", zp
->z_retry
);
fprintf(ddt
,", expire = %ld", zp
->z_expire
);
fprintf(ddt
,", minimum = %ld", zp
->z_minimum
);
fprintf(ddt
,", serial = %ld\n", zp
->z_serial
);
fprintf(ddt
,"z_time = %d", zp
->z_time
);
fprintf(ddt
,", now time : %d sec", tt
.tv_sec
);
fprintf(ddt
,", time left: %d sec", zp
->z_time
- tt
.tv_sec
);
fprintf(ddt
,"; state %x\n", zp
->z_state
);
* remove_zone (htp, zone) --
* Delete all RR's in the zone "zone" under specified hash table.
register struct hashbuf
*htp
;
register struct databuf
*dp
, *pdp
;
register struct namebuf
*np
;
struct namebuf
**npp
, **nppend
;
nppend
= htp
->h_tab
+ htp
->h_size
;
for (npp
= htp
->h_tab
; npp
< nppend
; npp
++)
for (np
= *npp
; np
!= NULL
; np
= np
->n_next
) {
for (pdp
= NULL
, dp
= np
->n_data
; dp
!= NULL
; ) {
dp
= rm_datum(dp
, np
, pdp
);
/* Call recursively to remove subdomains. */
remove_zone(np
->n_hash
, zone
);
* Abort an xfer that has taken too long.
register struct zoneinfo
*zp
;
kill(zp
->z_xferpid
, SIGKILL
); /* don't trust it at all */
fprintf(ddt
, "Killed child %d (zone %s) due to timeout\n",
zp
->z_xferpid
, zp
->z_origin
);
zp
->z_time
= tt
.tv_sec
+ zp
->z_retry
;
unsigned short w_termsig
:7; /* termination signal */
unsigned short w_coredump
:1; /* core dump indicator */
unsigned short w_retcode
:8; /* exit code if w_termsig==0 */
* SIGCHLD signal handler: process exit of xfer's.
* (Note: also called when outgoing transfer completes.)
register struct zoneinfo
*zp
;
status
.w_termsig
= stat
& 0x7f;
status
.w_retcode
= stat
>> 8;
wait3((int *)&status
, WNOHANG
, (struct rusage
*)NULL
)) > 0) {
for (zp
= zones
; zp
< &zones
[nzones
]; zp
++)
if (zp
->z_xferpid
== pid
) {
zp
->z_state
&= ~Z_XFER_RUNNING
;
"\nendxfer: child %d zone %s returned status=%d termsig=%d\n",
pid
, zp
->z_origin
, status
.w_retcode
,
if (status
.w_termsig
!= 0) {
if (status
.w_termsig
!= SIGKILL
) {
"named-xfer exited with signal %d\n",
"\tchild termination with signal %d\n",
zp
->z_time
= tt
.tv_sec
+ zp
->z_retry
;
} else switch (status
.w_retcode
) {
zp
->z_state
&= ~Z_SYSLOGGED
;
zp
->z_lastupdate
= tt
.tv_sec
;
zp
->z_time
= tt
.tv_sec
+ zp
->z_refresh
;
* Restore z_auth in case expired,
* but only if there were no errors
if ((zp
->z_state
& Z_DB_BAD
) == 0)
(void) utime(zp
->z_source
, &t
);
(void) utimes(zp
->z_source
, t
);
zp
->z_state
|= Z_NEED_RELOAD
;
zp
->z_state
&= ~Z_SYSLOGGED
;
"zoneref: Masters for secondary zone %s unreachable\n",
if ((zp
->z_state
& Z_SYSLOGGED
) == 0) {
zp
->z_state
|= Z_SYSLOGGED
;
"zoneref: Masters for secondary zone %s unreachable",
zp
->z_time
= tt
.tv_sec
+ zp
->z_retry
;
if ((zp
->z_state
& Z_SYSLOGGED
) == 0) {
zp
->z_state
|= Z_SYSLOGGED
;
"named-xfer exit code %d",
zp
->z_state
|= Z_SYSLOGGED
;
zp
->z_time
= tt
.tv_sec
+ zp
->z_retry
;
xfers_deferred
!= 0 && xfers_running
< MAX_XFERS_RUNNING
&&
zp
< &zones
[nzones
]; zp
++)
if (zp
->z_state
& Z_NEED_XFER
) {
(void)signal(SIGCLD
, endxfer
);
* Reload zones whose transfers have completed.
register struct zoneinfo
*zp
;
for (zp
= zones
; zp
< &zones
[nzones
]; zp
++)
if (zp
->z_state
& Z_NEED_RELOAD
) {
fprintf(ddt
, "loadxfer() '%s'\n",
zp
->z_origin
[0] ? zp
->z_origin
: ".");
zp
->z_state
&= ~Z_NEED_RELOAD
;
remove_zone(hashtab
, zp
- zones
);
if (db_load(zp
->z_source
, zp
->z_origin
, zp
, 0) == 0)
if (zp
->z_state
& Z_TMP_FILE
)
(void) unlink(zp
->z_source
);