"Fossies" - the Fresh Open Source Software Archive

Member "nsd-4.3.7/dbaccess.c" (22 Jul 2021, 19012 Bytes) of package /linux/misc/dns/nsd-4.3.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dbaccess.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.3.6_vs_4.3.7.

    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 
   34 static time_t udb_time = 0;
   35 static unsigned long udb_rrsets = 0;
   36 static unsigned long udb_rrset_count = 0;
   37 
   38 void
   39 namedb_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 
   52 void
   53 namedb_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 
   64 void
   65 apex_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 */
  106 static void
  107 read_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 */
  130 static uint16_t
  131 calculate_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 */
  145 static void
  146 read_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 */
  174 static 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. */
  206 static 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             ((char*)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             ((char*)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*)((char*)udb->base +
  226                         a->array[i].node.data));
  227             }
  228         }
  229     }
  230 }
  231 
  232 /** read zone data */
  233 static void
  234 read_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             ((char*)udb->base + RADTREE(&dtree)->root.data));
  244     udb_ptr_unlink(&dtree, udb);
  245 }
  246 
  247 /** create a zone */
  248 zone_type*
  249 namedb_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 
  283 void
  284 namedb_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 */
  323 static void
  324 read_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 */
  355 static void
  356 read_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 */
  379 static int
  380 try_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_ERR, "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_ERR, "%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 
  416 struct namedb *
  417 namedb_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) */
  495 int
  496 file_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 
  517 void
  518 namedb_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     assert(fname);
  531     if(!file_get_mtime(fname, &mtime, &nonexist)) {
  532         if(nonexist) {
  533             if(zone_is_slave(zone->opts)) {
  534                 /* for slave zones not as bad, no zonefile
  535                  * may just mean we have to transfer it */
  536                 VERBOSITY(2, (LOG_INFO, "zonefile %s does not exist",
  537                     fname));
  538             } else {
  539                 /* without a download option, we can never
  540                  * serve data, more severe error printout */
  541                 log_msg(LOG_ERR, "zonefile %s does not exist", fname);
  542             }
  543 
  544         } else
  545             log_msg(LOG_ERR, "zonefile %s: %s",
  546                 fname, strerror(errno));
  547         if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0);
  548         return;
  549     } else {
  550         const char* zone_fname = zone->filename;
  551         struct timespec zone_mtime = zone->mtime;
  552         if(nsd->db->udb) {
  553             zone_fname = udb_zone_get_file_str(nsd->db->udb,
  554                 dname_name(domain_dname(zone->apex)),
  555                 domain_dname(zone->apex)->name_size);
  556             udb_zone_get_mtime(nsd->db->udb,
  557                 dname_name(domain_dname(zone->apex)),
  558                 domain_dname(zone->apex)->name_size,
  559                 &zone_mtime);
  560         }
  561         /* if no zone_fname, then it was acquired in zone transfer,
  562          * see if the file is newer than the zone transfer
  563          * (regardless if this is a different file), because the
  564          * zone transfer is a different content source too */
  565         if(!zone_fname && timespec_compare(&zone_mtime, &mtime) >= 0) {
  566             VERBOSITY(3, (LOG_INFO, "zonefile %s is older than "
  567                 "zone transfer in memory", fname));
  568             return;
  569 
  570         /* if zone_fname, then the file was acquired from reading it,
  571          * and see if filename changed or mtime newer to read it */
  572         } else if(zone_fname && strcmp(zone_fname, fname) == 0 &&
  573            timespec_compare(&zone_mtime, &mtime) == 0) {
  574             VERBOSITY(3, (LOG_INFO, "zonefile %s is not modified",
  575                 fname));
  576             return;
  577         }
  578     }
  579 
  580     assert(parser);
  581     /* wipe zone from memory */
  582 #ifdef NSEC3
  583     nsec3_clear_precompile(nsd->db, zone);
  584     zone->nsec3_param = NULL;
  585 #endif
  586     delete_zone_rrs(nsd->db, zone);
  587     errors = zonec_read(zone->opts->name, fname, zone);
  588     if(errors > 0) {
  589         log_msg(LOG_ERR, "zone %s file %s read with %u errors",
  590             zone->opts->name, fname, errors);
  591         /* wipe (partial) zone from memory */
  592         zone->is_ok = 1;
  593 #ifdef NSEC3
  594         nsec3_clear_precompile(nsd->db, zone);
  595         zone->nsec3_param = NULL;
  596 #endif
  597         delete_zone_rrs(nsd->db, zone);
  598         if(nsd->db->udb) {
  599             region_type* dname_region;
  600             udb_ptr z;
  601             /* see if we can revert to the udb stored version */
  602             if(!udb_zone_search(nsd->db->udb, &z, dname_name(domain_dname(
  603                 zone->apex)), domain_dname(zone->apex)->name_size)) {
  604                 /* tell that zone contents has been lost */
  605                 if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0);
  606                 return;
  607             }
  608             /* read from udb */
  609             dname_region = region_create(xalloc, free);
  610             udb_rrsets = 0;
  611             udb_rrset_count = ZONE(&z)->rrset_count;
  612             udb_time = time(NULL);
  613             read_zone_data(nsd->db->udb, nsd->db, dname_region, &z, zone);
  614             region_destroy(dname_region);
  615             udb_ptr_unlink(&z, nsd->db->udb);
  616         } else {
  617             if(zone->filename)
  618                 region_recycle(nsd->db->region, zone->filename,
  619                     strlen(zone->filename)+1);
  620             zone->filename = NULL;
  621             if(zone->logstr)
  622                 region_recycle(nsd->db->region, zone->logstr,
  623                     strlen(zone->logstr)+1);
  624             zone->logstr = NULL;
  625         }
  626     } else {
  627         VERBOSITY(1, (LOG_INFO, "zone %s read with success",
  628             zone->opts->name));
  629         zone->is_ok = 1;
  630         zone->is_changed = 0;
  631         /* store zone into udb */
  632         if(nsd->db->udb) {
  633             if(!write_zone_to_udb(nsd->db->udb, zone, &mtime,
  634                 fname)) {
  635                 log_msg(LOG_ERR, "failed to store zone in db");
  636             } else {
  637                 VERBOSITY(2, (LOG_INFO, "zone %s written to db",
  638                     zone->opts->name));
  639             }
  640         } else {
  641             zone->mtime = mtime;
  642             if(zone->filename)
  643                 region_recycle(nsd->db->region, zone->filename,
  644                     strlen(zone->filename)+1);
  645             zone->filename = region_strdup(nsd->db->region, fname);
  646             if(zone->logstr)
  647                 region_recycle(nsd->db->region, zone->logstr,
  648                     strlen(zone->logstr)+1);
  649             zone->logstr = NULL;
  650         }
  651     }
  652     if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0);
  653 #ifdef NSEC3
  654     prehash_zone_complete(nsd->db, zone);
  655 #endif
  656 }
  657 
  658 void namedb_check_zonefile(struct nsd* nsd, udb_base* taskudb,
  659     udb_ptr* last_task, struct zone_options* zopt)
  660 {
  661     zone_type* zone;
  662     const dname_type* dname = (const dname_type*)zopt->node.key;
  663     /* find zone to go with it, or create it */
  664     zone = namedb_find_zone(nsd->db, dname);
  665     if(!zone) {
  666         zone = namedb_zone_create(nsd->db, dname, zopt);
  667     }
  668     namedb_read_zonefile(nsd, zone, taskudb, last_task);
  669 }
  670 
  671 void namedb_check_zonefiles(struct nsd* nsd, struct nsd_options* opt,
  672     udb_base* taskudb, udb_ptr* last_task)
  673 {
  674     struct zone_options* zo;
  675     /* check all zones in opt, create if not exist in main db */
  676     RBTREE_FOR(zo, struct zone_options*, opt->zone_options) {
  677         namedb_check_zonefile(nsd, taskudb, last_task, zo);
  678         if(nsd->signal_hint_shutdown) break;
  679     }
  680 }