2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001, 2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: masterdump.c,v 1.56.2.6 2004/03/09 06:11:03 marka Exp $ */
26 #include <isc/stdio.h>
27 #include <isc/string.h>
31 #include <dns/dbiterator.h>
32 #include <dns/fixedname.h>
34 #include <dns/masterdump.h>
35 #include <dns/rdata.h>
36 #include <dns/rdataclass.h>
37 #include <dns/rdataset.h>
38 #include <dns/rdatasetiter.h>
39 #include <dns/rdatatype.h>
40 #include <dns/result.h>
44 #define RETERR(x) do { \
45 isc_result_t _r = (x); \
46 if (_r != ISC_R_SUCCESS) \
50 struct dns_master_style {
51 unsigned int flags; /* DNS_STYLEFLAG_* */
52 unsigned int ttl_column;
53 unsigned int class_column;
54 unsigned int type_column;
55 unsigned int rdata_column;
56 unsigned int line_length;
57 unsigned int tab_width;
61 * Flags affecting master file formatting. Flags 0x0000FFFF
62 * define the formatting of the rdata part and are defined in
66 /* Omit the owner name when possible. */
67 #define DNS_STYLEFLAG_OMIT_OWNER 0x00010000U
70 * Omit the TTL when possible. If DNS_STYLEFLAG_TTL is
71 * also set, this means no TTLs are ever printed
72 * because $TTL directives are generated before every
73 * change in the TTL. In this case, no columns need to
74 * be reserved for the TTL. Master files generated with
75 * these options will be rejected by BIND 4.x because it
76 * does not recognize the $TTL directive.
78 * If DNS_STYLEFLAG_TTL is not also set, the TTL will be
79 * omitted when it is equal to the previous TTL.
80 * This is correct according to RFC1035, but the
81 * TTLs may be silently misinterpreted by older
82 * versions of BIND which use the SOA MINTTL as a
85 #define DNS_STYLEFLAG_OMIT_TTL 0x00020000U
87 /* Omit the class when possible. */
88 #define DNS_STYLEFLAG_OMIT_CLASS 0x00040000U
90 /* Output $TTL directives. */
91 #define DNS_STYLEFLAG_TTL 0x00080000U
94 * Output $ORIGIN directives and print owner names relative to
95 * the origin when possible.
97 #define DNS_STYLEFLAG_REL_OWNER 0x00100000U
99 /* Print domain names in RR data in relative form when possible.
100 For this to take effect, DNS_STYLEFLAG_REL_OWNER must also be set. */
101 #define DNS_STYLEFLAG_REL_DATA 0x00200000U
103 /* Print the trust level of each rdataset. */
104 #define DNS_STYLEFLAG_TRUST 0x00400000U
106 /* Print negative caching entries. */
107 #define DNS_STYLEFLAG_NCACHE 0x00800000U
111 * The maximum length of the newline+indentation that is output
112 * when inserting a line break in an RR. This effectively puts an
113 * upper limits on the value of "rdata_column", because if it is
114 * very large, the tabs and spaces needed to reach it will not fit.
116 #define DNS_TOTEXT_LINEBREAK_MAXLEN 100
119 * Context structure for a masterfile dump in progress.
121 typedef struct dns_totext_ctx {
122 dns_master_style_t style;
123 isc_boolean_t class_printed;
125 char linebreak_buf[DNS_TOTEXT_LINEBREAK_MAXLEN];
127 dns_name_t * neworigin;
128 dns_fixedname_t origin_fixname;
129 isc_uint32_t current_ttl;
130 isc_boolean_t current_ttl_valid;
133 LIBDNS_EXTERNAL_DATA const dns_master_style_t
134 dns_master_style_default = {
135 DNS_STYLEFLAG_OMIT_OWNER |
136 DNS_STYLEFLAG_OMIT_CLASS |
137 DNS_STYLEFLAG_REL_OWNER |
138 DNS_STYLEFLAG_REL_DATA |
139 DNS_STYLEFLAG_OMIT_TTL |
141 DNS_STYLEFLAG_COMMENT |
142 DNS_STYLEFLAG_MULTILINE,
143 24, 24, 24, 32, 80, 8
146 LIBDNS_EXTERNAL_DATA const dns_master_style_t
147 dns_master_style_explicitttl = {
148 DNS_STYLEFLAG_OMIT_OWNER |
149 DNS_STYLEFLAG_OMIT_CLASS |
150 DNS_STYLEFLAG_REL_OWNER |
151 DNS_STYLEFLAG_REL_DATA |
152 DNS_STYLEFLAG_COMMENT |
153 DNS_STYLEFLAG_MULTILINE,
154 24, 32, 32, 40, 80, 8
157 const dns_master_style_t
158 dns_master_style_cache = {
159 DNS_STYLEFLAG_OMIT_OWNER |
160 DNS_STYLEFLAG_OMIT_CLASS |
161 DNS_STYLEFLAG_MULTILINE |
162 DNS_STYLEFLAG_TRUST |
163 DNS_STYLEFLAG_NCACHE,
164 24, 32, 32, 40, 80, 8
167 const dns_master_style_t
168 dns_master_style_simple = {
170 24, 32, 32, 40, 80, 8
175 * A style suitable for dns_rdataset_totext().
177 LIBDNS_EXTERNAL_DATA const dns_master_style_t
178 dns_master_style_debug = {
179 DNS_STYLEFLAG_REL_OWNER,
180 24, 32, 40, 48, 80, 8
185 static char spaces[N_SPACES+1] = " ";
188 static char tabs[N_TABS+1] = "\t\t\t\t\t\t\t\t\t\t";
190 #define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
193 * Output tabs and spaces to go from column '*current' to
194 * column 'to', and update '*current' to reflect the new
198 indent(unsigned int *current, unsigned int to, int tabwidth,
199 isc_buffer_t *target)
204 int ntabs, nspaces, t;
211 ntabs = to / tabwidth - from / tabwidth;
216 isc_buffer_availableregion(target, &r);
217 if (r.length < (unsigned) ntabs)
218 return (ISC_R_NOSPACE);
230 isc_buffer_add(target, ntabs);
231 from = (to / tabwidth) * tabwidth;
235 INSIST(nspaces >= 0);
237 isc_buffer_availableregion(target, &r);
238 if (r.length < (unsigned) nspaces)
239 return (ISC_R_NOSPACE);
247 memcpy(p, spaces, n);
251 isc_buffer_add(target, nspaces);
254 return (ISC_R_SUCCESS);
258 totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) {
261 REQUIRE(style->tab_width != 0);
264 ctx->class_printed = ISC_FALSE;
266 dns_fixedname_init(&ctx->origin_fixname);
269 * Set up the line break string if needed.
271 if ((ctx->style.flags & DNS_STYLEFLAG_MULTILINE) != 0) {
274 unsigned int col = 0;
276 isc_buffer_init(&buf, ctx->linebreak_buf,
277 sizeof(ctx->linebreak_buf));
279 isc_buffer_availableregion(&buf, &r);
281 return (DNS_R_TEXTTOOLONG);
283 isc_buffer_add(&buf, 1);
285 result = indent(&col, ctx->style.rdata_column,
286 ctx->style.tab_width, &buf);
288 * Do not return ISC_R_NOSPACE if the line break string
289 * buffer is too small, because that would just make
290 * dump_rdataset() retry indenfinitely with ever
291 * bigger target buffers. That's a different buffer,
292 * so it won't help. Use DNS_R_TEXTTOOLONG as a substitute.
294 if (result == ISC_R_NOSPACE)
295 return (DNS_R_TEXTTOOLONG);
296 if (result != ISC_R_SUCCESS)
299 isc_buffer_availableregion(&buf, &r);
301 return (DNS_R_TEXTTOOLONG);
303 isc_buffer_add(&buf, 1);
304 ctx->linebreak = ctx->linebreak_buf;
306 ctx->linebreak = NULL;
310 ctx->neworigin = NULL;
311 ctx->current_ttl = 0;
312 ctx->current_ttl_valid = ISC_FALSE;
314 return (ISC_R_SUCCESS);
317 #define INDENT_TO(col) \
319 if ((result = indent(&column, ctx->style.col, \
320 ctx->style.tab_width, target)) \
327 str_totext(const char *source, isc_buffer_t *target) {
331 isc_buffer_availableregion(target, ®ion);
334 if (l > region.length)
335 return (ISC_R_NOSPACE);
337 memcpy(region.base, source, l);
338 isc_buffer_add(target, l);
339 return (ISC_R_SUCCESS);
343 * Convert 'rdataset' to master file text format according to 'ctx',
344 * storing the result in 'target'. If 'owner_name' is NULL, it
345 * is omitted; otherwise 'owner_name' must be valid and have at least
350 rdataset_totext(dns_rdataset_t *rdataset,
351 dns_name_t *owner_name,
352 dns_totext_ctx_t *ctx,
353 isc_boolean_t omit_final_dot,
354 isc_buffer_t *target)
358 isc_boolean_t first = ISC_TRUE;
359 isc_uint32_t current_ttl;
360 isc_boolean_t current_ttl_valid;
361 dns_rdatatype_t type;
363 REQUIRE(DNS_RDATASET_VALID(rdataset));
365 result = dns_rdataset_first(rdataset);
366 REQUIRE(result == ISC_R_SUCCESS);
368 current_ttl = ctx->current_ttl;
369 current_ttl_valid = ctx->current_ttl_valid;
377 if (owner_name != NULL &&
378 ! ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0 &&
381 unsigned int name_start = target->used;
382 RETERR(dns_name_totext(owner_name,
385 column += target->used - name_start;
391 if (! ((ctx->style.flags & DNS_STYLEFLAG_OMIT_TTL) != 0 &&
393 rdataset->ttl == current_ttl))
399 INDENT_TO(ttl_column);
400 length = sprintf(ttlbuf, "%u", rdataset->ttl);
401 INSIST(length <= sizeof ttlbuf);
402 isc_buffer_availableregion(target, &r);
403 if (r.length < length)
404 return (ISC_R_NOSPACE);
405 memcpy(r.base, ttlbuf, length);
406 isc_buffer_add(target, length);
410 * If the $TTL directive is not in use, the TTL we
411 * just printed becomes the default for subsequent RRs.
413 if ((ctx->style.flags & DNS_STYLEFLAG_TTL) == 0) {
414 current_ttl = rdataset->ttl;
415 current_ttl_valid = ISC_TRUE;
422 if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_CLASS) == 0 ||
423 ctx->class_printed == ISC_FALSE)
425 unsigned int class_start;
426 INDENT_TO(class_column);
427 class_start = target->used;
428 result = dns_rdataclass_totext(rdataset->rdclass,
430 if (result != ISC_R_SUCCESS)
432 column += (target->used - class_start);
439 if (rdataset->type == 0) {
440 type = rdataset->covers;
442 type = rdataset->type;
446 unsigned int type_start;
447 INDENT_TO(type_column);
448 type_start = target->used;
449 if (rdataset->type == 0)
450 RETERR(str_totext("\\-", target));
451 result = dns_rdatatype_totext(type, target);
452 if (result != ISC_R_SUCCESS)
454 column += (target->used - type_start);
460 INDENT_TO(rdata_column);
461 if (rdataset->type == 0) {
462 if (NXDOMAIN(rdataset))
463 RETERR(str_totext(";-$NXDOMAIN\n", target));
465 RETERR(str_totext(";-$NXRRSET\n", target));
467 dns_rdata_t rdata = DNS_RDATA_INIT;
470 dns_rdataset_current(rdataset, &rdata);
472 RETERR(dns_rdata_tofmttext(&rdata,
475 ctx->style.line_length -
476 ctx->style.rdata_column,
480 isc_buffer_availableregion(target, &r);
482 return (ISC_R_NOSPACE);
484 isc_buffer_add(target, 1);
488 result = dns_rdataset_next(rdataset);
489 } while (result == ISC_R_SUCCESS);
491 if (result != ISC_R_NOMORE)
495 * Update the ctx state to reflect what we just printed.
496 * This is done last, only when we are sure we will return
497 * success, because this function may be called multiple
498 * times with increasing buffer sizes until it succeeds,
499 * and failed attempts must not update the state prematurely.
501 ctx->class_printed = ISC_TRUE;
502 ctx->current_ttl= current_ttl;
503 ctx->current_ttl_valid = current_ttl_valid;
505 return (ISC_R_SUCCESS);
509 * Print the name, type, and class of an empty rdataset,
510 * such as those used to represent the question section
514 question_totext(dns_rdataset_t *rdataset,
515 dns_name_t *owner_name,
516 dns_totext_ctx_t *ctx,
517 isc_boolean_t omit_final_dot,
518 isc_buffer_t *target)
524 REQUIRE(DNS_RDATASET_VALID(rdataset));
525 result = dns_rdataset_first(rdataset);
526 REQUIRE(result == ISC_R_NOMORE);
532 unsigned int name_start = target->used;
533 RETERR(dns_name_totext(owner_name,
536 column += target->used - name_start;
541 unsigned int class_start;
542 INDENT_TO(class_column);
543 class_start = target->used;
544 result = dns_rdataclass_totext(rdataset->rdclass, target);
545 if (result != ISC_R_SUCCESS)
547 column += (target->used - class_start);
552 unsigned int type_start;
553 INDENT_TO(type_column);
554 type_start = target->used;
555 result = dns_rdatatype_totext(rdataset->type, target);
556 if (result != ISC_R_SUCCESS)
558 column += (target->used - type_start);
561 isc_buffer_availableregion(target, &r);
563 return (ISC_R_NOSPACE);
565 isc_buffer_add(target, 1);
567 return (ISC_R_SUCCESS);
571 dns_rdataset_totext(dns_rdataset_t *rdataset,
572 dns_name_t *owner_name,
573 isc_boolean_t omit_final_dot,
574 isc_boolean_t question,
575 isc_buffer_t *target)
577 dns_totext_ctx_t ctx;
579 result = totext_ctx_init(&dns_master_style_debug, &ctx);
580 if (result != ISC_R_SUCCESS) {
581 UNEXPECTED_ERROR(__FILE__, __LINE__,
582 "could not set master file style");
583 return (ISC_R_UNEXPECTED);
587 * The caller might want to give us an empty owner
588 * name (e.g. if they are outputting into a master
589 * file and this rdataset has the same name as the
592 if (dns_name_countlabels(owner_name) == 0)
596 return (question_totext(rdataset, owner_name, &ctx,
597 omit_final_dot, target));
599 return (rdataset_totext(rdataset, owner_name, &ctx,
600 omit_final_dot, target));
604 dns_master_rdatasettotext(dns_name_t *owner_name,
605 dns_rdataset_t *rdataset,
606 const dns_master_style_t *style,
607 isc_buffer_t *target)
609 dns_totext_ctx_t ctx;
611 result = totext_ctx_init(style, &ctx);
612 if (result != ISC_R_SUCCESS) {
613 UNEXPECTED_ERROR(__FILE__, __LINE__,
614 "could not set master file style");
615 return (ISC_R_UNEXPECTED);
618 return (rdataset_totext(rdataset, owner_name, &ctx,
623 dns_master_questiontotext(dns_name_t *owner_name,
624 dns_rdataset_t *rdataset,
625 const dns_master_style_t *style,
626 isc_buffer_t *target)
628 dns_totext_ctx_t ctx;
630 result = totext_ctx_init(style, &ctx);
631 if (result != ISC_R_SUCCESS) {
632 UNEXPECTED_ERROR(__FILE__, __LINE__,
633 "could not set master file style");
634 return (ISC_R_UNEXPECTED);
637 return (question_totext(rdataset, owner_name, &ctx,
642 * Print an rdataset. 'buffer' is a scratch buffer, which must have been
643 * dynamically allocated by the caller. It must be large enough to
644 * hold the result from dns_ttl_totext(). If more than that is needed,
645 * the buffer will be grown automatically.
649 dump_rdataset(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset,
650 dns_totext_ctx_t *ctx,
651 isc_buffer_t *buffer, FILE *f)
656 REQUIRE(buffer->length > 0);
659 * Output a $TTL directive if needed.
662 if ((ctx->style.flags & DNS_STYLEFLAG_TTL) != 0) {
663 if (ctx->current_ttl_valid == ISC_FALSE ||
664 ctx->current_ttl != rdataset->ttl)
666 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENT) != 0)
668 isc_buffer_clear(buffer);
669 result = dns_ttl_totext(rdataset->ttl,
671 INSIST(result == ISC_R_SUCCESS);
672 isc_buffer_usedregion(buffer, &r);
673 fprintf(f, "$TTL %u\t; %.*s\n", rdataset->ttl,
674 (int) r.length, (char *) r.base);
676 fprintf(f, "$TTL %u\n", rdataset->ttl);
678 ctx->current_ttl = rdataset->ttl;
679 ctx->current_ttl_valid = ISC_TRUE;
683 isc_buffer_clear(buffer);
686 * Generate the text representation of the rdataset into
687 * the buffer. If the buffer is too small, grow it.
692 result = rdataset_totext(rdataset, name, ctx,
694 if (result != ISC_R_NOSPACE)
697 newlength = buffer->length * 2;
698 newmem = isc_mem_get(mctx, newlength);
700 return (ISC_R_NOMEMORY);
701 isc_mem_put(mctx, buffer->base, buffer->length);
702 isc_buffer_init(buffer, newmem, newlength);
704 if (result != ISC_R_SUCCESS)
708 * Write the buffer contents to the master file.
710 isc_buffer_usedregion(buffer, &r);
711 result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL);
713 if (result != ISC_R_SUCCESS) {
714 UNEXPECTED_ERROR(__FILE__, __LINE__,
715 "master file write failed: %s",
716 isc_result_totext(result));
720 return (ISC_R_SUCCESS);
724 * Define the order in which rdatasets should be printed in zone
725 * files. We will print SOA and NS records before others, SIGs
726 * immediately following the things they sign, and order everything
727 * else by RR number. This is all just for aesthetics and
728 * compatibility with buggy software that expects the SOA to be first;
729 * the DNS specifications allow any order.
733 dump_order(const dns_rdataset_t *rds) {
736 if (rds->type == dns_rdatatype_sig) {
744 case dns_rdatatype_soa:
747 case dns_rdatatype_ns:
754 return (t << 1) + sig;
758 dump_order_compare(const void *a, const void *b) {
759 return (dump_order(*((const dns_rdataset_t * const *) a)) -
760 dump_order(*((const dns_rdataset_t * const *) b)));
764 * Dump all the rdatasets of a domain name to a master file. We make
765 * a "best effort" attempt to sort the RRsets in a nice order, but if
766 * there are more than MAXSORT RRsets, we punt and only sort them in
767 * groups of MAXSORT. This is not expected to ever happen in practice
768 * since much less than 64 RR types have been registered with the
769 * IANA, so far, and the output will be correct (though not
770 * aesthetically pleasing) even if it does happen.
775 static const char *trustnames[] = {
784 "local" /* aka ultimate */
788 dump_rdatasets(isc_mem_t *mctx, dns_name_t *name, dns_rdatasetiter_t *rdsiter,
789 dns_totext_ctx_t *ctx,
790 isc_buffer_t *buffer, FILE *f)
792 isc_result_t itresult, dumpresult;
794 dns_rdataset_t rdatasets[MAXSORT];
795 dns_rdataset_t *sorted[MAXSORT];
798 itresult = dns_rdatasetiter_first(rdsiter);
799 dumpresult = ISC_R_SUCCESS;
801 if (itresult == ISC_R_SUCCESS && ctx->neworigin != NULL) {
802 isc_buffer_clear(buffer);
803 itresult = dns_name_totext(ctx->neworigin, ISC_FALSE, buffer);
804 RUNTIME_CHECK(itresult == ISC_R_SUCCESS);
805 isc_buffer_usedregion(buffer, &r);
806 fprintf(f, "$ORIGIN %.*s\n", (int) r.length, (char *) r.base);
807 ctx->neworigin = NULL;
812 itresult == ISC_R_SUCCESS && i < MAXSORT;
813 itresult = dns_rdatasetiter_next(rdsiter), i++) {
814 dns_rdataset_init(&rdatasets[i]);
815 dns_rdatasetiter_current(rdsiter, &rdatasets[i]);
816 sorted[i] = &rdatasets[i];
819 INSIST(n <= MAXSORT);
821 qsort(sorted, n, sizeof(sorted[0]), dump_order_compare);
823 for (i = 0; i < n; i++) {
824 dns_rdataset_t *rds = sorted[i];
825 if (ctx->style.flags & DNS_STYLEFLAG_TRUST) {
826 unsigned int trust = rds->trust;
827 INSIST(trust < (sizeof(trustnames) /
828 sizeof(trustnames[0])));
829 fprintf(f, "; %s\n", trustnames[trust]);
831 if (rds->type == 0 &&
832 (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
833 /* Omit negative cache entries */
835 isc_result_t result =
836 dump_rdataset(mctx, name, rds, ctx,
838 if (result != ISC_R_SUCCESS)
840 if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0)
843 dns_rdataset_disassociate(rds);
846 if (dumpresult != ISC_R_SUCCESS)
850 * If we got more data than could be sorted at once,
851 * go handle the rest.
853 if (itresult == ISC_R_SUCCESS)
856 if (itresult == ISC_R_NOMORE)
857 itresult = ISC_R_SUCCESS;
864 * Initial size of text conversion buffer. The buffer is used
865 * for several purposes: converting origin names, rdatasets,
866 * $DATE timestamps, and comment strings for $TTL directives.
868 * When converting rdatasets, it is dynamically resized, but
869 * when converting origins, timestamps, etc it is not. Therefore,
870 * the initial size must large enough to hold the longest possible
871 * text representation of any domain name (for $ORIGIN).
873 static const int initial_buffer_length = 1200;
876 * Dump an entire database into a master file.
879 dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db,
880 dns_dbversion_t *version,
881 const dns_master_style_t *style,
884 dns_fixedname_t fixname;
886 dns_dbiterator_t *dbiter = NULL;
892 dns_totext_ctx_t ctx;
894 result = totext_ctx_init(style, &ctx);
895 if (result != ISC_R_SUCCESS) {
896 UNEXPECTED_ERROR(__FILE__, __LINE__,
897 "could not set master file style");
898 return (ISC_R_UNEXPECTED);
901 dns_fixedname_init(&fixname);
902 name = dns_fixedname_name(&fixname);
904 isc_stdtime_get(&now);
906 bufmem = isc_mem_get(mctx, initial_buffer_length);
908 return (ISC_R_NOMEMORY);
910 isc_buffer_init(&buffer, bufmem, initial_buffer_length);
913 * If the database has cache semantics, output an RFC2540
914 * $DATE directive so that the TTLs can be adjusted when
915 * it is reloaded. For zones it is not really needed, and
916 * it would make the file incompatible with pre-RFC2540
917 * software, so we omit it in the zone case.
919 if (dns_db_iscache(db)) {
920 result = dns_time32_totext(now, &buffer);
921 RUNTIME_CHECK(result == ISC_R_SUCCESS);
922 isc_buffer_usedregion(&buffer, &r);
923 fprintf(f, "$DATE %.*s\n", (int) r.length, (char *) r.base);
926 result = dns_db_createiterator(db,
927 ((ctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) ?
928 ISC_TRUE : ISC_FALSE,
930 if (result != ISC_R_SUCCESS)
931 goto create_iter_failure;
933 result = dns_dbiterator_first(dbiter);
935 while (result == ISC_R_SUCCESS) {
936 dns_rdatasetiter_t *rdsiter = NULL;
937 dns_dbnode_t *node = NULL;
938 result = dns_dbiterator_current(dbiter, &node, name);
939 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
941 if (result == DNS_R_NEWORIGIN) {
943 dns_fixedname_name(&ctx.origin_fixname);
944 result = dns_dbiterator_origin(dbiter, origin);
945 RUNTIME_CHECK(result == ISC_R_SUCCESS);
946 if ((ctx.style.flags & DNS_STYLEFLAG_REL_DATA) != 0)
948 ctx.neworigin = origin;
950 result = dns_db_allrdatasets(db, node, version, now, &rdsiter);
951 if (result != ISC_R_SUCCESS) {
952 dns_db_detachnode(db, &node);
955 result = dump_rdatasets(mctx, name, rdsiter, &ctx,
957 if (result != ISC_R_SUCCESS) {
958 dns_db_detachnode(db, &node);
961 dns_rdatasetiter_destroy(&rdsiter);
962 dns_db_detachnode(db, &node);
963 result = dns_dbiterator_next(dbiter);
965 if (result != ISC_R_NOMORE)
968 result = ISC_R_SUCCESS;
971 dns_dbiterator_destroy(&dbiter);
974 isc_mem_put(mctx, buffer.base, buffer.length);
980 dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
981 const dns_master_style_t *style, const char *filename)
988 tempnamelen = strlen(filename) + 20;
989 tempname = isc_mem_get(mctx, tempnamelen);
990 if (tempname == NULL)
991 return (ISC_R_NOMEMORY);
993 result = isc_file_mktemplate(filename, tempname, tempnamelen);
994 if (result != ISC_R_SUCCESS)
997 result = isc_file_openunique(tempname, &f);
998 if (result != ISC_R_SUCCESS) {
999 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1000 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1001 "dumping master file: %s: open: %s",
1002 tempname, isc_result_totext(result));
1006 result = dns_master_dumptostream(mctx, db, version, style, f);
1007 if (result != ISC_R_SUCCESS) {
1008 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1009 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1010 "dumping master file: %s: %s",
1011 tempname, isc_result_totext(result));
1012 (void)isc_stdio_close(f);
1013 (void)isc_file_remove(tempname);
1017 result = isc_stdio_sync(f);
1018 if (result != ISC_R_SUCCESS) {
1019 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1020 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1021 "dumping master file: %s: fsync: %s",
1022 tempname, isc_result_totext(result));
1023 (void)isc_stdio_close(f);
1024 (void)isc_file_remove(tempname);
1028 result = isc_stdio_close(f);
1029 if (result != ISC_R_SUCCESS) {
1030 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1031 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1032 "dumping master file: %s: close: %s",
1033 tempname, isc_result_totext(result));
1034 (void)isc_file_remove(tempname);
1038 result = isc_file_rename(tempname, filename);
1039 if (result != ISC_R_SUCCESS) {
1040 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1041 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1042 "dumping master file: rename: %s: %s",
1043 filename, isc_result_totext(result));
1048 isc_mem_put(mctx, tempname, tempnamelen);
1053 * Dump a database node into a master file.
1056 dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db,
1057 dns_dbversion_t *version,
1058 dns_dbnode_t *node, dns_name_t *name,
1059 const dns_master_style_t *style,
1062 isc_result_t result;
1063 isc_buffer_t buffer;
1066 dns_totext_ctx_t ctx;
1067 dns_rdatasetiter_t *rdsiter = NULL;
1069 result = totext_ctx_init(style, &ctx);
1070 if (result != ISC_R_SUCCESS) {
1071 UNEXPECTED_ERROR(__FILE__, __LINE__,
1072 "could not set master file style");
1073 return (ISC_R_UNEXPECTED);
1076 isc_stdtime_get(&now);
1078 bufmem = isc_mem_get(mctx, initial_buffer_length);
1080 return (ISC_R_NOMEMORY);
1082 isc_buffer_init(&buffer, bufmem, initial_buffer_length);
1084 result = dns_db_allrdatasets(db, node, version, now, &rdsiter);
1085 if (result != ISC_R_SUCCESS)
1087 result = dump_rdatasets(mctx, name, rdsiter, &ctx, &buffer, f);
1088 if (result != ISC_R_SUCCESS)
1090 dns_rdatasetiter_destroy(&rdsiter);
1092 result = ISC_R_SUCCESS;
1095 isc_mem_put(mctx, buffer.base, buffer.length);
1100 dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1101 dns_dbnode_t *node, dns_name_t *name,
1102 const dns_master_style_t *style, const char *filename)
1105 isc_result_t result;
1107 result = isc_stdio_open(filename, "w", &f);
1108 if (result != ISC_R_SUCCESS) {
1109 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1110 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1111 "dumping node to file: %s: open: %s", filename,
1112 isc_result_totext(result));
1113 return (ISC_R_UNEXPECTED);
1116 result = dns_master_dumpnodetostream(mctx, db, version, node, name,
1119 result = isc_stdio_close(f);
1120 if (result != ISC_R_SUCCESS) {
1121 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1122 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1123 "dumping master file: %s: close: %s", filename,
1124 isc_result_totext(result));
1125 return (ISC_R_UNEXPECTED);