1 /* $NetBSD: masterdump.c,v 1.11 2015/07/08 17:28:58 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004-2009, 2011-2015 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2003 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id */ 21 22 /*! \file */ 23 24 #include <config.h> 25 26 #include <stdlib.h> 27 28 #include <isc/event.h> 29 #include <isc/file.h> 30 #include <isc/magic.h> 31 #include <isc/mem.h> 32 #include <isc/print.h> 33 #include <isc/stdio.h> 34 #include <isc/string.h> 35 #include <isc/task.h> 36 #include <isc/time.h> 37 #include <isc/util.h> 38 39 #include <dns/db.h> 40 #include <dns/dbiterator.h> 41 #include <dns/events.h> 42 #include <dns/fixedname.h> 43 #include <dns/lib.h> 44 #include <dns/log.h> 45 #include <dns/master.h> 46 #include <dns/masterdump.h> 47 #include <dns/ncache.h> 48 #include <dns/rdata.h> 49 #include <dns/rdataclass.h> 50 #include <dns/rdataset.h> 51 #include <dns/rdatasetiter.h> 52 #include <dns/rdatatype.h> 53 #include <dns/result.h> 54 #include <dns/time.h> 55 #include <dns/ttl.h> 56 57 #define DNS_DCTX_MAGIC ISC_MAGIC('D', 'c', 't', 'x') 58 #define DNS_DCTX_VALID(d) ISC_MAGIC_VALID(d, DNS_DCTX_MAGIC) 59 60 #define RETERR(x) do { \ 61 isc_result_t _r = (x); \ 62 if (_r != ISC_R_SUCCESS) \ 63 return (_r); \ 64 } while (/*CONSTCOND*/0) 65 66 #define CHECK(x) do { \ 67 if ((x) != ISC_R_SUCCESS) \ 68 goto cleanup; \ 69 } while (/*CONSTCOND*/0) 70 71 struct dns_master_style { 72 unsigned int flags; /* DNS_STYLEFLAG_* */ 73 unsigned int ttl_column; 74 unsigned int class_column; 75 unsigned int type_column; 76 unsigned int rdata_column; 77 unsigned int line_length; 78 unsigned int tab_width; 79 unsigned int split_width; 80 }; 81 82 /*% 83 * The maximum length of the newline+indentation that is output 84 * when inserting a line break in an RR. This effectively puts an 85 * upper limits on the value of "rdata_column", because if it is 86 * very large, the tabs and spaces needed to reach it will not fit. 87 */ 88 #define DNS_TOTEXT_LINEBREAK_MAXLEN 100 89 90 /*% 91 * Context structure for a masterfile dump in progress. 92 */ 93 typedef struct dns_totext_ctx { 94 dns_master_style_t style; 95 isc_boolean_t class_printed; 96 char * linebreak; 97 char linebreak_buf[DNS_TOTEXT_LINEBREAK_MAXLEN]; 98 dns_name_t * origin; 99 dns_name_t * neworigin; 100 dns_fixedname_t origin_fixname; 101 isc_uint32_t current_ttl; 102 isc_boolean_t current_ttl_valid; 103 } dns_totext_ctx_t; 104 105 LIBDNS_EXTERNAL_DATA const dns_master_style_t 106 dns_master_style_keyzone = { 107 DNS_STYLEFLAG_OMIT_OWNER | 108 DNS_STYLEFLAG_OMIT_CLASS | 109 DNS_STYLEFLAG_REL_OWNER | 110 DNS_STYLEFLAG_REL_DATA | 111 DNS_STYLEFLAG_OMIT_TTL | 112 DNS_STYLEFLAG_TTL | 113 DNS_STYLEFLAG_COMMENT | 114 DNS_STYLEFLAG_RRCOMMENT | 115 DNS_STYLEFLAG_MULTILINE | 116 DNS_STYLEFLAG_KEYDATA, 117 24, 24, 24, 32, 80, 8, UINT_MAX 118 }; 119 120 LIBDNS_EXTERNAL_DATA const dns_master_style_t 121 dns_master_style_default = { 122 DNS_STYLEFLAG_OMIT_OWNER | 123 DNS_STYLEFLAG_OMIT_CLASS | 124 DNS_STYLEFLAG_REL_OWNER | 125 DNS_STYLEFLAG_REL_DATA | 126 DNS_STYLEFLAG_OMIT_TTL | 127 DNS_STYLEFLAG_TTL | 128 DNS_STYLEFLAG_COMMENT | 129 DNS_STYLEFLAG_RRCOMMENT | 130 DNS_STYLEFLAG_MULTILINE, 131 24, 24, 24, 32, 80, 8, UINT_MAX 132 }; 133 134 LIBDNS_EXTERNAL_DATA const dns_master_style_t 135 dns_master_style_full = { 136 DNS_STYLEFLAG_COMMENT | 137 DNS_STYLEFLAG_RESIGN, 138 46, 46, 46, 64, 120, 8, UINT_MAX 139 }; 140 141 LIBDNS_EXTERNAL_DATA const dns_master_style_t 142 dns_master_style_explicitttl = { 143 DNS_STYLEFLAG_OMIT_OWNER | 144 DNS_STYLEFLAG_OMIT_CLASS | 145 DNS_STYLEFLAG_REL_OWNER | 146 DNS_STYLEFLAG_REL_DATA | 147 DNS_STYLEFLAG_COMMENT | 148 DNS_STYLEFLAG_RRCOMMENT | 149 DNS_STYLEFLAG_MULTILINE, 150 24, 32, 32, 40, 80, 8, UINT_MAX 151 }; 152 153 LIBDNS_EXTERNAL_DATA const dns_master_style_t 154 dns_master_style_cache = { 155 DNS_STYLEFLAG_OMIT_OWNER | 156 DNS_STYLEFLAG_OMIT_CLASS | 157 DNS_STYLEFLAG_MULTILINE | 158 DNS_STYLEFLAG_RRCOMMENT | 159 DNS_STYLEFLAG_TRUST | 160 DNS_STYLEFLAG_NCACHE, 161 24, 32, 32, 40, 80, 8, UINT_MAX 162 }; 163 164 LIBDNS_EXTERNAL_DATA const dns_master_style_t 165 dns_master_style_simple = { 166 0, 167 24, 32, 32, 40, 80, 8, UINT_MAX 168 }; 169 170 /*% 171 * A style suitable for dns_rdataset_totext(). 172 */ 173 LIBDNS_EXTERNAL_DATA const dns_master_style_t 174 dns_master_style_debug = { 175 DNS_STYLEFLAG_REL_OWNER, 176 24, 32, 40, 48, 80, 8, UINT_MAX 177 }; 178 179 /*% 180 * Similar, but with each line commented out. 181 */ 182 LIBDNS_EXTERNAL_DATA const dns_master_style_t 183 dns_master_style_comment = { 184 DNS_STYLEFLAG_REL_OWNER | 185 DNS_STYLEFLAG_MULTILINE | 186 DNS_STYLEFLAG_RRCOMMENT | 187 DNS_STYLEFLAG_COMMENTDATA, 188 24, 32, 40, 48, 80, 8, UINT_MAX 189 }; 190 191 192 #define N_SPACES 10 193 static char spaces[N_SPACES+1] = " "; 194 195 #define N_TABS 10 196 static char tabs[N_TABS+1] = "\t\t\t\t\t\t\t\t\t\t"; 197 198 struct dns_dumpctx { 199 unsigned int magic; 200 isc_mem_t *mctx; 201 isc_mutex_t lock; 202 unsigned int references; 203 isc_boolean_t canceled; 204 isc_boolean_t first; 205 isc_boolean_t do_date; 206 isc_stdtime_t now; 207 FILE *f; 208 dns_db_t *db; 209 dns_dbversion_t *version; 210 dns_dbiterator_t *dbiter; 211 dns_totext_ctx_t tctx; 212 isc_task_t *task; 213 dns_dumpdonefunc_t done; 214 void *done_arg; 215 unsigned int nodes; 216 /* dns_master_dumpinc() */ 217 char *file; 218 char *tmpfile; 219 dns_masterformat_t format; 220 dns_masterrawheader_t header; 221 isc_result_t (*dumpsets)(isc_mem_t *mctx, dns_name_t *name, 222 dns_rdatasetiter_t *rdsiter, 223 dns_totext_ctx_t *ctx, 224 isc_buffer_t *buffer, FILE *f); 225 }; 226 227 #define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) 228 229 /*% 230 * Output tabs and spaces to go from column '*current' to 231 * column 'to', and update '*current' to reflect the new 232 * current column. 233 */ 234 static isc_result_t 235 indent(unsigned int *current, unsigned int to, int tabwidth, 236 isc_buffer_t *target) 237 { 238 isc_region_t r; 239 unsigned char *p; 240 unsigned int from; 241 int ntabs, nspaces, t; 242 243 from = *current; 244 245 if (to < from + 1) 246 to = from + 1; 247 248 ntabs = to / tabwidth - from / tabwidth; 249 if (ntabs < 0) 250 ntabs = 0; 251 252 if (ntabs > 0) { 253 isc_buffer_availableregion(target, &r); 254 if (r.length < (unsigned) ntabs) 255 return (ISC_R_NOSPACE); 256 p = r.base; 257 258 t = ntabs; 259 while (t) { 260 int n = t; 261 if (n > N_TABS) 262 n = N_TABS; 263 memmove(p, tabs, n); 264 p += n; 265 t -= n; 266 } 267 isc_buffer_add(target, ntabs); 268 from = (to / tabwidth) * tabwidth; 269 } 270 271 nspaces = to - from; 272 INSIST(nspaces >= 0); 273 274 isc_buffer_availableregion(target, &r); 275 if (r.length < (unsigned) nspaces) 276 return (ISC_R_NOSPACE); 277 p = r.base; 278 279 t = nspaces; 280 while (t) { 281 int n = t; 282 if (n > N_SPACES) 283 n = N_SPACES; 284 memmove(p, spaces, n); 285 p += n; 286 t -= n; 287 } 288 isc_buffer_add(target, nspaces); 289 290 *current = to; 291 return (ISC_R_SUCCESS); 292 } 293 294 static isc_result_t 295 totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) { 296 isc_result_t result; 297 298 REQUIRE(style->tab_width != 0); 299 300 ctx->style = *style; 301 ctx->class_printed = ISC_FALSE; 302 303 dns_fixedname_init(&ctx->origin_fixname); 304 305 /* 306 * Set up the line break string if needed. 307 */ 308 if ((ctx->style.flags & DNS_STYLEFLAG_MULTILINE) != 0) { 309 isc_buffer_t buf; 310 isc_region_t r; 311 unsigned int col = 0; 312 313 isc_buffer_init(&buf, ctx->linebreak_buf, 314 sizeof(ctx->linebreak_buf)); 315 316 isc_buffer_availableregion(&buf, &r); 317 if (r.length < 1) 318 return (DNS_R_TEXTTOOLONG); 319 r.base[0] = '\n'; 320 isc_buffer_add(&buf, 1); 321 322 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0) { 323 isc_buffer_availableregion(&buf, &r); 324 if (r.length < 1) 325 return (DNS_R_TEXTTOOLONG); 326 r.base[0] = ';'; 327 isc_buffer_add(&buf, 1); 328 } 329 330 result = indent(&col, ctx->style.rdata_column, 331 ctx->style.tab_width, &buf); 332 /* 333 * Do not return ISC_R_NOSPACE if the line break string 334 * buffer is too small, because that would just make 335 * dump_rdataset() retry indefinitely with ever 336 * bigger target buffers. That's a different buffer, 337 * so it won't help. Use DNS_R_TEXTTOOLONG as a substitute. 338 */ 339 if (result == ISC_R_NOSPACE) 340 return (DNS_R_TEXTTOOLONG); 341 if (result != ISC_R_SUCCESS) 342 return (result); 343 344 isc_buffer_availableregion(&buf, &r); 345 if (r.length < 1) 346 return (DNS_R_TEXTTOOLONG); 347 r.base[0] = '\0'; 348 isc_buffer_add(&buf, 1); 349 ctx->linebreak = ctx->linebreak_buf; 350 } else { 351 ctx->linebreak = NULL; 352 } 353 354 ctx->origin = NULL; 355 ctx->neworigin = NULL; 356 ctx->current_ttl = 0; 357 ctx->current_ttl_valid = ISC_FALSE; 358 359 return (ISC_R_SUCCESS); 360 } 361 362 #define INDENT_TO(col) \ 363 do { \ 364 if ((result = indent(&column, ctx->style.col, \ 365 ctx->style.tab_width, target)) \ 366 != ISC_R_SUCCESS) \ 367 return (result); \ 368 } while (/*CONSTCOND*/0) 369 370 371 static isc_result_t 372 str_totext(const char *source, isc_buffer_t *target) { 373 unsigned int l; 374 isc_region_t region; 375 376 isc_buffer_availableregion(target, ®ion); 377 l = strlen(source); 378 379 if (l > region.length) 380 return (ISC_R_NOSPACE); 381 382 memmove(region.base, source, l); 383 isc_buffer_add(target, l); 384 return (ISC_R_SUCCESS); 385 } 386 387 static isc_result_t 388 ncache_summary(dns_rdataset_t *rdataset, isc_boolean_t omit_final_dot, 389 isc_buffer_t *target) 390 { 391 isc_result_t result = ISC_R_SUCCESS; 392 dns_rdataset_t rds; 393 dns_name_t name; 394 395 dns_rdataset_init(&rds); 396 dns_name_init(&name, NULL); 397 398 do { 399 dns_ncache_current(rdataset, &name, &rds); 400 for (result = dns_rdataset_first(&rds); 401 result == ISC_R_SUCCESS; 402 result = dns_rdataset_next(&rds)) { 403 CHECK(str_totext("; ", target)); 404 CHECK(dns_name_totext(&name, omit_final_dot, target)); 405 CHECK(str_totext(" ", target)); 406 CHECK(dns_rdatatype_totext(rds.type, target)); 407 if (rds.type == dns_rdatatype_rrsig) { 408 CHECK(str_totext(" ", target)); 409 CHECK(dns_rdatatype_totext(rds.covers, target)); 410 CHECK(str_totext(" ...\n", target)); 411 } else { 412 dns_rdata_t rdata = DNS_RDATA_INIT; 413 dns_rdataset_current(&rds, &rdata); 414 CHECK(str_totext(" ", target)); 415 CHECK(dns_rdata_tofmttext(&rdata, dns_rootname, 416 0, 0, 0, " ", target)); 417 CHECK(str_totext("\n", target)); 418 } 419 } 420 dns_rdataset_disassociate(&rds); 421 result = dns_rdataset_next(rdataset); 422 } while (result == ISC_R_SUCCESS); 423 424 if (result == ISC_R_NOMORE) 425 result = ISC_R_SUCCESS; 426 cleanup: 427 if (dns_rdataset_isassociated(&rds)) 428 dns_rdataset_disassociate(&rds); 429 430 return (result); 431 } 432 433 /* 434 * Convert 'rdataset' to master file text format according to 'ctx', 435 * storing the result in 'target'. If 'owner_name' is NULL, it 436 * is omitted; otherwise 'owner_name' must be valid and have at least 437 * one label. 438 */ 439 440 static isc_result_t 441 rdataset_totext(dns_rdataset_t *rdataset, 442 dns_name_t *owner_name, 443 dns_totext_ctx_t *ctx, 444 isc_boolean_t omit_final_dot, 445 isc_buffer_t *target) 446 { 447 isc_result_t result; 448 unsigned int column; 449 isc_boolean_t first = ISC_TRUE; 450 isc_uint32_t current_ttl; 451 isc_boolean_t current_ttl_valid; 452 dns_rdatatype_t type; 453 unsigned int type_start; 454 455 REQUIRE(DNS_RDATASET_VALID(rdataset)); 456 457 rdataset->attributes |= DNS_RDATASETATTR_LOADORDER; 458 result = dns_rdataset_first(rdataset); 459 460 current_ttl = ctx->current_ttl; 461 current_ttl_valid = ctx->current_ttl_valid; 462 463 while (result == ISC_R_SUCCESS) { 464 column = 0; 465 466 /* 467 * Comment? 468 */ 469 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0) 470 RETERR(str_totext(";", target)); 471 472 /* 473 * Owner name. 474 */ 475 if (owner_name != NULL && 476 ! ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0 && 477 !first)) 478 { 479 unsigned int name_start = target->used; 480 RETERR(dns_name_totext(owner_name, 481 omit_final_dot, 482 target)); 483 column += target->used - name_start; 484 } 485 486 /* 487 * TTL. 488 */ 489 if ((ctx->style.flags & DNS_STYLEFLAG_NO_TTL) == 0 && 490 !((ctx->style.flags & DNS_STYLEFLAG_OMIT_TTL) != 0 && 491 current_ttl_valid && 492 rdataset->ttl == current_ttl)) 493 { 494 char ttlbuf[64]; 495 isc_region_t r; 496 unsigned int length; 497 498 INDENT_TO(ttl_column); 499 length = snprintf(ttlbuf, sizeof(ttlbuf), "%u", 500 rdataset->ttl); 501 INSIST(length <= sizeof(ttlbuf)); 502 isc_buffer_availableregion(target, &r); 503 if (r.length < length) 504 return (ISC_R_NOSPACE); 505 memmove(r.base, ttlbuf, length); 506 isc_buffer_add(target, length); 507 column += length; 508 509 /* 510 * If the $TTL directive is not in use, the TTL we 511 * just printed becomes the default for subsequent RRs. 512 */ 513 if ((ctx->style.flags & DNS_STYLEFLAG_TTL) == 0) { 514 current_ttl = rdataset->ttl; 515 current_ttl_valid = ISC_TRUE; 516 } 517 } 518 519 /* 520 * Class. 521 */ 522 if ((ctx->style.flags & DNS_STYLEFLAG_NO_CLASS) == 0 && 523 ((ctx->style.flags & DNS_STYLEFLAG_OMIT_CLASS) == 0 || 524 ctx->class_printed == ISC_FALSE)) 525 { 526 unsigned int class_start; 527 INDENT_TO(class_column); 528 class_start = target->used; 529 result = dns_rdataclass_totext(rdataset->rdclass, 530 target); 531 if (result != ISC_R_SUCCESS) 532 return (result); 533 column += (target->used - class_start); 534 } 535 536 /* 537 * Type. 538 */ 539 540 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) { 541 type = rdataset->covers; 542 } else { 543 type = rdataset->type; 544 } 545 546 INDENT_TO(type_column); 547 type_start = target->used; 548 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) 549 RETERR(str_totext("\\-", target)); 550 switch (type) { 551 case dns_rdatatype_keydata: 552 #define KEYDATA "KEYDATA" 553 if ((ctx->style.flags & DNS_STYLEFLAG_KEYDATA) != 0) { 554 if (isc_buffer_availablelength(target) < 555 (sizeof(KEYDATA) - 1)) 556 return (ISC_R_NOSPACE); 557 isc_buffer_putstr(target, KEYDATA); 558 break; 559 } 560 /* FALLTHROUGH */ 561 default: 562 result = dns_rdatatype_totext(type, target); 563 if (result != ISC_R_SUCCESS) 564 return (result); 565 } 566 column += (target->used - type_start); 567 568 /* 569 * Rdata. 570 */ 571 INDENT_TO(rdata_column); 572 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) { 573 if (NXDOMAIN(rdataset)) 574 RETERR(str_totext(";-$NXDOMAIN\n", target)); 575 else 576 RETERR(str_totext(";-$NXRRSET\n", target)); 577 /* 578 * Print a summary of the cached records which make 579 * up the negative response. 580 */ 581 RETERR(ncache_summary(rdataset, omit_final_dot, 582 target)); 583 break; 584 } else { 585 dns_rdata_t rdata = DNS_RDATA_INIT; 586 isc_region_t r; 587 588 dns_rdataset_current(rdataset, &rdata); 589 590 RETERR(dns_rdata_tofmttext(&rdata, 591 ctx->origin, 592 ctx->style.flags, 593 ctx->style.line_length - 594 ctx->style.rdata_column, 595 ctx->style.split_width, 596 ctx->linebreak, 597 target)); 598 599 isc_buffer_availableregion(target, &r); 600 if (r.length < 1) 601 return (ISC_R_NOSPACE); 602 r.base[0] = '\n'; 603 isc_buffer_add(target, 1); 604 } 605 606 first = ISC_FALSE; 607 result = dns_rdataset_next(rdataset); 608 } 609 610 if (result != ISC_R_NOMORE) 611 return (result); 612 613 /* 614 * Update the ctx state to reflect what we just printed. 615 * This is done last, only when we are sure we will return 616 * success, because this function may be called multiple 617 * times with increasing buffer sizes until it succeeds, 618 * and failed attempts must not update the state prematurely. 619 */ 620 ctx->class_printed = ISC_TRUE; 621 ctx->current_ttl= current_ttl; 622 ctx->current_ttl_valid = current_ttl_valid; 623 624 return (ISC_R_SUCCESS); 625 } 626 627 /* 628 * Print the name, type, and class of an empty rdataset, 629 * such as those used to represent the question section 630 * of a DNS message. 631 */ 632 static isc_result_t 633 question_totext(dns_rdataset_t *rdataset, 634 dns_name_t *owner_name, 635 dns_totext_ctx_t *ctx, 636 isc_boolean_t omit_final_dot, 637 isc_buffer_t *target) 638 { 639 unsigned int column; 640 isc_result_t result; 641 isc_region_t r; 642 643 REQUIRE(DNS_RDATASET_VALID(rdataset)); 644 result = dns_rdataset_first(rdataset); 645 REQUIRE(result == ISC_R_NOMORE); 646 647 column = 0; 648 649 /* Owner name */ 650 { 651 unsigned int name_start = target->used; 652 RETERR(dns_name_totext(owner_name, 653 omit_final_dot, 654 target)); 655 column += target->used - name_start; 656 } 657 658 /* Class */ 659 { 660 unsigned int class_start; 661 INDENT_TO(class_column); 662 class_start = target->used; 663 result = dns_rdataclass_totext(rdataset->rdclass, target); 664 if (result != ISC_R_SUCCESS) 665 return (result); 666 column += (target->used - class_start); 667 } 668 669 /* Type */ 670 { 671 unsigned int type_start; 672 INDENT_TO(type_column); 673 type_start = target->used; 674 result = dns_rdatatype_totext(rdataset->type, target); 675 if (result != ISC_R_SUCCESS) 676 return (result); 677 column += (target->used - type_start); 678 } 679 680 isc_buffer_availableregion(target, &r); 681 if (r.length < 1) 682 return (ISC_R_NOSPACE); 683 r.base[0] = '\n'; 684 isc_buffer_add(target, 1); 685 686 return (ISC_R_SUCCESS); 687 } 688 689 isc_result_t 690 dns_rdataset_totext(dns_rdataset_t *rdataset, 691 dns_name_t *owner_name, 692 isc_boolean_t omit_final_dot, 693 isc_boolean_t question, 694 isc_buffer_t *target) 695 { 696 dns_totext_ctx_t ctx; 697 isc_result_t result; 698 result = totext_ctx_init(&dns_master_style_debug, &ctx); 699 if (result != ISC_R_SUCCESS) { 700 UNEXPECTED_ERROR(__FILE__, __LINE__, 701 "could not set master file style"); 702 return (ISC_R_UNEXPECTED); 703 } 704 705 /* 706 * The caller might want to give us an empty owner 707 * name (e.g. if they are outputting into a master 708 * file and this rdataset has the same name as the 709 * previous one.) 710 */ 711 if (dns_name_countlabels(owner_name) == 0) 712 owner_name = NULL; 713 714 if (question) 715 return (question_totext(rdataset, owner_name, &ctx, 716 omit_final_dot, target)); 717 else 718 return (rdataset_totext(rdataset, owner_name, &ctx, 719 omit_final_dot, target)); 720 } 721 722 isc_result_t 723 dns_master_rdatasettotext(dns_name_t *owner_name, 724 dns_rdataset_t *rdataset, 725 const dns_master_style_t *style, 726 isc_buffer_t *target) 727 { 728 dns_totext_ctx_t ctx; 729 isc_result_t result; 730 result = totext_ctx_init(style, &ctx); 731 if (result != ISC_R_SUCCESS) { 732 UNEXPECTED_ERROR(__FILE__, __LINE__, 733 "could not set master file style"); 734 return (ISC_R_UNEXPECTED); 735 } 736 737 return (rdataset_totext(rdataset, owner_name, &ctx, 738 ISC_FALSE, target)); 739 } 740 741 isc_result_t 742 dns_master_questiontotext(dns_name_t *owner_name, 743 dns_rdataset_t *rdataset, 744 const dns_master_style_t *style, 745 isc_buffer_t *target) 746 { 747 dns_totext_ctx_t ctx; 748 isc_result_t result; 749 result = totext_ctx_init(style, &ctx); 750 if (result != ISC_R_SUCCESS) { 751 UNEXPECTED_ERROR(__FILE__, __LINE__, 752 "could not set master file style"); 753 return (ISC_R_UNEXPECTED); 754 } 755 756 return (question_totext(rdataset, owner_name, &ctx, 757 ISC_FALSE, target)); 758 } 759 760 /* 761 * Print an rdataset. 'buffer' is a scratch buffer, which must have been 762 * dynamically allocated by the caller. It must be large enough to 763 * hold the result from dns_ttl_totext(). If more than that is needed, 764 * the buffer will be grown automatically. 765 */ 766 767 static isc_result_t 768 dump_rdataset(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset, 769 dns_totext_ctx_t *ctx, 770 isc_buffer_t *buffer, FILE *f) 771 { 772 isc_region_t r; 773 isc_result_t result; 774 775 REQUIRE(buffer->length > 0); 776 777 /* 778 * Output a $TTL directive if needed. 779 */ 780 781 if ((ctx->style.flags & DNS_STYLEFLAG_TTL) != 0) { 782 if (ctx->current_ttl_valid == ISC_FALSE || 783 ctx->current_ttl != rdataset->ttl) 784 { 785 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENT) != 0) 786 { 787 isc_buffer_clear(buffer); 788 result = dns_ttl_totext(rdataset->ttl, 789 ISC_TRUE, buffer); 790 INSIST(result == ISC_R_SUCCESS); 791 isc_buffer_usedregion(buffer, &r); 792 fprintf(f, "$TTL %u\t; %.*s\n", rdataset->ttl, 793 (int) r.length, (char *) r.base); 794 } else { 795 fprintf(f, "$TTL %u\n", rdataset->ttl); 796 } 797 ctx->current_ttl = rdataset->ttl; 798 ctx->current_ttl_valid = ISC_TRUE; 799 } 800 } 801 802 isc_buffer_clear(buffer); 803 804 /* 805 * Generate the text representation of the rdataset into 806 * the buffer. If the buffer is too small, grow it. 807 */ 808 for (;;) { 809 int newlength; 810 void *newmem; 811 result = rdataset_totext(rdataset, name, ctx, 812 ISC_FALSE, buffer); 813 if (result != ISC_R_NOSPACE) 814 break; 815 816 newlength = buffer->length * 2; 817 newmem = isc_mem_get(mctx, newlength); 818 if (newmem == NULL) 819 return (ISC_R_NOMEMORY); 820 isc_mem_put(mctx, buffer->base, buffer->length); 821 isc_buffer_init(buffer, newmem, newlength); 822 } 823 if (result != ISC_R_SUCCESS) 824 return (result); 825 826 /* 827 * Write the buffer contents to the master file. 828 */ 829 isc_buffer_usedregion(buffer, &r); 830 result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL); 831 832 if (result != ISC_R_SUCCESS) { 833 UNEXPECTED_ERROR(__FILE__, __LINE__, 834 "master file write failed: %s", 835 isc_result_totext(result)); 836 return (result); 837 } 838 839 return (ISC_R_SUCCESS); 840 } 841 842 /* 843 * Define the order in which rdatasets should be printed in zone 844 * files. We will print SOA and NS records before others, SIGs 845 * immediately following the things they sign, and order everything 846 * else by RR number. This is all just for aesthetics and 847 * compatibility with buggy software that expects the SOA to be first; 848 * the DNS specifications allow any order. 849 */ 850 851 static int 852 dump_order(const dns_rdataset_t *rds) { 853 int t; 854 int sig; 855 if (rds->type == dns_rdatatype_rrsig) { 856 t = rds->covers; 857 sig = 1; 858 } else { 859 t = rds->type; 860 sig = 0; 861 } 862 switch (t) { 863 case dns_rdatatype_soa: 864 t = 0; 865 break; 866 case dns_rdatatype_ns: 867 t = 1; 868 break; 869 default: 870 t += 2; 871 break; 872 } 873 return (t << 1) + sig; 874 } 875 876 static int 877 dump_order_compare(const void *a, const void *b) { 878 return (dump_order(*((const dns_rdataset_t * const *) a)) - 879 dump_order(*((const dns_rdataset_t * const *) b))); 880 } 881 882 /* 883 * Dump all the rdatasets of a domain name to a master file. We make 884 * a "best effort" attempt to sort the RRsets in a nice order, but if 885 * there are more than MAXSORT RRsets, we punt and only sort them in 886 * groups of MAXSORT. This is not expected to ever happen in practice 887 * since much less than 64 RR types have been registered with the 888 * IANA, so far, and the output will be correct (though not 889 * aesthetically pleasing) even if it does happen. 890 */ 891 892 #define MAXSORT 64 893 894 static isc_result_t 895 dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name, 896 dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx, 897 isc_buffer_t *buffer, FILE *f) 898 { 899 isc_result_t itresult, dumpresult; 900 isc_region_t r; 901 dns_rdataset_t rdatasets[MAXSORT]; 902 dns_rdataset_t *sorted[MAXSORT]; 903 int i, n; 904 905 itresult = dns_rdatasetiter_first(rdsiter); 906 dumpresult = ISC_R_SUCCESS; 907 908 if (itresult == ISC_R_SUCCESS && ctx->neworigin != NULL) { 909 isc_buffer_clear(buffer); 910 itresult = dns_name_totext(ctx->neworigin, ISC_FALSE, buffer); 911 RUNTIME_CHECK(itresult == ISC_R_SUCCESS); 912 isc_buffer_usedregion(buffer, &r); 913 fprintf(f, "$ORIGIN %.*s\n", (int) r.length, (char *) r.base); 914 ctx->neworigin = NULL; 915 } 916 917 again: 918 for (i = 0; 919 itresult == ISC_R_SUCCESS && i < MAXSORT; 920 itresult = dns_rdatasetiter_next(rdsiter), i++) { 921 dns_rdataset_init(&rdatasets[i]); 922 dns_rdatasetiter_current(rdsiter, &rdatasets[i]); 923 sorted[i] = &rdatasets[i]; 924 } 925 n = i; 926 INSIST(n <= MAXSORT); 927 928 qsort(sorted, n, sizeof(sorted[0]), dump_order_compare); 929 930 for (i = 0; i < n; i++) { 931 dns_rdataset_t *rds = sorted[i]; 932 if (ctx->style.flags & DNS_STYLEFLAG_TRUST) 933 fprintf(f, "; %s\n", dns_trust_totext(rds->trust)); 934 if (((rds->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) && 935 (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) { 936 /* Omit negative cache entries */ 937 } else { 938 isc_result_t result = 939 dump_rdataset(mctx, name, rds, ctx, 940 buffer, f); 941 if (result != ISC_R_SUCCESS) 942 dumpresult = result; 943 if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0) 944 name = NULL; 945 } 946 if (ctx->style.flags & DNS_STYLEFLAG_RESIGN && 947 rds->attributes & DNS_RDATASETATTR_RESIGN) { 948 isc_buffer_t b; 949 char buf[sizeof("YYYYMMDDHHMMSS")]; 950 memset(buf, 0, sizeof(buf)); 951 isc_buffer_init(&b, buf, sizeof(buf) - 1); 952 dns_time64_totext((isc_uint64_t)rds->resign, &b); 953 fprintf(f, "; resign=%s\n", buf); 954 } 955 dns_rdataset_disassociate(rds); 956 } 957 958 if (dumpresult != ISC_R_SUCCESS) 959 return (dumpresult); 960 961 /* 962 * If we got more data than could be sorted at once, 963 * go handle the rest. 964 */ 965 if (itresult == ISC_R_SUCCESS) 966 goto again; 967 968 if (itresult == ISC_R_NOMORE) 969 itresult = ISC_R_SUCCESS; 970 971 return (itresult); 972 } 973 974 /* 975 * Dump given RRsets in the "raw" format. 976 */ 977 static isc_result_t 978 dump_rdataset_raw(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset, 979 isc_buffer_t *buffer, FILE *f) 980 { 981 isc_result_t result; 982 isc_uint32_t totallen; 983 isc_uint16_t dlen; 984 isc_region_t r, r_hdr; 985 986 REQUIRE(buffer->length > 0); 987 REQUIRE(DNS_RDATASET_VALID(rdataset)); 988 989 rdataset->attributes |= DNS_RDATASETATTR_LOADORDER; 990 restart: 991 totallen = 0; 992 result = dns_rdataset_first(rdataset); 993 REQUIRE(result == ISC_R_SUCCESS); 994 995 isc_buffer_clear(buffer); 996 997 /* 998 * Common header and owner name (length followed by name) 999 * These fields should be in a moderate length, so we assume we 1000 * can store all of them in the initial buffer. 1001 */ 1002 isc_buffer_availableregion(buffer, &r_hdr); 1003 INSIST(r_hdr.length >= sizeof(dns_masterrawrdataset_t)); 1004 isc_buffer_putuint32(buffer, totallen); /* XXX: leave space */ 1005 isc_buffer_putuint16(buffer, rdataset->rdclass); /* 16-bit class */ 1006 isc_buffer_putuint16(buffer, rdataset->type); /* 16-bit type */ 1007 isc_buffer_putuint16(buffer, rdataset->covers); /* same as type */ 1008 isc_buffer_putuint32(buffer, rdataset->ttl); /* 32-bit TTL */ 1009 isc_buffer_putuint32(buffer, dns_rdataset_count(rdataset)); 1010 totallen = isc_buffer_usedlength(buffer); 1011 INSIST(totallen <= sizeof(dns_masterrawrdataset_t)); 1012 1013 dns_name_toregion(name, &r); 1014 INSIST(isc_buffer_availablelength(buffer) >= 1015 (sizeof(dlen) + r.length)); 1016 dlen = (isc_uint16_t)r.length; 1017 isc_buffer_putuint16(buffer, dlen); 1018 isc_buffer_copyregion(buffer, &r); 1019 totallen += sizeof(dlen) + r.length; 1020 1021 do { 1022 dns_rdata_t rdata = DNS_RDATA_INIT; 1023 1024 dns_rdataset_current(rdataset, &rdata); 1025 dns_rdata_toregion(&rdata, &r); 1026 INSIST(r.length <= 0xffffU); 1027 dlen = (isc_uint16_t)r.length; 1028 1029 /* 1030 * Copy the rdata into the buffer. If the buffer is too small, 1031 * grow it. This should be rare, so we'll simply restart the 1032 * entire procedure (or should we copy the old data and 1033 * continue?). 1034 */ 1035 if (isc_buffer_availablelength(buffer) < 1036 sizeof(dlen) + r.length) { 1037 int newlength; 1038 void *newmem; 1039 1040 newlength = buffer->length * 2; 1041 newmem = isc_mem_get(mctx, newlength); 1042 if (newmem == NULL) 1043 return (ISC_R_NOMEMORY); 1044 isc_mem_put(mctx, buffer->base, buffer->length); 1045 isc_buffer_init(buffer, newmem, newlength); 1046 goto restart; 1047 } 1048 isc_buffer_putuint16(buffer, dlen); 1049 isc_buffer_copyregion(buffer, &r); 1050 totallen += sizeof(dlen) + r.length; 1051 1052 result = dns_rdataset_next(rdataset); 1053 } while (result == ISC_R_SUCCESS); 1054 1055 if (result != ISC_R_NOMORE) 1056 return (result); 1057 1058 /* 1059 * Fill in the total length field. 1060 * XXX: this is a bit tricky. Since we have already "used" the space 1061 * for the total length in the buffer, we first remember the entire 1062 * buffer length in the region, "rewind", and then write the value. 1063 */ 1064 isc_buffer_usedregion(buffer, &r); 1065 isc_buffer_clear(buffer); 1066 isc_buffer_putuint32(buffer, totallen); 1067 INSIST(isc_buffer_usedlength(buffer) < totallen); 1068 1069 /* 1070 * Write the buffer contents to the raw master file. 1071 */ 1072 result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL); 1073 1074 if (result != ISC_R_SUCCESS) { 1075 UNEXPECTED_ERROR(__FILE__, __LINE__, 1076 "raw master file write failed: %s", 1077 isc_result_totext(result)); 1078 return (result); 1079 } 1080 1081 return (result); 1082 } 1083 1084 static isc_result_t 1085 dump_rdatasets_raw(isc_mem_t *mctx, dns_name_t *name, 1086 dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx, 1087 isc_buffer_t *buffer, FILE *f) 1088 { 1089 isc_result_t result; 1090 dns_rdataset_t rdataset; 1091 1092 for (result = dns_rdatasetiter_first(rdsiter); 1093 result == ISC_R_SUCCESS; 1094 result = dns_rdatasetiter_next(rdsiter)) { 1095 1096 dns_rdataset_init(&rdataset); 1097 dns_rdatasetiter_current(rdsiter, &rdataset); 1098 1099 if (((rdataset.attributes & DNS_RDATASETATTR_NEGATIVE) != 0) && 1100 (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) { 1101 /* Omit negative cache entries */ 1102 } else { 1103 result = dump_rdataset_raw(mctx, name, &rdataset, 1104 buffer, f); 1105 } 1106 dns_rdataset_disassociate(&rdataset); 1107 if (result != ISC_R_SUCCESS) 1108 return (result); 1109 } 1110 1111 if (result == ISC_R_NOMORE) 1112 result = ISC_R_SUCCESS; 1113 1114 return (result); 1115 } 1116 1117 static isc_result_t 1118 dump_rdatasets_map(isc_mem_t *mctx, dns_name_t *name, 1119 dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx, 1120 isc_buffer_t *buffer, FILE *f) 1121 { 1122 UNUSED(mctx); 1123 UNUSED(name); 1124 UNUSED(rdsiter); 1125 UNUSED(ctx); 1126 UNUSED(buffer); 1127 UNUSED(f); 1128 1129 return (ISC_R_NOTIMPLEMENTED); 1130 } 1131 1132 /* 1133 * Initial size of text conversion buffer. The buffer is used 1134 * for several purposes: converting origin names, rdatasets, 1135 * $DATE timestamps, and comment strings for $TTL directives. 1136 * 1137 * When converting rdatasets, it is dynamically resized, but 1138 * when converting origins, timestamps, etc it is not. Therefore, 1139 * the initial size must large enough to hold the longest possible 1140 * text representation of any domain name (for $ORIGIN). 1141 */ 1142 static const int initial_buffer_length = 1200; 1143 1144 static isc_result_t 1145 dumptostreaminc(dns_dumpctx_t *dctx); 1146 1147 static void 1148 dumpctx_destroy(dns_dumpctx_t *dctx) { 1149 1150 dctx->magic = 0; 1151 DESTROYLOCK(&dctx->lock); 1152 dns_dbiterator_destroy(&dctx->dbiter); 1153 if (dctx->version != NULL) 1154 dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE); 1155 dns_db_detach(&dctx->db); 1156 if (dctx->task != NULL) 1157 isc_task_detach(&dctx->task); 1158 if (dctx->file != NULL) 1159 isc_mem_free(dctx->mctx, dctx->file); 1160 if (dctx->tmpfile != NULL) 1161 isc_mem_free(dctx->mctx, dctx->tmpfile); 1162 isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(*dctx)); 1163 } 1164 1165 void 1166 dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target) { 1167 1168 REQUIRE(DNS_DCTX_VALID(source)); 1169 REQUIRE(target != NULL && *target == NULL); 1170 1171 LOCK(&source->lock); 1172 INSIST(source->references > 0); 1173 source->references++; 1174 INSIST(source->references != 0); /* Overflow? */ 1175 UNLOCK(&source->lock); 1176 1177 *target = source; 1178 } 1179 1180 void 1181 dns_dumpctx_detach(dns_dumpctx_t **dctxp) { 1182 dns_dumpctx_t *dctx; 1183 isc_boolean_t need_destroy = ISC_FALSE; 1184 1185 REQUIRE(dctxp != NULL); 1186 dctx = *dctxp; 1187 REQUIRE(DNS_DCTX_VALID(dctx)); 1188 1189 *dctxp = NULL; 1190 1191 LOCK(&dctx->lock); 1192 INSIST(dctx->references != 0); 1193 dctx->references--; 1194 if (dctx->references == 0) 1195 need_destroy = ISC_TRUE; 1196 UNLOCK(&dctx->lock); 1197 if (need_destroy) 1198 dumpctx_destroy(dctx); 1199 } 1200 1201 dns_dbversion_t * 1202 dns_dumpctx_version(dns_dumpctx_t *dctx) { 1203 REQUIRE(DNS_DCTX_VALID(dctx)); 1204 return (dctx->version); 1205 } 1206 1207 dns_db_t * 1208 dns_dumpctx_db(dns_dumpctx_t *dctx) { 1209 REQUIRE(DNS_DCTX_VALID(dctx)); 1210 return (dctx->db); 1211 } 1212 1213 void 1214 dns_dumpctx_cancel(dns_dumpctx_t *dctx) { 1215 REQUIRE(DNS_DCTX_VALID(dctx)); 1216 1217 LOCK(&dctx->lock); 1218 dctx->canceled = ISC_TRUE; 1219 UNLOCK(&dctx->lock); 1220 } 1221 1222 static isc_result_t 1223 flushandsync(FILE *f, isc_result_t result, const char *temp) { 1224 isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS); 1225 1226 if (result == ISC_R_SUCCESS) 1227 result = isc_stdio_flush(f); 1228 if (result != ISC_R_SUCCESS && logit) { 1229 if (temp != NULL) 1230 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1231 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1232 "dumping to master file: %s: flush: %s", 1233 temp, isc_result_totext(result)); 1234 else 1235 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1236 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1237 "dumping to stream: flush: %s", 1238 isc_result_totext(result)); 1239 logit = ISC_FALSE; 1240 } 1241 1242 if (result == ISC_R_SUCCESS) 1243 result = isc_stdio_sync(f); 1244 if (result != ISC_R_SUCCESS && logit) { 1245 if (temp != NULL) 1246 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1247 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1248 "dumping to master file: %s: fsync: %s", 1249 temp, isc_result_totext(result)); 1250 else 1251 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1252 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1253 "dumping to stream: fsync: %s", 1254 isc_result_totext(result)); 1255 } 1256 return (result); 1257 } 1258 1259 static isc_result_t 1260 closeandrename(FILE *f, isc_result_t result, const char *temp, const char *file) 1261 { 1262 isc_result_t tresult; 1263 isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS); 1264 1265 result = flushandsync(f, result, temp); 1266 if (result != ISC_R_SUCCESS) 1267 logit = ISC_FALSE; 1268 1269 tresult = isc_stdio_close(f); 1270 if (result == ISC_R_SUCCESS) 1271 result = tresult; 1272 if (result != ISC_R_SUCCESS && logit) { 1273 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1274 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1275 "dumping master file: %s: fclose: %s", 1276 temp, isc_result_totext(result)); 1277 logit = ISC_FALSE; 1278 } 1279 if (result == ISC_R_SUCCESS) 1280 result = isc_file_rename(temp, file); 1281 else 1282 (void)isc_file_remove(temp); 1283 if (result != ISC_R_SUCCESS && logit) { 1284 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1285 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1286 "dumping master file: rename: %s: %s", 1287 file, isc_result_totext(result)); 1288 } 1289 return (result); 1290 } 1291 1292 static void 1293 dump_quantum(isc_task_t *task, isc_event_t *event) { 1294 isc_result_t result; 1295 isc_result_t tresult; 1296 dns_dumpctx_t *dctx; 1297 1298 REQUIRE(event != NULL); 1299 dctx = event->ev_arg; 1300 REQUIRE(DNS_DCTX_VALID(dctx)); 1301 if (dctx->canceled) 1302 result = ISC_R_CANCELED; 1303 else 1304 result = dumptostreaminc(dctx); 1305 if (result == DNS_R_CONTINUE) { 1306 event->ev_arg = dctx; 1307 isc_task_send(task, &event); 1308 return; 1309 } 1310 1311 if (dctx->file != NULL) { 1312 tresult = closeandrename(dctx->f, result, 1313 dctx->tmpfile, dctx->file); 1314 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS) 1315 result = tresult; 1316 } else 1317 result = flushandsync(dctx->f, result, NULL); 1318 (dctx->done)(dctx->done_arg, result); 1319 isc_event_free(&event); 1320 dns_dumpctx_detach(&dctx); 1321 } 1322 1323 static isc_result_t 1324 task_send(dns_dumpctx_t *dctx) { 1325 isc_event_t *event; 1326 1327 event = isc_event_allocate(dctx->mctx, NULL, DNS_EVENT_DUMPQUANTUM, 1328 dump_quantum, dctx, sizeof(*event)); 1329 if (event == NULL) 1330 return (ISC_R_NOMEMORY); 1331 isc_task_send(dctx->task, &event); 1332 return (ISC_R_SUCCESS); 1333 } 1334 1335 static isc_result_t 1336 dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1337 const dns_master_style_t *style, FILE *f, dns_dumpctx_t **dctxp, 1338 dns_masterformat_t format, dns_masterrawheader_t *header) 1339 { 1340 dns_dumpctx_t *dctx; 1341 isc_result_t result; 1342 unsigned int options; 1343 1344 dctx = isc_mem_get(mctx, sizeof(*dctx)); 1345 if (dctx == NULL) 1346 return (ISC_R_NOMEMORY); 1347 1348 dctx->mctx = NULL; 1349 dctx->f = f; 1350 dctx->dbiter = NULL; 1351 dctx->db = NULL; 1352 dctx->version = NULL; 1353 dctx->done = NULL; 1354 dctx->done_arg = NULL; 1355 dctx->task = NULL; 1356 dctx->nodes = 0; 1357 dctx->first = ISC_TRUE; 1358 dctx->canceled = ISC_FALSE; 1359 dctx->file = NULL; 1360 dctx->tmpfile = NULL; 1361 dctx->format = format; 1362 if (header == NULL) 1363 dns_master_initrawheader(&dctx->header); 1364 else 1365 dctx->header = *header; 1366 1367 switch (format) { 1368 case dns_masterformat_text: 1369 dctx->dumpsets = dump_rdatasets_text; 1370 break; 1371 case dns_masterformat_raw: 1372 dctx->dumpsets = dump_rdatasets_raw; 1373 break; 1374 case dns_masterformat_map: 1375 dctx->dumpsets = dump_rdatasets_map; 1376 break; 1377 default: 1378 INSIST(0); 1379 break; 1380 } 1381 1382 result = totext_ctx_init(style, &dctx->tctx); 1383 if (result != ISC_R_SUCCESS) { 1384 UNEXPECTED_ERROR(__FILE__, __LINE__, 1385 "could not set master file style"); 1386 goto cleanup; 1387 } 1388 1389 isc_stdtime_get(&dctx->now); 1390 dns_db_attach(db, &dctx->db); 1391 1392 dctx->do_date = dns_db_iscache(dctx->db); 1393 1394 if (dctx->format == dns_masterformat_text && 1395 (dctx->tctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) { 1396 options = DNS_DB_RELATIVENAMES; 1397 } else 1398 options = 0; 1399 result = dns_db_createiterator(dctx->db, options, &dctx->dbiter); 1400 if (result != ISC_R_SUCCESS) 1401 goto cleanup; 1402 1403 result = isc_mutex_init(&dctx->lock); 1404 if (result != ISC_R_SUCCESS) 1405 goto cleanup; 1406 if (version != NULL) 1407 dns_db_attachversion(dctx->db, version, &dctx->version); 1408 else if (!dns_db_iscache(db)) 1409 dns_db_currentversion(dctx->db, &dctx->version); 1410 isc_mem_attach(mctx, &dctx->mctx); 1411 dctx->references = 1; 1412 dctx->magic = DNS_DCTX_MAGIC; 1413 *dctxp = dctx; 1414 return (ISC_R_SUCCESS); 1415 1416 cleanup: 1417 if (dctx->dbiter != NULL) 1418 dns_dbiterator_destroy(&dctx->dbiter); 1419 if (dctx->db != NULL) 1420 dns_db_detach(&dctx->db); 1421 if (dctx != NULL) 1422 isc_mem_put(mctx, dctx, sizeof(*dctx)); 1423 return (result); 1424 } 1425 1426 static isc_result_t 1427 writeheader(dns_dumpctx_t *dctx) { 1428 isc_result_t result = ISC_R_SUCCESS; 1429 isc_buffer_t buffer; 1430 char *bufmem; 1431 isc_region_t r; 1432 dns_masterrawheader_t rawheader; 1433 isc_uint32_t rawversion, now32; 1434 1435 bufmem = isc_mem_get(dctx->mctx, initial_buffer_length); 1436 if (bufmem == NULL) 1437 return (ISC_R_NOMEMORY); 1438 1439 isc_buffer_init(&buffer, bufmem, initial_buffer_length); 1440 1441 switch (dctx->format) { 1442 case dns_masterformat_text: 1443 /* 1444 * If the database has cache semantics, output an 1445 * RFC2540 $DATE directive so that the TTLs can be 1446 * adjusted when it is reloaded. For zones it is not 1447 * really needed, and it would make the file 1448 * incompatible with pre-RFC2540 software, so we omit 1449 * it in the zone case. 1450 */ 1451 if (dctx->do_date) { 1452 result = dns_time32_totext(dctx->now, &buffer); 1453 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1454 isc_buffer_usedregion(&buffer, &r); 1455 fprintf(dctx->f, "$DATE %.*s\n", 1456 (int) r.length, (char *) r.base); 1457 } 1458 break; 1459 case dns_masterformat_raw: 1460 case dns_masterformat_map: 1461 r.base = (unsigned char *)&rawheader; 1462 r.length = sizeof(rawheader); 1463 isc_buffer_region(&buffer, &r); 1464 #if !defined(STDTIME_ON_32BITS) || (STDTIME_ON_32BITS + 0) != 1 1465 /* 1466 * We assume isc_stdtime_t is a 32-bit integer, 1467 * which should be the case on most platforms. 1468 * If it turns out to be uncommon, we'll need 1469 * to bump the version number and revise the 1470 * header format. 1471 */ 1472 isc_log_write(dns_lctx, 1473 ISC_LOGCATEGORY_GENERAL, 1474 DNS_LOGMODULE_MASTERDUMP, 1475 ISC_LOG_INFO, 1476 "dumping master file in raw " 1477 "format: stdtime is not 32bits"); 1478 now32 = 0; 1479 #else 1480 now32 = dctx->now; 1481 #endif 1482 rawversion = 1; 1483 if ((dctx->header.flags & DNS_MASTERRAW_COMPAT) != 0) 1484 rawversion = 0; 1485 1486 isc_buffer_putuint32(&buffer, dctx->format); 1487 isc_buffer_putuint32(&buffer, rawversion); 1488 isc_buffer_putuint32(&buffer, now32); 1489 1490 if (rawversion == 1) { 1491 isc_buffer_putuint32(&buffer, dctx->header.flags); 1492 isc_buffer_putuint32(&buffer, 1493 dctx->header.sourceserial); 1494 isc_buffer_putuint32(&buffer, dctx->header.lastxfrin); 1495 } 1496 1497 INSIST(isc_buffer_usedlength(&buffer) <= sizeof(rawheader)); 1498 result = isc_stdio_write(buffer.base, 1, 1499 isc_buffer_usedlength(&buffer), 1500 dctx->f, NULL); 1501 if (result != ISC_R_SUCCESS) 1502 break; 1503 1504 break; 1505 default: 1506 INSIST(0); 1507 } 1508 1509 isc_mem_put(dctx->mctx, buffer.base, buffer.length); 1510 return (result); 1511 } 1512 1513 static isc_result_t 1514 dumptostreaminc(dns_dumpctx_t *dctx) { 1515 isc_result_t result = ISC_R_SUCCESS; 1516 isc_buffer_t buffer; 1517 char *bufmem; 1518 dns_name_t *name; 1519 dns_fixedname_t fixname; 1520 unsigned int nodes; 1521 isc_time_t start; 1522 1523 bufmem = isc_mem_get(dctx->mctx, initial_buffer_length); 1524 if (bufmem == NULL) 1525 return (ISC_R_NOMEMORY); 1526 1527 isc_buffer_init(&buffer, bufmem, initial_buffer_length); 1528 1529 dns_fixedname_init(&fixname); 1530 name = dns_fixedname_name(&fixname); 1531 1532 if (dctx->first) { 1533 CHECK(writeheader(dctx)); 1534 1535 /* 1536 * Fast format is not currently written incrementally, 1537 * so we make the call to dns_db_serialize() here. 1538 * If the database is anything other than an rbtdb, 1539 * this should result in not implemented 1540 */ 1541 if (dctx->format == dns_masterformat_map) { 1542 result = dns_db_serialize(dctx->db, dctx->version, 1543 dctx->f); 1544 goto cleanup; 1545 } 1546 1547 result = dns_dbiterator_first(dctx->dbiter); 1548 if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) 1549 goto cleanup; 1550 1551 dctx->first = ISC_FALSE; 1552 } else 1553 result = ISC_R_SUCCESS; 1554 1555 nodes = dctx->nodes; 1556 isc_time_now(&start); 1557 while (result == ISC_R_SUCCESS && (dctx->nodes == 0 || nodes--)) { 1558 dns_rdatasetiter_t *rdsiter = NULL; 1559 dns_dbnode_t *node = NULL; 1560 1561 result = dns_dbiterator_current(dctx->dbiter, &node, name); 1562 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) 1563 break; 1564 if (result == DNS_R_NEWORIGIN) { 1565 dns_name_t *origin = 1566 dns_fixedname_name(&dctx->tctx.origin_fixname); 1567 result = dns_dbiterator_origin(dctx->dbiter, origin); 1568 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1569 if ((dctx->tctx.style.flags & 1570 DNS_STYLEFLAG_REL_DATA) != 0) 1571 dctx->tctx.origin = origin; 1572 dctx->tctx.neworigin = origin; 1573 } 1574 result = dns_db_allrdatasets(dctx->db, node, dctx->version, 1575 dctx->now, &rdsiter); 1576 if (result != ISC_R_SUCCESS) { 1577 dns_db_detachnode(dctx->db, &node); 1578 goto cleanup; 1579 } 1580 result = (dctx->dumpsets)(dctx->mctx, name, rdsiter, 1581 &dctx->tctx, &buffer, dctx->f); 1582 dns_rdatasetiter_destroy(&rdsiter); 1583 if (result != ISC_R_SUCCESS) { 1584 dns_db_detachnode(dctx->db, &node); 1585 goto cleanup; 1586 } 1587 dns_db_detachnode(dctx->db, &node); 1588 result = dns_dbiterator_next(dctx->dbiter); 1589 } 1590 1591 /* 1592 * Work out how many nodes can be written in the time between 1593 * two requests to the nameserver. Smooth the resulting number and 1594 * use it as a estimate for the number of nodes to be written in the 1595 * next iteration. 1596 */ 1597 if (dctx->nodes != 0 && result == ISC_R_SUCCESS) { 1598 unsigned int pps = dns_pps; /* packets per second */ 1599 unsigned int interval; 1600 isc_uint64_t usecs; 1601 isc_time_t end; 1602 1603 isc_time_now(&end); 1604 if (pps < 100) 1605 pps = 100; 1606 interval = 1000000 / pps; /* interval in usecs */ 1607 if (interval == 0) 1608 interval = 1; 1609 usecs = isc_time_microdiff(&end, &start); 1610 if (usecs == 0) { 1611 dctx->nodes = dctx->nodes * 2; 1612 if (dctx->nodes > 1000) 1613 dctx->nodes = 1000; 1614 } else { 1615 nodes = dctx->nodes * interval; 1616 nodes /= (unsigned int)usecs; 1617 if (nodes == 0) 1618 nodes = 1; 1619 else if (nodes > 1000) 1620 nodes = 1000; 1621 1622 /* Smooth and assign. */ 1623 dctx->nodes = (nodes + dctx->nodes * 7) / 8; 1624 1625 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1626 DNS_LOGMODULE_MASTERDUMP, 1627 ISC_LOG_DEBUG(1), 1628 "dumptostreaminc(%p) new nodes -> %d\n", 1629 dctx, dctx->nodes); 1630 } 1631 result = DNS_R_CONTINUE; 1632 } else if (result == ISC_R_NOMORE) 1633 result = ISC_R_SUCCESS; 1634 cleanup: 1635 RUNTIME_CHECK(dns_dbiterator_pause(dctx->dbiter) == ISC_R_SUCCESS); 1636 isc_mem_put(dctx->mctx, buffer.base, buffer.length); 1637 return (result); 1638 } 1639 1640 isc_result_t 1641 dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db, 1642 dns_dbversion_t *version, 1643 const dns_master_style_t *style, 1644 FILE *f, isc_task_t *task, 1645 dns_dumpdonefunc_t done, void *done_arg, 1646 dns_dumpctx_t **dctxp) 1647 { 1648 dns_dumpctx_t *dctx = NULL; 1649 isc_result_t result; 1650 1651 REQUIRE(task != NULL); 1652 REQUIRE(f != NULL); 1653 REQUIRE(done != NULL); 1654 1655 result = dumpctx_create(mctx, db, version, style, f, &dctx, 1656 dns_masterformat_text, NULL); 1657 if (result != ISC_R_SUCCESS) 1658 return (result); 1659 isc_task_attach(task, &dctx->task); 1660 dctx->done = done; 1661 dctx->done_arg = done_arg; 1662 dctx->nodes = 100; 1663 1664 result = task_send(dctx); 1665 if (result == ISC_R_SUCCESS) { 1666 dns_dumpctx_attach(dctx, dctxp); 1667 return (DNS_R_CONTINUE); 1668 } 1669 1670 dns_dumpctx_detach(&dctx); 1671 return (result); 1672 } 1673 1674 /* 1675 * Dump an entire database into a master file. 1676 */ 1677 isc_result_t 1678 dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db, 1679 dns_dbversion_t *version, 1680 const dns_master_style_t *style, 1681 FILE *f) 1682 { 1683 return (dns_master_dumptostream3(mctx, db, version, style, 1684 dns_masterformat_text, NULL, f)); 1685 } 1686 1687 isc_result_t 1688 dns_master_dumptostream2(isc_mem_t *mctx, dns_db_t *db, 1689 dns_dbversion_t *version, 1690 const dns_master_style_t *style, 1691 dns_masterformat_t format, FILE *f) 1692 { 1693 return (dns_master_dumptostream3(mctx, db, version, style, 1694 format, NULL, f)); 1695 } 1696 1697 isc_result_t 1698 dns_master_dumptostream3(isc_mem_t *mctx, dns_db_t *db, 1699 dns_dbversion_t *version, 1700 const dns_master_style_t *style, 1701 dns_masterformat_t format, 1702 dns_masterrawheader_t *header, FILE *f) 1703 { 1704 dns_dumpctx_t *dctx = NULL; 1705 isc_result_t result; 1706 1707 result = dumpctx_create(mctx, db, version, style, f, &dctx, 1708 format, header); 1709 if (result != ISC_R_SUCCESS) 1710 return (result); 1711 1712 result = dumptostreaminc(dctx); 1713 INSIST(result != DNS_R_CONTINUE); 1714 dns_dumpctx_detach(&dctx); 1715 1716 result = flushandsync(f, result, NULL); 1717 return (result); 1718 } 1719 1720 static isc_result_t 1721 opentmp(isc_mem_t *mctx, dns_masterformat_t format, const char *file, 1722 char **tempp, FILE **fp) { 1723 FILE *f = NULL; 1724 isc_result_t result; 1725 char *tempname = NULL; 1726 int tempnamelen; 1727 1728 tempnamelen = strlen(file) + 20; 1729 tempname = isc_mem_allocate(mctx, tempnamelen); 1730 if (tempname == NULL) 1731 return (ISC_R_NOMEMORY); 1732 1733 result = isc_file_mktemplate(file, tempname, tempnamelen); 1734 if (result != ISC_R_SUCCESS) 1735 goto cleanup; 1736 1737 if (format == dns_masterformat_text) 1738 result = isc_file_openunique(tempname, &f); 1739 else 1740 result = isc_file_bopenunique(tempname, &f); 1741 if (result != ISC_R_SUCCESS) { 1742 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1743 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1744 "dumping master file: %s: open: %s", 1745 tempname, isc_result_totext(result)); 1746 goto cleanup; 1747 } 1748 *tempp = tempname; 1749 *fp = f; 1750 return (ISC_R_SUCCESS); 1751 1752 cleanup: 1753 isc_mem_free(mctx, tempname); 1754 return (result); 1755 } 1756 1757 isc_result_t 1758 dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1759 const dns_master_style_t *style, const char *filename, 1760 isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg, 1761 dns_dumpctx_t **dctxp) 1762 { 1763 return (dns_master_dumpinc3(mctx, db, version, style, filename, task, 1764 done, done_arg, dctxp, 1765 dns_masterformat_text, NULL)); 1766 } 1767 1768 isc_result_t 1769 dns_master_dumpinc2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1770 const dns_master_style_t *style, const char *filename, 1771 isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg, 1772 dns_dumpctx_t **dctxp, dns_masterformat_t format) 1773 { 1774 return (dns_master_dumpinc3(mctx, db, version, style, filename, task, 1775 done, done_arg, dctxp, format, NULL)); 1776 } 1777 1778 isc_result_t 1779 dns_master_dumpinc3(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1780 const dns_master_style_t *style, const char *filename, 1781 isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg, 1782 dns_dumpctx_t **dctxp, dns_masterformat_t format, 1783 dns_masterrawheader_t *header) 1784 { 1785 FILE *f = NULL; 1786 isc_result_t result; 1787 char *tempname = NULL; 1788 char *file = NULL; 1789 dns_dumpctx_t *dctx = NULL; 1790 1791 file = isc_mem_strdup(mctx, filename); 1792 if (file == NULL) 1793 return (ISC_R_NOMEMORY); 1794 1795 result = opentmp(mctx, format, filename, &tempname, &f); 1796 if (result != ISC_R_SUCCESS) 1797 goto cleanup; 1798 1799 result = dumpctx_create(mctx, db, version, style, f, &dctx, 1800 format, header); 1801 if (result != ISC_R_SUCCESS) { 1802 (void)isc_stdio_close(f); 1803 (void)isc_file_remove(tempname); 1804 goto cleanup; 1805 } 1806 1807 isc_task_attach(task, &dctx->task); 1808 dctx->done = done; 1809 dctx->done_arg = done_arg; 1810 dctx->nodes = 100; 1811 dctx->file = file; 1812 file = NULL; 1813 dctx->tmpfile = tempname; 1814 tempname = NULL; 1815 1816 result = task_send(dctx); 1817 if (result == ISC_R_SUCCESS) { 1818 dns_dumpctx_attach(dctx, dctxp); 1819 return (DNS_R_CONTINUE); 1820 } 1821 1822 cleanup: 1823 if (dctx != NULL) 1824 dns_dumpctx_detach(&dctx); 1825 if (file != NULL) 1826 isc_mem_free(mctx, file); 1827 if (tempname != NULL) 1828 isc_mem_free(mctx, tempname); 1829 return (result); 1830 } 1831 1832 isc_result_t 1833 dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1834 const dns_master_style_t *style, const char *filename) 1835 { 1836 return (dns_master_dump3(mctx, db, version, style, filename, 1837 dns_masterformat_text, NULL)); 1838 } 1839 1840 isc_result_t 1841 dns_master_dump2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1842 const dns_master_style_t *style, const char *filename, 1843 dns_masterformat_t format) 1844 { 1845 return (dns_master_dump3(mctx, db, version, style, filename, 1846 format, NULL)); 1847 } 1848 1849 isc_result_t 1850 dns_master_dump3(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1851 const dns_master_style_t *style, const char *filename, 1852 dns_masterformat_t format, dns_masterrawheader_t *header) 1853 { 1854 FILE *f = NULL; 1855 isc_result_t result; 1856 char *tempname; 1857 dns_dumpctx_t *dctx = NULL; 1858 1859 result = opentmp(mctx, format, filename, &tempname, &f); 1860 if (result != ISC_R_SUCCESS) 1861 return (result); 1862 1863 result = dumpctx_create(mctx, db, version, style, f, &dctx, 1864 format, header); 1865 if (result != ISC_R_SUCCESS) 1866 goto cleanup; 1867 1868 result = dumptostreaminc(dctx); 1869 INSIST(result != DNS_R_CONTINUE); 1870 dns_dumpctx_detach(&dctx); 1871 1872 result = closeandrename(f, result, tempname, filename); 1873 1874 cleanup: 1875 isc_mem_free(mctx, tempname); 1876 return (result); 1877 } 1878 1879 /* 1880 * Dump a database node into a master file. 1881 * XXX: this function assumes the text format. 1882 */ 1883 isc_result_t 1884 dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db, 1885 dns_dbversion_t *version, 1886 dns_dbnode_t *node, dns_name_t *name, 1887 const dns_master_style_t *style, 1888 FILE *f) 1889 { 1890 isc_result_t result; 1891 isc_buffer_t buffer; 1892 char *bufmem; 1893 isc_stdtime_t now; 1894 dns_totext_ctx_t ctx; 1895 dns_rdatasetiter_t *rdsiter = NULL; 1896 1897 result = totext_ctx_init(style, &ctx); 1898 if (result != ISC_R_SUCCESS) { 1899 UNEXPECTED_ERROR(__FILE__, __LINE__, 1900 "could not set master file style"); 1901 return (ISC_R_UNEXPECTED); 1902 } 1903 1904 isc_stdtime_get(&now); 1905 1906 bufmem = isc_mem_get(mctx, initial_buffer_length); 1907 if (bufmem == NULL) 1908 return (ISC_R_NOMEMORY); 1909 1910 isc_buffer_init(&buffer, bufmem, initial_buffer_length); 1911 1912 result = dns_db_allrdatasets(db, node, version, now, &rdsiter); 1913 if (result != ISC_R_SUCCESS) 1914 goto failure; 1915 result = dump_rdatasets_text(mctx, name, rdsiter, &ctx, &buffer, f); 1916 if (result != ISC_R_SUCCESS) 1917 goto failure; 1918 dns_rdatasetiter_destroy(&rdsiter); 1919 1920 result = ISC_R_SUCCESS; 1921 1922 failure: 1923 isc_mem_put(mctx, buffer.base, buffer.length); 1924 return (result); 1925 } 1926 1927 isc_result_t 1928 dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1929 dns_dbnode_t *node, dns_name_t *name, 1930 const dns_master_style_t *style, const char *filename) 1931 { 1932 FILE *f = NULL; 1933 isc_result_t result; 1934 1935 result = isc_stdio_open(filename, "w", &f); 1936 if (result != ISC_R_SUCCESS) { 1937 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1938 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1939 "dumping node to file: %s: open: %s", filename, 1940 isc_result_totext(result)); 1941 return (ISC_R_UNEXPECTED); 1942 } 1943 1944 result = dns_master_dumpnodetostream(mctx, db, version, node, name, 1945 style, f); 1946 if (result != ISC_R_SUCCESS) { 1947 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1948 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1949 "dumping master file: %s: dump: %s", filename, 1950 isc_result_totext(result)); 1951 (void)isc_stdio_close(f); 1952 return (ISC_R_UNEXPECTED); 1953 } 1954 1955 result = isc_stdio_close(f); 1956 if (result != ISC_R_SUCCESS) { 1957 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1958 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1959 "dumping master file: %s: close: %s", filename, 1960 isc_result_totext(result)); 1961 return (ISC_R_UNEXPECTED); 1962 } 1963 1964 return (result); 1965 } 1966 1967 isc_result_t 1968 dns_master_stylecreate(dns_master_style_t **stylep, unsigned int flags, 1969 unsigned int ttl_column, unsigned int class_column, 1970 unsigned int type_column, unsigned int rdata_column, 1971 unsigned int line_length, unsigned int tab_width, 1972 isc_mem_t *mctx) 1973 { 1974 return (dns_master_stylecreate2(stylep, flags, ttl_column, 1975 class_column, type_column, 1976 rdata_column, line_length, 1977 tab_width, 0xffffffff, mctx)); 1978 } 1979 1980 isc_result_t 1981 dns_master_stylecreate2(dns_master_style_t **stylep, unsigned int flags, 1982 unsigned int ttl_column, unsigned int class_column, 1983 unsigned int type_column, unsigned int rdata_column, 1984 unsigned int line_length, unsigned int tab_width, 1985 unsigned int split_width, isc_mem_t *mctx) 1986 { 1987 dns_master_style_t *style; 1988 1989 REQUIRE(stylep != NULL && *stylep == NULL); 1990 style = isc_mem_get(mctx, sizeof(*style)); 1991 if (style == NULL) 1992 return (ISC_R_NOMEMORY); 1993 1994 style->flags = flags; 1995 style->ttl_column = ttl_column; 1996 style->class_column = class_column; 1997 style->type_column = type_column; 1998 style->rdata_column = rdata_column; 1999 style->line_length = line_length; 2000 style->tab_width = tab_width; 2001 style->split_width = split_width; 2002 2003 *stylep = style; 2004 return (ISC_R_SUCCESS); 2005 } 2006 2007 void 2008 dns_master_styledestroy(dns_master_style_t **stylep, isc_mem_t *mctx) { 2009 dns_master_style_t *style; 2010 2011 REQUIRE(stylep != NULL && *stylep != NULL); 2012 style = *stylep; 2013 *stylep = NULL; 2014 isc_mem_put(mctx, style, sizeof(*style)); 2015 } 2016