dbaccess.c revision 1.4
1/* 2 * dbaccess.c -- access methods for nsd(8) database 3 * 4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. 5 * 6 * See LICENSE for the license. 7 * 8 */ 9 10#include "config.h" 11 12#include <sys/types.h> 13#include <sys/stat.h> 14 15#include <errno.h> 16#include <stdlib.h> 17#include <string.h> 18#include <unistd.h> 19#include <fcntl.h> 20 21#include "dns.h" 22#include "namedb.h" 23#include "util.h" 24#include "options.h" 25#include "rdata.h" 26#include "udb.h" 27#include "udbradtree.h" 28#include "udbzone.h" 29#include "zonec.h" 30#include "nsec3.h" 31#include "difffile.h" 32#include "nsd.h" 33 34static time_t udb_time = 0; 35static unsigned long udb_rrsets = 0; 36static unsigned long udb_rrset_count = 0; 37 38void 39namedb_close(struct namedb* db) 40{ 41 if(db) { 42 if(db->udb) { 43 udb_base_close(db->udb); 44 udb_base_free(db->udb); 45 db->udb = NULL; 46 } 47 zonec_desetup_parser(); 48 region_destroy(db->region); 49 } 50} 51 52void 53namedb_close_udb(struct namedb* db) 54{ 55 if(db) { 56 /* we cannot actually munmap the data, because other 57 * processes still need to access the udb, so cleanup the 58 * udb */ 59 udb_base_free_keep_mmap(db->udb); 60 db->udb = NULL; 61 } 62} 63 64void 65apex_rrset_checks(namedb_type* db, rrset_type* rrset, domain_type* domain) 66{ 67 uint32_t soa_minimum; 68 unsigned i; 69 zone_type* zone = rrset->zone; 70 assert(domain == zone->apex); 71 (void)domain; 72 if (rrset_rrtype(rrset) == TYPE_SOA) { 73 zone->soa_rrset = rrset; 74 75 /* BUG #103 add another soa with a tweaked ttl */ 76 if(zone->soa_nx_rrset == 0) { 77 zone->soa_nx_rrset = region_alloc(db->region, 78 sizeof(rrset_type)); 79 zone->soa_nx_rrset->rr_count = 1; 80 zone->soa_nx_rrset->next = 0; 81 zone->soa_nx_rrset->zone = zone; 82 zone->soa_nx_rrset->rrs = region_alloc(db->region, 83 sizeof(rr_type)); 84 } 85 memcpy(zone->soa_nx_rrset->rrs, rrset->rrs, sizeof(rr_type)); 86 87 /* check the ttl and MINIMUM value and set accordingly */ 88 memcpy(&soa_minimum, rdata_atom_data(rrset->rrs->rdatas[6]), 89 rdata_atom_size(rrset->rrs->rdatas[6])); 90 if (rrset->rrs->ttl > ntohl(soa_minimum)) { 91 zone->soa_nx_rrset->rrs[0].ttl = ntohl(soa_minimum); 92 } 93 } else if (rrset_rrtype(rrset) == TYPE_NS) { 94 zone->ns_rrset = rrset; 95 } else if (rrset_rrtype(rrset) == TYPE_RRSIG) { 96 for (i = 0; i < rrset->rr_count; ++i) { 97 if(rr_rrsig_type_covered(&rrset->rrs[i])==TYPE_DNSKEY){ 98 zone->is_secure = 1; 99 break; 100 } 101 } 102 } 103} 104 105/** read rr */ 106static void 107read_rr(namedb_type* db, rr_type* rr, udb_ptr* urr, domain_type* domain) 108{ 109 buffer_type buffer; 110 ssize_t c; 111 assert(udb_ptr_get_type(urr) == udb_chunk_type_rr); 112 rr->owner = domain; 113 rr->type = RR(urr)->type; 114 rr->klass = RR(urr)->klass; 115 rr->ttl = RR(urr)->ttl; 116 117 buffer_create_from(&buffer, RR(urr)->wire, RR(urr)->len); 118 c = rdata_wireformat_to_rdata_atoms(db->region, db->domains, 119 rr->type, RR(urr)->len, &buffer, &rr->rdatas); 120 if(c == -1) { 121 /* safe on error */ 122 rr->rdata_count = 0; 123 rr->rdatas = NULL; 124 return; 125 } 126 rr->rdata_count = c; 127} 128 129/** calculate rr count */ 130static uint16_t 131calculate_rr_count(udb_base* udb, udb_ptr* rrset) 132{ 133 udb_ptr rr; 134 uint16_t num = 0; 135 udb_ptr_new(&rr, udb, &RRSET(rrset)->rrs); 136 while(rr.data) { 137 num++; 138 udb_ptr_set_rptr(&rr, udb, &RR(&rr)->next); 139 } 140 udb_ptr_unlink(&rr, udb); 141 return num; 142} 143 144/** read rrset */ 145static void 146read_rrset(udb_base* udb, namedb_type* db, zone_type* zone, 147 domain_type* domain, udb_ptr* urrset) 148{ 149 rrset_type* rrset; 150 udb_ptr urr; 151 unsigned i; 152 assert(udb_ptr_get_type(urrset) == udb_chunk_type_rrset); 153 /* if no RRs, do not create anything (robust) */ 154 if(RRSET(urrset)->rrs.data == 0) 155 return; 156 rrset = (rrset_type *) region_alloc(db->region, sizeof(rrset_type)); 157 rrset->zone = zone; 158 rrset->rr_count = calculate_rr_count(udb, urrset); 159 rrset->rrs = (rr_type *) region_alloc_array( 160 db->region, rrset->rr_count, sizeof(rr_type)); 161 /* add the RRs */ 162 udb_ptr_new(&urr, udb, &RRSET(urrset)->rrs); 163 for(i=0; i<rrset->rr_count; i++) { 164 read_rr(db, &rrset->rrs[i], &urr, domain); 165 udb_ptr_set_rptr(&urr, udb, &RR(&urr)->next); 166 } 167 udb_ptr_unlink(&urr, udb); 168 domain_add_rrset(domain, rrset); 169 if(domain == zone->apex) 170 apex_rrset_checks(db, rrset, domain); 171} 172 173/** read one elem from db, of type domain_d */ 174static void read_node_elem(udb_base* udb, namedb_type* db, 175 region_type* dname_region, zone_type* zone, struct domain_d* d) 176{ 177 const dname_type* dname; 178 domain_type* domain; 179 udb_ptr urrset; 180 181 dname = dname_make(dname_region, d->name, 0); 182 if(!dname) return; 183 domain = domain_table_insert(db->domains, dname); 184 assert(domain); /* domain_table_insert should always return non-NULL */ 185 186 /* add rrsets */ 187 udb_ptr_init(&urrset, udb); 188 udb_ptr_set_rptr(&urrset, udb, &d->rrsets); 189 while(urrset.data) { 190 read_rrset(udb, db, zone, domain, &urrset); 191 udb_ptr_set_rptr(&urrset, udb, &RRSET(&urrset)->next); 192 193 if(++udb_rrsets % ZONEC_PCT_COUNT == 0 && time(NULL) > udb_time + ZONEC_PCT_TIME) { 194 udb_time = time(NULL); 195 VERBOSITY(1, (LOG_INFO, "read %s %d %%", 196 zone->opts->name, 197 (int)(udb_rrsets*((unsigned long)100)/udb_rrset_count))); 198 } 199 } 200 region_free_all(dname_region); 201 udb_ptr_unlink(&urrset, udb); 202} 203 204/** recurse read radix from disk. This radix tree is by domain name, so max of 205 * 256 depth, and thus the stack usage is small. */ 206static void read_zone_recurse(udb_base* udb, namedb_type* db, 207 region_type* dname_region, zone_type* zone, struct udb_radnode_d* node) 208{ 209 if(node->elem.data) { 210 /* pre-order process of node->elem, for radix tree this is 211 * also in-order processing (identical to order tree_next()) */ 212 read_node_elem(udb, db, dname_region, zone, (struct domain_d*) 213 (udb->base + node->elem.data)); 214 } 215 if(node->lookup.data) { 216 uint16_t i; 217 struct udb_radarray_d* a = (struct udb_radarray_d*) 218 (udb->base + node->lookup.data); 219 /* we do not care for what the exact radix key is, we want 220 * to add all of them and the read routine does not need 221 * the radix-key, it has it stored */ 222 for(i=0; i<a->len; i++) { 223 if(a->array[i].node.data) { 224 read_zone_recurse(udb, db, dname_region, zone, 225 (struct udb_radnode_d*)(udb->base + 226 a->array[i].node.data)); 227 } 228 } 229 } 230} 231 232/** read zone data */ 233static void 234read_zone_data(udb_base* udb, namedb_type* db, region_type* dname_region, 235 udb_ptr* z, zone_type* zone) 236{ 237 udb_ptr dtree; 238 /* recursively read domains, we only read so ptrs stay valid */ 239 udb_ptr_new(&dtree, udb, &ZONE(z)->domains); 240 if(RADTREE(&dtree)->root.data) 241 read_zone_recurse(udb, db, dname_region, zone, 242 (struct udb_radnode_d*) 243 (udb->base + RADTREE(&dtree)->root.data)); 244 udb_ptr_unlink(&dtree, udb); 245} 246 247/** create a zone */ 248zone_type* 249namedb_zone_create(namedb_type* db, const dname_type* dname, 250 struct zone_options* zo) 251{ 252 zone_type* zone = (zone_type *) region_alloc(db->region, 253 sizeof(zone_type)); 254 zone->node = radname_insert(db->zonetree, dname_name(dname), 255 dname->name_size, zone); 256 assert(zone->node); 257 zone->apex = domain_table_insert(db->domains, dname); 258 zone->apex->usage++; /* the zone.apex reference */ 259 zone->apex->is_apex = 1; 260 zone->soa_rrset = NULL; 261 zone->soa_nx_rrset = NULL; 262 zone->ns_rrset = NULL; 263#ifdef NSEC3 264 zone->nsec3_param = NULL; 265 zone->nsec3_last = NULL; 266 zone->nsec3tree = NULL; 267 zone->hashtree = NULL; 268 zone->wchashtree = NULL; 269 zone->dshashtree = NULL; 270#endif 271 zone->opts = zo; 272 zone->filename = NULL; 273 zone->logstr = NULL; 274 zone->mtime.tv_sec = 0; 275 zone->mtime.tv_nsec = 0; 276 zone->zonestatid = 0; 277 zone->is_secure = 0; 278 zone->is_changed = 0; 279 zone->is_ok = 1; 280 return zone; 281} 282 283void 284namedb_zone_delete(namedb_type* db, zone_type* zone) 285{ 286 /* RRs and UDB and NSEC3 and so on must be already deleted */ 287 radix_delete(db->zonetree, zone->node); 288 289 /* see if apex can be deleted */ 290 if(zone->apex) { 291 zone->apex->usage --; 292 zone->apex->is_apex = 0; 293 if(zone->apex->usage == 0) { 294 /* delete the apex, possibly */ 295 domain_table_deldomain(db, zone->apex); 296 } 297 } 298 299 /* soa_rrset is freed when the SOA was deleted */ 300 if(zone->soa_nx_rrset) { 301 region_recycle(db->region, zone->soa_nx_rrset->rrs, 302 sizeof(rr_type)); 303 region_recycle(db->region, zone->soa_nx_rrset, 304 sizeof(rrset_type)); 305 } 306#ifdef NSEC3 307 hash_tree_delete(db->region, zone->nsec3tree); 308 hash_tree_delete(db->region, zone->hashtree); 309 hash_tree_delete(db->region, zone->wchashtree); 310 hash_tree_delete(db->region, zone->dshashtree); 311#endif 312 if(zone->filename) 313 region_recycle(db->region, zone->filename, 314 strlen(zone->filename)+1); 315 if(zone->logstr) 316 region_recycle(db->region, zone->logstr, 317 strlen(zone->logstr)+1); 318 region_recycle(db->region, zone, sizeof(zone_type)); 319} 320 321#ifdef HAVE_MMAP 322/** read a zone */ 323static void 324read_zone(udb_base* udb, namedb_type* db, struct nsd_options* opt, 325 region_type* dname_region, udb_ptr* z) 326{ 327 /* construct dname */ 328 const dname_type* dname = dname_make(dname_region, ZONE(z)->name, 0); 329 struct zone_options* zo = dname?zone_options_find(opt, dname):NULL; 330 zone_type* zone; 331 if(!dname) return; 332 if(!zo) { 333 /* deleted from the options, remove it from the nsd.db too */ 334 VERBOSITY(2, (LOG_WARNING, "zone %s is deleted", 335 dname_to_string(dname, NULL))); 336 udb_zone_delete(udb, z); 337 region_free_all(dname_region); 338 return; 339 } 340 assert(udb_ptr_get_type(z) == udb_chunk_type_zone); 341 udb_rrsets = 0; 342 udb_rrset_count = ZONE(z)->rrset_count; 343 zone = namedb_zone_create(db, dname, zo); 344 region_free_all(dname_region); 345 read_zone_data(udb, db, dname_region, z, zone); 346 zone->is_changed = (ZONE(z)->is_changed != 0); 347#ifdef NSEC3 348 prehash_zone_complete(db, zone); 349#endif 350} 351#endif /* HAVE_MMAP */ 352 353#ifdef HAVE_MMAP 354/** read zones from nsd.db */ 355static void 356read_zones(udb_base* udb, namedb_type* db, struct nsd_options* opt, 357 region_type* dname_region) 358{ 359 udb_ptr ztree, n, z; 360 udb_ptr_init(&z, udb); 361 udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); 362 udb_radix_first(udb,&ztree,&n); 363 udb_time = time(NULL); 364 while(n.data) { 365 udb_ptr_set_rptr(&z, udb, &RADNODE(&n)->elem); 366 udb_radix_next(udb, &n); /* store in case n is deleted */ 367 read_zone(udb, db, opt, dname_region, &z); 368 udb_ptr_zero(&z, udb); 369 if(nsd.signal_hint_shutdown) break; 370 } 371 udb_ptr_unlink(&ztree, udb); 372 udb_ptr_unlink(&n, udb); 373 udb_ptr_unlink(&z, udb); 374} 375#endif /* HAVE_MMAP */ 376 377#ifdef HAVE_MMAP 378/** try to read the udb file or fail */ 379static int 380try_read_udb(namedb_type* db, int fd, const char* filename, 381 struct nsd_options* opt) 382{ 383 /* 384 * Temporary region used while loading domain names from the 385 * database. The region is freed after each time a dname is 386 * read from the database. 387 */ 388 region_type* dname_region; 389 390 assert(fd != -1); 391 if(!(db->udb=udb_base_create_fd(filename, fd, &namedb_walkfunc, 392 NULL))) { 393 /* fd is closed by failed udb create call */ 394 VERBOSITY(1, (LOG_WARNING, "can not use %s, " 395 "will create anew", filename)); 396 return 0; 397 } 398 /* sanity check if can be opened */ 399 if(udb_base_get_userflags(db->udb) != 0) { 400 log_msg(LOG_WARNING, "%s was not closed properly, it might " 401 "be corrupted, will create anew", filename); 402 udb_base_free(db->udb); 403 db->udb = NULL; 404 return 0; 405 } 406 /* read if it can be opened */ 407 dname_region = region_create(xalloc, free); 408 /* this operation does not fail, we end up with 409 * something, even if that is an empty namedb */ 410 read_zones(db->udb, db, opt, dname_region); 411 region_destroy(dname_region); 412 return 1; 413} 414#endif /* HAVE_MMAP */ 415 416struct namedb * 417namedb_open (const char* filename, struct nsd_options* opt) 418{ 419 namedb_type* db; 420 421 /* 422 * Region used to store the loaded database. The region is 423 * freed in namedb_close. 424 */ 425 region_type* db_region; 426 int fd; 427 428#ifdef USE_MMAP_ALLOC 429 db_region = region_create_custom(mmap_alloc, mmap_free, MMAP_ALLOC_CHUNK_SIZE, 430 MMAP_ALLOC_LARGE_OBJECT_SIZE, MMAP_ALLOC_INITIAL_CLEANUP_SIZE, 1); 431#else /* !USE_MMAP_ALLOC */ 432 db_region = region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, 433 DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1); 434#endif /* !USE_MMAP_ALLOC */ 435 db = (namedb_type *) region_alloc(db_region, sizeof(struct namedb)); 436 db->region = db_region; 437 db->domains = domain_table_create(db->region); 438 db->zonetree = radix_tree_create(db->region); 439 db->diff_skip = 0; 440 db->diff_pos = 0; 441 zonec_setup_parser(db); 442 443 if (gettimeofday(&(db->diff_timestamp), NULL) != 0) { 444 log_msg(LOG_ERR, "unable to load %s: cannot initialize" 445 "timestamp", filename); 446 region_destroy(db_region); 447 return NULL; 448 } 449 450 /* in dbless mode there is no file to read or mmap */ 451 if(filename == NULL || filename[0] == 0) { 452 db->udb = NULL; 453 return db; 454 } 455 456#ifndef HAVE_MMAP 457 /* no mmap() system call, use dbless mode */ 458 VERBOSITY(1, (LOG_INFO, "no mmap(), ignoring database %s", filename)); 459 db->udb = NULL; 460 (void)fd; (void)opt; 461 return db; 462#else /* HAVE_MMAP */ 463 464 /* attempt to open, if does not exist, create a new one */ 465 fd = open(filename, O_RDWR); 466 if(fd == -1) { 467 if(errno != ENOENT) { 468 log_msg(LOG_ERR, "%s: %s", filename, strerror(errno)); 469 region_destroy(db_region); 470 return NULL; 471 } 472 } 473 /* attempt to read the file (if it exists) */ 474 if(fd != -1) { 475 if(!try_read_udb(db, fd, filename, opt)) 476 fd = -1; 477 } 478 /* attempt to create the file (if necessary or failed read) */ 479 if(fd == -1) { 480 if(!(db->udb=udb_base_create_new(filename, &namedb_walkfunc, 481 NULL))) { 482 region_destroy(db_region); 483 return NULL; 484 } 485 if(!udb_dns_init_file(db->udb)) { 486 region_destroy(db->region); 487 return NULL; 488 } 489 } 490 return db; 491#endif /* HAVE_MMAP */ 492} 493 494/** the the file mtime stat (or nonexist or error) */ 495int 496file_get_mtime(const char* file, struct timespec* mtime, int* nonexist) 497{ 498 struct stat s; 499 if(stat(file, &s) != 0) { 500 mtime->tv_sec = 0; 501 mtime->tv_nsec = 0; 502 *nonexist = (errno == ENOENT); 503 return 0; 504 } 505 *nonexist = 0; 506 mtime->tv_sec = s.st_mtime; 507#ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC 508 mtime->tv_nsec = s.st_mtimensec; 509#elif defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) 510 mtime->tv_nsec = s.st_mtim.tv_nsec; 511#else 512 mtime->tv_nsec = 0; 513#endif 514 return 1; 515} 516 517void 518namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb, 519 udb_ptr* last_task) 520{ 521 struct timespec mtime; 522 int nonexist = 0; 523 unsigned int errors; 524 const char* fname; 525 if(!nsd->db || !zone || !zone->opts || !zone->opts->pattern->zonefile) 526 return; 527 mtime.tv_sec = 0; 528 mtime.tv_nsec = 0; 529 fname = config_make_zonefile(zone->opts, nsd); 530 if(!file_get_mtime(fname, &mtime, &nonexist)) { 531 if(nonexist) { 532 VERBOSITY(2, (LOG_INFO, "zonefile %s does not exist", 533 fname)); 534 } else 535 log_msg(LOG_ERR, "zonefile %s: %s", 536 fname, strerror(errno)); 537 if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); 538 return; 539 } else { 540 const char* zone_fname = zone->filename; 541 struct timespec zone_mtime = zone->mtime; 542 if(nsd->db->udb) { 543 zone_fname = udb_zone_get_file_str(nsd->db->udb, 544 dname_name(domain_dname(zone->apex)), 545 domain_dname(zone->apex)->name_size); 546 udb_zone_get_mtime(nsd->db->udb, 547 dname_name(domain_dname(zone->apex)), 548 domain_dname(zone->apex)->name_size, 549 &zone_mtime); 550 } 551 /* if no zone_fname, then it was acquired in zone transfer, 552 * see if the file is newer than the zone transfer 553 * (regardless if this is a different file), because the 554 * zone transfer is a different content source too */ 555 if(!zone_fname && timespec_compare(&zone_mtime, &mtime) >= 0) { 556 VERBOSITY(3, (LOG_INFO, "zonefile %s is older than " 557 "zone transfer in memory", fname)); 558 return; 559 560 /* if zone_fname, then the file was acquired from reading it, 561 * and see if filename changed or mtime newer to read it */ 562 } else if(zone_fname && fname && 563 strcmp(zone_fname, fname) == 0 && 564 timespec_compare(&zone_mtime, &mtime) == 0) { 565 VERBOSITY(3, (LOG_INFO, "zonefile %s is not modified", 566 fname)); 567 return; 568 } 569 } 570 571 assert(parser); 572 /* wipe zone from memory */ 573#ifdef NSEC3 574 nsec3_hash_tree_clear(zone); 575#endif 576 delete_zone_rrs(nsd->db, zone); 577#ifdef NSEC3 578 nsec3_clear_precompile(nsd->db, zone); 579 zone->nsec3_param = NULL; 580#endif /* NSEC3 */ 581 errors = zonec_read(zone->opts->name, fname, zone); 582 if(errors > 0) { 583 log_msg(LOG_ERR, "zone %s file %s read with %u errors", 584 zone->opts->name, fname, errors); 585 /* wipe (partial) zone from memory */ 586 zone->is_ok = 1; 587#ifdef NSEC3 588 nsec3_hash_tree_clear(zone); 589#endif 590 delete_zone_rrs(nsd->db, zone); 591#ifdef NSEC3 592 nsec3_clear_precompile(nsd->db, zone); 593 zone->nsec3_param = NULL; 594#endif /* NSEC3 */ 595 if(nsd->db->udb) { 596 region_type* dname_region; 597 udb_ptr z; 598 /* see if we can revert to the udb stored version */ 599 if(!udb_zone_search(nsd->db->udb, &z, dname_name(domain_dname( 600 zone->apex)), domain_dname(zone->apex)->name_size)) { 601 /* tell that zone contents has been lost */ 602 if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); 603 return; 604 } 605 /* read from udb */ 606 dname_region = region_create(xalloc, free); 607 udb_rrsets = 0; 608 udb_rrset_count = ZONE(&z)->rrset_count; 609 udb_time = time(NULL); 610 read_zone_data(nsd->db->udb, nsd->db, dname_region, &z, zone); 611 region_destroy(dname_region); 612 udb_ptr_unlink(&z, nsd->db->udb); 613 } else { 614 if(zone->filename) 615 region_recycle(nsd->db->region, zone->filename, 616 strlen(zone->filename)+1); 617 zone->filename = NULL; 618 if(zone->logstr) 619 region_recycle(nsd->db->region, zone->logstr, 620 strlen(zone->logstr)+1); 621 zone->logstr = NULL; 622 } 623 } else { 624 VERBOSITY(1, (LOG_INFO, "zone %s read with success", 625 zone->opts->name)); 626 zone->is_ok = 1; 627 zone->is_changed = 0; 628 /* store zone into udb */ 629 if(nsd->db->udb) { 630 if(!write_zone_to_udb(nsd->db->udb, zone, &mtime, 631 fname)) { 632 log_msg(LOG_ERR, "failed to store zone in db"); 633 } else { 634 VERBOSITY(2, (LOG_INFO, "zone %s written to db", 635 zone->opts->name)); 636 } 637 } else { 638 zone->mtime = mtime; 639 if(zone->filename) 640 region_recycle(nsd->db->region, zone->filename, 641 strlen(zone->filename)+1); 642 zone->filename = region_strdup(nsd->db->region, fname); 643 if(zone->logstr) 644 region_recycle(nsd->db->region, zone->logstr, 645 strlen(zone->logstr)+1); 646 zone->logstr = NULL; 647 } 648 } 649 if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); 650#ifdef NSEC3 651 prehash_zone_complete(nsd->db, zone); 652#endif 653} 654 655void namedb_check_zonefile(struct nsd* nsd, udb_base* taskudb, 656 udb_ptr* last_task, struct zone_options* zopt) 657{ 658 zone_type* zone; 659 const dname_type* dname = (const dname_type*)zopt->node.key; 660 /* find zone to go with it, or create it */ 661 zone = namedb_find_zone(nsd->db, dname); 662 if(!zone) { 663 zone = namedb_zone_create(nsd->db, dname, zopt); 664 } 665 namedb_read_zonefile(nsd, zone, taskudb, last_task); 666} 667 668void namedb_check_zonefiles(struct nsd* nsd, struct nsd_options* opt, 669 udb_base* taskudb, udb_ptr* last_task) 670{ 671 struct zone_options* zo; 672 /* check all zones in opt, create if not exist in main db */ 673 RBTREE_FOR(zo, struct zone_options*, opt->zone_options) { 674 namedb_check_zonefile(nsd, taskudb, last_task, zo); 675 if(nsd->signal_hint_shutdown) break; 676 } 677} 678