4 * Copyright (C) 2004-2009 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.
20 /* Id: masterdump.c,v 1.99 2009/11/17 23:55:18 marka Exp */
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) \
66 #define CHECK(x) do { \
67 if ((x) != ISC_R_SUCCESS) \
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
;
82 * The maximum length of the newline+indentation that is output
83 * when inserting a line break in an RR. This effectively puts an
84 * upper limits on the value of "rdata_column", because if it is
85 * very large, the tabs and spaces needed to reach it will not fit.
87 #define DNS_TOTEXT_LINEBREAK_MAXLEN 100
90 * Context structure for a masterfile dump in progress.
92 typedef struct dns_totext_ctx
{
93 dns_master_style_t style
;
94 isc_boolean_t class_printed
;
96 char linebreak_buf
[DNS_TOTEXT_LINEBREAK_MAXLEN
];
98 dns_name_t
* neworigin
;
99 dns_fixedname_t origin_fixname
;
100 isc_uint32_t current_ttl
;
101 isc_boolean_t current_ttl_valid
;
104 LIBDNS_EXTERNAL_DATA
const dns_master_style_t
105 dns_master_style_default
= {
106 DNS_STYLEFLAG_OMIT_OWNER
|
107 DNS_STYLEFLAG_OMIT_CLASS
|
108 DNS_STYLEFLAG_REL_OWNER
|
109 DNS_STYLEFLAG_REL_DATA
|
110 DNS_STYLEFLAG_OMIT_TTL
|
112 DNS_STYLEFLAG_COMMENT
|
113 DNS_STYLEFLAG_MULTILINE
,
114 24, 24, 24, 32, 80, 8
117 LIBDNS_EXTERNAL_DATA
const dns_master_style_t
118 dns_master_style_full
= {
119 DNS_STYLEFLAG_COMMENT
|
120 DNS_STYLEFLAG_RESIGN
,
121 46, 46, 46, 64, 120, 8
124 LIBDNS_EXTERNAL_DATA
const dns_master_style_t
125 dns_master_style_explicitttl
= {
126 DNS_STYLEFLAG_OMIT_OWNER
|
127 DNS_STYLEFLAG_OMIT_CLASS
|
128 DNS_STYLEFLAG_REL_OWNER
|
129 DNS_STYLEFLAG_REL_DATA
|
130 DNS_STYLEFLAG_COMMENT
|
131 DNS_STYLEFLAG_MULTILINE
,
132 24, 32, 32, 40, 80, 8
135 LIBDNS_EXTERNAL_DATA
const dns_master_style_t
136 dns_master_style_cache
= {
137 DNS_STYLEFLAG_OMIT_OWNER
|
138 DNS_STYLEFLAG_OMIT_CLASS
|
139 DNS_STYLEFLAG_MULTILINE
|
140 DNS_STYLEFLAG_TRUST
|
141 DNS_STYLEFLAG_NCACHE
,
142 24, 32, 32, 40, 80, 8
145 LIBDNS_EXTERNAL_DATA
const dns_master_style_t
146 dns_master_style_simple
= {
148 24, 32, 32, 40, 80, 8
152 * A style suitable for dns_rdataset_totext().
154 LIBDNS_EXTERNAL_DATA
const dns_master_style_t
155 dns_master_style_debug
= {
156 DNS_STYLEFLAG_REL_OWNER
,
157 24, 32, 40, 48, 80, 8
162 static char spaces
[N_SPACES
+1] = " ";
165 static char tabs
[N_TABS
+1] = "\t\t\t\t\t\t\t\t\t\t";
172 unsigned int references
;
173 isc_boolean_t canceled
;
175 isc_boolean_t do_date
;
179 dns_dbversion_t
*version
;
180 dns_dbiterator_t
*dbiter
;
181 dns_totext_ctx_t tctx
;
183 dns_dumpdonefunc_t done
;
186 /* dns_master_dumpinc() */
189 dns_masterformat_t format
;
190 isc_result_t (*dumpsets
)(isc_mem_t
*mctx
, dns_name_t
*name
,
191 dns_rdatasetiter_t
*rdsiter
,
192 dns_totext_ctx_t
*ctx
,
193 isc_buffer_t
*buffer
, FILE *f
);
197 #define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
200 * Output tabs and spaces to go from column '*current' to
201 * column 'to', and update '*current' to reflect the new
205 indent(unsigned int *current
, unsigned int to
, int tabwidth
,
206 isc_buffer_t
*target
)
211 int ntabs
, nspaces
, t
;
218 ntabs
= to
/ tabwidth
- from
/ tabwidth
;
223 isc_buffer_availableregion(target
, &r
);
224 if (r
.length
< (unsigned) ntabs
)
225 return (ISC_R_NOSPACE
);
237 isc_buffer_add(target
, ntabs
);
238 from
= (to
/ tabwidth
) * tabwidth
;
242 INSIST(nspaces
>= 0);
244 isc_buffer_availableregion(target
, &r
);
245 if (r
.length
< (unsigned) nspaces
)
246 return (ISC_R_NOSPACE
);
254 memcpy(p
, spaces
, n
);
258 isc_buffer_add(target
, nspaces
);
261 return (ISC_R_SUCCESS
);
265 totext_ctx_init(const dns_master_style_t
*style
, dns_totext_ctx_t
*ctx
) {
268 REQUIRE(style
->tab_width
!= 0);
271 ctx
->class_printed
= ISC_FALSE
;
273 dns_fixedname_init(&ctx
->origin_fixname
);
276 * Set up the line break string if needed.
278 if ((ctx
->style
.flags
& DNS_STYLEFLAG_MULTILINE
) != 0) {
281 unsigned int col
= 0;
283 isc_buffer_init(&buf
, ctx
->linebreak_buf
,
284 sizeof(ctx
->linebreak_buf
));
286 isc_buffer_availableregion(&buf
, &r
);
288 return (DNS_R_TEXTTOOLONG
);
290 isc_buffer_add(&buf
, 1);
292 result
= indent(&col
, ctx
->style
.rdata_column
,
293 ctx
->style
.tab_width
, &buf
);
295 * Do not return ISC_R_NOSPACE if the line break string
296 * buffer is too small, because that would just make
297 * dump_rdataset() retry indefinitely with ever
298 * bigger target buffers. That's a different buffer,
299 * so it won't help. Use DNS_R_TEXTTOOLONG as a substitute.
301 if (result
== ISC_R_NOSPACE
)
302 return (DNS_R_TEXTTOOLONG
);
303 if (result
!= ISC_R_SUCCESS
)
306 isc_buffer_availableregion(&buf
, &r
);
308 return (DNS_R_TEXTTOOLONG
);
310 isc_buffer_add(&buf
, 1);
311 ctx
->linebreak
= ctx
->linebreak_buf
;
313 ctx
->linebreak
= NULL
;
317 ctx
->neworigin
= NULL
;
318 ctx
->current_ttl
= 0;
319 ctx
->current_ttl_valid
= ISC_FALSE
;
321 return (ISC_R_SUCCESS
);
324 #define INDENT_TO(col) \
326 if ((result = indent(&column, ctx->style.col, \
327 ctx->style.tab_width, target)) \
334 str_totext(const char *source
, isc_buffer_t
*target
) {
338 isc_buffer_availableregion(target
, ®ion
);
341 if (l
> region
.length
)
342 return (ISC_R_NOSPACE
);
344 memcpy(region
.base
, source
, l
);
345 isc_buffer_add(target
, l
);
346 return (ISC_R_SUCCESS
);
350 ncache_summary(dns_rdataset_t
*rdataset
, isc_boolean_t omit_final_dot
,
351 isc_buffer_t
*target
)
353 isc_result_t result
= ISC_R_SUCCESS
;
357 dns_rdataset_init(&rds
);
358 dns_name_init(&name
, NULL
);
361 dns_ncache_current(rdataset
, &name
, &rds
);
362 for (result
= dns_rdataset_first(&rds
);
363 result
== ISC_R_SUCCESS
;
364 result
= dns_rdataset_next(&rds
)) {
365 CHECK(str_totext("; ", target
));
366 CHECK(dns_name_totext(&name
, omit_final_dot
, target
));
367 CHECK(str_totext(" ", target
));
368 CHECK(dns_rdatatype_totext(rds
.type
, target
));
369 if (rds
.type
== dns_rdatatype_rrsig
) {
370 CHECK(str_totext(" ", target
));
371 CHECK(dns_rdatatype_totext(rds
.covers
, target
));
372 CHECK(str_totext(" ...\n", target
));
374 dns_rdata_t rdata
= DNS_RDATA_INIT
;
375 dns_rdataset_current(&rds
, &rdata
);
376 CHECK(str_totext(" ", target
));
377 CHECK(dns_rdata_tofmttext(&rdata
, dns_rootname
,
379 CHECK(str_totext("\n", target
));
382 dns_rdataset_disassociate(&rds
);
383 result
= dns_rdataset_next(rdataset
);
384 } while (result
== ISC_R_SUCCESS
);
386 if (result
== ISC_R_NOMORE
)
387 result
= ISC_R_SUCCESS
;
389 if (dns_rdataset_isassociated(&rds
))
390 dns_rdataset_disassociate(&rds
);
396 * Convert 'rdataset' to master file text format according to 'ctx',
397 * storing the result in 'target'. If 'owner_name' is NULL, it
398 * is omitted; otherwise 'owner_name' must be valid and have at least
403 rdataset_totext(dns_rdataset_t
*rdataset
,
404 dns_name_t
*owner_name
,
405 dns_totext_ctx_t
*ctx
,
406 isc_boolean_t omit_final_dot
,
407 isc_buffer_t
*target
)
411 isc_boolean_t first
= ISC_TRUE
;
412 isc_uint32_t current_ttl
;
413 isc_boolean_t current_ttl_valid
;
414 dns_rdatatype_t type
;
416 REQUIRE(DNS_RDATASET_VALID(rdataset
));
418 rdataset
->attributes
|= DNS_RDATASETATTR_LOADORDER
;
419 result
= dns_rdataset_first(rdataset
);
420 REQUIRE(result
== ISC_R_SUCCESS
);
422 current_ttl
= ctx
->current_ttl
;
423 current_ttl_valid
= ctx
->current_ttl_valid
;
431 if (owner_name
!= NULL
&&
432 ! ((ctx
->style
.flags
& DNS_STYLEFLAG_OMIT_OWNER
) != 0 &&
435 unsigned int name_start
= target
->used
;
436 RETERR(dns_name_totext(owner_name
,
439 column
+= target
->used
- name_start
;
445 if ((ctx
->style
.flags
& DNS_STYLEFLAG_NO_TTL
) == 0 &&
446 !((ctx
->style
.flags
& DNS_STYLEFLAG_OMIT_TTL
) != 0 &&
448 rdataset
->ttl
== current_ttl
))
454 INDENT_TO(ttl_column
);
455 length
= snprintf(ttlbuf
, sizeof(ttlbuf
), "%u",
457 INSIST(length
<= sizeof(ttlbuf
));
458 isc_buffer_availableregion(target
, &r
);
459 if (r
.length
< length
)
460 return (ISC_R_NOSPACE
);
461 memcpy(r
.base
, ttlbuf
, length
);
462 isc_buffer_add(target
, length
);
466 * If the $TTL directive is not in use, the TTL we
467 * just printed becomes the default for subsequent RRs.
469 if ((ctx
->style
.flags
& DNS_STYLEFLAG_TTL
) == 0) {
470 current_ttl
= rdataset
->ttl
;
471 current_ttl_valid
= ISC_TRUE
;
478 if ((ctx
->style
.flags
& DNS_STYLEFLAG_NO_CLASS
) == 0 &&
479 ((ctx
->style
.flags
& DNS_STYLEFLAG_OMIT_CLASS
) == 0 ||
480 ctx
->class_printed
== ISC_FALSE
))
482 unsigned int class_start
;
483 INDENT_TO(class_column
);
484 class_start
= target
->used
;
485 result
= dns_rdataclass_totext(rdataset
->rdclass
,
487 if (result
!= ISC_R_SUCCESS
)
489 column
+= (target
->used
- class_start
);
496 if (rdataset
->type
== 0) {
497 type
= rdataset
->covers
;
499 type
= rdataset
->type
;
503 unsigned int type_start
;
504 INDENT_TO(type_column
);
505 type_start
= target
->used
;
506 if (rdataset
->type
== 0)
507 RETERR(str_totext("\\-", target
));
508 result
= dns_rdatatype_totext(type
, target
);
509 if (result
!= ISC_R_SUCCESS
)
511 column
+= (target
->used
- type_start
);
517 INDENT_TO(rdata_column
);
518 if (rdataset
->type
== 0) {
519 if (NXDOMAIN(rdataset
))
520 RETERR(str_totext(";-$NXDOMAIN\n", target
));
522 RETERR(str_totext(";-$NXRRSET\n", target
));
524 * Print a summary of the cached records which make
525 * up the negative response.
527 RETERR(ncache_summary(rdataset
, omit_final_dot
,
531 dns_rdata_t rdata
= DNS_RDATA_INIT
;
534 dns_rdataset_current(rdataset
, &rdata
);
536 RETERR(dns_rdata_tofmttext(&rdata
,
539 ctx
->style
.line_length
-
540 ctx
->style
.rdata_column
,
544 isc_buffer_availableregion(target
, &r
);
546 return (ISC_R_NOSPACE
);
548 isc_buffer_add(target
, 1);
552 result
= dns_rdataset_next(rdataset
);
553 } while (result
== ISC_R_SUCCESS
);
555 if (result
!= ISC_R_NOMORE
)
559 * Update the ctx state to reflect what we just printed.
560 * This is done last, only when we are sure we will return
561 * success, because this function may be called multiple
562 * times with increasing buffer sizes until it succeeds,
563 * and failed attempts must not update the state prematurely.
565 ctx
->class_printed
= ISC_TRUE
;
566 ctx
->current_ttl
= current_ttl
;
567 ctx
->current_ttl_valid
= current_ttl_valid
;
569 return (ISC_R_SUCCESS
);
573 * Print the name, type, and class of an empty rdataset,
574 * such as those used to represent the question section
578 question_totext(dns_rdataset_t
*rdataset
,
579 dns_name_t
*owner_name
,
580 dns_totext_ctx_t
*ctx
,
581 isc_boolean_t omit_final_dot
,
582 isc_buffer_t
*target
)
588 REQUIRE(DNS_RDATASET_VALID(rdataset
));
589 result
= dns_rdataset_first(rdataset
);
590 REQUIRE(result
== ISC_R_NOMORE
);
596 unsigned int name_start
= target
->used
;
597 RETERR(dns_name_totext(owner_name
,
600 column
+= target
->used
- name_start
;
605 unsigned int class_start
;
606 INDENT_TO(class_column
);
607 class_start
= target
->used
;
608 result
= dns_rdataclass_totext(rdataset
->rdclass
, target
);
609 if (result
!= ISC_R_SUCCESS
)
611 column
+= (target
->used
- class_start
);
616 unsigned int type_start
;
617 INDENT_TO(type_column
);
618 type_start
= target
->used
;
619 result
= dns_rdatatype_totext(rdataset
->type
, target
);
620 if (result
!= ISC_R_SUCCESS
)
622 column
+= (target
->used
- type_start
);
625 isc_buffer_availableregion(target
, &r
);
627 return (ISC_R_NOSPACE
);
629 isc_buffer_add(target
, 1);
631 return (ISC_R_SUCCESS
);
635 dns_rdataset_totext(dns_rdataset_t
*rdataset
,
636 dns_name_t
*owner_name
,
637 isc_boolean_t omit_final_dot
,
638 isc_boolean_t question
,
639 isc_buffer_t
*target
)
641 dns_totext_ctx_t ctx
;
643 result
= totext_ctx_init(&dns_master_style_debug
, &ctx
);
644 if (result
!= ISC_R_SUCCESS
) {
645 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
646 "could not set master file style");
647 return (ISC_R_UNEXPECTED
);
651 * The caller might want to give us an empty owner
652 * name (e.g. if they are outputting into a master
653 * file and this rdataset has the same name as the
656 if (dns_name_countlabels(owner_name
) == 0)
660 return (question_totext(rdataset
, owner_name
, &ctx
,
661 omit_final_dot
, target
));
663 return (rdataset_totext(rdataset
, owner_name
, &ctx
,
664 omit_final_dot
, target
));
668 dns_master_rdatasettotext(dns_name_t
*owner_name
,
669 dns_rdataset_t
*rdataset
,
670 const dns_master_style_t
*style
,
671 isc_buffer_t
*target
)
673 dns_totext_ctx_t ctx
;
675 result
= totext_ctx_init(style
, &ctx
);
676 if (result
!= ISC_R_SUCCESS
) {
677 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
678 "could not set master file style");
679 return (ISC_R_UNEXPECTED
);
682 return (rdataset_totext(rdataset
, owner_name
, &ctx
,
687 dns_master_questiontotext(dns_name_t
*owner_name
,
688 dns_rdataset_t
*rdataset
,
689 const dns_master_style_t
*style
,
690 isc_buffer_t
*target
)
692 dns_totext_ctx_t ctx
;
694 result
= totext_ctx_init(style
, &ctx
);
695 if (result
!= ISC_R_SUCCESS
) {
696 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
697 "could not set master file style");
698 return (ISC_R_UNEXPECTED
);
701 return (question_totext(rdataset
, owner_name
, &ctx
,
707 * Print an rdataset. 'buffer' is a scratch buffer, which must have been
708 * dynamically allocated by the caller. It must be large enough to
709 * hold the result from dns_ttl_totext(). If more than that is needed,
710 * the buffer will be grown automatically.
714 dump_rdataset(isc_mem_t
*mctx
, dns_name_t
*name
, dns_rdataset_t
*rdataset
,
715 dns_totext_ctx_t
*ctx
,
716 isc_buffer_t
*buffer
, FILE *f
)
721 REQUIRE(buffer
->length
> 0);
724 * Output a $TTL directive if needed.
727 if ((ctx
->style
.flags
& DNS_STYLEFLAG_TTL
) != 0) {
728 if (ctx
->current_ttl_valid
== ISC_FALSE
||
729 ctx
->current_ttl
!= rdataset
->ttl
)
731 if ((ctx
->style
.flags
& DNS_STYLEFLAG_COMMENT
) != 0)
733 isc_buffer_clear(buffer
);
734 result
= dns_ttl_totext(rdataset
->ttl
,
736 INSIST(result
== ISC_R_SUCCESS
);
737 isc_buffer_usedregion(buffer
, &r
);
738 fprintf(f
, "$TTL %u\t; %.*s\n", rdataset
->ttl
,
739 (int) r
.length
, (char *) r
.base
);
741 fprintf(f
, "$TTL %u\n", rdataset
->ttl
);
743 ctx
->current_ttl
= rdataset
->ttl
;
744 ctx
->current_ttl_valid
= ISC_TRUE
;
748 isc_buffer_clear(buffer
);
751 * Generate the text representation of the rdataset into
752 * the buffer. If the buffer is too small, grow it.
757 result
= rdataset_totext(rdataset
, name
, ctx
,
759 if (result
!= ISC_R_NOSPACE
)
762 newlength
= buffer
->length
* 2;
763 newmem
= isc_mem_get(mctx
, newlength
);
765 return (ISC_R_NOMEMORY
);
766 isc_mem_put(mctx
, buffer
->base
, buffer
->length
);
767 isc_buffer_init(buffer
, newmem
, newlength
);
769 if (result
!= ISC_R_SUCCESS
)
773 * Write the buffer contents to the master file.
775 isc_buffer_usedregion(buffer
, &r
);
776 result
= isc_stdio_write(r
.base
, 1, (size_t)r
.length
, f
, NULL
);
778 if (result
!= ISC_R_SUCCESS
) {
779 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
780 "master file write failed: %s",
781 isc_result_totext(result
));
785 return (ISC_R_SUCCESS
);
789 * Define the order in which rdatasets should be printed in zone
790 * files. We will print SOA and NS records before others, SIGs
791 * immediately following the things they sign, and order everything
792 * else by RR number. This is all just for aesthetics and
793 * compatibility with buggy software that expects the SOA to be first;
794 * the DNS specifications allow any order.
798 dump_order(const dns_rdataset_t
*rds
) {
801 if (rds
->type
== dns_rdatatype_rrsig
) {
809 case dns_rdatatype_soa
:
812 case dns_rdatatype_ns
:
819 return (t
<< 1) + sig
;
823 dump_order_compare(const void *a
, const void *b
) {
824 return (dump_order(*((const dns_rdataset_t
* const *) a
)) -
825 dump_order(*((const dns_rdataset_t
* const *) b
)));
829 * Dump all the rdatasets of a domain name to a master file. We make
830 * a "best effort" attempt to sort the RRsets in a nice order, but if
831 * there are more than MAXSORT RRsets, we punt and only sort them in
832 * groups of MAXSORT. This is not expected to ever happen in practice
833 * since much less than 64 RR types have been registered with the
834 * IANA, so far, and the output will be correct (though not
835 * aesthetically pleasing) even if it does happen.
840 static const char *trustnames
[] = {
842 "pending-additional",
850 "local" /* aka ultimate */
854 dns_trust_totext(dns_trust_t trust
) {
855 if (trust
>= sizeof(trustnames
)/sizeof(*trustnames
))
857 return (trustnames
[trust
]);
861 dump_rdatasets_text(isc_mem_t
*mctx
, dns_name_t
*name
,
862 dns_rdatasetiter_t
*rdsiter
, dns_totext_ctx_t
*ctx
,
863 isc_buffer_t
*buffer
, FILE *f
)
865 isc_result_t itresult
, dumpresult
;
867 dns_rdataset_t rdatasets
[MAXSORT
];
868 dns_rdataset_t
*sorted
[MAXSORT
];
871 itresult
= dns_rdatasetiter_first(rdsiter
);
872 dumpresult
= ISC_R_SUCCESS
;
874 if (itresult
== ISC_R_SUCCESS
&& ctx
->neworigin
!= NULL
) {
875 isc_buffer_clear(buffer
);
876 itresult
= dns_name_totext(ctx
->neworigin
, ISC_FALSE
, buffer
);
877 RUNTIME_CHECK(itresult
== ISC_R_SUCCESS
);
878 isc_buffer_usedregion(buffer
, &r
);
879 fprintf(f
, "$ORIGIN %.*s\n", (int) r
.length
, (char *) r
.base
);
880 ctx
->neworigin
= NULL
;
885 itresult
== ISC_R_SUCCESS
&& i
< MAXSORT
;
886 itresult
= dns_rdatasetiter_next(rdsiter
), i
++) {
887 dns_rdataset_init(&rdatasets
[i
]);
888 dns_rdatasetiter_current(rdsiter
, &rdatasets
[i
]);
889 sorted
[i
] = &rdatasets
[i
];
892 INSIST(n
<= MAXSORT
);
894 qsort(sorted
, n
, sizeof(sorted
[0]), dump_order_compare
);
896 for (i
= 0; i
< n
; i
++) {
897 dns_rdataset_t
*rds
= sorted
[i
];
898 if (ctx
->style
.flags
& DNS_STYLEFLAG_TRUST
) {
899 unsigned int trust
= rds
->trust
;
900 INSIST(trust
< (sizeof(trustnames
) /
901 sizeof(trustnames
[0])));
902 fprintf(f
, "; %s\n", trustnames
[trust
]);
904 if (rds
->type
== 0 &&
905 (ctx
->style
.flags
& DNS_STYLEFLAG_NCACHE
) == 0) {
906 /* Omit negative cache entries */
908 isc_result_t result
=
909 dump_rdataset(mctx
, name
, rds
, ctx
,
911 if (result
!= ISC_R_SUCCESS
)
913 if ((ctx
->style
.flags
& DNS_STYLEFLAG_OMIT_OWNER
) != 0)
916 if (ctx
->style
.flags
& DNS_STYLEFLAG_RESIGN
&&
917 rds
->attributes
& DNS_RDATASETATTR_RESIGN
) {
919 char buf
[sizeof("YYYYMMDDHHMMSS")];
920 memset(buf
, 0, sizeof(buf
));
921 isc_buffer_init(&b
, buf
, sizeof(buf
) - 1);
922 dns_time64_totext((isc_uint64_t
)rds
->resign
, &b
);
923 fprintf(f
, "; resign=%s\n", buf
);
925 dns_rdataset_disassociate(rds
);
928 if (dumpresult
!= ISC_R_SUCCESS
)
932 * If we got more data than could be sorted at once,
933 * go handle the rest.
935 if (itresult
== ISC_R_SUCCESS
)
938 if (itresult
== ISC_R_NOMORE
)
939 itresult
= ISC_R_SUCCESS
;
945 * Dump given RRsets in the "raw" format.
948 dump_rdataset_raw(isc_mem_t
*mctx
, dns_name_t
*name
, dns_rdataset_t
*rdataset
,
949 isc_buffer_t
*buffer
, FILE *f
)
952 isc_uint32_t totallen
;
954 isc_region_t r
, r_hdr
;
956 REQUIRE(buffer
->length
> 0);
957 REQUIRE(DNS_RDATASET_VALID(rdataset
));
961 result
= dns_rdataset_first(rdataset
);
962 REQUIRE(result
== ISC_R_SUCCESS
);
964 isc_buffer_clear(buffer
);
967 * Common header and owner name (length followed by name)
968 * These fields should be in a moderate length, so we assume we
969 * can store all of them in the initial buffer.
971 isc_buffer_availableregion(buffer
, &r_hdr
);
972 INSIST(r_hdr
.length
>= sizeof(dns_masterrawrdataset_t
));
973 isc_buffer_putuint32(buffer
, totallen
); /* XXX: leave space */
974 isc_buffer_putuint16(buffer
, rdataset
->rdclass
); /* 16-bit class */
975 isc_buffer_putuint16(buffer
, rdataset
->type
); /* 16-bit type */
976 isc_buffer_putuint16(buffer
, rdataset
->covers
); /* same as type */
977 isc_buffer_putuint32(buffer
, rdataset
->ttl
); /* 32-bit TTL */
978 isc_buffer_putuint32(buffer
, dns_rdataset_count(rdataset
));
979 totallen
= isc_buffer_usedlength(buffer
);
980 INSIST(totallen
<= sizeof(dns_masterrawrdataset_t
));
982 dns_name_toregion(name
, &r
);
983 INSIST(isc_buffer_availablelength(buffer
) >=
984 (sizeof(dlen
) + r
.length
));
985 dlen
= (isc_uint16_t
)r
.length
;
986 isc_buffer_putuint16(buffer
, dlen
);
987 isc_buffer_copyregion(buffer
, &r
);
988 totallen
+= sizeof(dlen
) + r
.length
;
991 dns_rdata_t rdata
= DNS_RDATA_INIT
;
994 dns_rdataset_current(rdataset
, &rdata
);
995 dns_rdata_toregion(&rdata
, &r
);
996 INSIST(r
.length
<= 0xffffU
);
997 dlen
= (isc_uint16_t
)r
.length
;
1000 * Copy the rdata into the buffer. If the buffer is too small,
1001 * grow it. This should be rare, so we'll simply restart the
1002 * entire procedure (or should we copy the old data and
1005 if (isc_buffer_availablelength(buffer
) <
1006 sizeof(dlen
) + r
.length
) {
1010 newlength
= buffer
->length
* 2;
1011 newmem
= isc_mem_get(mctx
, newlength
);
1013 return (ISC_R_NOMEMORY
);
1014 isc_mem_put(mctx
, buffer
->base
, buffer
->length
);
1015 isc_buffer_init(buffer
, newmem
, newlength
);
1018 isc_buffer_putuint16(buffer
, dlen
);
1019 isc_buffer_copyregion(buffer
, &r
);
1020 totallen
+= sizeof(dlen
) + r
.length
;
1022 result
= dns_rdataset_next(rdataset
);
1023 } while (result
== ISC_R_SUCCESS
);
1025 if (result
!= ISC_R_NOMORE
)
1029 * Fill in the total length field.
1030 * XXX: this is a bit tricky. Since we have already "used" the space
1031 * for the total length in the buffer, we first remember the entire
1032 * buffer length in the region, "rewind", and then write the value.
1034 isc_buffer_usedregion(buffer
, &r
);
1035 isc_buffer_clear(buffer
);
1036 isc_buffer_putuint32(buffer
, totallen
);
1037 INSIST(isc_buffer_usedlength(buffer
) < totallen
);
1040 * Write the buffer contents to the raw master file.
1042 result
= isc_stdio_write(r
.base
, 1, (size_t)r
.length
, f
, NULL
);
1044 if (result
!= ISC_R_SUCCESS
) {
1045 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1046 "raw master file write failed: %s",
1047 isc_result_totext(result
));
1055 dump_rdatasets_raw(isc_mem_t
*mctx
, dns_name_t
*name
,
1056 dns_rdatasetiter_t
*rdsiter
, dns_totext_ctx_t
*ctx
,
1057 isc_buffer_t
*buffer
, FILE *f
)
1059 isc_result_t result
;
1060 dns_rdataset_t rdataset
;
1062 for (result
= dns_rdatasetiter_first(rdsiter
);
1063 result
== ISC_R_SUCCESS
;
1064 result
= dns_rdatasetiter_next(rdsiter
)) {
1066 dns_rdataset_init(&rdataset
);
1067 dns_rdatasetiter_current(rdsiter
, &rdataset
);
1069 if (rdataset
.type
== 0 &&
1070 (ctx
->style
.flags
& DNS_STYLEFLAG_NCACHE
) == 0) {
1071 /* Omit negative cache entries */
1073 result
= dump_rdataset_raw(mctx
, name
, &rdataset
,
1076 dns_rdataset_disassociate(&rdataset
);
1079 if (result
== ISC_R_NOMORE
)
1080 result
= ISC_R_SUCCESS
;
1086 * Initial size of text conversion buffer. The buffer is used
1087 * for several purposes: converting origin names, rdatasets,
1088 * $DATE timestamps, and comment strings for $TTL directives.
1090 * When converting rdatasets, it is dynamically resized, but
1091 * when converting origins, timestamps, etc it is not. Therefore,
1092 * the initial size must large enough to hold the longest possible
1093 * text representation of any domain name (for $ORIGIN).
1095 static const int initial_buffer_length
= 1200;
1098 dumptostreaminc(dns_dumpctx_t
*dctx
);
1101 dumpctx_destroy(dns_dumpctx_t
*dctx
) {
1104 DESTROYLOCK(&dctx
->lock
);
1105 dns_dbiterator_destroy(&dctx
->dbiter
);
1106 if (dctx
->version
!= NULL
)
1107 dns_db_closeversion(dctx
->db
, &dctx
->version
, ISC_FALSE
);
1108 dns_db_detach(&dctx
->db
);
1109 if (dctx
->task
!= NULL
)
1110 isc_task_detach(&dctx
->task
);
1111 if (dctx
->file
!= NULL
)
1112 isc_mem_free(dctx
->mctx
, dctx
->file
);
1113 if (dctx
->tmpfile
!= NULL
)
1114 isc_mem_free(dctx
->mctx
, dctx
->tmpfile
);
1115 isc_mem_putanddetach(&dctx
->mctx
, dctx
, sizeof(*dctx
));
1119 dns_dumpctx_attach(dns_dumpctx_t
*source
, dns_dumpctx_t
**target
) {
1121 REQUIRE(DNS_DCTX_VALID(source
));
1122 REQUIRE(target
!= NULL
&& *target
== NULL
);
1124 LOCK(&source
->lock
);
1125 INSIST(source
->references
> 0);
1126 source
->references
++;
1127 INSIST(source
->references
!= 0); /* Overflow? */
1128 UNLOCK(&source
->lock
);
1134 dns_dumpctx_detach(dns_dumpctx_t
**dctxp
) {
1135 dns_dumpctx_t
*dctx
;
1136 isc_boolean_t need_destroy
= ISC_FALSE
;
1138 REQUIRE(dctxp
!= NULL
);
1140 REQUIRE(DNS_DCTX_VALID(dctx
));
1145 INSIST(dctx
->references
!= 0);
1147 if (dctx
->references
== 0)
1148 need_destroy
= ISC_TRUE
;
1149 UNLOCK(&dctx
->lock
);
1151 dumpctx_destroy(dctx
);
1155 dns_dumpctx_version(dns_dumpctx_t
*dctx
) {
1156 REQUIRE(DNS_DCTX_VALID(dctx
));
1157 return (dctx
->version
);
1161 dns_dumpctx_db(dns_dumpctx_t
*dctx
) {
1162 REQUIRE(DNS_DCTX_VALID(dctx
));
1167 dns_dumpctx_cancel(dns_dumpctx_t
*dctx
) {
1168 REQUIRE(DNS_DCTX_VALID(dctx
));
1171 dctx
->canceled
= ISC_TRUE
;
1172 UNLOCK(&dctx
->lock
);
1176 closeandrename(FILE *f
, isc_result_t result
, const char *temp
, const char *file
)
1178 isc_result_t tresult
;
1179 isc_boolean_t logit
= ISC_TF(result
== ISC_R_SUCCESS
);
1181 if (result
== ISC_R_SUCCESS
)
1182 result
= isc_stdio_sync(f
);
1183 if (result
!= ISC_R_SUCCESS
&& logit
) {
1184 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
1185 DNS_LOGMODULE_MASTERDUMP
, ISC_LOG_ERROR
,
1186 "dumping master file: %s: fsync: %s",
1187 temp
, isc_result_totext(result
));
1190 tresult
= isc_stdio_close(f
);
1191 if (result
== ISC_R_SUCCESS
)
1193 if (result
!= ISC_R_SUCCESS
&& logit
) {
1194 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
1195 DNS_LOGMODULE_MASTERDUMP
, ISC_LOG_ERROR
,
1196 "dumping master file: %s: fclose: %s",
1197 temp
, isc_result_totext(result
));
1200 if (result
== ISC_R_SUCCESS
)
1201 result
= isc_file_rename(temp
, file
);
1203 (void)isc_file_remove(temp
);
1204 if (result
!= ISC_R_SUCCESS
&& logit
) {
1205 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
1206 DNS_LOGMODULE_MASTERDUMP
, ISC_LOG_ERROR
,
1207 "dumping master file: rename: %s: %s",
1208 file
, isc_result_totext(result
));
1214 dump_quantum(isc_task_t
*task
, isc_event_t
*event
) {
1215 isc_result_t result
;
1216 isc_result_t tresult
;
1217 dns_dumpctx_t
*dctx
;
1219 REQUIRE(event
!= NULL
);
1220 dctx
= event
->ev_arg
;
1221 REQUIRE(DNS_DCTX_VALID(dctx
));
1223 result
= ISC_R_CANCELED
;
1225 result
= dumptostreaminc(dctx
);
1226 if (result
== DNS_R_CONTINUE
) {
1227 event
->ev_arg
= dctx
;
1228 isc_task_send(task
, &event
);
1232 if (dctx
->file
!= NULL
) {
1233 tresult
= closeandrename(dctx
->f
, result
,
1234 dctx
->tmpfile
, dctx
->file
);
1235 if (tresult
!= ISC_R_SUCCESS
&& result
== ISC_R_SUCCESS
)
1238 (dctx
->done
)(dctx
->done_arg
, result
);
1239 isc_event_free(&event
);
1240 dns_dumpctx_detach(&dctx
);
1244 task_send(dns_dumpctx_t
*dctx
) {
1247 event
= isc_event_allocate(dctx
->mctx
, NULL
, DNS_EVENT_DUMPQUANTUM
,
1248 dump_quantum
, dctx
, sizeof(*event
));
1250 return (ISC_R_NOMEMORY
);
1251 isc_task_send(dctx
->task
, &event
);
1252 return (ISC_R_SUCCESS
);
1256 dumpctx_create(isc_mem_t
*mctx
, dns_db_t
*db
, dns_dbversion_t
*version
,
1257 const dns_master_style_t
*style
, FILE *f
, dns_dumpctx_t
**dctxp
,
1258 dns_masterformat_t format
)
1260 dns_dumpctx_t
*dctx
;
1261 isc_result_t result
;
1262 unsigned int options
;
1264 dctx
= isc_mem_get(mctx
, sizeof(*dctx
));
1266 return (ISC_R_NOMEMORY
);
1270 dctx
->dbiter
= NULL
;
1272 dctx
->version
= NULL
;
1274 dctx
->done_arg
= NULL
;
1277 dctx
->first
= ISC_TRUE
;
1278 dctx
->canceled
= ISC_FALSE
;
1280 dctx
->tmpfile
= NULL
;
1281 dctx
->format
= format
;
1284 case dns_masterformat_text
:
1285 dctx
->dumpsets
= dump_rdatasets_text
;
1287 case dns_masterformat_raw
:
1288 dctx
->dumpsets
= dump_rdatasets_raw
;
1295 result
= totext_ctx_init(style
, &dctx
->tctx
);
1296 if (result
!= ISC_R_SUCCESS
) {
1297 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1298 "could not set master file style");
1302 isc_stdtime_get(&dctx
->now
);
1303 dns_db_attach(db
, &dctx
->db
);
1305 dctx
->do_date
= dns_db_iscache(dctx
->db
);
1307 if (dctx
->format
== dns_masterformat_text
&&
1308 (dctx
->tctx
.style
.flags
& DNS_STYLEFLAG_REL_OWNER
) != 0) {
1309 options
= DNS_DB_RELATIVENAMES
;
1312 result
= dns_db_createiterator(dctx
->db
, options
, &dctx
->dbiter
);
1313 if (result
!= ISC_R_SUCCESS
)
1316 result
= isc_mutex_init(&dctx
->lock
);
1317 if (result
!= ISC_R_SUCCESS
)
1319 if (version
!= NULL
)
1320 dns_db_attachversion(dctx
->db
, version
, &dctx
->version
);
1321 else if (!dns_db_iscache(db
))
1322 dns_db_currentversion(dctx
->db
, &dctx
->version
);
1323 isc_mem_attach(mctx
, &dctx
->mctx
);
1324 dctx
->references
= 1;
1325 dctx
->magic
= DNS_DCTX_MAGIC
;
1327 return (ISC_R_SUCCESS
);
1330 if (dctx
->dbiter
!= NULL
)
1331 dns_dbiterator_destroy(&dctx
->dbiter
);
1332 if (dctx
->db
!= NULL
)
1333 dns_db_detach(&dctx
->db
);
1335 isc_mem_put(mctx
, dctx
, sizeof(*dctx
));
1340 dumptostreaminc(dns_dumpctx_t
*dctx
) {
1341 isc_result_t result
;
1342 isc_buffer_t buffer
;
1346 dns_fixedname_t fixname
;
1348 dns_masterrawheader_t rawheader
;
1352 bufmem
= isc_mem_get(dctx
->mctx
, initial_buffer_length
);
1354 return (ISC_R_NOMEMORY
);
1356 isc_buffer_init(&buffer
, bufmem
, initial_buffer_length
);
1358 dns_fixedname_init(&fixname
);
1359 name
= dns_fixedname_name(&fixname
);
1362 switch (dctx
->format
) {
1363 case dns_masterformat_text
:
1365 * If the database has cache semantics, output an
1366 * RFC2540 $DATE directive so that the TTLs can be
1367 * adjusted when it is reloaded. For zones it is not
1368 * really needed, and it would make the file
1369 * incompatible with pre-RFC2540 software, so we omit
1370 * it in the zone case.
1372 if (dctx
->do_date
) {
1373 result
= dns_time32_totext(dctx
->now
, &buffer
);
1374 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
1375 isc_buffer_usedregion(&buffer
, &r
);
1376 fprintf(dctx
->f
, "$DATE %.*s\n",
1377 (int) r
.length
, (char *) r
.base
);
1380 case dns_masterformat_raw
:
1381 r
.base
= (unsigned char *)&rawheader
;
1382 r
.length
= sizeof(rawheader
);
1383 isc_buffer_region(&buffer
, &r
);
1384 isc_buffer_putuint32(&buffer
, dns_masterformat_raw
);
1385 isc_buffer_putuint32(&buffer
, DNS_RAWFORMAT_VERSION
);
1386 if (sizeof(now32
) != sizeof(dctx
->now
)) {
1388 * We assume isc_stdtime_t is a 32-bit integer,
1389 * which should be the case on most cases.
1390 * If it turns out to be uncommon, we'll need
1391 * to bump the version number and revise the
1394 isc_log_write(dns_lctx
,
1395 ISC_LOGCATEGORY_GENERAL
,
1396 DNS_LOGMODULE_MASTERDUMP
,
1398 "dumping master file in raw "
1399 "format: stdtime is not 32bits");
1403 isc_buffer_putuint32(&buffer
, now32
);
1404 INSIST(isc_buffer_usedlength(&buffer
) <=
1406 result
= isc_stdio_write(buffer
.base
, 1,
1407 isc_buffer_usedlength(&buffer
),
1409 if (result
!= ISC_R_SUCCESS
)
1411 isc_buffer_clear(&buffer
);
1417 result
= dns_dbiterator_first(dctx
->dbiter
);
1418 dctx
->first
= ISC_FALSE
;
1420 result
= ISC_R_SUCCESS
;
1422 nodes
= dctx
->nodes
;
1423 isc_time_now(&start
);
1424 while (result
== ISC_R_SUCCESS
&& (dctx
->nodes
== 0 || nodes
--)) {
1425 dns_rdatasetiter_t
*rdsiter
= NULL
;
1426 dns_dbnode_t
*node
= NULL
;
1428 result
= dns_dbiterator_current(dctx
->dbiter
, &node
, name
);
1429 if (result
!= ISC_R_SUCCESS
&& result
!= DNS_R_NEWORIGIN
)
1431 if (result
== DNS_R_NEWORIGIN
) {
1432 dns_name_t
*origin
=
1433 dns_fixedname_name(&dctx
->tctx
.origin_fixname
);
1434 result
= dns_dbiterator_origin(dctx
->dbiter
, origin
);
1435 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
1436 if ((dctx
->tctx
.style
.flags
& DNS_STYLEFLAG_REL_DATA
) != 0)
1437 dctx
->tctx
.origin
= origin
;
1438 dctx
->tctx
.neworigin
= origin
;
1440 result
= dns_db_allrdatasets(dctx
->db
, node
, dctx
->version
,
1441 dctx
->now
, &rdsiter
);
1442 if (result
!= ISC_R_SUCCESS
) {
1443 dns_db_detachnode(dctx
->db
, &node
);
1446 result
= (dctx
->dumpsets
)(dctx
->mctx
, name
, rdsiter
,
1447 &dctx
->tctx
, &buffer
, dctx
->f
);
1448 dns_rdatasetiter_destroy(&rdsiter
);
1449 if (result
!= ISC_R_SUCCESS
) {
1450 dns_db_detachnode(dctx
->db
, &node
);
1453 dns_db_detachnode(dctx
->db
, &node
);
1454 result
= dns_dbiterator_next(dctx
->dbiter
);
1458 * Work out how many nodes can be written in the time between
1459 * two requests to the nameserver. Smooth the resulting number and
1460 * use it as a estimate for the number of nodes to be written in the
1463 if (dctx
->nodes
!= 0 && result
== ISC_R_SUCCESS
) {
1464 unsigned int pps
= dns_pps
; /* packets per second */
1465 unsigned int interval
;
1472 interval
= 1000000 / pps
; /* interval in usecs */
1475 usecs
= isc_time_microdiff(&end
, &start
);
1477 dctx
->nodes
= dctx
->nodes
* 2;
1478 if (dctx
->nodes
> 1000)
1481 nodes
= dctx
->nodes
* interval
;
1482 nodes
/= (unsigned int)usecs
;
1485 else if (nodes
> 1000)
1488 /* Smooth and assign. */
1489 dctx
->nodes
= (nodes
+ dctx
->nodes
* 7) / 8;
1491 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
1492 DNS_LOGMODULE_MASTERDUMP
,
1494 "dumptostreaminc(%p) new nodes -> %d\n",
1497 result
= DNS_R_CONTINUE
;
1498 } else if (result
== ISC_R_NOMORE
)
1499 result
= ISC_R_SUCCESS
;
1501 RUNTIME_CHECK(dns_dbiterator_pause(dctx
->dbiter
) == ISC_R_SUCCESS
);
1502 isc_mem_put(dctx
->mctx
, buffer
.base
, buffer
.length
);
1507 dns_master_dumptostreaminc(isc_mem_t
*mctx
, dns_db_t
*db
,
1508 dns_dbversion_t
*version
,
1509 const dns_master_style_t
*style
,
1510 FILE *f
, isc_task_t
*task
,
1511 dns_dumpdonefunc_t done
, void *done_arg
,
1512 dns_dumpctx_t
**dctxp
)
1514 dns_dumpctx_t
*dctx
= NULL
;
1515 isc_result_t result
;
1517 REQUIRE(task
!= NULL
);
1519 REQUIRE(done
!= NULL
);
1521 result
= dumpctx_create(mctx
, db
, version
, style
, f
, &dctx
,
1522 dns_masterformat_text
);
1523 if (result
!= ISC_R_SUCCESS
)
1525 isc_task_attach(task
, &dctx
->task
);
1527 dctx
->done_arg
= done_arg
;
1530 result
= task_send(dctx
);
1531 if (result
== ISC_R_SUCCESS
) {
1532 dns_dumpctx_attach(dctx
, dctxp
);
1533 return (DNS_R_CONTINUE
);
1536 dns_dumpctx_detach(&dctx
);
1541 * Dump an entire database into a master file.
1544 dns_master_dumptostream(isc_mem_t
*mctx
, dns_db_t
*db
,
1545 dns_dbversion_t
*version
,
1546 const dns_master_style_t
*style
,
1549 return (dns_master_dumptostream2(mctx
, db
, version
, style
,
1550 dns_masterformat_text
, f
));
1554 dns_master_dumptostream2(isc_mem_t
*mctx
, dns_db_t
*db
,
1555 dns_dbversion_t
*version
,
1556 const dns_master_style_t
*style
,
1557 dns_masterformat_t format
, FILE *f
)
1559 dns_dumpctx_t
*dctx
= NULL
;
1560 isc_result_t result
;
1562 result
= dumpctx_create(mctx
, db
, version
, style
, f
, &dctx
, format
);
1563 if (result
!= ISC_R_SUCCESS
)
1566 result
= dumptostreaminc(dctx
);
1567 INSIST(result
!= DNS_R_CONTINUE
);
1568 dns_dumpctx_detach(&dctx
);
1573 opentmp(isc_mem_t
*mctx
, const char *file
, char **tempp
, FILE **fp
) {
1575 isc_result_t result
;
1576 char *tempname
= NULL
;
1579 tempnamelen
= strlen(file
) + 20;
1580 tempname
= isc_mem_allocate(mctx
, tempnamelen
);
1581 if (tempname
== NULL
)
1582 return (ISC_R_NOMEMORY
);
1584 result
= isc_file_mktemplate(file
, tempname
, tempnamelen
);
1585 if (result
!= ISC_R_SUCCESS
)
1588 result
= isc_file_openunique(tempname
, &f
);
1589 if (result
!= ISC_R_SUCCESS
) {
1590 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
1591 DNS_LOGMODULE_MASTERDUMP
, ISC_LOG_ERROR
,
1592 "dumping master file: %s: open: %s",
1593 tempname
, isc_result_totext(result
));
1598 return (ISC_R_SUCCESS
);
1601 isc_mem_free(mctx
, tempname
);
1606 dns_master_dumpinc(isc_mem_t
*mctx
, dns_db_t
*db
, dns_dbversion_t
*version
,
1607 const dns_master_style_t
*style
, const char *filename
,
1608 isc_task_t
*task
, dns_dumpdonefunc_t done
, void *done_arg
,
1609 dns_dumpctx_t
**dctxp
)
1611 return (dns_master_dumpinc2(mctx
, db
, version
, style
, filename
, task
,
1612 done
, done_arg
, dctxp
,
1613 dns_masterformat_text
));
1617 dns_master_dumpinc2(isc_mem_t
*mctx
, dns_db_t
*db
, dns_dbversion_t
*version
,
1618 const dns_master_style_t
*style
, const char *filename
,
1619 isc_task_t
*task
, dns_dumpdonefunc_t done
, void *done_arg
,
1620 dns_dumpctx_t
**dctxp
, dns_masterformat_t format
)
1623 isc_result_t result
;
1624 char *tempname
= NULL
;
1626 dns_dumpctx_t
*dctx
= NULL
;
1628 file
= isc_mem_strdup(mctx
, filename
);
1630 return (ISC_R_NOMEMORY
);
1632 result
= opentmp(mctx
, filename
, &tempname
, &f
);
1633 if (result
!= ISC_R_SUCCESS
)
1636 result
= dumpctx_create(mctx
, db
, version
, style
, f
, &dctx
, format
);
1637 if (result
!= ISC_R_SUCCESS
) {
1638 (void)isc_stdio_close(f
);
1639 (void)isc_file_remove(tempname
);
1643 isc_task_attach(task
, &dctx
->task
);
1645 dctx
->done_arg
= done_arg
;
1649 dctx
->tmpfile
= tempname
;
1652 result
= task_send(dctx
);
1653 if (result
== ISC_R_SUCCESS
) {
1654 dns_dumpctx_attach(dctx
, dctxp
);
1655 return (DNS_R_CONTINUE
);
1660 dns_dumpctx_detach(&dctx
);
1662 isc_mem_free(mctx
, file
);
1663 if (tempname
!= NULL
)
1664 isc_mem_free(mctx
, tempname
);
1669 dns_master_dump(isc_mem_t
*mctx
, dns_db_t
*db
, dns_dbversion_t
*version
,
1670 const dns_master_style_t
*style
, const char *filename
)
1672 return (dns_master_dump2(mctx
, db
, version
, style
, filename
,
1673 dns_masterformat_text
));
1677 dns_master_dump2(isc_mem_t
*mctx
, dns_db_t
*db
, dns_dbversion_t
*version
,
1678 const dns_master_style_t
*style
, const char *filename
,
1679 dns_masterformat_t format
)
1682 isc_result_t result
;
1684 dns_dumpctx_t
*dctx
= NULL
;
1686 result
= opentmp(mctx
, filename
, &tempname
, &f
);
1687 if (result
!= ISC_R_SUCCESS
)
1690 result
= dumpctx_create(mctx
, db
, version
, style
, f
, &dctx
, format
);
1691 if (result
!= ISC_R_SUCCESS
)
1694 result
= dumptostreaminc(dctx
);
1695 INSIST(result
!= DNS_R_CONTINUE
);
1696 dns_dumpctx_detach(&dctx
);
1698 result
= closeandrename(f
, result
, tempname
, filename
);
1701 isc_mem_free(mctx
, tempname
);
1706 * Dump a database node into a master file.
1707 * XXX: this function assumes the text format.
1710 dns_master_dumpnodetostream(isc_mem_t
*mctx
, dns_db_t
*db
,
1711 dns_dbversion_t
*version
,
1712 dns_dbnode_t
*node
, dns_name_t
*name
,
1713 const dns_master_style_t
*style
,
1716 isc_result_t result
;
1717 isc_buffer_t buffer
;
1720 dns_totext_ctx_t ctx
;
1721 dns_rdatasetiter_t
*rdsiter
= NULL
;
1723 result
= totext_ctx_init(style
, &ctx
);
1724 if (result
!= ISC_R_SUCCESS
) {
1725 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1726 "could not set master file style");
1727 return (ISC_R_UNEXPECTED
);
1730 isc_stdtime_get(&now
);
1732 bufmem
= isc_mem_get(mctx
, initial_buffer_length
);
1734 return (ISC_R_NOMEMORY
);
1736 isc_buffer_init(&buffer
, bufmem
, initial_buffer_length
);
1738 result
= dns_db_allrdatasets(db
, node
, version
, now
, &rdsiter
);
1739 if (result
!= ISC_R_SUCCESS
)
1741 result
= dump_rdatasets_text(mctx
, name
, rdsiter
, &ctx
, &buffer
, f
);
1742 if (result
!= ISC_R_SUCCESS
)
1744 dns_rdatasetiter_destroy(&rdsiter
);
1746 result
= ISC_R_SUCCESS
;
1749 isc_mem_put(mctx
, buffer
.base
, buffer
.length
);
1754 dns_master_dumpnode(isc_mem_t
*mctx
, dns_db_t
*db
, dns_dbversion_t
*version
,
1755 dns_dbnode_t
*node
, dns_name_t
*name
,
1756 const dns_master_style_t
*style
, const char *filename
)
1759 isc_result_t result
;
1761 result
= isc_stdio_open(filename
, "w", &f
);
1762 if (result
!= ISC_R_SUCCESS
) {
1763 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
1764 DNS_LOGMODULE_MASTERDUMP
, ISC_LOG_ERROR
,
1765 "dumping node to file: %s: open: %s", filename
,
1766 isc_result_totext(result
));
1767 return (ISC_R_UNEXPECTED
);
1770 result
= dns_master_dumpnodetostream(mctx
, db
, version
, node
, name
,
1773 result
= isc_stdio_close(f
);
1774 if (result
!= ISC_R_SUCCESS
) {
1775 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
1776 DNS_LOGMODULE_MASTERDUMP
, ISC_LOG_ERROR
,
1777 "dumping master file: %s: close: %s", filename
,
1778 isc_result_totext(result
));
1779 return (ISC_R_UNEXPECTED
);
1787 dns_master_stylecreate(dns_master_style_t
**stylep
, unsigned int flags
,
1788 unsigned int ttl_column
, unsigned int class_column
,
1789 unsigned int type_column
, unsigned int rdata_column
,
1790 unsigned int line_length
, unsigned int tab_width
,
1793 dns_master_style_t
*style
;
1795 REQUIRE(stylep
!= NULL
&& *stylep
== NULL
);
1796 style
= isc_mem_get(mctx
, sizeof(*style
));
1798 return (ISC_R_NOMEMORY
);
1800 style
->flags
= flags
;
1801 style
->ttl_column
= ttl_column
;
1802 style
->class_column
= class_column
;
1803 style
->type_column
= type_column
;
1804 style
->rdata_column
= rdata_column
;
1805 style
->line_length
= line_length
;
1806 style
->tab_width
= tab_width
;
1809 return (ISC_R_SUCCESS
);
1813 dns_master_styledestroy(dns_master_style_t
**stylep
, isc_mem_t
*mctx
) {
1814 dns_master_style_t
*style
;
1816 REQUIRE(stylep
!= NULL
&& *stylep
!= NULL
);
1819 isc_mem_put(mctx
, style
, sizeof(*style
));