xref: /openbsd/usr.sbin/nsd/dbaccess.c (revision cecf84d4)
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 accordinly */
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(
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 			(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 */
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 			(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 	zone_options_t* 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 = 0;
275 	zone->zonestatid = 0;
276 	zone->is_secure = 0;
277 	zone->is_changed = 0;
278 	zone->is_ok = 1;
279 	return zone;
280 }
281 
282 void
283 namedb_zone_delete(namedb_type* db, zone_type* zone)
284 {
285 	/* RRs and UDB and NSEC3 and so on must be already deleted */
286 	radix_delete(db->zonetree, zone->node);
287 
288 	/* see if apex can be deleted */
289 	if(zone->apex) {
290 		zone->apex->usage --;
291 		if(zone->apex->usage == 0) {
292 			/* delete the apex, possibly */
293 			domain_table_deldomain(db, zone->apex);
294 		}
295 	}
296 
297 	/* soa_rrset is freed when the SOA was deleted */
298 	if(zone->soa_nx_rrset) {
299 		region_recycle(db->region, zone->soa_nx_rrset->rrs,
300 			sizeof(rr_type));
301 		region_recycle(db->region, zone->soa_nx_rrset,
302 			sizeof(rrset_type));
303 	}
304 #ifdef NSEC3
305 	hash_tree_delete(db->region, zone->nsec3tree);
306 	hash_tree_delete(db->region, zone->hashtree);
307 	hash_tree_delete(db->region, zone->wchashtree);
308 	hash_tree_delete(db->region, zone->dshashtree);
309 #endif
310 	if(zone->filename)
311 		region_recycle(db->region, zone->filename,
312 			strlen(zone->filename)+1);
313 	if(zone->logstr)
314 		region_recycle(db->region, zone->logstr,
315 			strlen(zone->logstr)+1);
316 	region_recycle(db->region, zone, sizeof(zone_type));
317 }
318 
319 #ifdef HAVE_MMAP
320 /** read a zone */
321 static void
322 read_zone(udb_base* udb, namedb_type* db, nsd_options_t* opt,
323 	region_type* dname_region, udb_ptr* z)
324 {
325 	/* construct dname */
326 	const dname_type* dname = dname_make(dname_region, ZONE(z)->name, 0);
327 	zone_options_t* zo = dname?zone_options_find(opt, dname):NULL;
328 	zone_type* zone;
329 	if(!dname) return;
330 	if(!zo) {
331 		/* deleted from the options, remove it from the nsd.db too */
332 		VERBOSITY(2, (LOG_WARNING, "zone %s is deleted",
333 			dname_to_string(dname, NULL)));
334 		udb_zone_delete(udb, z);
335 		region_free_all(dname_region);
336 		return;
337 	}
338 	assert(udb_ptr_get_type(z) == udb_chunk_type_zone);
339 	udb_rrsets = 0;
340 	udb_rrset_count = ZONE(z)->rrset_count;
341 	zone = namedb_zone_create(db, dname, zo);
342 	region_free_all(dname_region);
343 	read_zone_data(udb, db, dname_region, z, zone);
344 	zone->is_changed = (ZONE(z)->is_changed != 0);
345 #ifdef NSEC3
346 	prehash_zone_complete(db, zone);
347 #endif
348 }
349 #endif /* HAVE_MMAP */
350 
351 #ifdef HAVE_MMAP
352 /** read zones from nsd.db */
353 static void
354 read_zones(udb_base* udb, namedb_type* db, nsd_options_t* opt,
355 	region_type* dname_region)
356 {
357 	udb_ptr ztree, n, z;
358 	udb_ptr_init(&z, udb);
359 	udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb));
360 	udb_radix_first(udb,&ztree,&n);
361 	udb_time = time(NULL);
362 	while(n.data) {
363 		udb_ptr_set_rptr(&z, udb, &RADNODE(&n)->elem);
364 		udb_radix_next(udb, &n); /* store in case n is deleted */
365 		read_zone(udb, db, opt, dname_region, &z);
366 		udb_ptr_zero(&z, udb);
367 		if(nsd.signal_hint_shutdown) break;
368 	}
369 	udb_ptr_unlink(&ztree, udb);
370 	udb_ptr_unlink(&n, udb);
371 	udb_ptr_unlink(&z, udb);
372 }
373 #endif /* HAVE_MMAP */
374 
375 #ifdef HAVE_MMAP
376 /** try to read the udb file or fail */
377 static int
378 try_read_udb(namedb_type* db, int fd, const char* filename,
379 	nsd_options_t* opt)
380 {
381 	/*
382 	 * Temporary region used while loading domain names from the
383 	 * database.  The region is freed after each time a dname is
384 	 * read from the database.
385 	 */
386 	region_type* dname_region;
387 
388 	assert(fd != -1);
389 	if(!(db->udb=udb_base_create_fd(filename, fd, &namedb_walkfunc,
390 		NULL))) {
391 		/* fd is closed by failed udb create call */
392 		VERBOSITY(1, (LOG_WARNING, "can not use %s, "
393 			"will create anew", filename));
394 		return 0;
395 	}
396 	/* sanity check if can be opened */
397 	if(udb_base_get_userflags(db->udb) != 0) {
398 		log_msg(LOG_WARNING, "%s was not closed properly, it might "
399 			"be corrupted, will create anew", filename);
400 		udb_base_free(db->udb);
401 		db->udb = NULL;
402 		return 0;
403 	}
404 	/* read if it can be opened */
405 	dname_region = region_create(xalloc, free);
406 	/* this operation does not fail, we end up with
407 	 * something, even if that is an empty namedb */
408 	read_zones(db->udb, db, opt, dname_region);
409 	region_destroy(dname_region);
410 	return 1;
411 }
412 #endif /* HAVE_MMAP */
413 
414 struct namedb *
415 namedb_open (const char* filename, nsd_options_t* opt)
416 {
417 	namedb_type* db;
418 
419 	/*
420 	 * Region used to store the loaded database.  The region is
421 	 * freed in namedb_close.
422 	 */
423 	region_type* db_region;
424 	int fd;
425 
426 #ifdef USE_MMAP_ALLOC
427 	db_region = region_create_custom(mmap_alloc, mmap_free, MMAP_ALLOC_CHUNK_SIZE,
428 		MMAP_ALLOC_LARGE_OBJECT_SIZE, MMAP_ALLOC_INITIAL_CLEANUP_SIZE, 1);
429 #else /* !USE_MMAP_ALLOC */
430 	db_region = region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE,
431 		DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1);
432 #endif /* !USE_MMAP_ALLOC */
433 	db = (namedb_type *) region_alloc(db_region, sizeof(struct namedb));
434 	db->region = db_region;
435 	db->domains = domain_table_create(db->region);
436 	db->zonetree = radix_tree_create(db->region);
437 	db->diff_skip = 0;
438 	db->diff_pos = 0;
439 	zonec_setup_parser(db);
440 
441 	if (gettimeofday(&(db->diff_timestamp), NULL) != 0) {
442 		log_msg(LOG_ERR, "unable to load %s: cannot initialize"
443 				 "timestamp", filename);
444 		region_destroy(db_region);
445 		return NULL;
446         }
447 
448 	/* in dbless mode there is no file to read or mmap */
449 	if(filename == NULL || filename[0] == 0) {
450 		db->udb = NULL;
451 		return db;
452 	}
453 
454 #ifndef HAVE_MMAP
455 	/* no mmap() system call, use dbless mode */
456 	VERBOSITY(1, (LOG_INFO, "no mmap(), ignoring database %s", filename));
457 	db->udb = NULL;
458 	(void)fd; (void)opt;
459 	return db;
460 #else /* HAVE_MMAP */
461 
462 	/* attempt to open, if does not exist, create a new one */
463 	fd = open(filename, O_RDWR);
464 	if(fd == -1) {
465 		if(errno != ENOENT) {
466 			log_msg(LOG_ERR, "%s: %s", filename, strerror(errno));
467 			region_destroy(db_region);
468 			return NULL;
469 		}
470 	}
471 	/* attempt to read the file (if it exists) */
472 	if(fd != -1) {
473 		if(!try_read_udb(db, fd, filename, opt))
474 			fd = -1;
475 	}
476 	/* attempt to create the file (if necessary or failed read) */
477 	if(fd == -1) {
478 		if(!(db->udb=udb_base_create_new(filename, &namedb_walkfunc,
479 			NULL))) {
480 			region_destroy(db_region);
481 			return NULL;
482 		}
483 		if(!udb_dns_init_file(db->udb)) {
484 			region_destroy(db->region);
485 			return NULL;
486 		}
487 	}
488 	return db;
489 #endif /* HAVE_MMAP */
490 }
491 
492 /** the the file mtime stat (or nonexist or error) */
493 static int
494 file_get_mtime(const char* file, time_t* mtime, int* nonexist)
495 {
496 	struct stat s;
497 	if(stat(file, &s) != 0) {
498 		*mtime = 0;
499 		*nonexist = (errno == ENOENT);
500 		return 0;
501 	}
502 	*nonexist = 0;
503 	*mtime = s.st_mtime;
504 	return 1;
505 }
506 
507 void
508 namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb,
509 	udb_ptr* last_task)
510 {
511 	time_t mtime = 0;
512 	int nonexist = 0;
513 	unsigned int errors;
514 	const char* fname;
515 	if(!nsd->db || !zone || !zone->opts || !zone->opts->pattern->zonefile)
516 		return;
517 	fname = config_make_zonefile(zone->opts, nsd);
518 	if(!file_get_mtime(fname, &mtime, &nonexist)) {
519 		if(nonexist) {
520 			VERBOSITY(2, (LOG_INFO, "zonefile %s does not exist",
521 				fname));
522 		} else
523 			log_msg(LOG_ERR, "zonefile %s: %s",
524 				fname, strerror(errno));
525 		if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0);
526 		return;
527 	} else {
528 		const char* zone_fname = zone->filename;
529 		time_t zone_mtime = zone->mtime;
530 		if(nsd->db->udb) {
531 			zone_fname = udb_zone_get_file_str(nsd->db->udb,
532 				dname_name(domain_dname(zone->apex)),
533 				domain_dname(zone->apex)->name_size);
534 			zone_mtime = (time_t)udb_zone_get_mtime(nsd->db->udb,
535 				dname_name(domain_dname(zone->apex)),
536 				domain_dname(zone->apex)->name_size);
537 		}
538 		/* if no zone_fname, then it was acquired in zone transfer,
539 		 * see if the file is newer than the zone transfer
540 		 * (regardless if this is a different file), because the
541 		 * zone transfer is a different content source too */
542 		if(!zone_fname && zone_mtime >= mtime) {
543 			VERBOSITY(3, (LOG_INFO, "zonefile %s is older than "
544 				"zone transfer in memory", fname));
545 			return;
546 
547 		/* if zone_fname, then the file was acquired from reading it,
548 		 * and see if filename changed or mtime newer to read it */
549 		} else if(zone_fname && fname &&
550 		   strcmp(zone_fname, fname) == 0 && zone_mtime >= mtime) {
551 			VERBOSITY(3, (LOG_INFO, "zonefile %s is not modified",
552 				fname));
553 			return;
554 		}
555 	}
556 
557 	assert(parser);
558 	/* wipe zone from memory */
559 #ifdef NSEC3
560 	nsec3_hash_tree_clear(zone);
561 #endif
562 	delete_zone_rrs(nsd->db, zone);
563 #ifdef NSEC3
564 	nsec3_clear_precompile(nsd->db, zone);
565 	zone->nsec3_param = NULL;
566 #endif /* NSEC3 */
567 	errors = zonec_read(zone->opts->name, fname, zone);
568 	if(errors > 0) {
569 		log_msg(LOG_ERR, "zone %s file %s read with %u errors",
570 			zone->opts->name, fname, errors);
571 		/* wipe (partial) zone from memory */
572 		zone->is_ok = 1;
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 		if(nsd->db->udb) {
582 			region_type* dname_region;
583 			udb_ptr z;
584 			/* see if we can revert to the udb stored version */
585 			if(!udb_zone_search(nsd->db->udb, &z, dname_name(domain_dname(
586 				zone->apex)), domain_dname(zone->apex)->name_size)) {
587 				/* tell that zone contents has been lost */
588 				if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0);
589 				return;
590 			}
591 			/* read from udb */
592 			dname_region = region_create(xalloc, free);
593 			udb_rrsets = 0;
594 			udb_rrset_count = ZONE(&z)->rrset_count;
595 			udb_time = time(NULL);
596 			read_zone_data(nsd->db->udb, nsd->db, dname_region, &z, zone);
597 			region_destroy(dname_region);
598 			udb_ptr_unlink(&z, nsd->db->udb);
599 		} else {
600 			if(zone->filename)
601 				region_recycle(nsd->db->region, zone->filename,
602 					strlen(zone->filename)+1);
603 			zone->filename = NULL;
604 			if(zone->logstr)
605 				region_recycle(nsd->db->region, zone->logstr,
606 					strlen(zone->logstr)+1);
607 			zone->logstr = NULL;
608 		}
609 	} else {
610 		VERBOSITY(1, (LOG_INFO, "zone %s read with no errors",
611 			zone->opts->name));
612 		zone->is_ok = 1;
613 		zone->is_changed = 0;
614 		/* store zone into udb */
615 		if(nsd->db->udb) {
616 			if(!write_zone_to_udb(nsd->db->udb, zone, mtime, fname)) {
617 				log_msg(LOG_ERR, "failed to store zone in db");
618 			} else {
619 				VERBOSITY(2, (LOG_INFO, "zone %s written to db",
620 					zone->opts->name));
621 			}
622 		} else {
623 			zone->mtime = mtime;
624 			if(zone->filename)
625 				region_recycle(nsd->db->region, zone->filename,
626 					strlen(zone->filename)+1);
627 			zone->filename = region_strdup(nsd->db->region, fname);
628 			if(zone->logstr)
629 				region_recycle(nsd->db->region, zone->logstr,
630 					strlen(zone->logstr)+1);
631 			zone->logstr = NULL;
632 		}
633 	}
634 	if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0);
635 #ifdef NSEC3
636 	prehash_zone_complete(nsd->db, zone);
637 #endif
638 }
639 
640 void namedb_check_zonefile(struct nsd* nsd, udb_base* taskudb,
641 	udb_ptr* last_task, zone_options_t* zopt)
642 {
643 	zone_type* zone;
644 	const dname_type* dname = (const dname_type*)zopt->node.key;
645 	/* find zone to go with it, or create it */
646 	zone = namedb_find_zone(nsd->db, dname);
647 	if(!zone) {
648 		zone = namedb_zone_create(nsd->db, dname, zopt);
649 	}
650 	namedb_read_zonefile(nsd, zone, taskudb, last_task);
651 }
652 
653 void namedb_check_zonefiles(struct nsd* nsd, nsd_options_t* opt,
654 	udb_base* taskudb, udb_ptr* last_task)
655 {
656 	zone_options_t* zo;
657 	/* check all zones in opt, create if not exist in main db */
658 	RBTREE_FOR(zo, zone_options_t*, opt->zone_options) {
659 		namedb_check_zonefile(nsd, taskudb, last_task, zo);
660 		if(nsd->signal_hint_shutdown) break;
661 	}
662 }
663