00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <stdlib.h>
00025
00026 #include <isc/event.h>
00027 #include <isc/file.h>
00028 #include <isc/magic.h>
00029 #include <isc/mem.h>
00030 #include <isc/print.h>
00031 #include <isc/stdio.h>
00032 #include <isc/string.h>
00033 #include <isc/task.h>
00034 #include <isc/time.h>
00035 #include <isc/util.h>
00036
00037 #include <dns/db.h>
00038 #include <dns/dbiterator.h>
00039 #include <dns/events.h>
00040 #include <dns/fixedname.h>
00041 #include <dns/lib.h>
00042 #include <dns/log.h>
00043 #include <dns/master.h>
00044 #include <dns/masterdump.h>
00045 #include <dns/ncache.h>
00046 #include <dns/rdata.h>
00047 #include <dns/rdataclass.h>
00048 #include <dns/rdataset.h>
00049 #include <dns/rdatasetiter.h>
00050 #include <dns/rdatatype.h>
00051 #include <dns/result.h>
00052 #include <dns/time.h>
00053 #include <dns/ttl.h>
00054
00055 #define DNS_DCTX_MAGIC ISC_MAGIC('D', 'c', 't', 'x')
00056 #define DNS_DCTX_VALID(d) ISC_MAGIC_VALID(d, DNS_DCTX_MAGIC)
00057
00058 #define RETERR(x) do { \
00059 isc_result_t _r = (x); \
00060 if (_r != ISC_R_SUCCESS) \
00061 return (_r); \
00062 } while (0)
00063
00064 #define CHECK(x) do { \
00065 if ((x) != ISC_R_SUCCESS) \
00066 goto cleanup; \
00067 } while (0)
00068
00069 struct dns_master_style {
00070 unsigned int flags;
00071 unsigned int ttl_column;
00072 unsigned int class_column;
00073 unsigned int type_column;
00074 unsigned int rdata_column;
00075 unsigned int line_length;
00076 unsigned int tab_width;
00077 unsigned int split_width;
00078 };
00079
00080
00081
00082
00083
00084
00085
00086 #define DNS_TOTEXT_LINEBREAK_MAXLEN 100
00087
00088
00089
00090
00091 typedef struct dns_totext_ctx {
00092 dns_master_style_t style;
00093 isc_boolean_t class_printed;
00094 char * linebreak;
00095 char linebreak_buf[DNS_TOTEXT_LINEBREAK_MAXLEN];
00096 dns_name_t * origin;
00097 dns_name_t * neworigin;
00098 dns_fixedname_t origin_fixname;
00099 isc_uint32_t current_ttl;
00100 isc_boolean_t current_ttl_valid;
00101 } dns_totext_ctx_t;
00102
00103 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00104 dns_master_style_keyzone = {
00105 DNS_STYLEFLAG_OMIT_OWNER |
00106 DNS_STYLEFLAG_OMIT_CLASS |
00107 DNS_STYLEFLAG_REL_OWNER |
00108 DNS_STYLEFLAG_REL_DATA |
00109 DNS_STYLEFLAG_OMIT_TTL |
00110 DNS_STYLEFLAG_TTL |
00111 DNS_STYLEFLAG_COMMENT |
00112 DNS_STYLEFLAG_RRCOMMENT |
00113 DNS_STYLEFLAG_MULTILINE |
00114 DNS_STYLEFLAG_KEYDATA,
00115 24, 24, 24, 32, 80, 8, UINT_MAX
00116 };
00117
00118 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00119 dns_master_style_default = {
00120 DNS_STYLEFLAG_OMIT_OWNER |
00121 DNS_STYLEFLAG_OMIT_CLASS |
00122 DNS_STYLEFLAG_REL_OWNER |
00123 DNS_STYLEFLAG_REL_DATA |
00124 DNS_STYLEFLAG_OMIT_TTL |
00125 DNS_STYLEFLAG_TTL |
00126 DNS_STYLEFLAG_COMMENT |
00127 DNS_STYLEFLAG_RRCOMMENT |
00128 DNS_STYLEFLAG_MULTILINE,
00129 24, 24, 24, 32, 80, 8, UINT_MAX
00130 };
00131
00132 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00133 dns_master_style_full = {
00134 DNS_STYLEFLAG_COMMENT |
00135 DNS_STYLEFLAG_RESIGN,
00136 46, 46, 46, 64, 120, 8, UINT_MAX
00137 };
00138
00139 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00140 dns_master_style_explicitttl = {
00141 DNS_STYLEFLAG_OMIT_OWNER |
00142 DNS_STYLEFLAG_OMIT_CLASS |
00143 DNS_STYLEFLAG_REL_OWNER |
00144 DNS_STYLEFLAG_REL_DATA |
00145 DNS_STYLEFLAG_COMMENT |
00146 DNS_STYLEFLAG_RRCOMMENT |
00147 DNS_STYLEFLAG_MULTILINE,
00148 24, 32, 32, 40, 80, 8, UINT_MAX
00149 };
00150
00151 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00152 dns_master_style_cache = {
00153 DNS_STYLEFLAG_OMIT_OWNER |
00154 DNS_STYLEFLAG_OMIT_CLASS |
00155 DNS_STYLEFLAG_MULTILINE |
00156 DNS_STYLEFLAG_RRCOMMENT |
00157 DNS_STYLEFLAG_TRUST |
00158 DNS_STYLEFLAG_NCACHE,
00159 24, 32, 32, 40, 80, 8, UINT_MAX
00160 };
00161
00162 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00163 dns_master_style_simple = {
00164 0,
00165 24, 32, 32, 40, 80, 8, UINT_MAX
00166 };
00167
00168
00169
00170
00171 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00172 dns_master_style_debug = {
00173 DNS_STYLEFLAG_REL_OWNER,
00174 24, 32, 40, 48, 80, 8, UINT_MAX
00175 };
00176
00177
00178
00179
00180 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00181 dns_master_style_comment = {
00182 DNS_STYLEFLAG_REL_OWNER |
00183 DNS_STYLEFLAG_MULTILINE |
00184 DNS_STYLEFLAG_RRCOMMENT |
00185 DNS_STYLEFLAG_COMMENTDATA,
00186 24, 32, 40, 48, 80, 8, UINT_MAX
00187 };
00188
00189
00190 #define N_SPACES 10
00191 static char spaces[N_SPACES+1] = " ";
00192
00193 #define N_TABS 10
00194 static char tabs[N_TABS+1] = "\t\t\t\t\t\t\t\t\t\t";
00195
00196 struct dns_dumpctx {
00197 unsigned int magic;
00198 isc_mem_t *mctx;
00199 isc_mutex_t lock;
00200 unsigned int references;
00201 isc_boolean_t canceled;
00202 isc_boolean_t first;
00203 isc_boolean_t do_date;
00204 isc_stdtime_t now;
00205 FILE *f;
00206 dns_db_t *db;
00207 dns_dbversion_t *version;
00208 dns_dbiterator_t *dbiter;
00209 dns_totext_ctx_t tctx;
00210 isc_task_t *task;
00211 dns_dumpdonefunc_t done;
00212 void *done_arg;
00213 unsigned int nodes;
00214
00215 char *file;
00216 char *tmpfile;
00217 dns_masterformat_t format;
00218 dns_masterrawheader_t header;
00219 isc_result_t (*dumpsets)(isc_mem_t *mctx, dns_name_t *name,
00220 dns_rdatasetiter_t *rdsiter,
00221 dns_totext_ctx_t *ctx,
00222 isc_buffer_t *buffer, FILE *f);
00223 };
00224
00225 #define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
00226
00227
00228
00229
00230
00231
00232 static isc_result_t
00233 indent(unsigned int *current, unsigned int to, int tabwidth,
00234 isc_buffer_t *target)
00235 {
00236 isc_region_t r;
00237 unsigned char *p;
00238 unsigned int from;
00239 int ntabs, nspaces, t;
00240
00241 from = *current;
00242
00243 if (to < from + 1)
00244 to = from + 1;
00245
00246 ntabs = to / tabwidth - from / tabwidth;
00247 if (ntabs < 0)
00248 ntabs = 0;
00249
00250 if (ntabs > 0) {
00251 isc_buffer_availableregion(target, &r);
00252 if (r.length < (unsigned) ntabs)
00253 return (ISC_R_NOSPACE);
00254 p = r.base;
00255
00256 t = ntabs;
00257 while (t) {
00258 int n = t;
00259 if (n > N_TABS)
00260 n = N_TABS;
00261 memmove(p, tabs, n);
00262 p += n;
00263 t -= n;
00264 }
00265 isc_buffer_add(target, ntabs);
00266 from = (to / tabwidth) * tabwidth;
00267 }
00268
00269 nspaces = to - from;
00270 INSIST(nspaces >= 0);
00271
00272 isc_buffer_availableregion(target, &r);
00273 if (r.length < (unsigned) nspaces)
00274 return (ISC_R_NOSPACE);
00275 p = r.base;
00276
00277 t = nspaces;
00278 while (t) {
00279 int n = t;
00280 if (n > N_SPACES)
00281 n = N_SPACES;
00282 memmove(p, spaces, n);
00283 p += n;
00284 t -= n;
00285 }
00286 isc_buffer_add(target, nspaces);
00287
00288 *current = to;
00289 return (ISC_R_SUCCESS);
00290 }
00291
00292 static isc_result_t
00293 totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) {
00294 isc_result_t result;
00295
00296 REQUIRE(style->tab_width != 0);
00297
00298 ctx->style = *style;
00299 ctx->class_printed = ISC_FALSE;
00300
00301 dns_fixedname_init(&ctx->origin_fixname);
00302
00303
00304
00305
00306 if ((ctx->style.flags & DNS_STYLEFLAG_MULTILINE) != 0) {
00307 isc_buffer_t buf;
00308 isc_region_t r;
00309 unsigned int col = 0;
00310
00311 isc_buffer_init(&buf, ctx->linebreak_buf,
00312 sizeof(ctx->linebreak_buf));
00313
00314 isc_buffer_availableregion(&buf, &r);
00315 if (r.length < 1)
00316 return (DNS_R_TEXTTOOLONG);
00317 r.base[0] = '\n';
00318 isc_buffer_add(&buf, 1);
00319
00320 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0) {
00321 isc_buffer_availableregion(&buf, &r);
00322 if (r.length < 1)
00323 return (DNS_R_TEXTTOOLONG);
00324 r.base[0] = ';';
00325 isc_buffer_add(&buf, 1);
00326 }
00327
00328 result = indent(&col, ctx->style.rdata_column,
00329 ctx->style.tab_width, &buf);
00330
00331
00332
00333
00334
00335
00336
00337 if (result == ISC_R_NOSPACE)
00338 return (DNS_R_TEXTTOOLONG);
00339 if (result != ISC_R_SUCCESS)
00340 return (result);
00341
00342 isc_buffer_availableregion(&buf, &r);
00343 if (r.length < 1)
00344 return (DNS_R_TEXTTOOLONG);
00345 r.base[0] = '\0';
00346 isc_buffer_add(&buf, 1);
00347 ctx->linebreak = ctx->linebreak_buf;
00348 } else {
00349 ctx->linebreak = NULL;
00350 }
00351
00352 ctx->origin = NULL;
00353 ctx->neworigin = NULL;
00354 ctx->current_ttl = 0;
00355 ctx->current_ttl_valid = ISC_FALSE;
00356
00357 return (ISC_R_SUCCESS);
00358 }
00359
00360 #define INDENT_TO(col) \
00361 do { \
00362 if ((result = indent(&column, ctx->style.col, \
00363 ctx->style.tab_width, target)) \
00364 != ISC_R_SUCCESS) \
00365 return (result); \
00366 } while (0)
00367
00368
00369 static isc_result_t
00370 str_totext(const char *source, isc_buffer_t *target) {
00371 unsigned int l;
00372 isc_region_t region;
00373
00374 isc_buffer_availableregion(target, ®ion);
00375 l = strlen(source);
00376
00377 if (l > region.length)
00378 return (ISC_R_NOSPACE);
00379
00380 memmove(region.base, source, l);
00381 isc_buffer_add(target, l);
00382 return (ISC_R_SUCCESS);
00383 }
00384
00385 static isc_result_t
00386 ncache_summary(dns_rdataset_t *rdataset, isc_boolean_t omit_final_dot,
00387 isc_buffer_t *target)
00388 {
00389 isc_result_t result = ISC_R_SUCCESS;
00390 dns_rdataset_t rds;
00391 dns_name_t name;
00392
00393 dns_rdataset_init(&rds);
00394 dns_name_init(&name, NULL);
00395
00396 do {
00397 dns_ncache_current(rdataset, &name, &rds);
00398 for (result = dns_rdataset_first(&rds);
00399 result == ISC_R_SUCCESS;
00400 result = dns_rdataset_next(&rds)) {
00401 CHECK(str_totext("; ", target));
00402 CHECK(dns_name_totext(&name, omit_final_dot, target));
00403 CHECK(str_totext(" ", target));
00404 CHECK(dns_rdatatype_totext(rds.type, target));
00405 if (rds.type == dns_rdatatype_rrsig) {
00406 CHECK(str_totext(" ", target));
00407 CHECK(dns_rdatatype_totext(rds.covers, target));
00408 CHECK(str_totext(" ...\n", target));
00409 } else {
00410 dns_rdata_t rdata = DNS_RDATA_INIT;
00411 dns_rdataset_current(&rds, &rdata);
00412 CHECK(str_totext(" ", target));
00413 CHECK(dns_rdata_tofmttext(&rdata, dns_rootname,
00414 0, 0, 0, " ", target));
00415 CHECK(str_totext("\n", target));
00416 }
00417 }
00418 dns_rdataset_disassociate(&rds);
00419 result = dns_rdataset_next(rdataset);
00420 } while (result == ISC_R_SUCCESS);
00421
00422 if (result == ISC_R_NOMORE)
00423 result = ISC_R_SUCCESS;
00424 cleanup:
00425 if (dns_rdataset_isassociated(&rds))
00426 dns_rdataset_disassociate(&rds);
00427
00428 return (result);
00429 }
00430
00431
00432
00433
00434
00435
00436
00437
00438 static isc_result_t
00439 rdataset_totext(dns_rdataset_t *rdataset,
00440 dns_name_t *owner_name,
00441 dns_totext_ctx_t *ctx,
00442 isc_boolean_t omit_final_dot,
00443 isc_buffer_t *target)
00444 {
00445 isc_result_t result;
00446 unsigned int column;
00447 isc_boolean_t first = ISC_TRUE;
00448 isc_uint32_t current_ttl;
00449 isc_boolean_t current_ttl_valid;
00450 dns_rdatatype_t type;
00451 unsigned int type_start;
00452 dns_fixedname_t fixed;
00453 dns_name_t *name = NULL;
00454
00455 REQUIRE(DNS_RDATASET_VALID(rdataset));
00456
00457 rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
00458 result = dns_rdataset_first(rdataset);
00459
00460 current_ttl = ctx->current_ttl;
00461 current_ttl_valid = ctx->current_ttl_valid;
00462
00463 if (owner_name != NULL) {
00464 dns_fixedname_init(&fixed);
00465 name = dns_fixedname_name(&fixed);
00466 dns_name_copy(owner_name, name, NULL);
00467 dns_rdataset_getownercase(rdataset, name);
00468 }
00469
00470 while (result == ISC_R_SUCCESS) {
00471 column = 0;
00472
00473
00474
00475
00476 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0)
00477 RETERR(str_totext(";", target));
00478
00479
00480
00481
00482 if (name != NULL &&
00483 ! ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0 &&
00484 !first))
00485 {
00486 unsigned int name_start = target->used;
00487 RETERR(dns_name_totext(name, omit_final_dot, target));
00488 column += target->used - name_start;
00489 }
00490
00491
00492
00493
00494 if ((ctx->style.flags & DNS_STYLEFLAG_NO_TTL) == 0 &&
00495 !((ctx->style.flags & DNS_STYLEFLAG_OMIT_TTL) != 0 &&
00496 current_ttl_valid &&
00497 rdataset->ttl == current_ttl))
00498 {
00499 char ttlbuf[64];
00500 isc_region_t r;
00501 unsigned int length;
00502
00503 INDENT_TO(ttl_column);
00504 if ((ctx->style.flags & DNS_STYLEFLAG_TTL_UNITS) != 0) {
00505 length = target->used;
00506 result = dns_ttl_totext2(rdataset->ttl,
00507 ISC_FALSE, ISC_FALSE,
00508 target);
00509 if (result != ISC_R_SUCCESS)
00510 return (result);
00511 column += target->used - length;
00512 } else {
00513 length = snprintf(ttlbuf, sizeof(ttlbuf), "%u",
00514 rdataset->ttl);
00515 INSIST(length <= sizeof(ttlbuf));
00516 isc_buffer_availableregion(target, &r);
00517 if (r.length < length)
00518 return (ISC_R_NOSPACE);
00519 memmove(r.base, ttlbuf, length);
00520 isc_buffer_add(target, length);
00521 column += length;
00522 }
00523
00524
00525
00526
00527
00528 if ((ctx->style.flags & DNS_STYLEFLAG_TTL) == 0) {
00529 current_ttl = rdataset->ttl;
00530 current_ttl_valid = ISC_TRUE;
00531 }
00532 }
00533
00534
00535
00536
00537 if ((ctx->style.flags & DNS_STYLEFLAG_NO_CLASS) == 0 &&
00538 ((ctx->style.flags & DNS_STYLEFLAG_OMIT_CLASS) == 0 ||
00539 ctx->class_printed == ISC_FALSE))
00540 {
00541 unsigned int class_start;
00542 INDENT_TO(class_column);
00543 class_start = target->used;
00544 result = dns_rdataclass_totext(rdataset->rdclass,
00545 target);
00546 if (result != ISC_R_SUCCESS)
00547 return (result);
00548 column += (target->used - class_start);
00549 }
00550
00551
00552
00553
00554
00555 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
00556 type = rdataset->covers;
00557 } else {
00558 type = rdataset->type;
00559 }
00560
00561 INDENT_TO(type_column);
00562 type_start = target->used;
00563 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
00564 RETERR(str_totext("\\-", target));
00565 switch (type) {
00566 case dns_rdatatype_keydata:
00567 #define KEYDATA "KEYDATA"
00568 if ((ctx->style.flags & DNS_STYLEFLAG_KEYDATA) != 0) {
00569 if (isc_buffer_availablelength(target) <
00570 (sizeof(KEYDATA) - 1))
00571 return (ISC_R_NOSPACE);
00572 isc_buffer_putstr(target, KEYDATA);
00573 break;
00574 }
00575
00576 default:
00577 result = dns_rdatatype_totext(type, target);
00578 if (result != ISC_R_SUCCESS)
00579 return (result);
00580 }
00581 column += (target->used - type_start);
00582
00583
00584
00585
00586 INDENT_TO(rdata_column);
00587 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
00588 if (NXDOMAIN(rdataset))
00589 RETERR(str_totext(";-$NXDOMAIN\n", target));
00590 else
00591 RETERR(str_totext(";-$NXRRSET\n", target));
00592
00593
00594
00595
00596 RETERR(ncache_summary(rdataset, omit_final_dot,
00597 target));
00598 break;
00599 } else {
00600 dns_rdata_t rdata = DNS_RDATA_INIT;
00601 isc_region_t r;
00602
00603 dns_rdataset_current(rdataset, &rdata);
00604
00605 RETERR(dns_rdata_tofmttext(&rdata,
00606 ctx->origin,
00607 ctx->style.flags,
00608 ctx->style.line_length -
00609 ctx->style.rdata_column,
00610 ctx->style.split_width,
00611 ctx->linebreak,
00612 target));
00613
00614 isc_buffer_availableregion(target, &r);
00615 if (r.length < 1)
00616 return (ISC_R_NOSPACE);
00617 r.base[0] = '\n';
00618 isc_buffer_add(target, 1);
00619 }
00620
00621 first = ISC_FALSE;
00622 result = dns_rdataset_next(rdataset);
00623 }
00624
00625 if (result != ISC_R_NOMORE)
00626 return (result);
00627
00628
00629
00630
00631
00632
00633
00634
00635 ctx->class_printed = ISC_TRUE;
00636 ctx->current_ttl= current_ttl;
00637 ctx->current_ttl_valid = current_ttl_valid;
00638
00639 return (ISC_R_SUCCESS);
00640 }
00641
00642
00643
00644
00645
00646
00647 static isc_result_t
00648 question_totext(dns_rdataset_t *rdataset,
00649 dns_name_t *owner_name,
00650 dns_totext_ctx_t *ctx,
00651 isc_boolean_t omit_final_dot,
00652 isc_buffer_t *target)
00653 {
00654 unsigned int column;
00655 isc_result_t result;
00656 isc_region_t r;
00657
00658 REQUIRE(DNS_RDATASET_VALID(rdataset));
00659 result = dns_rdataset_first(rdataset);
00660 REQUIRE(result == ISC_R_NOMORE);
00661
00662 column = 0;
00663
00664
00665 {
00666 unsigned int name_start = target->used;
00667 RETERR(dns_name_totext(owner_name,
00668 omit_final_dot,
00669 target));
00670 column += target->used - name_start;
00671 }
00672
00673
00674 {
00675 unsigned int class_start;
00676 INDENT_TO(class_column);
00677 class_start = target->used;
00678 result = dns_rdataclass_totext(rdataset->rdclass, target);
00679 if (result != ISC_R_SUCCESS)
00680 return (result);
00681 column += (target->used - class_start);
00682 }
00683
00684
00685 {
00686 unsigned int type_start;
00687 INDENT_TO(type_column);
00688 type_start = target->used;
00689 result = dns_rdatatype_totext(rdataset->type, target);
00690 if (result != ISC_R_SUCCESS)
00691 return (result);
00692 column += (target->used - type_start);
00693 }
00694
00695 isc_buffer_availableregion(target, &r);
00696 if (r.length < 1)
00697 return (ISC_R_NOSPACE);
00698 r.base[0] = '\n';
00699 isc_buffer_add(target, 1);
00700
00701 return (ISC_R_SUCCESS);
00702 }
00703
00704 isc_result_t
00705 dns_rdataset_totext(dns_rdataset_t *rdataset,
00706 dns_name_t *owner_name,
00707 isc_boolean_t omit_final_dot,
00708 isc_boolean_t question,
00709 isc_buffer_t *target)
00710 {
00711 dns_totext_ctx_t ctx;
00712 isc_result_t result;
00713 result = totext_ctx_init(&dns_master_style_debug, &ctx);
00714 if (result != ISC_R_SUCCESS) {
00715 UNEXPECTED_ERROR(__FILE__, __LINE__,
00716 "could not set master file style");
00717 return (ISC_R_UNEXPECTED);
00718 }
00719
00720
00721
00722
00723
00724
00725
00726 if (dns_name_countlabels(owner_name) == 0)
00727 owner_name = NULL;
00728
00729 if (question)
00730 return (question_totext(rdataset, owner_name, &ctx,
00731 omit_final_dot, target));
00732 else
00733 return (rdataset_totext(rdataset, owner_name, &ctx,
00734 omit_final_dot, target));
00735 }
00736
00737 isc_result_t
00738 dns_master_rdatasettotext(dns_name_t *owner_name,
00739 dns_rdataset_t *rdataset,
00740 const dns_master_style_t *style,
00741 isc_buffer_t *target)
00742 {
00743 dns_totext_ctx_t ctx;
00744 isc_result_t result;
00745 result = totext_ctx_init(style, &ctx);
00746 if (result != ISC_R_SUCCESS) {
00747 UNEXPECTED_ERROR(__FILE__, __LINE__,
00748 "could not set master file style");
00749 return (ISC_R_UNEXPECTED);
00750 }
00751
00752 return (rdataset_totext(rdataset, owner_name, &ctx,
00753 ISC_FALSE, target));
00754 }
00755
00756 isc_result_t
00757 dns_master_questiontotext(dns_name_t *owner_name,
00758 dns_rdataset_t *rdataset,
00759 const dns_master_style_t *style,
00760 isc_buffer_t *target)
00761 {
00762 dns_totext_ctx_t ctx;
00763 isc_result_t result;
00764 result = totext_ctx_init(style, &ctx);
00765 if (result != ISC_R_SUCCESS) {
00766 UNEXPECTED_ERROR(__FILE__, __LINE__,
00767 "could not set master file style");
00768 return (ISC_R_UNEXPECTED);
00769 }
00770
00771 return (question_totext(rdataset, owner_name, &ctx,
00772 ISC_FALSE, target));
00773 }
00774
00775
00776
00777
00778
00779
00780
00781
00782 static isc_result_t
00783 dump_rdataset(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset,
00784 dns_totext_ctx_t *ctx,
00785 isc_buffer_t *buffer, FILE *f)
00786 {
00787 isc_region_t r;
00788 isc_result_t result;
00789
00790 REQUIRE(buffer->length > 0);
00791
00792
00793
00794
00795
00796 if ((ctx->style.flags & DNS_STYLEFLAG_TTL) != 0) {
00797 if (ctx->current_ttl_valid == ISC_FALSE ||
00798 ctx->current_ttl != rdataset->ttl)
00799 {
00800 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENT) != 0)
00801 {
00802 isc_buffer_clear(buffer);
00803 result = dns_ttl_totext(rdataset->ttl,
00804 ISC_TRUE, buffer);
00805 INSIST(result == ISC_R_SUCCESS);
00806 isc_buffer_usedregion(buffer, &r);
00807 fprintf(f, "$TTL %u\t; %.*s\n", rdataset->ttl,
00808 (int) r.length, (char *) r.base);
00809 } else {
00810 fprintf(f, "$TTL %u\n", rdataset->ttl);
00811 }
00812 ctx->current_ttl = rdataset->ttl;
00813 ctx->current_ttl_valid = ISC_TRUE;
00814 }
00815 }
00816
00817 isc_buffer_clear(buffer);
00818
00819
00820
00821
00822
00823 for (;;) {
00824 int newlength;
00825 void *newmem;
00826 result = rdataset_totext(rdataset, name, ctx,
00827 ISC_FALSE, buffer);
00828 if (result != ISC_R_NOSPACE)
00829 break;
00830
00831 newlength = buffer->length * 2;
00832 newmem = isc_mem_get(mctx, newlength);
00833 if (newmem == NULL)
00834 return (ISC_R_NOMEMORY);
00835 isc_mem_put(mctx, buffer->base, buffer->length);
00836 isc_buffer_init(buffer, newmem, newlength);
00837 }
00838 if (result != ISC_R_SUCCESS)
00839 return (result);
00840
00841
00842
00843
00844 isc_buffer_usedregion(buffer, &r);
00845 result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL);
00846
00847 if (result != ISC_R_SUCCESS) {
00848 UNEXPECTED_ERROR(__FILE__, __LINE__,
00849 "master file write failed: %s",
00850 isc_result_totext(result));
00851 return (result);
00852 }
00853
00854 return (ISC_R_SUCCESS);
00855 }
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866 static int
00867 dump_order(const dns_rdataset_t *rds) {
00868 int t;
00869 int sig;
00870 if (rds->type == dns_rdatatype_rrsig) {
00871 t = rds->covers;
00872 sig = 1;
00873 } else {
00874 t = rds->type;
00875 sig = 0;
00876 }
00877 switch (t) {
00878 case dns_rdatatype_soa:
00879 t = 0;
00880 break;
00881 case dns_rdatatype_ns:
00882 t = 1;
00883 break;
00884 default:
00885 t += 2;
00886 break;
00887 }
00888 return (t << 1) + sig;
00889 }
00890
00891 static int
00892 dump_order_compare(const void *a, const void *b) {
00893 return (dump_order(*((const dns_rdataset_t * const *) a)) -
00894 dump_order(*((const dns_rdataset_t * const *) b)));
00895 }
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907 #define MAXSORT 64
00908
00909 static isc_result_t
00910 dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name,
00911 dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
00912 isc_buffer_t *buffer, FILE *f)
00913 {
00914 isc_result_t itresult, dumpresult;
00915 isc_region_t r;
00916 dns_rdataset_t rdatasets[MAXSORT];
00917 dns_rdataset_t *sorted[MAXSORT];
00918 int i, n;
00919
00920 itresult = dns_rdatasetiter_first(rdsiter);
00921 dumpresult = ISC_R_SUCCESS;
00922
00923 if (itresult == ISC_R_SUCCESS && ctx->neworigin != NULL) {
00924 isc_buffer_clear(buffer);
00925 itresult = dns_name_totext(ctx->neworigin, ISC_FALSE, buffer);
00926 RUNTIME_CHECK(itresult == ISC_R_SUCCESS);
00927 isc_buffer_usedregion(buffer, &r);
00928 fprintf(f, "$ORIGIN %.*s\n", (int) r.length, (char *) r.base);
00929 ctx->neworigin = NULL;
00930 }
00931
00932 again:
00933 for (i = 0;
00934 itresult == ISC_R_SUCCESS && i < MAXSORT;
00935 itresult = dns_rdatasetiter_next(rdsiter), i++) {
00936 dns_rdataset_init(&rdatasets[i]);
00937 dns_rdatasetiter_current(rdsiter, &rdatasets[i]);
00938 sorted[i] = &rdatasets[i];
00939 }
00940 n = i;
00941 INSIST(n <= MAXSORT);
00942
00943 qsort(sorted, n, sizeof(sorted[0]), dump_order_compare);
00944
00945 for (i = 0; i < n; i++) {
00946 dns_rdataset_t *rds = sorted[i];
00947 if (ctx->style.flags & DNS_STYLEFLAG_TRUST)
00948 fprintf(f, "; %s\n", dns_trust_totext(rds->trust));
00949 if (((rds->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) &&
00950 (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
00951
00952 } else {
00953 isc_result_t result =
00954 dump_rdataset(mctx, name, rds, ctx,
00955 buffer, f);
00956 if (result != ISC_R_SUCCESS)
00957 dumpresult = result;
00958 if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0)
00959 name = NULL;
00960 }
00961 if (ctx->style.flags & DNS_STYLEFLAG_RESIGN &&
00962 rds->attributes & DNS_RDATASETATTR_RESIGN) {
00963 isc_buffer_t b;
00964 char buf[sizeof("YYYYMMDDHHMMSS")];
00965 memset(buf, 0, sizeof(buf));
00966 isc_buffer_init(&b, buf, sizeof(buf) - 1);
00967 dns_time64_totext((isc_uint64_t)rds->resign, &b);
00968 fprintf(f, "; resign=%s\n", buf);
00969 }
00970 dns_rdataset_disassociate(rds);
00971 }
00972
00973 if (dumpresult != ISC_R_SUCCESS)
00974 return (dumpresult);
00975
00976
00977
00978
00979
00980 if (itresult == ISC_R_SUCCESS)
00981 goto again;
00982
00983 if (itresult == ISC_R_NOMORE)
00984 itresult = ISC_R_SUCCESS;
00985
00986 return (itresult);
00987 }
00988
00989
00990
00991
00992 static isc_result_t
00993 dump_rdataset_raw(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset,
00994 isc_buffer_t *buffer, FILE *f)
00995 {
00996 isc_result_t result;
00997 isc_uint32_t totallen;
00998 isc_uint16_t dlen;
00999 isc_region_t r, r_hdr;
01000
01001 REQUIRE(buffer->length > 0);
01002 REQUIRE(DNS_RDATASET_VALID(rdataset));
01003
01004 rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
01005 restart:
01006 totallen = 0;
01007 result = dns_rdataset_first(rdataset);
01008 REQUIRE(result == ISC_R_SUCCESS);
01009
01010 isc_buffer_clear(buffer);
01011
01012
01013
01014
01015
01016
01017 isc_buffer_availableregion(buffer, &r_hdr);
01018 INSIST(r_hdr.length >= sizeof(dns_masterrawrdataset_t));
01019 isc_buffer_putuint32(buffer, totallen);
01020 isc_buffer_putuint16(buffer, rdataset->rdclass);
01021 isc_buffer_putuint16(buffer, rdataset->type);
01022 isc_buffer_putuint16(buffer, rdataset->covers);
01023 isc_buffer_putuint32(buffer, rdataset->ttl);
01024 isc_buffer_putuint32(buffer, dns_rdataset_count(rdataset));
01025 totallen = isc_buffer_usedlength(buffer);
01026 INSIST(totallen <= sizeof(dns_masterrawrdataset_t));
01027
01028 dns_name_toregion(name, &r);
01029 INSIST(isc_buffer_availablelength(buffer) >=
01030 (sizeof(dlen) + r.length));
01031 dlen = (isc_uint16_t)r.length;
01032 isc_buffer_putuint16(buffer, dlen);
01033 isc_buffer_copyregion(buffer, &r);
01034 totallen += sizeof(dlen) + r.length;
01035
01036 do {
01037 dns_rdata_t rdata = DNS_RDATA_INIT;
01038
01039 dns_rdataset_current(rdataset, &rdata);
01040 dns_rdata_toregion(&rdata, &r);
01041 INSIST(r.length <= 0xffffU);
01042 dlen = (isc_uint16_t)r.length;
01043
01044
01045
01046
01047
01048
01049
01050 if (isc_buffer_availablelength(buffer) <
01051 sizeof(dlen) + r.length) {
01052 int newlength;
01053 void *newmem;
01054
01055 newlength = buffer->length * 2;
01056 newmem = isc_mem_get(mctx, newlength);
01057 if (newmem == NULL)
01058 return (ISC_R_NOMEMORY);
01059 isc_mem_put(mctx, buffer->base, buffer->length);
01060 isc_buffer_init(buffer, newmem, newlength);
01061 goto restart;
01062 }
01063 isc_buffer_putuint16(buffer, dlen);
01064 isc_buffer_copyregion(buffer, &r);
01065 totallen += sizeof(dlen) + r.length;
01066
01067 result = dns_rdataset_next(rdataset);
01068 } while (result == ISC_R_SUCCESS);
01069
01070 if (result != ISC_R_NOMORE)
01071 return (result);
01072
01073
01074
01075
01076
01077
01078
01079 isc_buffer_usedregion(buffer, &r);
01080 isc_buffer_clear(buffer);
01081 isc_buffer_putuint32(buffer, totallen);
01082 INSIST(isc_buffer_usedlength(buffer) < totallen);
01083
01084
01085
01086
01087 result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL);
01088
01089 if (result != ISC_R_SUCCESS) {
01090 UNEXPECTED_ERROR(__FILE__, __LINE__,
01091 "raw master file write failed: %s",
01092 isc_result_totext(result));
01093 return (result);
01094 }
01095
01096 return (result);
01097 }
01098
01099 static isc_result_t
01100 dump_rdatasets_raw(isc_mem_t *mctx, dns_name_t *name,
01101 dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
01102 isc_buffer_t *buffer, FILE *f)
01103 {
01104 isc_result_t result;
01105 dns_rdataset_t rdataset;
01106
01107 for (result = dns_rdatasetiter_first(rdsiter);
01108 result == ISC_R_SUCCESS;
01109 result = dns_rdatasetiter_next(rdsiter)) {
01110
01111 dns_rdataset_init(&rdataset);
01112 dns_rdatasetiter_current(rdsiter, &rdataset);
01113
01114 if (((rdataset.attributes & DNS_RDATASETATTR_NEGATIVE) != 0) &&
01115 (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
01116
01117 } else {
01118 result = dump_rdataset_raw(mctx, name, &rdataset,
01119 buffer, f);
01120 }
01121 dns_rdataset_disassociate(&rdataset);
01122 if (result != ISC_R_SUCCESS)
01123 return (result);
01124 }
01125
01126 if (result == ISC_R_NOMORE)
01127 result = ISC_R_SUCCESS;
01128
01129 return (result);
01130 }
01131
01132 static isc_result_t
01133 dump_rdatasets_map(isc_mem_t *mctx, dns_name_t *name,
01134 dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
01135 isc_buffer_t *buffer, FILE *f)
01136 {
01137 UNUSED(mctx);
01138 UNUSED(name);
01139 UNUSED(rdsiter);
01140 UNUSED(ctx);
01141 UNUSED(buffer);
01142 UNUSED(f);
01143
01144 return (ISC_R_NOTIMPLEMENTED);
01145 }
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157 static const int initial_buffer_length = 1200;
01158
01159 static isc_result_t
01160 dumptostreaminc(dns_dumpctx_t *dctx);
01161
01162 static void
01163 dumpctx_destroy(dns_dumpctx_t *dctx) {
01164
01165 dctx->magic = 0;
01166 DESTROYLOCK(&dctx->lock);
01167 dns_dbiterator_destroy(&dctx->dbiter);
01168 if (dctx->version != NULL)
01169 dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
01170 dns_db_detach(&dctx->db);
01171 if (dctx->task != NULL)
01172 isc_task_detach(&dctx->task);
01173 if (dctx->file != NULL)
01174 isc_mem_free(dctx->mctx, dctx->file);
01175 if (dctx->tmpfile != NULL)
01176 isc_mem_free(dctx->mctx, dctx->tmpfile);
01177 isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(*dctx));
01178 }
01179
01180 void
01181 dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target) {
01182
01183 REQUIRE(DNS_DCTX_VALID(source));
01184 REQUIRE(target != NULL && *target == NULL);
01185
01186 LOCK(&source->lock);
01187 INSIST(source->references > 0);
01188 source->references++;
01189 INSIST(source->references != 0);
01190 UNLOCK(&source->lock);
01191
01192 *target = source;
01193 }
01194
01195 void
01196 dns_dumpctx_detach(dns_dumpctx_t **dctxp) {
01197 dns_dumpctx_t *dctx;
01198 isc_boolean_t need_destroy = ISC_FALSE;
01199
01200 REQUIRE(dctxp != NULL);
01201 dctx = *dctxp;
01202 REQUIRE(DNS_DCTX_VALID(dctx));
01203
01204 *dctxp = NULL;
01205
01206 LOCK(&dctx->lock);
01207 INSIST(dctx->references != 0);
01208 dctx->references--;
01209 if (dctx->references == 0)
01210 need_destroy = ISC_TRUE;
01211 UNLOCK(&dctx->lock);
01212 if (need_destroy)
01213 dumpctx_destroy(dctx);
01214 }
01215
01216 dns_dbversion_t *
01217 dns_dumpctx_version(dns_dumpctx_t *dctx) {
01218 REQUIRE(DNS_DCTX_VALID(dctx));
01219 return (dctx->version);
01220 }
01221
01222 dns_db_t *
01223 dns_dumpctx_db(dns_dumpctx_t *dctx) {
01224 REQUIRE(DNS_DCTX_VALID(dctx));
01225 return (dctx->db);
01226 }
01227
01228 void
01229 dns_dumpctx_cancel(dns_dumpctx_t *dctx) {
01230 REQUIRE(DNS_DCTX_VALID(dctx));
01231
01232 LOCK(&dctx->lock);
01233 dctx->canceled = ISC_TRUE;
01234 UNLOCK(&dctx->lock);
01235 }
01236
01237 static isc_result_t
01238 flushandsync(FILE *f, isc_result_t result, const char *temp) {
01239 isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS);
01240
01241 if (result == ISC_R_SUCCESS)
01242 result = isc_stdio_flush(f);
01243 if (result != ISC_R_SUCCESS && logit) {
01244 if (temp != NULL)
01245 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01246 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01247 "dumping to master file: %s: flush: %s",
01248 temp, isc_result_totext(result));
01249 else
01250 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01251 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01252 "dumping to stream: flush: %s",
01253 isc_result_totext(result));
01254 logit = ISC_FALSE;
01255 }
01256
01257 if (result == ISC_R_SUCCESS)
01258 result = isc_stdio_sync(f);
01259 if (result != ISC_R_SUCCESS && logit) {
01260 if (temp != NULL)
01261 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01262 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01263 "dumping to master file: %s: fsync: %s",
01264 temp, isc_result_totext(result));
01265 else
01266 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01267 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01268 "dumping to stream: fsync: %s",
01269 isc_result_totext(result));
01270 }
01271 return (result);
01272 }
01273
01274 static isc_result_t
01275 closeandrename(FILE *f, isc_result_t result, const char *temp, const char *file)
01276 {
01277 isc_result_t tresult;
01278 isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS);
01279
01280 result = flushandsync(f, result, temp);
01281 if (result != ISC_R_SUCCESS)
01282 logit = ISC_FALSE;
01283
01284 tresult = isc_stdio_close(f);
01285 if (result == ISC_R_SUCCESS)
01286 result = tresult;
01287 if (result != ISC_R_SUCCESS && logit) {
01288 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01289 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01290 "dumping master file: %s: fclose: %s",
01291 temp, isc_result_totext(result));
01292 logit = ISC_FALSE;
01293 }
01294 if (result == ISC_R_SUCCESS)
01295 result = isc_file_rename(temp, file);
01296 else
01297 (void)isc_file_remove(temp);
01298 if (result != ISC_R_SUCCESS && logit) {
01299 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01300 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01301 "dumping master file: rename: %s: %s",
01302 file, isc_result_totext(result));
01303 }
01304 return (result);
01305 }
01306
01307 static void
01308 dump_quantum(isc_task_t *task, isc_event_t *event) {
01309 isc_result_t result;
01310 isc_result_t tresult;
01311 dns_dumpctx_t *dctx;
01312
01313 REQUIRE(event != NULL);
01314 dctx = event->ev_arg;
01315 REQUIRE(DNS_DCTX_VALID(dctx));
01316 if (dctx->canceled)
01317 result = ISC_R_CANCELED;
01318 else
01319 result = dumptostreaminc(dctx);
01320 if (result == DNS_R_CONTINUE) {
01321 event->ev_arg = dctx;
01322 isc_task_send(task, &event);
01323 return;
01324 }
01325
01326 if (dctx->file != NULL) {
01327 tresult = closeandrename(dctx->f, result,
01328 dctx->tmpfile, dctx->file);
01329 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
01330 result = tresult;
01331 } else
01332 result = flushandsync(dctx->f, result, NULL);
01333 (dctx->done)(dctx->done_arg, result);
01334 isc_event_free(&event);
01335 dns_dumpctx_detach(&dctx);
01336 }
01337
01338 static isc_result_t
01339 task_send(dns_dumpctx_t *dctx) {
01340 isc_event_t *event;
01341
01342 event = isc_event_allocate(dctx->mctx, NULL, DNS_EVENT_DUMPQUANTUM,
01343 dump_quantum, dctx, sizeof(*event));
01344 if (event == NULL)
01345 return (ISC_R_NOMEMORY);
01346 isc_task_send(dctx->task, &event);
01347 return (ISC_R_SUCCESS);
01348 }
01349
01350 static isc_result_t
01351 dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01352 const dns_master_style_t *style, FILE *f, dns_dumpctx_t **dctxp,
01353 dns_masterformat_t format, dns_masterrawheader_t *header)
01354 {
01355 dns_dumpctx_t *dctx;
01356 isc_result_t result;
01357 unsigned int options;
01358
01359 dctx = isc_mem_get(mctx, sizeof(*dctx));
01360 if (dctx == NULL)
01361 return (ISC_R_NOMEMORY);
01362
01363 dctx->mctx = NULL;
01364 dctx->f = f;
01365 dctx->dbiter = NULL;
01366 dctx->db = NULL;
01367 dctx->version = NULL;
01368 dctx->done = NULL;
01369 dctx->done_arg = NULL;
01370 dctx->task = NULL;
01371 dctx->nodes = 0;
01372 dctx->first = ISC_TRUE;
01373 dctx->canceled = ISC_FALSE;
01374 dctx->file = NULL;
01375 dctx->tmpfile = NULL;
01376 dctx->format = format;
01377 if (header == NULL)
01378 dns_master_initrawheader(&dctx->header);
01379 else
01380 dctx->header = *header;
01381
01382 switch (format) {
01383 case dns_masterformat_text:
01384 dctx->dumpsets = dump_rdatasets_text;
01385 break;
01386 case dns_masterformat_raw:
01387 dctx->dumpsets = dump_rdatasets_raw;
01388 break;
01389 case dns_masterformat_map:
01390 dctx->dumpsets = dump_rdatasets_map;
01391 break;
01392 default:
01393 INSIST(0);
01394 break;
01395 }
01396
01397 result = totext_ctx_init(style, &dctx->tctx);
01398 if (result != ISC_R_SUCCESS) {
01399 UNEXPECTED_ERROR(__FILE__, __LINE__,
01400 "could not set master file style");
01401 goto cleanup;
01402 }
01403
01404 isc_stdtime_get(&dctx->now);
01405 dns_db_attach(db, &dctx->db);
01406
01407 dctx->do_date = dns_db_iscache(dctx->db);
01408
01409 if (dctx->format == dns_masterformat_text &&
01410 (dctx->tctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) {
01411 options = DNS_DB_RELATIVENAMES;
01412 } else
01413 options = 0;
01414 result = dns_db_createiterator(dctx->db, options, &dctx->dbiter);
01415 if (result != ISC_R_SUCCESS)
01416 goto cleanup;
01417
01418 result = isc_mutex_init(&dctx->lock);
01419 if (result != ISC_R_SUCCESS)
01420 goto cleanup;
01421 if (version != NULL)
01422 dns_db_attachversion(dctx->db, version, &dctx->version);
01423 else if (!dns_db_iscache(db))
01424 dns_db_currentversion(dctx->db, &dctx->version);
01425 isc_mem_attach(mctx, &dctx->mctx);
01426 dctx->references = 1;
01427 dctx->magic = DNS_DCTX_MAGIC;
01428 *dctxp = dctx;
01429 return (ISC_R_SUCCESS);
01430
01431 cleanup:
01432 if (dctx->dbiter != NULL)
01433 dns_dbiterator_destroy(&dctx->dbiter);
01434 if (dctx->db != NULL)
01435 dns_db_detach(&dctx->db);
01436 if (dctx != NULL)
01437 isc_mem_put(mctx, dctx, sizeof(*dctx));
01438 return (result);
01439 }
01440
01441 static isc_result_t
01442 writeheader(dns_dumpctx_t *dctx) {
01443 isc_result_t result = ISC_R_SUCCESS;
01444 isc_buffer_t buffer;
01445 char *bufmem;
01446 isc_region_t r;
01447 dns_masterrawheader_t rawheader;
01448 isc_uint32_t rawversion, now32;
01449
01450 bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
01451 if (bufmem == NULL)
01452 return (ISC_R_NOMEMORY);
01453
01454 isc_buffer_init(&buffer, bufmem, initial_buffer_length);
01455
01456 switch (dctx->format) {
01457 case dns_masterformat_text:
01458
01459
01460
01461
01462
01463
01464
01465
01466 if (dctx->do_date) {
01467 result = dns_time32_totext(dctx->now, &buffer);
01468 RUNTIME_CHECK(result == ISC_R_SUCCESS);
01469 isc_buffer_usedregion(&buffer, &r);
01470 fprintf(dctx->f, "$DATE %.*s\n",
01471 (int) r.length, (char *) r.base);
01472 }
01473 break;
01474 case dns_masterformat_raw:
01475 case dns_masterformat_map:
01476 r.base = (unsigned char *)&rawheader;
01477 r.length = sizeof(rawheader);
01478 isc_buffer_region(&buffer, &r);
01479 #if !defined(STDTIME_ON_32BITS) || (STDTIME_ON_32BITS + 0) != 1
01480
01481
01482
01483
01484
01485
01486
01487 isc_log_write(dns_lctx,
01488 ISC_LOGCATEGORY_GENERAL,
01489 DNS_LOGMODULE_MASTERDUMP,
01490 ISC_LOG_INFO,
01491 "dumping master file in raw "
01492 "format: stdtime is not 32bits");
01493 now32 = 0;
01494 #else
01495 now32 = dctx->now;
01496 #endif
01497 rawversion = 1;
01498 if ((dctx->header.flags & DNS_MASTERRAW_COMPAT) != 0)
01499 rawversion = 0;
01500
01501 isc_buffer_putuint32(&buffer, dctx->format);
01502 isc_buffer_putuint32(&buffer, rawversion);
01503 isc_buffer_putuint32(&buffer, now32);
01504
01505 if (rawversion == 1) {
01506 isc_buffer_putuint32(&buffer, dctx->header.flags);
01507 isc_buffer_putuint32(&buffer,
01508 dctx->header.sourceserial);
01509 isc_buffer_putuint32(&buffer, dctx->header.lastxfrin);
01510 }
01511
01512 INSIST(isc_buffer_usedlength(&buffer) <= sizeof(rawheader));
01513 result = isc_stdio_write(buffer.base, 1,
01514 isc_buffer_usedlength(&buffer),
01515 dctx->f, NULL);
01516 if (result != ISC_R_SUCCESS)
01517 break;
01518
01519 break;
01520 default:
01521 INSIST(0);
01522 }
01523
01524 isc_mem_put(dctx->mctx, buffer.base, buffer.length);
01525 return (result);
01526 }
01527
01528 static isc_result_t
01529 dumptostreaminc(dns_dumpctx_t *dctx) {
01530 isc_result_t result = ISC_R_SUCCESS;
01531 isc_buffer_t buffer;
01532 char *bufmem;
01533 dns_name_t *name;
01534 dns_fixedname_t fixname;
01535 unsigned int nodes;
01536 isc_time_t start;
01537
01538 bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
01539 if (bufmem == NULL)
01540 return (ISC_R_NOMEMORY);
01541
01542 isc_buffer_init(&buffer, bufmem, initial_buffer_length);
01543
01544 dns_fixedname_init(&fixname);
01545 name = dns_fixedname_name(&fixname);
01546
01547 if (dctx->first) {
01548 CHECK(writeheader(dctx));
01549
01550
01551
01552
01553
01554
01555
01556 if (dctx->format == dns_masterformat_map) {
01557 result = dns_db_serialize(dctx->db, dctx->version,
01558 dctx->f);
01559 goto cleanup;
01560 }
01561
01562 result = dns_dbiterator_first(dctx->dbiter);
01563 if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
01564 goto cleanup;
01565
01566 dctx->first = ISC_FALSE;
01567 } else
01568 result = ISC_R_SUCCESS;
01569
01570 nodes = dctx->nodes;
01571 isc_time_now(&start);
01572 while (result == ISC_R_SUCCESS && (dctx->nodes == 0 || nodes--)) {
01573 dns_rdatasetiter_t *rdsiter = NULL;
01574 dns_dbnode_t *node = NULL;
01575
01576 result = dns_dbiterator_current(dctx->dbiter, &node, name);
01577 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
01578 break;
01579 if (result == DNS_R_NEWORIGIN) {
01580 dns_name_t *origin =
01581 dns_fixedname_name(&dctx->tctx.origin_fixname);
01582 result = dns_dbiterator_origin(dctx->dbiter, origin);
01583 RUNTIME_CHECK(result == ISC_R_SUCCESS);
01584 if ((dctx->tctx.style.flags &
01585 DNS_STYLEFLAG_REL_DATA) != 0)
01586 dctx->tctx.origin = origin;
01587 dctx->tctx.neworigin = origin;
01588 }
01589 result = dns_db_allrdatasets(dctx->db, node, dctx->version,
01590 dctx->now, &rdsiter);
01591 if (result != ISC_R_SUCCESS) {
01592 dns_db_detachnode(dctx->db, &node);
01593 goto cleanup;
01594 }
01595 result = (dctx->dumpsets)(dctx->mctx, name, rdsiter,
01596 &dctx->tctx, &buffer, dctx->f);
01597 dns_rdatasetiter_destroy(&rdsiter);
01598 if (result != ISC_R_SUCCESS) {
01599 dns_db_detachnode(dctx->db, &node);
01600 goto cleanup;
01601 }
01602 dns_db_detachnode(dctx->db, &node);
01603 result = dns_dbiterator_next(dctx->dbiter);
01604 }
01605
01606
01607
01608
01609
01610
01611
01612 if (dctx->nodes != 0 && result == ISC_R_SUCCESS) {
01613 unsigned int pps = dns_pps;
01614 unsigned int interval;
01615 isc_uint64_t usecs;
01616 isc_time_t end;
01617
01618 isc_time_now(&end);
01619 if (pps < 100)
01620 pps = 100;
01621 interval = 1000000 / pps;
01622 if (interval == 0)
01623 interval = 1;
01624 usecs = isc_time_microdiff(&end, &start);
01625 if (usecs == 0) {
01626 dctx->nodes = dctx->nodes * 2;
01627 if (dctx->nodes > 1000)
01628 dctx->nodes = 1000;
01629 } else {
01630 nodes = dctx->nodes * interval;
01631 nodes /= (unsigned int)usecs;
01632 if (nodes == 0)
01633 nodes = 1;
01634 else if (nodes > 1000)
01635 nodes = 1000;
01636
01637
01638 dctx->nodes = (nodes + dctx->nodes * 7) / 8;
01639
01640 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01641 DNS_LOGMODULE_MASTERDUMP,
01642 ISC_LOG_DEBUG(1),
01643 "dumptostreaminc(%p) new nodes -> %d\n",
01644 dctx, dctx->nodes);
01645 }
01646 result = DNS_R_CONTINUE;
01647 } else if (result == ISC_R_NOMORE)
01648 result = ISC_R_SUCCESS;
01649 cleanup:
01650 RUNTIME_CHECK(dns_dbiterator_pause(dctx->dbiter) == ISC_R_SUCCESS);
01651 isc_mem_put(dctx->mctx, buffer.base, buffer.length);
01652 return (result);
01653 }
01654
01655 isc_result_t
01656 dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db,
01657 dns_dbversion_t *version,
01658 const dns_master_style_t *style,
01659 FILE *f, isc_task_t *task,
01660 dns_dumpdonefunc_t done, void *done_arg,
01661 dns_dumpctx_t **dctxp)
01662 {
01663 dns_dumpctx_t *dctx = NULL;
01664 isc_result_t result;
01665
01666 REQUIRE(task != NULL);
01667 REQUIRE(f != NULL);
01668 REQUIRE(done != NULL);
01669
01670 result = dumpctx_create(mctx, db, version, style, f, &dctx,
01671 dns_masterformat_text, NULL);
01672 if (result != ISC_R_SUCCESS)
01673 return (result);
01674 isc_task_attach(task, &dctx->task);
01675 dctx->done = done;
01676 dctx->done_arg = done_arg;
01677 dctx->nodes = 100;
01678
01679 result = task_send(dctx);
01680 if (result == ISC_R_SUCCESS) {
01681 dns_dumpctx_attach(dctx, dctxp);
01682 return (DNS_R_CONTINUE);
01683 }
01684
01685 dns_dumpctx_detach(&dctx);
01686 return (result);
01687 }
01688
01689
01690
01691
01692 isc_result_t
01693 dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db,
01694 dns_dbversion_t *version,
01695 const dns_master_style_t *style,
01696 FILE *f)
01697 {
01698 return (dns_master_dumptostream3(mctx, db, version, style,
01699 dns_masterformat_text, NULL, f));
01700 }
01701
01702 isc_result_t
01703 dns_master_dumptostream2(isc_mem_t *mctx, dns_db_t *db,
01704 dns_dbversion_t *version,
01705 const dns_master_style_t *style,
01706 dns_masterformat_t format, FILE *f)
01707 {
01708 return (dns_master_dumptostream3(mctx, db, version, style,
01709 format, NULL, f));
01710 }
01711
01712 isc_result_t
01713 dns_master_dumptostream3(isc_mem_t *mctx, dns_db_t *db,
01714 dns_dbversion_t *version,
01715 const dns_master_style_t *style,
01716 dns_masterformat_t format,
01717 dns_masterrawheader_t *header, FILE *f)
01718 {
01719 dns_dumpctx_t *dctx = NULL;
01720 isc_result_t result;
01721
01722 result = dumpctx_create(mctx, db, version, style, f, &dctx,
01723 format, header);
01724 if (result != ISC_R_SUCCESS)
01725 return (result);
01726
01727 result = dumptostreaminc(dctx);
01728 INSIST(result != DNS_R_CONTINUE);
01729 dns_dumpctx_detach(&dctx);
01730
01731 result = flushandsync(f, result, NULL);
01732 return (result);
01733 }
01734
01735 static isc_result_t
01736 opentmp(isc_mem_t *mctx, dns_masterformat_t format, const char *file,
01737 char **tempp, FILE **fp) {
01738 FILE *f = NULL;
01739 isc_result_t result;
01740 char *tempname = NULL;
01741 int tempnamelen;
01742
01743 tempnamelen = strlen(file) + 20;
01744 tempname = isc_mem_allocate(mctx, tempnamelen);
01745 if (tempname == NULL)
01746 return (ISC_R_NOMEMORY);
01747
01748 result = isc_file_mktemplate(file, tempname, tempnamelen);
01749 if (result != ISC_R_SUCCESS)
01750 goto cleanup;
01751
01752 if (format == dns_masterformat_text)
01753 result = isc_file_openunique(tempname, &f);
01754 else
01755 result = isc_file_bopenunique(tempname, &f);
01756 if (result != ISC_R_SUCCESS) {
01757 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01758 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01759 "dumping master file: %s: open: %s",
01760 tempname, isc_result_totext(result));
01761 goto cleanup;
01762 }
01763 *tempp = tempname;
01764 *fp = f;
01765 return (ISC_R_SUCCESS);
01766
01767 cleanup:
01768 isc_mem_free(mctx, tempname);
01769 return (result);
01770 }
01771
01772 isc_result_t
01773 dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01774 const dns_master_style_t *style, const char *filename,
01775 isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
01776 dns_dumpctx_t **dctxp)
01777 {
01778 return (dns_master_dumpinc3(mctx, db, version, style, filename, task,
01779 done, done_arg, dctxp,
01780 dns_masterformat_text, NULL));
01781 }
01782
01783 isc_result_t
01784 dns_master_dumpinc2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01785 const dns_master_style_t *style, const char *filename,
01786 isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
01787 dns_dumpctx_t **dctxp, dns_masterformat_t format)
01788 {
01789 return (dns_master_dumpinc3(mctx, db, version, style, filename, task,
01790 done, done_arg, dctxp, format, NULL));
01791 }
01792
01793 isc_result_t
01794 dns_master_dumpinc3(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01795 const dns_master_style_t *style, const char *filename,
01796 isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
01797 dns_dumpctx_t **dctxp, dns_masterformat_t format,
01798 dns_masterrawheader_t *header)
01799 {
01800 FILE *f = NULL;
01801 isc_result_t result;
01802 char *tempname = NULL;
01803 char *file = NULL;
01804 dns_dumpctx_t *dctx = NULL;
01805
01806 file = isc_mem_strdup(mctx, filename);
01807 if (file == NULL)
01808 return (ISC_R_NOMEMORY);
01809
01810 result = opentmp(mctx, format, filename, &tempname, &f);
01811 if (result != ISC_R_SUCCESS)
01812 goto cleanup;
01813
01814 result = dumpctx_create(mctx, db, version, style, f, &dctx,
01815 format, header);
01816 if (result != ISC_R_SUCCESS) {
01817 (void)isc_stdio_close(f);
01818 (void)isc_file_remove(tempname);
01819 goto cleanup;
01820 }
01821
01822 isc_task_attach(task, &dctx->task);
01823 dctx->done = done;
01824 dctx->done_arg = done_arg;
01825 dctx->nodes = 100;
01826 dctx->file = file;
01827 file = NULL;
01828 dctx->tmpfile = tempname;
01829 tempname = NULL;
01830
01831 result = task_send(dctx);
01832 if (result == ISC_R_SUCCESS) {
01833 dns_dumpctx_attach(dctx, dctxp);
01834 return (DNS_R_CONTINUE);
01835 }
01836
01837 cleanup:
01838 if (dctx != NULL)
01839 dns_dumpctx_detach(&dctx);
01840 if (file != NULL)
01841 isc_mem_free(mctx, file);
01842 if (tempname != NULL)
01843 isc_mem_free(mctx, tempname);
01844 return (result);
01845 }
01846
01847 isc_result_t
01848 dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01849 const dns_master_style_t *style, const char *filename)
01850 {
01851 return (dns_master_dump3(mctx, db, version, style, filename,
01852 dns_masterformat_text, NULL));
01853 }
01854
01855 isc_result_t
01856 dns_master_dump2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01857 const dns_master_style_t *style, const char *filename,
01858 dns_masterformat_t format)
01859 {
01860 return (dns_master_dump3(mctx, db, version, style, filename,
01861 format, NULL));
01862 }
01863
01864 isc_result_t
01865 dns_master_dump3(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01866 const dns_master_style_t *style, const char *filename,
01867 dns_masterformat_t format, dns_masterrawheader_t *header)
01868 {
01869 FILE *f = NULL;
01870 isc_result_t result;
01871 char *tempname;
01872 dns_dumpctx_t *dctx = NULL;
01873
01874 result = opentmp(mctx, format, filename, &tempname, &f);
01875 if (result != ISC_R_SUCCESS)
01876 return (result);
01877
01878 result = dumpctx_create(mctx, db, version, style, f, &dctx,
01879 format, header);
01880 if (result != ISC_R_SUCCESS)
01881 goto cleanup;
01882
01883 result = dumptostreaminc(dctx);
01884 INSIST(result != DNS_R_CONTINUE);
01885 dns_dumpctx_detach(&dctx);
01886
01887 result = closeandrename(f, result, tempname, filename);
01888
01889 cleanup:
01890 isc_mem_free(mctx, tempname);
01891 return (result);
01892 }
01893
01894
01895
01896
01897
01898 isc_result_t
01899 dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db,
01900 dns_dbversion_t *version,
01901 dns_dbnode_t *node, dns_name_t *name,
01902 const dns_master_style_t *style,
01903 FILE *f)
01904 {
01905 isc_result_t result;
01906 isc_buffer_t buffer;
01907 char *bufmem;
01908 isc_stdtime_t now;
01909 dns_totext_ctx_t ctx;
01910 dns_rdatasetiter_t *rdsiter = NULL;
01911
01912 result = totext_ctx_init(style, &ctx);
01913 if (result != ISC_R_SUCCESS) {
01914 UNEXPECTED_ERROR(__FILE__, __LINE__,
01915 "could not set master file style");
01916 return (ISC_R_UNEXPECTED);
01917 }
01918
01919 isc_stdtime_get(&now);
01920
01921 bufmem = isc_mem_get(mctx, initial_buffer_length);
01922 if (bufmem == NULL)
01923 return (ISC_R_NOMEMORY);
01924
01925 isc_buffer_init(&buffer, bufmem, initial_buffer_length);
01926
01927 result = dns_db_allrdatasets(db, node, version, now, &rdsiter);
01928 if (result != ISC_R_SUCCESS)
01929 goto failure;
01930 result = dump_rdatasets_text(mctx, name, rdsiter, &ctx, &buffer, f);
01931 if (result != ISC_R_SUCCESS)
01932 goto failure;
01933 dns_rdatasetiter_destroy(&rdsiter);
01934
01935 result = ISC_R_SUCCESS;
01936
01937 failure:
01938 isc_mem_put(mctx, buffer.base, buffer.length);
01939 return (result);
01940 }
01941
01942 isc_result_t
01943 dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01944 dns_dbnode_t *node, dns_name_t *name,
01945 const dns_master_style_t *style, const char *filename)
01946 {
01947 FILE *f = NULL;
01948 isc_result_t result;
01949
01950 result = isc_stdio_open(filename, "w", &f);
01951 if (result != ISC_R_SUCCESS) {
01952 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01953 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01954 "dumping node to file: %s: open: %s", filename,
01955 isc_result_totext(result));
01956 return (ISC_R_UNEXPECTED);
01957 }
01958
01959 result = dns_master_dumpnodetostream(mctx, db, version, node, name,
01960 style, f);
01961 if (result != ISC_R_SUCCESS) {
01962 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01963 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01964 "dumping master file: %s: dump: %s", filename,
01965 isc_result_totext(result));
01966 (void)isc_stdio_close(f);
01967 return (ISC_R_UNEXPECTED);
01968 }
01969
01970 result = isc_stdio_close(f);
01971 if (result != ISC_R_SUCCESS) {
01972 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01973 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01974 "dumping master file: %s: close: %s", filename,
01975 isc_result_totext(result));
01976 return (ISC_R_UNEXPECTED);
01977 }
01978
01979 return (result);
01980 }
01981
01982 isc_result_t
01983 dns_master_stylecreate(dns_master_style_t **stylep, unsigned int flags,
01984 unsigned int ttl_column, unsigned int class_column,
01985 unsigned int type_column, unsigned int rdata_column,
01986 unsigned int line_length, unsigned int tab_width,
01987 isc_mem_t *mctx)
01988 {
01989 return (dns_master_stylecreate2(stylep, flags, ttl_column,
01990 class_column, type_column,
01991 rdata_column, line_length,
01992 tab_width, 0xffffffff, mctx));
01993 }
01994
01995 isc_result_t
01996 dns_master_stylecreate2(dns_master_style_t **stylep, unsigned int flags,
01997 unsigned int ttl_column, unsigned int class_column,
01998 unsigned int type_column, unsigned int rdata_column,
01999 unsigned int line_length, unsigned int tab_width,
02000 unsigned int split_width, isc_mem_t *mctx)
02001 {
02002 dns_master_style_t *style;
02003
02004 REQUIRE(stylep != NULL && *stylep == NULL);
02005 style = isc_mem_get(mctx, sizeof(*style));
02006 if (style == NULL)
02007 return (ISC_R_NOMEMORY);
02008
02009 style->flags = flags;
02010 style->ttl_column = ttl_column;
02011 style->class_column = class_column;
02012 style->type_column = type_column;
02013 style->rdata_column = rdata_column;
02014 style->line_length = line_length;
02015 style->tab_width = tab_width;
02016 style->split_width = split_width;
02017
02018 *stylep = style;
02019 return (ISC_R_SUCCESS);
02020 }
02021
02022 void
02023 dns_master_styledestroy(dns_master_style_t **stylep, isc_mem_t *mctx) {
02024 dns_master_style_t *style;
02025
02026 REQUIRE(stylep != NULL && *stylep != NULL);
02027 style = *stylep;
02028 *stylep = NULL;
02029 isc_mem_put(mctx, style, sizeof(*style));
02030 }