db.c revision 170222
1/* 2 * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2001, 2003 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: db.c,v 1.74.18.6 2005/10/13 02:12:24 marka Exp $ */ 19 20/*! \file */ 21 22/*** 23 *** Imports 24 ***/ 25 26#include <config.h> 27 28#include <isc/buffer.h> 29#include <isc/mem.h> 30#include <isc/once.h> 31#include <isc/rwlock.h> 32#include <isc/string.h> 33#include <isc/util.h> 34 35#include <dns/callbacks.h> 36#include <dns/db.h> 37#include <dns/log.h> 38#include <dns/master.h> 39#include <dns/rdata.h> 40#include <dns/rdataset.h> 41#include <dns/result.h> 42 43/*** 44 *** Private Types 45 ***/ 46 47struct dns_dbimplementation { 48 const char * name; 49 dns_dbcreatefunc_t create; 50 isc_mem_t * mctx; 51 void * driverarg; 52 ISC_LINK(dns_dbimplementation_t) link; 53}; 54 55/*** 56 *** Supported DB Implementations Registry 57 ***/ 58 59/* 60 * Built in database implementations are registered here. 61 */ 62 63#include "rbtdb.h" 64#include "rbtdb64.h" 65 66static ISC_LIST(dns_dbimplementation_t) implementations; 67static isc_rwlock_t implock; 68static isc_once_t once = ISC_ONCE_INIT; 69 70static dns_dbimplementation_t rbtimp; 71static dns_dbimplementation_t rbt64imp; 72 73static void 74initialize(void) { 75 RUNTIME_CHECK(isc_rwlock_init(&implock, 0, 0) == ISC_R_SUCCESS); 76 77 rbtimp.name = "rbt"; 78 rbtimp.create = dns_rbtdb_create; 79 rbtimp.mctx = NULL; 80 rbtimp.driverarg = NULL; 81 ISC_LINK_INIT(&rbtimp, link); 82 83 rbt64imp.name = "rbt64"; 84 rbt64imp.create = dns_rbtdb64_create; 85 rbt64imp.mctx = NULL; 86 rbt64imp.driverarg = NULL; 87 ISC_LINK_INIT(&rbt64imp, link); 88 89 ISC_LIST_INIT(implementations); 90 ISC_LIST_APPEND(implementations, &rbtimp, link); 91 ISC_LIST_APPEND(implementations, &rbt64imp, link); 92} 93 94static inline dns_dbimplementation_t * 95impfind(const char *name) { 96 dns_dbimplementation_t *imp; 97 98 for (imp = ISC_LIST_HEAD(implementations); 99 imp != NULL; 100 imp = ISC_LIST_NEXT(imp, link)) 101 if (strcasecmp(name, imp->name) == 0) 102 return (imp); 103 return (NULL); 104} 105 106 107/*** 108 *** Basic DB Methods 109 ***/ 110 111isc_result_t 112dns_db_create(isc_mem_t *mctx, const char *db_type, dns_name_t *origin, 113 dns_dbtype_t type, dns_rdataclass_t rdclass, 114 unsigned int argc, char *argv[], dns_db_t **dbp) 115{ 116 dns_dbimplementation_t *impinfo; 117 118 RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); 119 120 /* 121 * Create a new database using implementation 'db_type'. 122 */ 123 124 REQUIRE(dbp != NULL && *dbp == NULL); 125 REQUIRE(dns_name_isabsolute(origin)); 126 127 RWLOCK(&implock, isc_rwlocktype_read); 128 impinfo = impfind(db_type); 129 if (impinfo != NULL) { 130 isc_result_t result; 131 result = ((impinfo->create)(mctx, origin, type, 132 rdclass, argc, argv, 133 impinfo->driverarg, dbp)); 134 RWUNLOCK(&implock, isc_rwlocktype_read); 135 return (result); 136 } 137 138 RWUNLOCK(&implock, isc_rwlocktype_read); 139 140 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, 141 DNS_LOGMODULE_DB, ISC_LOG_ERROR, 142 "unsupported database type '%s'", db_type); 143 144 return (ISC_R_NOTFOUND); 145} 146 147void 148dns_db_attach(dns_db_t *source, dns_db_t **targetp) { 149 150 /* 151 * Attach *targetp to source. 152 */ 153 154 REQUIRE(DNS_DB_VALID(source)); 155 REQUIRE(targetp != NULL && *targetp == NULL); 156 157 (source->methods->attach)(source, targetp); 158 159 ENSURE(*targetp == source); 160} 161 162void 163dns_db_detach(dns_db_t **dbp) { 164 165 /* 166 * Detach *dbp from its database. 167 */ 168 169 REQUIRE(dbp != NULL); 170 REQUIRE(DNS_DB_VALID(*dbp)); 171 172 ((*dbp)->methods->detach)(dbp); 173 174 ENSURE(*dbp == NULL); 175} 176 177isc_result_t 178dns_db_ondestroy(dns_db_t *db, isc_task_t *task, isc_event_t **eventp) 179{ 180 REQUIRE(DNS_DB_VALID(db)); 181 182 return (isc_ondestroy_register(&db->ondest, task, eventp)); 183} 184 185 186isc_boolean_t 187dns_db_iscache(dns_db_t *db) { 188 189 /* 190 * Does 'db' have cache semantics? 191 */ 192 193 REQUIRE(DNS_DB_VALID(db)); 194 195 if ((db->attributes & DNS_DBATTR_CACHE) != 0) 196 return (ISC_TRUE); 197 198 return (ISC_FALSE); 199} 200 201isc_boolean_t 202dns_db_iszone(dns_db_t *db) { 203 204 /* 205 * Does 'db' have zone semantics? 206 */ 207 208 REQUIRE(DNS_DB_VALID(db)); 209 210 if ((db->attributes & (DNS_DBATTR_CACHE|DNS_DBATTR_STUB)) == 0) 211 return (ISC_TRUE); 212 213 return (ISC_FALSE); 214} 215 216isc_boolean_t 217dns_db_isstub(dns_db_t *db) { 218 219 /* 220 * Does 'db' have stub semantics? 221 */ 222 223 REQUIRE(DNS_DB_VALID(db)); 224 225 if ((db->attributes & DNS_DBATTR_STUB) != 0) 226 return (ISC_TRUE); 227 228 return (ISC_FALSE); 229} 230 231isc_boolean_t 232dns_db_issecure(dns_db_t *db) { 233 234 /* 235 * Is 'db' secure? 236 */ 237 238 REQUIRE(DNS_DB_VALID(db)); 239 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0); 240 241 return ((db->methods->issecure)(db)); 242} 243 244isc_boolean_t 245dns_db_ispersistent(dns_db_t *db) { 246 247 /* 248 * Is 'db' persistent? 249 */ 250 251 REQUIRE(DNS_DB_VALID(db)); 252 253 return ((db->methods->ispersistent)(db)); 254} 255 256dns_name_t * 257dns_db_origin(dns_db_t *db) { 258 /* 259 * The origin of the database. 260 */ 261 262 REQUIRE(DNS_DB_VALID(db)); 263 264 return (&db->origin); 265} 266 267dns_rdataclass_t 268dns_db_class(dns_db_t *db) { 269 /* 270 * The class of the database. 271 */ 272 273 REQUIRE(DNS_DB_VALID(db)); 274 275 return (db->rdclass); 276} 277 278isc_result_t 279dns_db_beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, 280 dns_dbload_t **dbloadp) { 281 /* 282 * Begin loading 'db'. 283 */ 284 285 REQUIRE(DNS_DB_VALID(db)); 286 REQUIRE(addp != NULL && *addp == NULL); 287 REQUIRE(dbloadp != NULL && *dbloadp == NULL); 288 289 return ((db->methods->beginload)(db, addp, dbloadp)); 290} 291 292isc_result_t 293dns_db_endload(dns_db_t *db, dns_dbload_t **dbloadp) { 294 /* 295 * Finish loading 'db'. 296 */ 297 298 REQUIRE(DNS_DB_VALID(db)); 299 REQUIRE(dbloadp != NULL && *dbloadp != NULL); 300 301 return ((db->methods->endload)(db, dbloadp)); 302} 303 304isc_result_t 305dns_db_load(dns_db_t *db, const char *filename) { 306 return (dns_db_load2(db, filename, dns_masterformat_text)); 307} 308 309isc_result_t 310dns_db_load2(dns_db_t *db, const char *filename, dns_masterformat_t format) { 311 isc_result_t result, eresult; 312 dns_rdatacallbacks_t callbacks; 313 unsigned int options = 0; 314 315 /* 316 * Load master file 'filename' into 'db'. 317 */ 318 319 REQUIRE(DNS_DB_VALID(db)); 320 321 if ((db->attributes & DNS_DBATTR_CACHE) != 0) 322 options |= DNS_MASTER_AGETTL; 323 324 dns_rdatacallbacks_init(&callbacks); 325 326 result = dns_db_beginload(db, &callbacks.add, &callbacks.add_private); 327 if (result != ISC_R_SUCCESS) 328 return (result); 329 result = dns_master_loadfile2(filename, &db->origin, &db->origin, 330 db->rdclass, options, 331 &callbacks, db->mctx, format); 332 eresult = dns_db_endload(db, &callbacks.add_private); 333 /* 334 * We always call dns_db_endload(), but we only want to return its 335 * result if dns_master_loadfile() succeeded. If dns_master_loadfile() 336 * failed, we want to return the result code it gave us. 337 */ 338 if (eresult != ISC_R_SUCCESS && 339 (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE)) 340 result = eresult; 341 342 return (result); 343} 344 345isc_result_t 346dns_db_dump(dns_db_t *db, dns_dbversion_t *version, const char *filename) { 347 return ((db->methods->dump)(db, version, filename, 348 dns_masterformat_text)); 349} 350 351isc_result_t 352dns_db_dump2(dns_db_t *db, dns_dbversion_t *version, const char *filename, 353 dns_masterformat_t masterformat) { 354 /* 355 * Dump 'db' into master file 'filename' in the 'masterformat' format. 356 * XXXJT: is it okay to modify the interface to the existing "dump" 357 * method? 358 */ 359 360 REQUIRE(DNS_DB_VALID(db)); 361 362 return ((db->methods->dump)(db, version, filename, masterformat)); 363} 364 365/*** 366 *** Version Methods 367 ***/ 368 369void 370dns_db_currentversion(dns_db_t *db, dns_dbversion_t **versionp) { 371 372 /* 373 * Open the current version for reading. 374 */ 375 376 REQUIRE(DNS_DB_VALID(db)); 377 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0); 378 REQUIRE(versionp != NULL && *versionp == NULL); 379 380 (db->methods->currentversion)(db, versionp); 381} 382 383isc_result_t 384dns_db_newversion(dns_db_t *db, dns_dbversion_t **versionp) { 385 386 /* 387 * Open a new version for reading and writing. 388 */ 389 390 REQUIRE(DNS_DB_VALID(db)); 391 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0); 392 REQUIRE(versionp != NULL && *versionp == NULL); 393 394 return ((db->methods->newversion)(db, versionp)); 395} 396 397void 398dns_db_attachversion(dns_db_t *db, dns_dbversion_t *source, 399 dns_dbversion_t **targetp) 400{ 401 /* 402 * Attach '*targetp' to 'source'. 403 */ 404 405 REQUIRE(DNS_DB_VALID(db)); 406 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0); 407 REQUIRE(source != NULL); 408 REQUIRE(targetp != NULL && *targetp == NULL); 409 410 (db->methods->attachversion)(db, source, targetp); 411 412 ENSURE(*targetp != NULL); 413} 414 415void 416dns_db_closeversion(dns_db_t *db, dns_dbversion_t **versionp, 417 isc_boolean_t commit) 418{ 419 420 /* 421 * Close version '*versionp'. 422 */ 423 424 REQUIRE(DNS_DB_VALID(db)); 425 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0); 426 REQUIRE(versionp != NULL && *versionp != NULL); 427 428 (db->methods->closeversion)(db, versionp, commit); 429 430 ENSURE(*versionp == NULL); 431} 432 433/*** 434 *** Node Methods 435 ***/ 436 437isc_result_t 438dns_db_findnode(dns_db_t *db, dns_name_t *name, 439 isc_boolean_t create, dns_dbnode_t **nodep) 440{ 441 442 /* 443 * Find the node with name 'name'. 444 */ 445 446 REQUIRE(DNS_DB_VALID(db)); 447 REQUIRE(nodep != NULL && *nodep == NULL); 448 449 return ((db->methods->findnode)(db, name, create, nodep)); 450} 451 452isc_result_t 453dns_db_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, 454 dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, 455 dns_dbnode_t **nodep, dns_name_t *foundname, 456 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) 457{ 458 459 /* 460 * Find the best match for 'name' and 'type' in version 'version' 461 * of 'db'. 462 */ 463 464 REQUIRE(DNS_DB_VALID(db)); 465 REQUIRE(type != dns_rdatatype_rrsig); 466 REQUIRE(nodep == NULL || (nodep != NULL && *nodep == NULL)); 467 REQUIRE(dns_name_hasbuffer(foundname)); 468 REQUIRE(rdataset == NULL || 469 (DNS_RDATASET_VALID(rdataset) && 470 ! dns_rdataset_isassociated(rdataset))); 471 REQUIRE(sigrdataset == NULL || 472 (DNS_RDATASET_VALID(sigrdataset) && 473 ! dns_rdataset_isassociated(sigrdataset))); 474 475 return ((db->methods->find)(db, name, version, type, options, now, 476 nodep, foundname, rdataset, sigrdataset)); 477} 478 479isc_result_t 480dns_db_findzonecut(dns_db_t *db, dns_name_t *name, 481 unsigned int options, isc_stdtime_t now, 482 dns_dbnode_t **nodep, dns_name_t *foundname, 483 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) 484{ 485 /* 486 * Find the deepest known zonecut which encloses 'name' in 'db'. 487 */ 488 489 REQUIRE(DNS_DB_VALID(db)); 490 REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0); 491 REQUIRE(nodep == NULL || (nodep != NULL && *nodep == NULL)); 492 REQUIRE(dns_name_hasbuffer(foundname)); 493 REQUIRE(sigrdataset == NULL || 494 (DNS_RDATASET_VALID(sigrdataset) && 495 ! dns_rdataset_isassociated(sigrdataset))); 496 497 return ((db->methods->findzonecut)(db, name, options, now, nodep, 498 foundname, rdataset, sigrdataset)); 499} 500 501void 502dns_db_attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) { 503 504 /* 505 * Attach *targetp to source. 506 */ 507 508 REQUIRE(DNS_DB_VALID(db)); 509 REQUIRE(source != NULL); 510 REQUIRE(targetp != NULL && *targetp == NULL); 511 512 (db->methods->attachnode)(db, source, targetp); 513} 514 515void 516dns_db_detachnode(dns_db_t *db, dns_dbnode_t **nodep) { 517 518 /* 519 * Detach *nodep from its node. 520 */ 521 522 REQUIRE(DNS_DB_VALID(db)); 523 REQUIRE(nodep != NULL && *nodep != NULL); 524 525 (db->methods->detachnode)(db, nodep); 526 527 ENSURE(*nodep == NULL); 528} 529 530isc_result_t 531dns_db_expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) { 532 533 /* 534 * Mark as stale all records at 'node' which expire at or before 'now'. 535 */ 536 537 REQUIRE(DNS_DB_VALID(db)); 538 REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0); 539 REQUIRE(node != NULL); 540 541 return ((db->methods->expirenode)(db, node, now)); 542} 543 544void 545dns_db_printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) { 546 /* 547 * Print a textual representation of the contents of the node to 548 * 'out'. 549 */ 550 551 REQUIRE(DNS_DB_VALID(db)); 552 REQUIRE(node != NULL); 553 554 (db->methods->printnode)(db, node, out); 555} 556 557/*** 558 *** DB Iterator Creation 559 ***/ 560 561isc_result_t 562dns_db_createiterator(dns_db_t *db, isc_boolean_t relative_names, 563 dns_dbiterator_t **iteratorp) 564{ 565 /* 566 * Create an iterator for version 'version' of 'db'. 567 */ 568 569 REQUIRE(DNS_DB_VALID(db)); 570 REQUIRE(iteratorp != NULL && *iteratorp == NULL); 571 572 return (db->methods->createiterator(db, relative_names, iteratorp)); 573} 574 575/*** 576 *** Rdataset Methods 577 ***/ 578 579isc_result_t 580dns_db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 581 dns_rdatatype_t type, dns_rdatatype_t covers, 582 isc_stdtime_t now, dns_rdataset_t *rdataset, 583 dns_rdataset_t *sigrdataset) 584{ 585 /* 586 * Search for an rdataset of type 'type' at 'node' that are in version 587 * 'version' of 'db'. If found, make 'rdataset' refer to it. 588 */ 589 590 REQUIRE(DNS_DB_VALID(db)); 591 REQUIRE(node != NULL); 592 REQUIRE(DNS_RDATASET_VALID(rdataset)); 593 REQUIRE(! dns_rdataset_isassociated(rdataset)); 594 REQUIRE(covers == 0 || type == dns_rdatatype_rrsig); 595 REQUIRE(type != dns_rdatatype_any); 596 REQUIRE(sigrdataset == NULL || 597 (DNS_RDATASET_VALID(sigrdataset) && 598 ! dns_rdataset_isassociated(sigrdataset))); 599 600 return ((db->methods->findrdataset)(db, node, version, type, covers, 601 now, rdataset, sigrdataset)); 602} 603 604isc_result_t 605dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 606 isc_stdtime_t now, dns_rdatasetiter_t **iteratorp) 607{ 608 /* 609 * Make '*iteratorp' an rdataset iteratator for all rdatasets at 610 * 'node' in version 'version' of 'db'. 611 */ 612 613 REQUIRE(DNS_DB_VALID(db)); 614 REQUIRE(iteratorp != NULL && *iteratorp == NULL); 615 616 return ((db->methods->allrdatasets)(db, node, version, now, 617 iteratorp)); 618} 619 620isc_result_t 621dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 622 isc_stdtime_t now, dns_rdataset_t *rdataset, 623 unsigned int options, dns_rdataset_t *addedrdataset) 624{ 625 /* 626 * Add 'rdataset' to 'node' in version 'version' of 'db'. 627 */ 628 629 REQUIRE(DNS_DB_VALID(db)); 630 REQUIRE(node != NULL); 631 REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL)|| 632 ((db->attributes & DNS_DBATTR_CACHE) != 0 && 633 version == NULL && (options & DNS_DBADD_MERGE) == 0)); 634 REQUIRE((options & DNS_DBADD_EXACT) == 0 || 635 (options & DNS_DBADD_MERGE) != 0); 636 REQUIRE(DNS_RDATASET_VALID(rdataset)); 637 REQUIRE(dns_rdataset_isassociated(rdataset)); 638 REQUIRE(rdataset->rdclass == db->rdclass); 639 REQUIRE(addedrdataset == NULL || 640 (DNS_RDATASET_VALID(addedrdataset) && 641 ! dns_rdataset_isassociated(addedrdataset))); 642 643 return ((db->methods->addrdataset)(db, node, version, now, rdataset, 644 options, addedrdataset)); 645} 646 647isc_result_t 648dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node, 649 dns_dbversion_t *version, dns_rdataset_t *rdataset, 650 unsigned int options, dns_rdataset_t *newrdataset) 651{ 652 /* 653 * Remove any rdata in 'rdataset' from 'node' in version 'version' of 654 * 'db'. 655 */ 656 657 REQUIRE(DNS_DB_VALID(db)); 658 REQUIRE(node != NULL); 659 REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL); 660 REQUIRE(DNS_RDATASET_VALID(rdataset)); 661 REQUIRE(dns_rdataset_isassociated(rdataset)); 662 REQUIRE(rdataset->rdclass == db->rdclass); 663 REQUIRE(newrdataset == NULL || 664 (DNS_RDATASET_VALID(newrdataset) && 665 ! dns_rdataset_isassociated(newrdataset))); 666 667 return ((db->methods->subtractrdataset)(db, node, version, rdataset, 668 options, newrdataset)); 669} 670 671isc_result_t 672dns_db_deleterdataset(dns_db_t *db, dns_dbnode_t *node, 673 dns_dbversion_t *version, dns_rdatatype_t type, 674 dns_rdatatype_t covers) 675{ 676 /* 677 * Make it so that no rdataset of type 'type' exists at 'node' in 678 * version version 'version' of 'db'. 679 */ 680 681 REQUIRE(DNS_DB_VALID(db)); 682 REQUIRE(node != NULL); 683 REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL)|| 684 ((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL)); 685 686 return ((db->methods->deleterdataset)(db, node, version, 687 type, covers)); 688} 689 690void 691dns_db_overmem(dns_db_t *db, isc_boolean_t overmem) { 692 693 REQUIRE(DNS_DB_VALID(db)); 694 695 (db->methods->overmem)(db, overmem); 696} 697 698isc_result_t 699dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, isc_uint32_t *serialp) 700{ 701 isc_result_t result; 702 dns_dbnode_t *node = NULL; 703 dns_rdataset_t rdataset; 704 dns_rdata_t rdata = DNS_RDATA_INIT; 705 isc_buffer_t buffer; 706 707 REQUIRE(dns_db_iszone(db) || dns_db_isstub(db)); 708 709 result = dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node); 710 if (result != ISC_R_SUCCESS) 711 return (result); 712 713 dns_rdataset_init(&rdataset); 714 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0, 715 (isc_stdtime_t)0, &rdataset, NULL); 716 if (result != ISC_R_SUCCESS) 717 goto freenode; 718 719 result = dns_rdataset_first(&rdataset); 720 if (result != ISC_R_SUCCESS) 721 goto freerdataset; 722 dns_rdataset_current(&rdataset, &rdata); 723 result = dns_rdataset_next(&rdataset); 724 INSIST(result == ISC_R_NOMORE); 725 726 INSIST(rdata.length > 20); 727 isc_buffer_init(&buffer, rdata.data, rdata.length); 728 isc_buffer_add(&buffer, rdata.length); 729 isc_buffer_forward(&buffer, rdata.length - 20); 730 *serialp = isc_buffer_getuint32(&buffer); 731 732 result = ISC_R_SUCCESS; 733 734 freerdataset: 735 dns_rdataset_disassociate(&rdataset); 736 737 freenode: 738 dns_db_detachnode(db, &node); 739 return (result); 740} 741 742unsigned int 743dns_db_nodecount(dns_db_t *db) { 744 REQUIRE(DNS_DB_VALID(db)); 745 746 return ((db->methods->nodecount)(db)); 747} 748 749void 750dns_db_settask(dns_db_t *db, isc_task_t *task) { 751 REQUIRE(DNS_DB_VALID(db)); 752 753 (db->methods->settask)(db, task); 754} 755 756isc_result_t 757dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg, 758 isc_mem_t *mctx, dns_dbimplementation_t **dbimp) 759{ 760 dns_dbimplementation_t *imp; 761 762 REQUIRE(name != NULL); 763 REQUIRE(dbimp != NULL && *dbimp == NULL); 764 765 RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); 766 767 RWLOCK(&implock, isc_rwlocktype_write); 768 imp = impfind(name); 769 if (imp != NULL) { 770 RWUNLOCK(&implock, isc_rwlocktype_write); 771 return (ISC_R_EXISTS); 772 } 773 774 imp = isc_mem_get(mctx, sizeof(dns_dbimplementation_t)); 775 if (imp == NULL) { 776 RWUNLOCK(&implock, isc_rwlocktype_write); 777 return (ISC_R_NOMEMORY); 778 } 779 imp->name = name; 780 imp->create = create; 781 imp->mctx = NULL; 782 imp->driverarg = driverarg; 783 isc_mem_attach(mctx, &imp->mctx); 784 ISC_LINK_INIT(imp, link); 785 ISC_LIST_APPEND(implementations, imp, link); 786 RWUNLOCK(&implock, isc_rwlocktype_write); 787 788 *dbimp = imp; 789 790 return (ISC_R_SUCCESS); 791} 792 793void 794dns_db_unregister(dns_dbimplementation_t **dbimp) { 795 dns_dbimplementation_t *imp; 796 isc_mem_t *mctx; 797 798 REQUIRE(dbimp != NULL && *dbimp != NULL); 799 800 RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); 801 802 imp = *dbimp; 803 RWLOCK(&implock, isc_rwlocktype_write); 804 ISC_LIST_UNLINK(implementations, imp, link); 805 mctx = imp->mctx; 806 isc_mem_put(mctx, imp, sizeof(dns_dbimplementation_t)); 807 isc_mem_detach(&mctx); 808 RWUNLOCK(&implock, isc_rwlocktype_write); 809} 810 811isc_result_t 812dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) { 813 REQUIRE(DNS_DB_VALID(db)); 814 REQUIRE(dns_db_iszone(db) == ISC_TRUE); 815 REQUIRE(nodep != NULL && *nodep == NULL); 816 817 if (db->methods->getoriginnode != NULL) 818 return ((db->methods->getoriginnode)(db, nodep)); 819 820 return (ISC_R_NOTFOUND); 821} 822