2 * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-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.5.2.15 2006/03/10 00:17:21 marka Exp $ */
24 #include <isc/event.h>
26 #include <isc/magic.h>
28 #include <isc/print.h>
29 #include <isc/stdio.h>
30 #include <isc/string.h>
35 #include <dns/dbiterator.h>
36 #include <dns/events.h>
37 #include <dns/fixedname.h>
39 #include <dns/masterdump.h>
40 #include <dns/rdata.h>
41 #include <dns/rdataclass.h>
42 #include <dns/rdataset.h>
43 #include <dns/rdatasetiter.h>
44 #include <dns/rdatatype.h>
45 #include <dns/result.h>
49 #define DNS_DCTX_MAGIC ISC_MAGIC('D', 'c', 't', 'x')
50 #define DNS_DCTX_VALID(d) ISC_MAGIC_VALID(d, DNS_DCTX_MAGIC)
52 #define RETERR(x) do { \
53 isc_result_t _r = (x); \
54 if (_r != ISC_R_SUCCESS) \
58 struct dns_master_style
{
59 unsigned int flags
; /* DNS_STYLEFLAG_* */
60 unsigned int ttl_column
;
61 unsigned int class_column
;
62 unsigned int type_column
;
63 unsigned int rdata_column
;
64 unsigned int line_length
;
65 unsigned int tab_width
;
69 * The maximum length of the newline+indentation that is output
70 * when inserting a line break in an RR. This effectively puts an
71 * upper limits on the value of "rdata_column", because if it is
72 * very large, the tabs and spaces needed to reach it will not fit.
74 #define DNS_TOTEXT_LINEBREAK_MAXLEN 100
77 * Context structure for a masterfile dump in progress.
79 typedef struct dns_totext_ctx
{
80 dns_master_style_t style
;
81 isc_boolean_t class_printed
;
83 char linebreak_buf
[DNS_TOTEXT_LINEBREAK_MAXLEN
];
85 dns_name_t
* neworigin
;
86 dns_fixedname_t origin_fixname
;
87 isc_uint32_t current_ttl
;
88 isc_boolean_t current_ttl_valid
;
91 LIBDNS_EXTERNAL_DATA
const dns_master_style_t
92 dns_master_style_default
= {
93 DNS_STYLEFLAG_OMIT_OWNER
|
94 DNS_STYLEFLAG_OMIT_CLASS
|
95 DNS_STYLEFLAG_REL_OWNER
|
96 DNS_STYLEFLAG_REL_DATA
|
97 DNS_STYLEFLAG_OMIT_TTL
|
99 DNS_STYLEFLAG_COMMENT
|
100 DNS_STYLEFLAG_MULTILINE
,
101 24, 24, 24, 32, 80, 8
104 LIBDNS_EXTERNAL_DATA
const dns_master_style_t
105 dns_master_style_full
= {
106 DNS_STYLEFLAG_COMMENT
,
107 46, 46, 46, 64, 120, 8
110 LIBDNS_EXTERNAL_DATA
const dns_master_style_t
111 dns_master_style_explicitttl
= {
112 DNS_STYLEFLAG_OMIT_OWNER
|
113 DNS_STYLEFLAG_OMIT_CLASS
|
114 DNS_STYLEFLAG_REL_OWNER
|
115 DNS_STYLEFLAG_REL_DATA
|
116 DNS_STYLEFLAG_COMMENT
|
117 DNS_STYLEFLAG_MULTILINE
,
118 24, 32, 32, 40, 80, 8
121 LIBDNS_EXTERNAL_DATA
const dns_master_style_t
122 dns_master_style_cache
= {
123 DNS_STYLEFLAG_OMIT_OWNER
|
124 DNS_STYLEFLAG_OMIT_CLASS
|
125 DNS_STYLEFLAG_MULTILINE
|
126 DNS_STYLEFLAG_TRUST
|
127 DNS_STYLEFLAG_NCACHE
,
128 24, 32, 32, 40, 80, 8
131 LIBDNS_EXTERNAL_DATA
const dns_master_style_t
132 dns_master_style_simple
= {
134 24, 32, 32, 40, 80, 8
138 * A style suitable for dns_rdataset_totext().
140 LIBDNS_EXTERNAL_DATA
const dns_master_style_t
141 dns_master_style_debug
= {
142 DNS_STYLEFLAG_REL_OWNER
,
143 24, 32, 40, 48, 80, 8
148 static char spaces
[N_SPACES
+1] = " ";
151 static char tabs
[N_TABS
+1] = "\t\t\t\t\t\t\t\t\t\t";
157 unsigned int references
;
158 isc_boolean_t canceled
;
160 isc_boolean_t do_date
;
164 dns_dbversion_t
*version
;
165 dns_dbiterator_t
*dbiter
;
166 dns_totext_ctx_t tctx
;
168 dns_dumpdonefunc_t done
;
171 /* dns_master_dumpinc() */
176 #define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
179 * Output tabs and spaces to go from column '*current' to
180 * column 'to', and update '*current' to reflect the new
184 indent(unsigned int *current
, unsigned int to
, int tabwidth
,
185 isc_buffer_t
*target
)
190 int ntabs
, nspaces
, t
;
197 ntabs
= to
/ tabwidth
- from
/ tabwidth
;
202 isc_buffer_availableregion(target
, &r
);
203 if (r
.length
< (unsigned) ntabs
)
204 return (ISC_R_NOSPACE
);
216 isc_buffer_add(target
, ntabs
);
217 from
= (to
/ tabwidth
) * tabwidth
;
221 INSIST(nspaces
>= 0);
223 isc_buffer_availableregion(target
, &r
);
224 if (r
.length
< (unsigned) nspaces
)
225 return (ISC_R_NOSPACE
);
233 memcpy(p
, spaces
, n
);
237 isc_buffer_add(target
, nspaces
);
240 return (ISC_R_SUCCESS
);
244 totext_ctx_init(const dns_master_style_t
*style
, dns_totext_ctx_t
*ctx
) {
247 REQUIRE(style
->tab_width
!= 0);
250 ctx
->class_printed
= ISC_FALSE
;
252 dns_fixedname_init(&ctx
->origin_fixname
);
255 * Set up the line break string if needed.
257 if ((ctx
->style
.flags
& DNS_STYLEFLAG_MULTILINE
) != 0) {
260 unsigned int col
= 0;
262 isc_buffer_init(&buf
, ctx
->linebreak_buf
,
263 sizeof(ctx
->linebreak_buf
));
265 isc_buffer_availableregion(&buf
, &r
);
267 return (DNS_R_TEXTTOOLONG
);
269 isc_buffer_add(&buf
, 1);
271 result
= indent(&col
, ctx
->style
.rdata_column
,
272 ctx
->style
.tab_width
, &buf
);
274 * Do not return ISC_R_NOSPACE if the line break string
275 * buffer is too small, because that would just make
276 * dump_rdataset() retry indenfinitely with ever
277 * bigger target buffers. That's a different buffer,
278 * so it won't help. Use DNS_R_TEXTTOOLONG as a substitute.
280 if (result
== ISC_R_NOSPACE
)
281 return (DNS_R_TEXTTOOLONG
);
282 if (result
!= ISC_R_SUCCESS
)
285 isc_buffer_availableregion(&buf
, &r
);
287 return (DNS_R_TEXTTOOLONG
);
289 isc_buffer_add(&buf
, 1);
290 ctx
->linebreak
= ctx
->linebreak_buf
;
292 ctx
->linebreak
= NULL
;
296 ctx
->neworigin
= NULL
;
297 ctx
->current_ttl
= 0;
298 ctx
->current_ttl_valid
= ISC_FALSE
;
300 return (ISC_R_SUCCESS
);
303 #define INDENT_TO(col) \
305 if ((result = indent(&column, ctx->style.col, \
306 ctx->style.tab_width, target)) \
313 str_totext(const char *source
, isc_buffer_t
*target
) {
317 isc_buffer_availableregion(target
, ®ion
);
320 if (l
> region
.length
)
321 return (ISC_R_NOSPACE
);
323 memcpy(region
.base
, source
, l
);
324 isc_buffer_add(target
, l
);
325 return (ISC_R_SUCCESS
);
329 * Convert 'rdataset' to master file text format according to 'ctx',
330 * storing the result in 'target'. If 'owner_name' is NULL, it
331 * is omitted; otherwise 'owner_name' must be valid and have at least
336 rdataset_totext(dns_rdataset_t
*rdataset
,
337 dns_name_t
*owner_name
,
338 dns_totext_ctx_t
*ctx
,
339 isc_boolean_t omit_final_dot
,
340 isc_buffer_t
*target
)
344 isc_boolean_t first
= ISC_TRUE
;
345 isc_uint32_t current_ttl
;
346 isc_boolean_t current_ttl_valid
;
347 dns_rdatatype_t type
;
349 REQUIRE(DNS_RDATASET_VALID(rdataset
));
351 result
= dns_rdataset_first(rdataset
);
352 REQUIRE(result
== ISC_R_SUCCESS
);
354 current_ttl
= ctx
->current_ttl
;
355 current_ttl_valid
= ctx
->current_ttl_valid
;
363 if (owner_name
!= NULL
&&
364 ! ((ctx
->style
.flags
& DNS_STYLEFLAG_OMIT_OWNER
) != 0 &&
367 unsigned int name_start
= target
->used
;
368 RETERR(dns_name_totext(owner_name
,
371 column
+= target
->used
- name_start
;
377 if ((ctx
->style
.flags
& DNS_STYLEFLAG_NO_TTL
) == 0 &&
378 !((ctx
->style
.flags
& DNS_STYLEFLAG_OMIT_TTL
) != 0 &&
380 rdataset
->ttl
== current_ttl
))
386 INDENT_TO(ttl_column
);
387 length
= snprintf(ttlbuf
, sizeof(ttlbuf
), "%u",
389 INSIST(length
<= sizeof(ttlbuf
));
390 isc_buffer_availableregion(target
, &r
);
391 if (r
.length
< length
)
392 return (ISC_R_NOSPACE
);
393 memcpy(r
.base
, ttlbuf
, length
);
394 isc_buffer_add(target
, length
);
398 * If the $TTL directive is not in use, the TTL we
399 * just printed becomes the default for subsequent RRs.
401 if ((ctx
->style
.flags
& DNS_STYLEFLAG_TTL
) == 0) {
402 current_ttl
= rdataset
->ttl
;
403 current_ttl_valid
= ISC_TRUE
;
410 if ((ctx
->style
.flags
& DNS_STYLEFLAG_NO_CLASS
) == 0 &&
411 ((ctx
->style
.flags
& DNS_STYLEFLAG_OMIT_CLASS
) == 0 ||
412 ctx
->class_printed
== ISC_FALSE
))
414 unsigned int class_start
;
415 INDENT_TO(class_column
);
416 class_start
= target
->used
;
417 result
= dns_rdataclass_totext(rdataset
->rdclass
,
419 if (result
!= ISC_R_SUCCESS
)
421 column
+= (target
->used
- class_start
);
428 if (rdataset
->type
== 0) {
429 type
= rdataset
->covers
;
431 type
= rdataset
->type
;
435 unsigned int type_start
;
436 INDENT_TO(type_column
);
437 type_start
= target
->used
;
438 if (rdataset
->type
== 0)
439 RETERR(str_totext("\\-", target
));
440 result
= dns_rdatatype_totext(type
, target
);
441 if (result
!= ISC_R_SUCCESS
)
443 column
+= (target
->used
- type_start
);
449 INDENT_TO(rdata_column
);
450 if (rdataset
->type
== 0) {
451 if (NXDOMAIN(rdataset
))
452 RETERR(str_totext(";-$NXDOMAIN\n", target
));
454 RETERR(str_totext(";-$NXRRSET\n", target
));
456 dns_rdata_t rdata
= DNS_RDATA_INIT
;
459 dns_rdataset_current(rdataset
, &rdata
);
461 RETERR(dns_rdata_tofmttext(&rdata
,
464 ctx
->style
.line_length
-
465 ctx
->style
.rdata_column
,
469 isc_buffer_availableregion(target
, &r
);
471 return (ISC_R_NOSPACE
);
473 isc_buffer_add(target
, 1);
477 result
= dns_rdataset_next(rdataset
);
478 } while (result
== ISC_R_SUCCESS
);
480 if (result
!= ISC_R_NOMORE
)
484 * Update the ctx state to reflect what we just printed.
485 * This is done last, only when we are sure we will return
486 * success, because this function may be called multiple
487 * times with increasing buffer sizes until it succeeds,
488 * and failed attempts must not update the state prematurely.
490 ctx
->class_printed
= ISC_TRUE
;
491 ctx
->current_ttl
= current_ttl
;
492 ctx
->current_ttl_valid
= current_ttl_valid
;
494 return (ISC_R_SUCCESS
);
498 * Print the name, type, and class of an empty rdataset,
499 * such as those used to represent the question section
503 question_totext(dns_rdataset_t
*rdataset
,
504 dns_name_t
*owner_name
,
505 dns_totext_ctx_t
*ctx
,
506 isc_boolean_t omit_final_dot
,
507 isc_buffer_t
*target
)
513 REQUIRE(DNS_RDATASET_VALID(rdataset
));
514 result
= dns_rdataset_first(rdataset
);
515 REQUIRE(result
== ISC_R_NOMORE
);
521 unsigned int name_start
= target
->used
;
522 RETERR(dns_name_totext(owner_name
,
525 column
+= target
->used
- name_start
;
530 unsigned int class_start
;
531 INDENT_TO(class_column
);
532 class_start
= target
->used
;
533 result
= dns_rdataclass_totext(rdataset
->rdclass
, target
);
534 if (result
!= ISC_R_SUCCESS
)
536 column
+= (target
->used
- class_start
);
541 unsigned int type_start
;
542 INDENT_TO(type_column
);
543 type_start
= target
->used
;
544 result
= dns_rdatatype_totext(rdataset
->type
, target
);
545 if (result
!= ISC_R_SUCCESS
)
547 column
+= (target
->used
- type_start
);
550 isc_buffer_availableregion(target
, &r
);
552 return (ISC_R_NOSPACE
);
554 isc_buffer_add(target
, 1);
556 return (ISC_R_SUCCESS
);
560 dns_rdataset_totext(dns_rdataset_t
*rdataset
,
561 dns_name_t
*owner_name
,
562 isc_boolean_t omit_final_dot
,
563 isc_boolean_t question
,
564 isc_buffer_t
*target
)
566 dns_totext_ctx_t ctx
;
568 result
= totext_ctx_init(&dns_master_style_debug
, &ctx
);
569 if (result
!= ISC_R_SUCCESS
) {
570 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
571 "could not set master file style");
572 return (ISC_R_UNEXPECTED
);
576 * The caller might want to give us an empty owner
577 * name (e.g. if they are outputting into a master
578 * file and this rdataset has the same name as the
581 if (dns_name_countlabels(owner_name
) == 0)
585 return (question_totext(rdataset
, owner_name
, &ctx
,
586 omit_final_dot
, target
));
588 return (rdataset_totext(rdataset
, owner_name
, &ctx
,
589 omit_final_dot
, target
));
593 dns_master_rdatasettotext(dns_name_t
*owner_name
,
594 dns_rdataset_t
*rdataset
,
595 const dns_master_style_t
*style
,
596 isc_buffer_t
*target
)
598 dns_totext_ctx_t ctx
;
600 result
= totext_ctx_init(style
, &ctx
);
601 if (result
!= ISC_R_SUCCESS
) {
602 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
603 "could not set master file style");
604 return (ISC_R_UNEXPECTED
);
607 return (rdataset_totext(rdataset
, owner_name
, &ctx
,
612 dns_master_questiontotext(dns_name_t
*owner_name
,
613 dns_rdataset_t
*rdataset
,
614 const dns_master_style_t
*style
,
615 isc_buffer_t
*target
)
617 dns_totext_ctx_t ctx
;
619 result
= totext_ctx_init(style
, &ctx
);
620 if (result
!= ISC_R_SUCCESS
) {
621 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
622 "could not set master file style");
623 return (ISC_R_UNEXPECTED
);
626 return (question_totext(rdataset
, owner_name
, &ctx
,
631 * Print an rdataset. 'buffer' is a scratch buffer, which must have been
632 * dynamically allocated by the caller. It must be large enough to
633 * hold the result from dns_ttl_totext(). If more than that is needed,
634 * the buffer will be grown automatically.
638 dump_rdataset(isc_mem_t
*mctx
, dns_name_t
*name
, dns_rdataset_t
*rdataset
,
639 dns_totext_ctx_t
*ctx
,
640 isc_buffer_t
*buffer
, FILE *f
)
645 REQUIRE(buffer
->length
> 0);
648 * Output a $TTL directive if needed.
651 if ((ctx
->style
.flags
& DNS_STYLEFLAG_TTL
) != 0) {
652 if (ctx
->current_ttl_valid
== ISC_FALSE
||
653 ctx
->current_ttl
!= rdataset
->ttl
)
655 if ((ctx
->style
.flags
& DNS_STYLEFLAG_COMMENT
) != 0)
657 isc_buffer_clear(buffer
);
658 result
= dns_ttl_totext(rdataset
->ttl
,
660 INSIST(result
== ISC_R_SUCCESS
);
661 isc_buffer_usedregion(buffer
, &r
);
662 fprintf(f
, "$TTL %u\t; %.*s\n", rdataset
->ttl
,
663 (int) r
.length
, (char *) r
.base
);
665 fprintf(f
, "$TTL %u\n", rdataset
->ttl
);
667 ctx
->current_ttl
= rdataset
->ttl
;
668 ctx
->current_ttl_valid
= ISC_TRUE
;
672 isc_buffer_clear(buffer
);
675 * Generate the text representation of the rdataset into
676 * the buffer. If the buffer is too small, grow it.
681 result
= rdataset_totext(rdataset
, name
, ctx
,
683 if (result
!= ISC_R_NOSPACE
)
686 newlength
= buffer
->length
* 2;
687 newmem
= isc_mem_get(mctx
, newlength
);
689 return (ISC_R_NOMEMORY
);
690 isc_mem_put(mctx
, buffer
->base
, buffer
->length
);
691 isc_buffer_init(buffer
, newmem
, newlength
);
693 if (result
!= ISC_R_SUCCESS
)
697 * Write the buffer contents to the master file.
699 isc_buffer_usedregion(buffer
, &r
);
700 result
= isc_stdio_write(r
.base
, 1, (size_t)r
.length
, f
, NULL
);
702 if (result
!= ISC_R_SUCCESS
) {
703 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
704 "master file write failed: %s",
705 isc_result_totext(result
));
709 return (ISC_R_SUCCESS
);
713 * Define the order in which rdatasets should be printed in zone
714 * files. We will print SOA and NS records before others, SIGs
715 * immediately following the things they sign, and order everything
716 * else by RR number. This is all just for aesthetics and
717 * compatibility with buggy software that expects the SOA to be first;
718 * the DNS specifications allow any order.
722 dump_order(const dns_rdataset_t
*rds
) {
725 if (rds
->type
== dns_rdatatype_rrsig
) {
733 case dns_rdatatype_soa
:
736 case dns_rdatatype_ns
:
743 return (t
<< 1) + sig
;
747 dump_order_compare(const void *a
, const void *b
) {
748 return (dump_order(*((const dns_rdataset_t
* const *) a
)) -
749 dump_order(*((const dns_rdataset_t
* const *) b
)));
753 * Dump all the rdatasets of a domain name to a master file. We make
754 * a "best effort" attempt to sort the RRsets in a nice order, but if
755 * there are more than MAXSORT RRsets, we punt and only sort them in
756 * groups of MAXSORT. This is not expected to ever happen in practice
757 * since much less than 64 RR types have been registered with the
758 * IANA, so far, and the output will be correct (though not
759 * aesthetically pleasing) even if it does happen.
764 static const char *trustnames
[] = {
773 "local" /* aka ultimate */
777 dump_rdatasets(isc_mem_t
*mctx
, dns_name_t
*name
, dns_rdatasetiter_t
*rdsiter
,
778 dns_totext_ctx_t
*ctx
,
779 isc_buffer_t
*buffer
, FILE *f
)
781 isc_result_t itresult
, dumpresult
;
783 dns_rdataset_t rdatasets
[MAXSORT
];
784 dns_rdataset_t
*sorted
[MAXSORT
];
787 itresult
= dns_rdatasetiter_first(rdsiter
);
788 dumpresult
= ISC_R_SUCCESS
;
790 if (itresult
== ISC_R_SUCCESS
&& ctx
->neworigin
!= NULL
) {
791 isc_buffer_clear(buffer
);
792 itresult
= dns_name_totext(ctx
->neworigin
, ISC_FALSE
, buffer
);
793 RUNTIME_CHECK(itresult
== ISC_R_SUCCESS
);
794 isc_buffer_usedregion(buffer
, &r
);
795 fprintf(f
, "$ORIGIN %.*s\n", (int) r
.length
, (char *) r
.base
);
796 ctx
->neworigin
= NULL
;
801 itresult
== ISC_R_SUCCESS
&& i
< MAXSORT
;
802 itresult
= dns_rdatasetiter_next(rdsiter
), i
++) {
803 dns_rdataset_init(&rdatasets
[i
]);
804 dns_rdatasetiter_current(rdsiter
, &rdatasets
[i
]);
805 sorted
[i
] = &rdatasets
[i
];
808 INSIST(n
<= MAXSORT
);
810 qsort(sorted
, n
, sizeof(sorted
[0]), dump_order_compare
);
812 for (i
= 0; i
< n
; i
++) {
813 dns_rdataset_t
*rds
= sorted
[i
];
814 if (ctx
->style
.flags
& DNS_STYLEFLAG_TRUST
) {
815 unsigned int trust
= rds
->trust
;
816 INSIST(trust
< (sizeof(trustnames
) /
817 sizeof(trustnames
[0])));
818 fprintf(f
, "; %s\n", trustnames
[trust
]);
820 if (rds
->type
== 0 &&
821 (ctx
->style
.flags
& DNS_STYLEFLAG_NCACHE
) == 0) {
822 /* Omit negative cache entries */
824 isc_result_t result
=
825 dump_rdataset(mctx
, name
, rds
, ctx
,
827 if (result
!= ISC_R_SUCCESS
)
829 if ((ctx
->style
.flags
& DNS_STYLEFLAG_OMIT_OWNER
) != 0)
832 dns_rdataset_disassociate(rds
);
835 if (dumpresult
!= ISC_R_SUCCESS
)
839 * If we got more data than could be sorted at once,
840 * go handle the rest.
842 if (itresult
== ISC_R_SUCCESS
)
845 if (itresult
== ISC_R_NOMORE
)
846 itresult
= ISC_R_SUCCESS
;
853 * Initial size of text conversion buffer. The buffer is used
854 * for several purposes: converting origin names, rdatasets,
855 * $DATE timestamps, and comment strings for $TTL directives.
857 * When converting rdatasets, it is dynamically resized, but
858 * when converting origins, timestamps, etc it is not. Therefore,
859 * the initial size must large enough to hold the longest possible
860 * text representation of any domain name (for $ORIGIN).
862 static const int initial_buffer_length
= 1200;
865 dumptostreaminc(dns_dumpctx_t
*dctx
);
868 dumpctx_destroy(dns_dumpctx_t
*dctx
) {
871 DESTROYLOCK(&dctx
->lock
);
872 if (dctx
->version
!= NULL
)
873 dns_db_closeversion(dctx
->db
, &dctx
->version
, ISC_FALSE
);
874 dns_dbiterator_destroy(&dctx
->dbiter
);
875 dns_db_detach(&dctx
->db
);
876 if (dctx
->task
!= NULL
)
877 isc_task_detach(&dctx
->task
);
878 if (dctx
->file
!= NULL
)
879 isc_mem_free(dctx
->mctx
, dctx
->file
);
880 if (dctx
->tmpfile
!= NULL
)
881 isc_mem_free(dctx
->mctx
, dctx
->tmpfile
);
882 isc_mem_putanddetach(&dctx
->mctx
, dctx
, sizeof(*dctx
));
886 dns_dumpctx_attach(dns_dumpctx_t
*source
, dns_dumpctx_t
**target
) {
888 REQUIRE(DNS_DCTX_VALID(source
));
889 REQUIRE(target
!= NULL
&& *target
== NULL
);
892 INSIST(source
->references
> 0);
893 source
->references
++;
894 INSIST(source
->references
!= 0); /* Overflow? */
895 UNLOCK(&source
->lock
);
901 dns_dumpctx_detach(dns_dumpctx_t
**dctxp
) {
903 isc_boolean_t need_destroy
= ISC_FALSE
;
905 REQUIRE(dctxp
!= NULL
);
907 REQUIRE(DNS_DCTX_VALID(dctx
));
912 INSIST(dctx
->references
!= 0);
914 if (dctx
->references
== 0)
915 need_destroy
= ISC_TRUE
;
918 dumpctx_destroy(dctx
);
922 dns_dumpctx_version(dns_dumpctx_t
*dctx
) {
923 REQUIRE(DNS_DCTX_VALID(dctx
));
924 return (dctx
->version
);
928 dns_dumpctx_db(dns_dumpctx_t
*dctx
) {
929 REQUIRE(DNS_DCTX_VALID(dctx
));
934 dns_dumpctx_cancel(dns_dumpctx_t
*dctx
) {
935 REQUIRE(DNS_DCTX_VALID(dctx
));
938 dctx
->canceled
= ISC_TRUE
;
943 closeandrename(FILE *f
, isc_result_t result
, const char *temp
, const char *file
)
945 isc_result_t tresult
;
946 isc_boolean_t logit
= ISC_TF(result
== ISC_R_SUCCESS
);
948 if (result
== ISC_R_SUCCESS
)
949 result
= isc_stdio_sync(f
);
950 if (result
!= ISC_R_SUCCESS
&& logit
) {
951 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
952 DNS_LOGMODULE_MASTERDUMP
, ISC_LOG_ERROR
,
953 "dumping master file: %s: fsync: %s",
954 temp
, isc_result_totext(result
));
957 tresult
= isc_stdio_close(f
);
958 if (result
== ISC_R_SUCCESS
)
960 if (result
!= ISC_R_SUCCESS
&& logit
) {
961 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
962 DNS_LOGMODULE_MASTERDUMP
, ISC_LOG_ERROR
,
963 "dumping master file: %s: fclose: %s",
964 temp
, isc_result_totext(result
));
967 if (result
== ISC_R_SUCCESS
)
968 result
= isc_file_rename(temp
, file
);
970 (void)isc_file_remove(temp
);
971 if (result
!= ISC_R_SUCCESS
&& logit
) {
972 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
973 DNS_LOGMODULE_MASTERDUMP
, ISC_LOG_ERROR
,
974 "dumping master file: rename: %s: %s",
975 file
, isc_result_totext(result
));
981 dump_quantum(isc_task_t
*task
, isc_event_t
*event
) {
983 isc_result_t tresult
;
986 REQUIRE(event
!= NULL
);
987 dctx
= event
->ev_arg
;
988 REQUIRE(DNS_DCTX_VALID(dctx
));
990 result
= ISC_R_CANCELED
;
992 result
= dumptostreaminc(dctx
);
993 if (result
== DNS_R_CONTINUE
) {
994 event
->ev_arg
= dctx
;
995 isc_task_send(task
, &event
);
999 if (dctx
->file
!= NULL
) {
1000 tresult
= closeandrename(dctx
->f
, result
,
1001 dctx
->tmpfile
, dctx
->file
);
1002 if (tresult
!= ISC_R_SUCCESS
&& result
== ISC_R_SUCCESS
)
1005 (dctx
->done
)(dctx
->done_arg
, result
);
1006 isc_event_free(&event
);
1007 dns_dumpctx_detach(&dctx
);
1011 task_send(dns_dumpctx_t
*dctx
) {
1014 event
= isc_event_allocate(dctx
->mctx
, NULL
, DNS_EVENT_DUMPQUANTUM
,
1015 dump_quantum
, dctx
, sizeof(*event
));
1017 return (ISC_R_NOMEMORY
);
1018 isc_task_send(dctx
->task
, &event
);
1019 return (ISC_R_SUCCESS
);
1023 dumpctx_create(isc_mem_t
*mctx
, dns_db_t
*db
, dns_dbversion_t
*version
,
1024 const dns_master_style_t
*style
, FILE *f
, dns_dumpctx_t
**dctxp
)
1026 dns_dumpctx_t
*dctx
;
1027 isc_result_t result
;
1028 isc_boolean_t relative
;
1030 dctx
= isc_mem_get(mctx
, sizeof(*dctx
));
1032 return (ISC_R_NOMEMORY
);
1036 dctx
->dbiter
= NULL
;
1038 dctx
->version
= NULL
;
1040 dctx
->done_arg
= NULL
;
1043 dctx
->first
= ISC_TRUE
;
1044 dctx
->canceled
= ISC_FALSE
;
1046 dctx
->tmpfile
= NULL
;
1048 result
= totext_ctx_init(style
, &dctx
->tctx
);
1049 if (result
!= ISC_R_SUCCESS
) {
1050 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1051 "could not set master file style");
1055 isc_stdtime_get(&dctx
->now
);
1056 dns_db_attach(db
, &dctx
->db
);
1058 dctx
->do_date
= dns_db_iscache(dctx
->db
);
1060 relative
= ((dctx
->tctx
.style
.flags
& DNS_STYLEFLAG_REL_OWNER
) != 0) ?
1061 ISC_TRUE
: ISC_FALSE
;
1062 result
= dns_db_createiterator(dctx
->db
, relative
, &dctx
->dbiter
);
1063 if (result
!= ISC_R_SUCCESS
)
1066 result
= isc_mutex_init(&dctx
->lock
);
1067 if (result
!= ISC_R_SUCCESS
)
1069 if (version
!= NULL
)
1070 dns_db_attachversion(dctx
->db
, version
, &dctx
->version
);
1071 else if (!dns_db_iscache(db
))
1072 dns_db_currentversion(dctx
->db
, &dctx
->version
);
1073 isc_mem_attach(mctx
, &dctx
->mctx
);
1074 dctx
->references
= 1;
1075 dctx
->magic
= DNS_DCTX_MAGIC
;
1077 return (ISC_R_SUCCESS
);
1080 if (dctx
->dbiter
!= NULL
)
1081 dns_dbiterator_destroy(&dctx
->dbiter
);
1082 if (dctx
->db
!= NULL
)
1083 dns_db_detach(&dctx
->db
);
1085 isc_mem_put(mctx
, dctx
, sizeof(*dctx
));
1090 dumptostreaminc(dns_dumpctx_t
*dctx
) {
1091 isc_result_t result
;
1092 isc_buffer_t buffer
;
1096 dns_fixedname_t fixname
;
1099 bufmem
= isc_mem_get(dctx
->mctx
, initial_buffer_length
);
1101 return (ISC_R_NOMEMORY
);
1103 isc_buffer_init(&buffer
, bufmem
, initial_buffer_length
);
1105 dns_fixedname_init(&fixname
);
1106 name
= dns_fixedname_name(&fixname
);
1110 * If the database has cache semantics, output an RFC2540
1111 * $DATE directive so that the TTLs can be adjusted when
1112 * it is reloaded. For zones it is not really needed, and
1113 * it would make the file incompatible with pre-RFC2540
1114 * software, so we omit it in the zone case.
1116 if (dctx
->do_date
) {
1117 result
= dns_time32_totext(dctx
->now
, &buffer
);
1118 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
1119 isc_buffer_usedregion(&buffer
, &r
);
1120 fprintf(dctx
->f
, "$DATE %.*s\n",
1121 (int) r
.length
, (char *) r
.base
);
1123 result
= dns_dbiterator_first(dctx
->dbiter
);
1124 dctx
->first
= ISC_FALSE
;
1126 result
= ISC_R_SUCCESS
;
1128 nodes
= dctx
->nodes
;
1129 while (result
== ISC_R_SUCCESS
&& (dctx
->nodes
== 0 || nodes
--)) {
1130 dns_rdatasetiter_t
*rdsiter
= NULL
;
1131 dns_dbnode_t
*node
= NULL
;
1133 result
= dns_dbiterator_current(dctx
->dbiter
, &node
, name
);
1134 if (result
!= ISC_R_SUCCESS
&& result
!= DNS_R_NEWORIGIN
)
1136 if (result
== DNS_R_NEWORIGIN
) {
1137 dns_name_t
*origin
=
1138 dns_fixedname_name(&dctx
->tctx
.origin_fixname
);
1139 result
= dns_dbiterator_origin(dctx
->dbiter
, origin
);
1140 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
1141 if ((dctx
->tctx
.style
.flags
& DNS_STYLEFLAG_REL_DATA
) != 0)
1142 dctx
->tctx
.origin
= origin
;
1143 dctx
->tctx
.neworigin
= origin
;
1145 result
= dns_db_allrdatasets(dctx
->db
, node
, dctx
->version
,
1146 dctx
->now
, &rdsiter
);
1147 if (result
!= ISC_R_SUCCESS
) {
1148 dns_db_detachnode(dctx
->db
, &node
);
1151 result
= dump_rdatasets(dctx
->mctx
, name
, rdsiter
, &dctx
->tctx
,
1153 dns_rdatasetiter_destroy(&rdsiter
);
1154 if (result
!= ISC_R_SUCCESS
) {
1155 dns_db_detachnode(dctx
->db
, &node
);
1158 dns_db_detachnode(dctx
->db
, &node
);
1159 result
= dns_dbiterator_next(dctx
->dbiter
);
1162 if (dctx
->nodes
!= 0 && result
== ISC_R_SUCCESS
) {
1163 result
= dns_dbiterator_pause(dctx
->dbiter
);
1164 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
1165 result
= DNS_R_CONTINUE
;
1166 } else if (result
== ISC_R_NOMORE
)
1167 result
= ISC_R_SUCCESS
;
1169 isc_mem_put(dctx
->mctx
, buffer
.base
, buffer
.length
);
1174 dns_master_dumptostreaminc(isc_mem_t
*mctx
, dns_db_t
*db
,
1175 dns_dbversion_t
*version
,
1176 const dns_master_style_t
*style
,
1177 FILE *f
, isc_task_t
*task
,
1178 dns_dumpdonefunc_t done
, void *done_arg
,
1179 dns_dumpctx_t
**dctxp
)
1181 dns_dumpctx_t
*dctx
= NULL
;
1182 isc_result_t result
;
1184 REQUIRE(task
!= NULL
);
1186 REQUIRE(done
!= NULL
);
1188 result
= dumpctx_create(mctx
, db
, version
, style
, f
, &dctx
);
1189 if (result
!= ISC_R_SUCCESS
)
1191 isc_task_attach(task
, &dctx
->task
);
1193 dctx
->done_arg
= done_arg
;
1196 result
= task_send(dctx
);
1197 if (result
== ISC_R_SUCCESS
) {
1198 dns_dumpctx_attach(dctx
, dctxp
);
1199 return (DNS_R_CONTINUE
);
1202 dns_dumpctx_detach(&dctx
);
1207 * Dump an entire database into a master file.
1210 dns_master_dumptostream(isc_mem_t
*mctx
, dns_db_t
*db
,
1211 dns_dbversion_t
*version
,
1212 const dns_master_style_t
*style
,
1215 dns_dumpctx_t
*dctx
= NULL
;
1216 isc_result_t result
;
1218 result
= dumpctx_create(mctx
, db
, version
, style
, f
, &dctx
);
1219 if (result
!= ISC_R_SUCCESS
)
1222 result
= dumptostreaminc(dctx
);
1223 INSIST(result
!= DNS_R_CONTINUE
);
1224 dns_dumpctx_detach(&dctx
);
1229 opentmp(isc_mem_t
*mctx
, const char *file
, char **tempp
, FILE **fp
) {
1231 isc_result_t result
;
1232 char *tempname
= NULL
;
1235 tempnamelen
= strlen(file
) + 20;
1236 tempname
= isc_mem_allocate(mctx
, tempnamelen
);
1237 if (tempname
== NULL
)
1238 return (ISC_R_NOMEMORY
);
1240 result
= isc_file_mktemplate(file
, tempname
, tempnamelen
);
1241 if (result
!= ISC_R_SUCCESS
)
1244 result
= isc_file_openunique(tempname
, &f
);
1245 if (result
!= ISC_R_SUCCESS
) {
1246 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
1247 DNS_LOGMODULE_MASTERDUMP
, ISC_LOG_ERROR
,
1248 "dumping master file: %s: open: %s",
1249 tempname
, isc_result_totext(result
));
1254 return (ISC_R_SUCCESS
);
1257 isc_mem_free(mctx
, tempname
);
1262 dns_master_dumpinc(isc_mem_t
*mctx
, dns_db_t
*db
, dns_dbversion_t
*version
,
1263 const dns_master_style_t
*style
, const char *filename
,
1264 isc_task_t
*task
, dns_dumpdonefunc_t done
, void *done_arg
,
1265 dns_dumpctx_t
**dctxp
)
1268 isc_result_t result
;
1269 char *tempname
= NULL
;
1271 dns_dumpctx_t
*dctx
= NULL
;
1273 file
= isc_mem_strdup(mctx
, filename
);
1275 return (ISC_R_NOMEMORY
);
1277 result
= opentmp(mctx
, filename
, &tempname
, &f
);
1278 if (result
!= ISC_R_SUCCESS
)
1281 result
= dumpctx_create(mctx
, db
, version
, style
, f
, &dctx
);
1282 if (result
!= ISC_R_SUCCESS
) {
1283 (void)isc_stdio_close(f
);
1284 (void)isc_file_remove(tempname
);
1288 isc_task_attach(task
, &dctx
->task
);
1290 dctx
->done_arg
= done_arg
;
1294 dctx
->tmpfile
= tempname
;
1297 result
= task_send(dctx
);
1298 if (result
== ISC_R_SUCCESS
) {
1299 dns_dumpctx_attach(dctx
, dctxp
);
1300 return (DNS_R_CONTINUE
);
1305 dns_dumpctx_detach(&dctx
);
1307 isc_mem_free(mctx
, file
);
1308 if (tempname
!= NULL
)
1309 isc_mem_free(mctx
, tempname
);
1314 dns_master_dump(isc_mem_t
*mctx
, dns_db_t
*db
, dns_dbversion_t
*version
,
1315 const dns_master_style_t
*style
, const char *filename
)
1318 isc_result_t result
;
1320 dns_dumpctx_t
*dctx
= NULL
;
1322 result
= opentmp(mctx
, filename
, &tempname
, &f
);
1323 if (result
!= ISC_R_SUCCESS
)
1326 result
= dumpctx_create(mctx
, db
, version
, style
, f
, &dctx
);
1327 if (result
!= ISC_R_SUCCESS
)
1330 result
= dumptostreaminc(dctx
);
1331 INSIST(result
!= DNS_R_CONTINUE
);
1332 dns_dumpctx_detach(&dctx
);
1334 result
= closeandrename(f
, result
, tempname
, filename
);
1337 isc_mem_free(mctx
, tempname
);
1342 * Dump a database node into a master file.
1345 dns_master_dumpnodetostream(isc_mem_t
*mctx
, dns_db_t
*db
,
1346 dns_dbversion_t
*version
,
1347 dns_dbnode_t
*node
, dns_name_t
*name
,
1348 const dns_master_style_t
*style
,
1351 isc_result_t result
;
1352 isc_buffer_t buffer
;
1355 dns_totext_ctx_t ctx
;
1356 dns_rdatasetiter_t
*rdsiter
= NULL
;
1358 result
= totext_ctx_init(style
, &ctx
);
1359 if (result
!= ISC_R_SUCCESS
) {
1360 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1361 "could not set master file style");
1362 return (ISC_R_UNEXPECTED
);
1365 isc_stdtime_get(&now
);
1367 bufmem
= isc_mem_get(mctx
, initial_buffer_length
);
1369 return (ISC_R_NOMEMORY
);
1371 isc_buffer_init(&buffer
, bufmem
, initial_buffer_length
);
1373 result
= dns_db_allrdatasets(db
, node
, version
, now
, &rdsiter
);
1374 if (result
!= ISC_R_SUCCESS
)
1376 result
= dump_rdatasets(mctx
, name
, rdsiter
, &ctx
, &buffer
, f
);
1377 if (result
!= ISC_R_SUCCESS
)
1379 dns_rdatasetiter_destroy(&rdsiter
);
1381 result
= ISC_R_SUCCESS
;
1384 isc_mem_put(mctx
, buffer
.base
, buffer
.length
);
1389 dns_master_dumpnode(isc_mem_t
*mctx
, dns_db_t
*db
, dns_dbversion_t
*version
,
1390 dns_dbnode_t
*node
, dns_name_t
*name
,
1391 const dns_master_style_t
*style
, const char *filename
)
1394 isc_result_t result
;
1396 result
= isc_stdio_open(filename
, "w", &f
);
1397 if (result
!= ISC_R_SUCCESS
) {
1398 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
1399 DNS_LOGMODULE_MASTERDUMP
, ISC_LOG_ERROR
,
1400 "dumping node to file: %s: open: %s", filename
,
1401 isc_result_totext(result
));
1402 return (ISC_R_UNEXPECTED
);
1405 result
= dns_master_dumpnodetostream(mctx
, db
, version
, node
, name
,
1408 result
= isc_stdio_close(f
);
1409 if (result
!= ISC_R_SUCCESS
) {
1410 isc_log_write(dns_lctx
, ISC_LOGCATEGORY_GENERAL
,
1411 DNS_LOGMODULE_MASTERDUMP
, ISC_LOG_ERROR
,
1412 "dumping master file: %s: close: %s", filename
,
1413 isc_result_totext(result
));
1414 return (ISC_R_UNEXPECTED
);
1421 dns_master_stylecreate(dns_master_style_t
**stylep
, unsigned int flags
,
1422 unsigned int ttl_column
, unsigned int class_column
,
1423 unsigned int type_column
, unsigned int rdata_column
,
1424 unsigned int line_length
, unsigned int tab_width
,
1427 dns_master_style_t
*style
;
1429 REQUIRE(stylep
!= NULL
&& *stylep
== NULL
);
1430 style
= isc_mem_get(mctx
, sizeof(*style
));
1432 return (ISC_R_NOMEMORY
);
1434 style
->flags
= flags
;
1435 style
->ttl_column
= ttl_column
;
1436 style
->class_column
= class_column
;
1437 style
->type_column
= type_column
;
1438 style
->rdata_column
= rdata_column
;
1439 style
->line_length
= line_length
;
1440 style
->tab_width
= tab_width
;
1443 return (ISC_R_SUCCESS
);
1447 dns_master_styledestroy(dns_master_style_t
**stylep
, isc_mem_t
*mctx
) {
1448 dns_master_style_t
*style
;
1450 REQUIRE(stylep
!= NULL
&& *stylep
!= NULL
);
1453 isc_mem_put(mctx
, style
, sizeof(*style
));