zt.c revision 170222
1/* 2 * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2002 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: zt.c,v 1.38.18.5 2005/11/30 03:44:39 marka Exp $ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <isc/file.h> 25#include <isc/magic.h> 26#include <isc/mem.h> 27#include <isc/string.h> 28#include <isc/util.h> 29 30#include <dns/log.h> 31#include <dns/name.h> 32#include <dns/rbt.h> 33#include <dns/rdataclass.h> 34#include <dns/result.h> 35#include <dns/view.h> 36#include <dns/zone.h> 37#include <dns/zt.h> 38 39struct dns_zt { 40 /* Unlocked. */ 41 unsigned int magic; 42 isc_mem_t *mctx; 43 dns_rdataclass_t rdclass; 44 isc_rwlock_t rwlock; 45 /* Locked by lock. */ 46 isc_uint32_t references; 47 dns_rbt_t *table; 48}; 49 50#define ZTMAGIC ISC_MAGIC('Z', 'T', 'b', 'l') 51#define VALID_ZT(zt) ISC_MAGIC_VALID(zt, ZTMAGIC) 52 53static void 54auto_detach(void *, void *); 55 56static isc_result_t 57load(dns_zone_t *zone, void *uap); 58 59static isc_result_t 60loadnew(dns_zone_t *zone, void *uap); 61 62static isc_result_t 63freezezones(dns_zone_t *zone, void *uap); 64 65isc_result_t 66dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) { 67 dns_zt_t *zt; 68 isc_result_t result; 69 70 REQUIRE(ztp != NULL && *ztp == NULL); 71 72 zt = isc_mem_get(mctx, sizeof(*zt)); 73 if (zt == NULL) 74 return (ISC_R_NOMEMORY); 75 76 zt->table = NULL; 77 result = dns_rbt_create(mctx, auto_detach, zt, &zt->table); 78 if (result != ISC_R_SUCCESS) 79 goto cleanup_zt; 80 81 result = isc_rwlock_init(&zt->rwlock, 0, 0); 82 if (result != ISC_R_SUCCESS) 83 goto cleanup_rbt; 84 85 zt->mctx = mctx; 86 zt->references = 1; 87 zt->rdclass = rdclass; 88 zt->magic = ZTMAGIC; 89 *ztp = zt; 90 91 return (ISC_R_SUCCESS); 92 93 cleanup_rbt: 94 dns_rbt_destroy(&zt->table); 95 96 cleanup_zt: 97 isc_mem_put(mctx, zt, sizeof(*zt)); 98 99 return (result); 100} 101 102isc_result_t 103dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone) { 104 isc_result_t result; 105 dns_zone_t *dummy = NULL; 106 dns_name_t *name; 107 108 REQUIRE(VALID_ZT(zt)); 109 110 name = dns_zone_getorigin(zone); 111 112 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 113 114 result = dns_rbt_addname(zt->table, name, zone); 115 if (result == ISC_R_SUCCESS) 116 dns_zone_attach(zone, &dummy); 117 118 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 119 120 return (result); 121} 122 123isc_result_t 124dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone) { 125 isc_result_t result; 126 dns_name_t *name; 127 128 REQUIRE(VALID_ZT(zt)); 129 130 name = dns_zone_getorigin(zone); 131 132 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 133 134 result = dns_rbt_deletename(zt->table, name, ISC_FALSE); 135 136 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 137 138 return (result); 139} 140 141isc_result_t 142dns_zt_find(dns_zt_t *zt, dns_name_t *name, unsigned int options, 143 dns_name_t *foundname, dns_zone_t **zonep) 144{ 145 isc_result_t result; 146 dns_zone_t *dummy = NULL; 147 unsigned int rbtoptions = 0; 148 149 REQUIRE(VALID_ZT(zt)); 150 151 if ((options & DNS_ZTFIND_NOEXACT) != 0) 152 rbtoptions |= DNS_RBTFIND_NOEXACT; 153 154 RWLOCK(&zt->rwlock, isc_rwlocktype_read); 155 156 result = dns_rbt_findname(zt->table, name, rbtoptions, foundname, 157 (void **) (void*)&dummy); 158 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) 159 dns_zone_attach(dummy, zonep); 160 161 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 162 163 return (result); 164} 165 166void 167dns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp) { 168 169 REQUIRE(VALID_ZT(zt)); 170 REQUIRE(ztp != NULL && *ztp == NULL); 171 172 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 173 174 INSIST(zt->references > 0); 175 zt->references++; 176 INSIST(zt->references != 0); 177 178 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 179 180 *ztp = zt; 181} 182 183static isc_result_t 184flush(dns_zone_t *zone, void *uap) { 185 UNUSED(uap); 186 return (dns_zone_flush(zone)); 187} 188 189static void 190zt_flushanddetach(dns_zt_t **ztp, isc_boolean_t need_flush) { 191 isc_boolean_t destroy = ISC_FALSE; 192 dns_zt_t *zt; 193 194 REQUIRE(ztp != NULL && VALID_ZT(*ztp)); 195 196 zt = *ztp; 197 198 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 199 200 INSIST(zt->references > 0); 201 zt->references--; 202 if (zt->references == 0) 203 destroy = ISC_TRUE; 204 205 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 206 207 if (destroy) { 208 if (need_flush) 209 (void)dns_zt_apply(zt, ISC_FALSE, flush, NULL); 210 dns_rbt_destroy(&zt->table); 211 isc_rwlock_destroy(&zt->rwlock); 212 zt->magic = 0; 213 isc_mem_put(zt->mctx, zt, sizeof(*zt)); 214 } 215 216 *ztp = NULL; 217} 218 219void 220dns_zt_flushanddetach(dns_zt_t **ztp) { 221 zt_flushanddetach(ztp, ISC_TRUE); 222} 223 224void 225dns_zt_detach(dns_zt_t **ztp) { 226 zt_flushanddetach(ztp, ISC_FALSE); 227} 228 229isc_result_t 230dns_zt_load(dns_zt_t *zt, isc_boolean_t stop) { 231 isc_result_t result; 232 233 REQUIRE(VALID_ZT(zt)); 234 235 RWLOCK(&zt->rwlock, isc_rwlocktype_read); 236 result = dns_zt_apply(zt, stop, load, NULL); 237 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 238 return (result); 239} 240 241static isc_result_t 242load(dns_zone_t *zone, void *uap) { 243 isc_result_t result; 244 UNUSED(uap); 245 result = dns_zone_load(zone); 246 if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE) 247 result = ISC_R_SUCCESS; 248 return (result); 249} 250 251isc_result_t 252dns_zt_loadnew(dns_zt_t *zt, isc_boolean_t stop) { 253 isc_result_t result; 254 255 REQUIRE(VALID_ZT(zt)); 256 257 RWLOCK(&zt->rwlock, isc_rwlocktype_read); 258 result = dns_zt_apply(zt, stop, loadnew, NULL); 259 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 260 return (result); 261} 262 263static isc_result_t 264loadnew(dns_zone_t *zone, void *uap) { 265 isc_result_t result; 266 UNUSED(uap); 267 result = dns_zone_loadnew(zone); 268 if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE || 269 result == DNS_R_DYNAMIC) 270 result = ISC_R_SUCCESS; 271 return (result); 272} 273 274isc_result_t 275dns_zt_freezezones(dns_zt_t *zt, isc_boolean_t freeze) { 276 isc_result_t result, tresult; 277 278 REQUIRE(VALID_ZT(zt)); 279 280 RWLOCK(&zt->rwlock, isc_rwlocktype_read); 281 result = dns_zt_apply2(zt, ISC_FALSE, &tresult, freezezones, &freeze); 282 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 283 return ((result == ISC_R_SUCCESS) ? tresult : result); 284} 285 286static isc_result_t 287freezezones(dns_zone_t *zone, void *uap) { 288 isc_boolean_t freeze = *(isc_boolean_t *)uap; 289 isc_boolean_t frozen; 290 isc_result_t result = ISC_R_SUCCESS; 291 char classstr[DNS_RDATACLASS_FORMATSIZE]; 292 char zonename[DNS_NAME_FORMATSIZE]; 293 dns_view_t *view; 294 char *journal; 295 const char *vname; 296 const char *sep; 297 int level; 298 299 if (dns_zone_gettype(zone) != dns_zone_master) 300 return (ISC_R_SUCCESS); 301 302 frozen = dns_zone_getupdatedisabled(zone); 303 if (freeze) { 304 if (frozen) 305 result = DNS_R_FROZEN; 306 if (result == ISC_R_SUCCESS) 307 result = dns_zone_flush(zone); 308 if (result == ISC_R_SUCCESS) { 309 journal = dns_zone_getjournal(zone); 310 if (journal != NULL) 311 (void)isc_file_remove(journal); 312 } 313 } else { 314 if (frozen) { 315 result = dns_zone_load(zone); 316 if (result == DNS_R_CONTINUE || 317 result == DNS_R_UPTODATE) 318 result = ISC_R_SUCCESS; 319 } 320 } 321 if (result == ISC_R_SUCCESS) 322 dns_zone_setupdatedisabled(zone, freeze); 323 view = dns_zone_getview(zone); 324 if (strcmp(view->name, "_bind") == 0 || 325 strcmp(view->name, "_default") == 0) 326 { 327 vname = ""; 328 sep = ""; 329 } else { 330 vname = view->name; 331 sep = " "; 332 } 333 dns_rdataclass_format(dns_zone_getclass(zone), classstr, 334 sizeof(classstr)); 335 dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename)); 336 level = (result != ISC_R_SUCCESS) ? ISC_LOG_ERROR : ISC_LOG_DEBUG(1); 337 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, 338 level, "%s zone '%s/%s'%s%s: %s", 339 freeze ? "freezing" : "thawing", 340 zonename, classstr, sep, vname, 341 isc_result_totext(result)); 342 return (result); 343} 344 345isc_result_t 346dns_zt_apply(dns_zt_t *zt, isc_boolean_t stop, 347 isc_result_t (*action)(dns_zone_t *, void *), void *uap) 348{ 349 return (dns_zt_apply2(zt, stop, NULL, action, uap)); 350} 351 352isc_result_t 353dns_zt_apply2(dns_zt_t *zt, isc_boolean_t stop, isc_result_t *sub, 354 isc_result_t (*action)(dns_zone_t *, void *), void *uap) 355{ 356 dns_rbtnode_t *node; 357 dns_rbtnodechain_t chain; 358 isc_result_t result, tresult = ISC_R_SUCCESS; 359 dns_zone_t *zone; 360 361 REQUIRE(VALID_ZT(zt)); 362 REQUIRE(action != NULL); 363 364 dns_rbtnodechain_init(&chain, zt->mctx); 365 result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL); 366 if (result == ISC_R_NOTFOUND) { 367 /* 368 * The tree is empty. 369 */ 370 result = ISC_R_NOMORE; 371 } 372 while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) { 373 result = dns_rbtnodechain_current(&chain, NULL, NULL, 374 &node); 375 if (result == ISC_R_SUCCESS) { 376 zone = node->data; 377 if (zone != NULL) 378 result = (action)(zone, uap); 379 if (result != ISC_R_SUCCESS && stop) { 380 tresult = result; 381 goto cleanup; /* don't break */ 382 } else if (result != ISC_R_SUCCESS && 383 tresult == ISC_R_SUCCESS) 384 tresult = result; 385 } 386 result = dns_rbtnodechain_next(&chain, NULL, NULL); 387 } 388 if (result == ISC_R_NOMORE) 389 result = ISC_R_SUCCESS; 390 391 cleanup: 392 dns_rbtnodechain_invalidate(&chain); 393 if (sub != NULL) 394 *sub = tresult; 395 396 return (result); 397} 398 399/*** 400 *** Private 401 ***/ 402 403static void 404auto_detach(void *data, void *arg) { 405 dns_zone_t *zone = data; 406 407 UNUSED(arg); 408 409 dns_zone_detach(&zone); 410} 411