1 /* $NetBSD: masterdump.c,v 1.11 2015/07/08 17:28:58 christos Exp $ */
4 * Copyright (C) 2004-2009, 2011-2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
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.
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.
28 #include <isc/event.h>
30 #include <isc/magic.h>
32 #include <isc/print.h>
33 #include <isc/stdio.h>
34 #include <isc/string.h>
40 #include <dns/dbiterator.h>
41 #include <dns/events.h>
42 #include <dns/fixedname.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>
57 #define DNS_DCTX_MAGIC ISC_MAGIC('D', 'c', 't', 'x')
58 #define DNS_DCTX_VALID(d) ISC_MAGIC_VALID(d, DNS_DCTX_MAGIC)
60 #define RETERR(x) do { \
61 isc_result_t _r = (x); \
62 if (_r != ISC_R_SUCCESS) \
64 } while (/*CONSTCOND*/0)
66 #define CHECK(x) do { \
67 if ((x) != ISC_R_SUCCESS) \
69 } while (/*CONSTCOND*/0)
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
;
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.
88 #define DNS_TOTEXT_LINEBREAK_MAXLEN 100
91 * Context structure for a masterfile dump in progress.
93 typedef struct dns_totext_ctx
{
94 dns_master_style_t style
;
95 isc_boolean_t class_printed
;
97 char linebreak_buf
[DNS_TOTEXT_LINEBREAK_MAXLEN
];
99 dns_name_t
* neworigin
;
100 dns_fixedname_t origin_fixname
;
101 isc_uint32_t current_ttl
;
102 isc_boolean_t current_ttl_valid
;
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
|
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
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
|
128 DNS_STYLEFLAG_COMMENT
|
129 DNS_STYLEFLAG_RRCOMMENT
|
130 DNS_STYLEFLAG_MULTILINE
,
131 24, 24, 24, 32, 80, 8, UINT_MAX
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
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
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
164 LIBDNS_EXTERNAL_DATA
const dns_master_style_t
165 dns_master_style_simple
= {
167 24, 32, 32, 40, 80, 8, UINT_MAX
171 * A style suitable for dns_rdataset_totext().
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
180 * Similar, but with each line commented out.
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
193 static char spaces
[N_SPACES
+1] = " ";
196 static char tabs
[N_TABS
+1] = "\t\t\t\t\t\t\t\t\t\t";
202 unsigned int references
;
203 isc_boolean_t canceled
;
205 isc_boolean_t do_date
;
209 dns_dbversion_t
*version
;
210 dns_dbiterator_t
*dbiter
;
211 dns_totext_ctx_t tctx
;
213 dns_dumpdonefunc_t done
;
216 /* dns_master_dumpinc() */
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
);
227 #define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
230 * Output tabs and spaces to go from column '*current' to
231 * column 'to', and update '*current' to reflect the new
235 indent(unsigned int *current
, unsigned int to
, int tabwidth
,
236 isc_buffer_t
*target
)
241 int ntabs
, nspaces
, t
;
248 ntabs
= to
/ tabwidth
- from
/ tabwidth
;
253 isc_buffer_availableregion(target
, &r
);
254 if (r
.length
< (unsigned) ntabs
)
255 return (ISC_R_NOSPACE
);
267 isc_buffer_add(target
, ntabs
);
268 from
= (to
/ tabwidth
) * tabwidth
;
272 INSIST(nspaces
>= 0);
274 isc_buffer_availableregion(target
, &r
);
275 if (r
.length
< (unsigned) nspaces
)
276 return (ISC_R_NOSPACE
);
284 memmove(p
, spaces
, n
);
288 isc_buffer_add(target
, nspaces
);
291 return (ISC_R_SUCCESS
);
295 totext_ctx_init(const dns_master_style_t
*style
, dns_totext_ctx_t
*ctx
) {
298 REQUIRE(style
->tab_width
!= 0);
301 ctx
->class_printed
= ISC_FALSE
;
303 dns_fixedname_init(&ctx
->origin_fixname
);
306 * Set up the line break string if needed.
308 if ((ctx
->style
.flags
& DNS_STYLEFLAG_MULTILINE
) != 0) {
311 unsigned int col
= 0;
313 isc_buffer_init(&buf
, ctx
->linebreak_buf
,
314 sizeof(ctx
->linebreak_buf
));
316 isc_buffer_availableregion(&buf
, &r
);
318 return (DNS_R_TEXTTOOLONG
);
320 isc_buffer_add(&buf
, 1);
322 if ((ctx
->style
.flags
& DNS_STYLEFLAG_COMMENTDATA
) != 0) {
323 isc_buffer_availableregion(&buf
, &r
);
325 return (DNS_R_TEXTTOOLONG
);
327 isc_buffer_add(&buf
, 1);
330 result
= indent(&col
, ctx
->style
.rdata_column
,
331 ctx
->style
.tab_width
, &buf
);
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.
339 if (result
== ISC_R_NOSPACE
)
340 return (DNS_R_TEXTTOOLONG
);
341 if (result
!= ISC_R_SUCCESS
)
344 isc_buffer_availableregion(&buf
, &r
);
346 return (DNS_R_TEXTTOOLONG
);
348 isc_buffer_add(&buf
, 1);
349 ctx
->linebreak
= ctx
->linebreak_buf
;
351 ctx
->linebreak
= NULL
;
355 ctx
->neworigin
= NULL
;
356 ctx
->current_ttl
= 0;
357 ctx
->current_ttl_valid
= ISC_FALSE
;
359 return (ISC_R_SUCCESS
);
362 #define INDENT_TO(col) \
364 if ((result = indent(&column, ctx->style.col, \
365 ctx->style.tab_width, target)) \
368 } while (/*CONSTCOND*/0)
372 str_totext(const char *source
, isc_buffer_t
*target
) {
376 isc_buffer_availableregion(target
, ®ion
);
379 if (l
> region
.length
)
380 return (ISC_R_NOSPACE
);
382 memmove(region
.base
, source
, l
);
383 isc_buffer_add(target
, l
);
384 return (ISC_R_SUCCESS
);
388 ncache_summary(dns_rdataset_t
*rdataset
, isc_boolean_t omit_final_dot
,
389 isc_buffer_t
*target
)
391 isc_result_t result
= ISC_R_SUCCESS
;
395 dns_rdataset_init(&rds
);
396 dns_name_init(&name
, NULL
);
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
));
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
));
420 dns_rdataset_disassociate(&rds
);
421 result
= dns_rdataset_next(rdataset
);
422 } while (result
== ISC_R_SUCCESS
);
424 if (result
== ISC_R_NOMORE
)
425 result
= ISC_R_SUCCESS
;
427 if (dns_rdataset_isassociated(&rds
))
428 dns_rdataset_disassociate(&rds
);
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
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
)
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
;
455 REQUIRE(DNS_RDATASET_VALID(rdataset
));
457 rdataset
->attributes
|= DNS_RDATASETATTR_LOADORDER
;
458 result
= dns_rdataset_first(rdataset
);
460 current_ttl
= ctx
->current_ttl
;
461 current_ttl_valid
= ctx
->current_ttl_valid
;
463 while (result
== ISC_R_SUCCESS
) {
469 if ((ctx
->style
.flags
& DNS_STYLEFLAG_COMMENTDATA
) != 0)
470 RETERR(str_totext(";", target
));
475 if (owner_name
!= NULL
&&
476 ! ((ctx
->style
.flags
& DNS_STYLEFLAG_OMIT_OWNER
) != 0 &&
479 unsigned int name_start
= target
->used
;
480 RETERR(dns_name_totext(owner_name
,
483 column
+= target
->used
- name_start
;
489 if ((ctx
->style
.flags
& DNS_STYLEFLAG_NO_TTL
) == 0 &&
490 !((ctx
->style
.flags
& DNS_STYLEFLAG_OMIT_TTL
) != 0 &&
492 rdataset
->ttl
== current_ttl
))
498 INDENT_TO(ttl_column
);
499 length
= snprintf(ttlbuf
, sizeof(ttlbuf
), "%u",
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
);
510 * If the $TTL directive is not in use, the TTL we
511 * just printed becomes the default for subsequent RRs.
513 if ((ctx
->style
.flags
& DNS_STYLEFLAG_TTL
) == 0) {
514 current_ttl
= rdataset
->ttl
;
515 current_ttl_valid
= ISC_TRUE
;
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
))
526 unsigned int class_start
;
527 INDENT_TO(class_column
);
528 class_start
= target
->used
;
529 result
= dns_rdataclass_totext(rdataset
->rdclass
,
531 if (result
!= ISC_R_SUCCESS
)
533 column
+= (target
->used
- class_start
);
540 if ((rdataset
->attributes
& DNS_RDATASETATTR_NEGATIVE
) != 0) {
541 type
= rdataset
->covers
;
543 type
= rdataset
->type
;
546 INDENT_TO(type_column
);
547 type_start
= target
->used
;
548 if ((rdataset
->attributes
& DNS_RDATASETATTR_NEGATIVE
) != 0)
549 RETERR(str_totext("\\-", target
));
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
);
562 result
= dns_rdatatype_totext(type
, target
);
563 if (result
!= ISC_R_SUCCESS
)
566 column
+= (target
->used
- type_start
);
571 INDENT_TO(rdata_column
);
572 if ((rdataset
->attributes
& DNS_RDATASETATTR_NEGATIVE
) != 0) {
573 if (NXDOMAIN(rdataset
))
574 RETERR(str_totext(";-$NXDOMAIN\n", target
));
576 RETERR(str_totext(";-$NXRRSET\n", target
));
578 * Print a summary of the cached records which make
579 * up the negative response.
581 RETERR(ncache_summary(rdataset
, omit_final_dot
,
585 dns_rdata_t rdata
= DNS_RDATA_INIT
;
588 dns_rdataset_current(rdataset
, &rdata
);
590 RETERR(dns_rdata_tofmttext(&rdata
,
593 ctx
->style
.line_length
-
594 ctx
->style
.rdata_column
,
595 ctx
->style
.split_width
,
599 isc_buffer_availableregion(target
, &r
);
601 return (ISC_R_NOSPACE
);
603 isc_buffer_add(target
, 1);
607 result
= dns_rdataset_next(rdataset
);
610 if (result
!= ISC_R_NOMORE
)
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.
620 ctx
->class_printed
= ISC_TRUE
;
621 ctx
->current_ttl
= current_ttl
;
622 ctx
->current_ttl_valid
= current_ttl_valid
;
624 return (ISC_R_SUCCESS
);
628 * Print the name, type, and class of an empty rdataset,
629 * such as those used to represent the question section
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
)
643 REQUIRE(DNS_RDATASET_VALID(rdataset
));
644 result
= dns_rdataset_first(rdataset
);
645 REQUIRE(result
== ISC_R_NOMORE
);
651 unsigned int name_start
= target
->used
;
652 RETERR(dns_name_totext(owner_name
,
655 column
+= target
->used
- name_start
;
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
)
666 column
+= (target
->used
- class_start
);
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
)
677 column
+= (target
->used
- type_start
);
680 isc_buffer_availableregion(target
, &r
);
682 return (ISC_R_NOSPACE
);
684 isc_buffer_add(target
, 1);
686 return (ISC_R_SUCCESS
);
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
)
696 dns_totext_ctx_t ctx
;
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
);
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
711 if (dns_name_countlabels(owner_name
) == 0)
715 return (question_totext(rdataset
, owner_name
, &ctx
,
716 omit_final_dot
, target
));
718 return (rdataset_totext(rdataset
, owner_name
, &ctx
,
719 omit_final_dot
, target
));
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
)
728 dns_totext_ctx_t ctx
;
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
);
737 return (rdataset_totext(rdataset
, owner_name
, &ctx
,
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
)
747 dns_totext_ctx_t ctx
;
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
);
756 return (question_totext(rdataset
, owner_name
, &ctx
,
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.
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
)
775 REQUIRE(buffer
->length
> 0);
778 * Output a $TTL directive if needed.
781 if ((ctx
->style
.flags
& DNS_STYLEFLAG_TTL
) != 0) {
782 if (ctx
->current_ttl_valid
== ISC_FALSE
||
783 ctx
->current_ttl
!= rdataset
->ttl
)
785 if ((ctx
->style
.flags
& DNS_STYLEFLAG_COMMENT
) != 0)
787 isc_buffer_clear(buffer
);
788 result
= dns_ttl_totext(rdataset
->ttl
,
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
);
795 fprintf(f
, "$TTL %u\n", rdataset
->ttl
);
797 ctx
->current_ttl
= rdataset
->ttl
;
798 ctx
->current_ttl_valid
= ISC_TRUE
;
802 isc_buffer_clear(buffer
);
805 * Generate the text representation of the rdataset into
806 * the buffer. If the buffer is too small, grow it.
811 result
= rdataset_totext(rdataset
, name
, ctx
,
813 if (result
!= ISC_R_NOSPACE
)
816 newlength
= buffer
->length
* 2;
817 newmem
= isc_mem_get(mctx
, newlength
);
819 return (ISC_R_NOMEMORY
);
820 isc_mem_put(mctx
, buffer
->base
, buffer
->length
);
821 isc_buffer_init(buffer
, newmem
, newlength
);
823 if (result
!= ISC_R_SUCCESS
)
827 * Write the buffer contents to the master file.
829 isc_buffer_usedregion(buffer
, &r
);
830 result
= isc_stdio_write(r
.base
, 1, (size_t)r
.length
, f
, NULL
);
832 if (result
!= ISC_R_SUCCESS
) {
833 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
834 "master file write failed: %s",
835 isc_result_totext(result
));
839 return (ISC_R_SUCCESS
);
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.
852 dump_order(const dns_rdataset_t
*rds
) {
855 if (rds
->type
== dns_rdatatype_rrsig
) {
863 case dns_rdatatype_soa
:
866 case dns_rdatatype_ns
:
873 return (t
<< 1) + sig
;
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
)));
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.
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
)
899 isc_result_t itresult
, dumpresult
;
901 dns_rdataset_t rdatasets
[MAXSORT
];
902 dns_rdataset_t
*sorted
[MAXSORT
];
905 itresult
= dns_rdatasetiter_first(rdsiter
);
906 dumpresult
= ISC_R_SUCCESS
;
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
;
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
];
926 INSIST(n
<= MAXSORT
);
928 qsort(sorted
, n
, sizeof(sorted
[0]), dump_order_compare
);
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 */
938 isc_result_t result
=
939 dump_rdataset(mctx
, name
, rds
, ctx
,
941 if (result
!= ISC_R_SUCCESS
)
943 if ((ctx
->style
.flags
& DNS_STYLEFLAG_OMIT_OWNER
) != 0)
946 if (ctx
->style
.flags
& DNS_STYLEFLAG_RESIGN
&&
947 rds
->attributes
& DNS_RDATASETATTR_RESIGN
) {
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
);
955 dns_rdataset_disassociate(rds
);
958 if (dumpresult
!= ISC_R_SUCCESS
)
962 * If we got more data than could be sorted at once,
963 * go handle the rest.
965 if (itresult
== ISC_R_SUCCESS
)
968 if (itresult
== ISC_R_NOMORE
)
969 itresult
= ISC_R_SUCCESS
;
975 * Dump given RRsets in the "raw" format.
978 dump_rdataset_raw(isc_mem_t
*mctx
, dns_name_t
*name
, dns_rdataset_t
*rdataset
,
979 isc_buffer_t
*buffer
, FILE *f
)
982 isc_uint32_t totallen
;
984 isc_region_t r
, r_hdr
;
986 REQUIRE(buffer
->length
> 0);
987 REQUIRE(DNS_RDATASET_VALID(rdataset
));
989 rdataset
->attributes
|= DNS_RDATASETATTR_LOADORDER
;
992 result
= dns_rdataset_first(rdataset
);
993 REQUIRE(result
== ISC_R_SUCCESS
);
995 isc_buffer_clear(buffer
);
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.
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
));
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
;
1022 dns_rdata_t rdata
= DNS_RDATA_INIT
;
1024 dns_rdataset_current(rdataset
, &rdata
);
1025 dns_rdata_toregion(&rdata
, &r
);
1026 INSIST(r
.length
<= 0xffffU
);
1027 dlen
= (isc_uint16_t
)r
.length
;
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
1035 if (isc_buffer_availablelength(buffer
) <
1036 sizeof(dlen
) + r
.length
) {
1040 newlength
= buffer
->length
* 2;
1041 newmem
= isc_mem_get(mctx
, newlength
);
1043 return (ISC_R_NOMEMORY
);
1044 isc_mem_put(mctx
, buffer
->base
, buffer
->length
);
1045 isc_buffer_init(buffer
, newmem
, newlength
);
1048 isc_buffer_putuint16(buffer
, dlen
);
1049 isc_buffer_copyregion(buffer
, &r
);
1050 totallen
+= sizeof(dlen
) + r
.length
;
1052 result
= dns_rdataset_next(rdataset
);
1053 } while (result
== ISC_R_SUCCESS
);
1055 if (result
!= ISC_R_NOMORE
)
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.
1064 isc_buffer_usedregion(buffer
, &r
);
1065 isc_buffer_clear(buffer
);
1066 isc_buffer_putuint32(buffer
, totallen
);
1067 INSIST(isc_buffer_usedlength(buffer
) < totallen
);
1070 * Write the buffer contents to the raw master file.
1072 result
= isc_stdio_write(r
.base
, 1, (size_t)r
.length
, f
, NULL
);
1074 if (result
!= ISC_R_SUCCESS
) {
1075 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1076 "raw master file write failed: %s",
1077 isc_result_totext(result
));
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
)
1089 isc_result_t result
;
1090 dns_rdataset_t rdataset
;
1092 for (result
= dns_rdatasetiter_first(rdsiter
);
1093 result
== ISC_R_SUCCESS
;
1094 result
= dns_rdatasetiter_next(rdsiter
)) {
1096 dns_rdataset_init(&rdataset
);
1097 dns_rdatasetiter_current(rdsiter
, &rdataset
);
1099 if (((rdataset
.attributes
& DNS_RDATASETATTR_NEGATIVE
) != 0) &&
1100 (ctx
->style
.flags
& DNS_STYLEFLAG_NCACHE
) == 0) {
1101 /* Omit negative cache entries */
1103 result
= dump_rdataset_raw(mctx
, name
, &rdataset
,
1106 dns_rdataset_disassociate(&rdataset
);
1107 if (result
!= ISC_R_SUCCESS
)
1111 if (result
== ISC_R_NOMORE
)
1112 result
= ISC_R_SUCCESS
;
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
)
1129 return (ISC_R_NOTIMPLEMENTED
);
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.
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).
1142 static const int initial_buffer_length
= 1200;
1145 dumptostreaminc(dns_dumpctx_t
*dctx
);
1148 dumpctx_destroy(dns_dumpctx_t
*dctx
) {
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
));
1166 dns_dumpctx_attach(dns_dumpctx_t
*source
, dns_dumpctx_t
**target
) {
1168 REQUIRE(DNS_DCTX_VALID(source
));
1169 REQUIRE(target
!= NULL
&& *target
== NULL
);
1171 LOCK(&source
->lock
);
1172 INSIST(source
->references
> 0);
1173 source
->references
++;
1174 INSIST(source
->references
!= 0); /* Overflow? */
1175 UNLOCK(&source
->lock
);
1181 dns_dumpctx_detach(dns_dumpctx_t
**dctxp
) {
1182 dns_dumpctx_t
*dctx
;
1183 isc_boolean_t need_destroy
= ISC_FALSE
;
1185 REQUIRE(dctxp
!= NULL
);
1187 REQUIRE(DNS_DCTX_VALID(dctx
));
1192 INSIST(dctx
->references
!= 0);
1194 if (dctx
->references
== 0)
1195 need_destroy
= ISC_TRUE
;
1196 UNLOCK(&dctx
->lock
);
1198 dumpctx_destroy(dctx
);
1202 dns_dumpctx_version(dns_dumpctx_t
*dctx
) {
1203 REQUIRE(DNS_DCTX_VALID(dctx
));
1204 return (dctx
->version
);
1208 dns_dumpctx_db(dns_dumpctx_t
*dctx
) {
1209 REQUIRE(DNS_DCTX_VALID(dctx
));
1214 dns_dumpctx_cancel(dns_dumpctx_t
*dctx
) {
1215 REQUIRE(DNS_DCTX_VALID(dctx
));
1218 dctx
->canceled
= ISC_TRUE
;
1219 UNLOCK(&dctx
->lock
);
1223 flushandsync(FILE *f
, isc_result_t result
, const char *temp
) {
1224 isc_boolean_t logit
= ISC_TF(result
== ISC_R_SUCCESS
);
1226 if (result
== ISC_R_SUCCESS
)
1227 result
= isc_stdio_flush(f
);
1228 if (result
!= ISC_R_SUCCESS
&& logit
) {
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
));
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
));
1242 if (result
== ISC_R_SUCCESS
)
1243 result
= isc_stdio_sync(f
);
1244 if (result
!= ISC_R_SUCCESS
&& logit
) {
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
));
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
));
1260 closeandrename(FILE *f
, isc_result_t result
, const char *temp
, const char *file
)
1262 isc_result_t tresult
;
1263 isc_boolean_t logit
= ISC_TF(result
== ISC_R_SUCCESS
);
1265 result
= flushandsync(f
, result
, temp
);
1266 if (result
!= ISC_R_SUCCESS
)
1269 tresult
= isc_stdio_close(f
);
1270 if (result
== ISC_R_SUCCESS
)
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
));
1279 if (result
== ISC_R_SUCCESS
)
1280 result
= isc_file_rename(temp
, file
);
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
));
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
;
1298 REQUIRE(event
!= NULL
);
1299 dctx
= event
->ev_arg
;
1300 REQUIRE(DNS_DCTX_VALID(dctx
));
1302 result
= ISC_R_CANCELED
;
1304 result
= dumptostreaminc(dctx
);
1305 if (result
== DNS_R_CONTINUE
) {
1306 event
->ev_arg
= dctx
;
1307 isc_task_send(task
, &event
);
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
)
1317 result
= flushandsync(dctx
->f
, result
, NULL
);
1318 (dctx
->done
)(dctx
->done_arg
, result
);
1319 isc_event_free(&event
);
1320 dns_dumpctx_detach(&dctx
);
1324 task_send(dns_dumpctx_t
*dctx
) {
1327 event
= isc_event_allocate(dctx
->mctx
, NULL
, DNS_EVENT_DUMPQUANTUM
,
1328 dump_quantum
, dctx
, sizeof(*event
));
1330 return (ISC_R_NOMEMORY
);
1331 isc_task_send(dctx
->task
, &event
);
1332 return (ISC_R_SUCCESS
);
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
)
1340 dns_dumpctx_t
*dctx
;
1341 isc_result_t result
;
1342 unsigned int options
;
1344 dctx
= isc_mem_get(mctx
, sizeof(*dctx
));
1346 return (ISC_R_NOMEMORY
);
1350 dctx
->dbiter
= NULL
;
1352 dctx
->version
= NULL
;
1354 dctx
->done_arg
= NULL
;
1357 dctx
->first
= ISC_TRUE
;
1358 dctx
->canceled
= ISC_FALSE
;
1360 dctx
->tmpfile
= NULL
;
1361 dctx
->format
= format
;
1363 dns_master_initrawheader(&dctx
->header
);
1365 dctx
->header
= *header
;
1368 case dns_masterformat_text
:
1369 dctx
->dumpsets
= dump_rdatasets_text
;
1371 case dns_masterformat_raw
:
1372 dctx
->dumpsets
= dump_rdatasets_raw
;
1374 case dns_masterformat_map
:
1375 dctx
->dumpsets
= dump_rdatasets_map
;
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");
1389 isc_stdtime_get(&dctx
->now
);
1390 dns_db_attach(db
, &dctx
->db
);
1392 dctx
->do_date
= dns_db_iscache(dctx
->db
);
1394 if (dctx
->format
== dns_masterformat_text
&&
1395 (dctx
->tctx
.style
.flags
& DNS_STYLEFLAG_REL_OWNER
) != 0) {
1396 options
= DNS_DB_RELATIVENAMES
;
1399 result
= dns_db_createiterator(dctx
->db
, options
, &dctx
->dbiter
);
1400 if (result
!= ISC_R_SUCCESS
)
1403 result
= isc_mutex_init(&dctx
->lock
);
1404 if (result
!= ISC_R_SUCCESS
)
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
;
1414 return (ISC_R_SUCCESS
);
1417 if (dctx
->dbiter
!= NULL
)
1418 dns_dbiterator_destroy(&dctx
->dbiter
);
1419 if (dctx
->db
!= NULL
)
1420 dns_db_detach(&dctx
->db
);
1422 isc_mem_put(mctx
, dctx
, sizeof(*dctx
));
1427 writeheader(dns_dumpctx_t
*dctx
) {
1428 isc_result_t result
= ISC_R_SUCCESS
;
1429 isc_buffer_t buffer
;
1432 dns_masterrawheader_t rawheader
;
1433 isc_uint32_t rawversion
, now32
;
1435 bufmem
= isc_mem_get(dctx
->mctx
, initial_buffer_length
);
1437 return (ISC_R_NOMEMORY
);
1439 isc_buffer_init(&buffer
, bufmem
, initial_buffer_length
);
1441 switch (dctx
->format
) {
1442 case dns_masterformat_text
:
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.
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
);
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
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
1472 isc_log_write(dns_lctx
,
1473 ISC_LOGCATEGORY_GENERAL
,
1474 DNS_LOGMODULE_MASTERDUMP
,
1476 "dumping master file in raw "
1477 "format: stdtime is not 32bits");
1483 if ((dctx
->header
.flags
& DNS_MASTERRAW_COMPAT
) != 0)
1486 isc_buffer_putuint32(&buffer
, dctx
->format
);
1487 isc_buffer_putuint32(&buffer
, rawversion
);
1488 isc_buffer_putuint32(&buffer
, now32
);
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
);
1497 INSIST(isc_buffer_usedlength(&buffer
) <= sizeof(rawheader
));
1498 result
= isc_stdio_write(buffer
.base
, 1,
1499 isc_buffer_usedlength(&buffer
),
1501 if (result
!= ISC_R_SUCCESS
)
1509 isc_mem_put(dctx
->mctx
, buffer
.base
, buffer
.length
);
1514 dumptostreaminc(dns_dumpctx_t
*dctx
) {
1515 isc_result_t result
= ISC_R_SUCCESS
;
1516 isc_buffer_t buffer
;
1519 dns_fixedname_t fixname
;
1523 bufmem
= isc_mem_get(dctx
->mctx
, initial_buffer_length
);
1525 return (ISC_R_NOMEMORY
);
1527 isc_buffer_init(&buffer
, bufmem
, initial_buffer_length
);
1529 dns_fixedname_init(&fixname
);
1530 name
= dns_fixedname_name(&fixname
);
1533 CHECK(writeheader(dctx
));
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
1541 if (dctx
->format
== dns_masterformat_map
) {
1542 result
= dns_db_serialize(dctx
->db
, dctx
->version
,
1547 result
= dns_dbiterator_first(dctx
->dbiter
);
1548 if (result
!= ISC_R_SUCCESS
&& result
!= ISC_R_NOMORE
)
1551 dctx
->first
= ISC_FALSE
;
1553 result
= ISC_R_SUCCESS
;
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
;
1561 result
= dns_dbiterator_current(dctx
->dbiter
, &node
, name
);
1562 if (result
!= ISC_R_SUCCESS
&& result
!= DNS_R_NEWORIGIN
)
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
;
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
);
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
);
1587 dns_db_detachnode(dctx
->db
, &node
);
1588 result
= dns_dbiterator_next(dctx
->dbiter
);
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
1597 if (dctx
->nodes
!= 0 && result
== ISC_R_SUCCESS
) {
1598 unsigned int pps
= dns_pps
; /* packets per second */
1599 unsigned int interval
;
1606 interval
= 1000000 / pps
; /* interval in usecs */
1609 usecs
= isc_time_microdiff(&end
, &start
);
1611 dctx
->nodes
= dctx
->nodes
* 2;
1612 if (dctx
->nodes
> 1000)
1615 nodes
= dctx
->nodes
* interval
;
1616 nodes
/= (unsigned int)usecs
;
1619 else if (nodes
> 1000)
1622 /* Smooth and assign. */
1623 dctx
->nodes
= (nodes
+ dctx
->nodes
* 7) / 8;
1625 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
1626 DNS_LOGMODULE_MASTERDUMP
,
1628 "dumptostreaminc(%p) new nodes -> %d\n",
1631 result
= DNS_R_CONTINUE
;
1632 } else if (result
== ISC_R_NOMORE
)
1633 result
= ISC_R_SUCCESS
;
1635 RUNTIME_CHECK(dns_dbiterator_pause(dctx
->dbiter
) == ISC_R_SUCCESS
);
1636 isc_mem_put(dctx
->mctx
, buffer
.base
, buffer
.length
);
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
)
1648 dns_dumpctx_t
*dctx
= NULL
;
1649 isc_result_t result
;
1651 REQUIRE(task
!= NULL
);
1653 REQUIRE(done
!= NULL
);
1655 result
= dumpctx_create(mctx
, db
, version
, style
, f
, &dctx
,
1656 dns_masterformat_text
, NULL
);
1657 if (result
!= ISC_R_SUCCESS
)
1659 isc_task_attach(task
, &dctx
->task
);
1661 dctx
->done_arg
= done_arg
;
1664 result
= task_send(dctx
);
1665 if (result
== ISC_R_SUCCESS
) {
1666 dns_dumpctx_attach(dctx
, dctxp
);
1667 return (DNS_R_CONTINUE
);
1670 dns_dumpctx_detach(&dctx
);
1675 * Dump an entire database into a master file.
1678 dns_master_dumptostream(isc_mem_t
*mctx
, dns_db_t
*db
,
1679 dns_dbversion_t
*version
,
1680 const dns_master_style_t
*style
,
1683 return (dns_master_dumptostream3(mctx
, db
, version
, style
,
1684 dns_masterformat_text
, NULL
, f
));
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
)
1693 return (dns_master_dumptostream3(mctx
, db
, version
, style
,
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
)
1704 dns_dumpctx_t
*dctx
= NULL
;
1705 isc_result_t result
;
1707 result
= dumpctx_create(mctx
, db
, version
, style
, f
, &dctx
,
1709 if (result
!= ISC_R_SUCCESS
)
1712 result
= dumptostreaminc(dctx
);
1713 INSIST(result
!= DNS_R_CONTINUE
);
1714 dns_dumpctx_detach(&dctx
);
1716 result
= flushandsync(f
, result
, NULL
);
1721 opentmp(isc_mem_t
*mctx
, dns_masterformat_t format
, const char *file
,
1722 char **tempp
, FILE **fp
) {
1724 isc_result_t result
;
1725 char *tempname
= NULL
;
1728 tempnamelen
= strlen(file
) + 20;
1729 tempname
= isc_mem_allocate(mctx
, tempnamelen
);
1730 if (tempname
== NULL
)
1731 return (ISC_R_NOMEMORY
);
1733 result
= isc_file_mktemplate(file
, tempname
, tempnamelen
);
1734 if (result
!= ISC_R_SUCCESS
)
1737 if (format
== dns_masterformat_text
)
1738 result
= isc_file_openunique(tempname
, &f
);
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
));
1750 return (ISC_R_SUCCESS
);
1753 isc_mem_free(mctx
, tempname
);
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
)
1763 return (dns_master_dumpinc3(mctx
, db
, version
, style
, filename
, task
,
1764 done
, done_arg
, dctxp
,
1765 dns_masterformat_text
, NULL
));
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
)
1774 return (dns_master_dumpinc3(mctx
, db
, version
, style
, filename
, task
,
1775 done
, done_arg
, dctxp
, format
, NULL
));
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
)
1786 isc_result_t result
;
1787 char *tempname
= NULL
;
1789 dns_dumpctx_t
*dctx
= NULL
;
1791 file
= isc_mem_strdup(mctx
, filename
);
1793 return (ISC_R_NOMEMORY
);
1795 result
= opentmp(mctx
, format
, filename
, &tempname
, &f
);
1796 if (result
!= ISC_R_SUCCESS
)
1799 result
= dumpctx_create(mctx
, db
, version
, style
, f
, &dctx
,
1801 if (result
!= ISC_R_SUCCESS
) {
1802 (void)isc_stdio_close(f
);
1803 (void)isc_file_remove(tempname
);
1807 isc_task_attach(task
, &dctx
->task
);
1809 dctx
->done_arg
= done_arg
;
1813 dctx
->tmpfile
= tempname
;
1816 result
= task_send(dctx
);
1817 if (result
== ISC_R_SUCCESS
) {
1818 dns_dumpctx_attach(dctx
, dctxp
);
1819 return (DNS_R_CONTINUE
);
1824 dns_dumpctx_detach(&dctx
);
1826 isc_mem_free(mctx
, file
);
1827 if (tempname
!= NULL
)
1828 isc_mem_free(mctx
, tempname
);
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
)
1836 return (dns_master_dump3(mctx
, db
, version
, style
, filename
,
1837 dns_masterformat_text
, NULL
));
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
)
1845 return (dns_master_dump3(mctx
, db
, version
, style
, filename
,
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
)
1855 isc_result_t result
;
1857 dns_dumpctx_t
*dctx
= NULL
;
1859 result
= opentmp(mctx
, format
, filename
, &tempname
, &f
);
1860 if (result
!= ISC_R_SUCCESS
)
1863 result
= dumpctx_create(mctx
, db
, version
, style
, f
, &dctx
,
1865 if (result
!= ISC_R_SUCCESS
)
1868 result
= dumptostreaminc(dctx
);
1869 INSIST(result
!= DNS_R_CONTINUE
);
1870 dns_dumpctx_detach(&dctx
);
1872 result
= closeandrename(f
, result
, tempname
, filename
);
1875 isc_mem_free(mctx
, tempname
);
1880 * Dump a database node into a master file.
1881 * XXX: this function assumes the text format.
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
,
1890 isc_result_t result
;
1891 isc_buffer_t buffer
;
1894 dns_totext_ctx_t ctx
;
1895 dns_rdatasetiter_t
*rdsiter
= NULL
;
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
);
1904 isc_stdtime_get(&now
);
1906 bufmem
= isc_mem_get(mctx
, initial_buffer_length
);
1908 return (ISC_R_NOMEMORY
);
1910 isc_buffer_init(&buffer
, bufmem
, initial_buffer_length
);
1912 result
= dns_db_allrdatasets(db
, node
, version
, now
, &rdsiter
);
1913 if (result
!= ISC_R_SUCCESS
)
1915 result
= dump_rdatasets_text(mctx
, name
, rdsiter
, &ctx
, &buffer
, f
);
1916 if (result
!= ISC_R_SUCCESS
)
1918 dns_rdatasetiter_destroy(&rdsiter
);
1920 result
= ISC_R_SUCCESS
;
1923 isc_mem_put(mctx
, buffer
.base
, buffer
.length
);
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
)
1933 isc_result_t result
;
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
);
1944 result
= dns_master_dumpnodetostream(mctx
, db
, version
, node
, name
,
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
);
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
);
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
,
1974 return (dns_master_stylecreate2(stylep
, flags
, ttl_column
,
1975 class_column
, type_column
,
1976 rdata_column
, line_length
,
1977 tab_width
, 0xffffffff, mctx
));
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
)
1987 dns_master_style_t
*style
;
1989 REQUIRE(stylep
!= NULL
&& *stylep
== NULL
);
1990 style
= isc_mem_get(mctx
, sizeof(*style
));
1992 return (ISC_R_NOMEMORY
);
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
;
2004 return (ISC_R_SUCCESS
);
2008 dns_master_styledestroy(dns_master_style_t
**stylep
, isc_mem_t
*mctx
) {
2009 dns_master_style_t
*style
;
2011 REQUIRE(stylep
!= NULL
&& *stylep
!= NULL
);
2014 isc_mem_put(mctx
, style
, sizeof(*style
));