Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / dns / masterdump.c
blobd70256d18a4094eef8ae18b9bea492b30176ed59
1 /* $NetBSD: masterdump.c,v 1.11 2015/07/08 17:28:58 christos Exp $ */
3 /*
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.
20 /* Id */
22 /*! \file */
24 #include <config.h>
26 #include <stdlib.h>
28 #include <isc/event.h>
29 #include <isc/file.h>
30 #include <isc/magic.h>
31 #include <isc/mem.h>
32 #include <isc/print.h>
33 #include <isc/stdio.h>
34 #include <isc/string.h>
35 #include <isc/task.h>
36 #include <isc/time.h>
37 #include <isc/util.h>
39 #include <dns/db.h>
40 #include <dns/dbiterator.h>
41 #include <dns/events.h>
42 #include <dns/fixedname.h>
43 #include <dns/lib.h>
44 #include <dns/log.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>
54 #include <dns/time.h>
55 #include <dns/ttl.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) \
63 return (_r); \
64 } while (/*CONSTCOND*/0)
66 #define CHECK(x) do { \
67 if ((x) != ISC_R_SUCCESS) \
68 goto cleanup; \
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;
82 /*%
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
90 /*%
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;
96 char * linebreak;
97 char linebreak_buf[DNS_TOTEXT_LINEBREAK_MAXLEN];
98 dns_name_t * origin;
99 dns_name_t * neworigin;
100 dns_fixedname_t origin_fixname;
101 isc_uint32_t current_ttl;
102 isc_boolean_t current_ttl_valid;
103 } dns_totext_ctx_t;
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 |
112 DNS_STYLEFLAG_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 |
127 DNS_STYLEFLAG_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
192 #define N_SPACES 10
193 static char spaces[N_SPACES+1] = " ";
195 #define N_TABS 10
196 static char tabs[N_TABS+1] = "\t\t\t\t\t\t\t\t\t\t";
198 struct dns_dumpctx {
199 unsigned int magic;
200 isc_mem_t *mctx;
201 isc_mutex_t lock;
202 unsigned int references;
203 isc_boolean_t canceled;
204 isc_boolean_t first;
205 isc_boolean_t do_date;
206 isc_stdtime_t now;
207 FILE *f;
208 dns_db_t *db;
209 dns_dbversion_t *version;
210 dns_dbiterator_t *dbiter;
211 dns_totext_ctx_t tctx;
212 isc_task_t *task;
213 dns_dumpdonefunc_t done;
214 void *done_arg;
215 unsigned int nodes;
216 /* dns_master_dumpinc() */
217 char *file;
218 char *tmpfile;
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
232 * current column.
234 static isc_result_t
235 indent(unsigned int *current, unsigned int to, int tabwidth,
236 isc_buffer_t *target)
238 isc_region_t r;
239 unsigned char *p;
240 unsigned int from;
241 int ntabs, nspaces, t;
243 from = *current;
245 if (to < from + 1)
246 to = from + 1;
248 ntabs = to / tabwidth - from / tabwidth;
249 if (ntabs < 0)
250 ntabs = 0;
252 if (ntabs > 0) {
253 isc_buffer_availableregion(target, &r);
254 if (r.length < (unsigned) ntabs)
255 return (ISC_R_NOSPACE);
256 p = r.base;
258 t = ntabs;
259 while (t) {
260 int n = t;
261 if (n > N_TABS)
262 n = N_TABS;
263 memmove(p, tabs, n);
264 p += n;
265 t -= n;
267 isc_buffer_add(target, ntabs);
268 from = (to / tabwidth) * tabwidth;
271 nspaces = to - from;
272 INSIST(nspaces >= 0);
274 isc_buffer_availableregion(target, &r);
275 if (r.length < (unsigned) nspaces)
276 return (ISC_R_NOSPACE);
277 p = r.base;
279 t = nspaces;
280 while (t) {
281 int n = t;
282 if (n > N_SPACES)
283 n = N_SPACES;
284 memmove(p, spaces, n);
285 p += n;
286 t -= n;
288 isc_buffer_add(target, nspaces);
290 *current = to;
291 return (ISC_R_SUCCESS);
294 static isc_result_t
295 totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) {
296 isc_result_t result;
298 REQUIRE(style->tab_width != 0);
300 ctx->style = *style;
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) {
309 isc_buffer_t buf;
310 isc_region_t r;
311 unsigned int col = 0;
313 isc_buffer_init(&buf, ctx->linebreak_buf,
314 sizeof(ctx->linebreak_buf));
316 isc_buffer_availableregion(&buf, &r);
317 if (r.length < 1)
318 return (DNS_R_TEXTTOOLONG);
319 r.base[0] = '\n';
320 isc_buffer_add(&buf, 1);
322 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0) {
323 isc_buffer_availableregion(&buf, &r);
324 if (r.length < 1)
325 return (DNS_R_TEXTTOOLONG);
326 r.base[0] = ';';
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)
342 return (result);
344 isc_buffer_availableregion(&buf, &r);
345 if (r.length < 1)
346 return (DNS_R_TEXTTOOLONG);
347 r.base[0] = '\0';
348 isc_buffer_add(&buf, 1);
349 ctx->linebreak = ctx->linebreak_buf;
350 } else {
351 ctx->linebreak = NULL;
354 ctx->origin = 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) \
363 do { \
364 if ((result = indent(&column, ctx->style.col, \
365 ctx->style.tab_width, target)) \
366 != ISC_R_SUCCESS) \
367 return (result); \
368 } while (/*CONSTCOND*/0)
371 static isc_result_t
372 str_totext(const char *source, isc_buffer_t *target) {
373 unsigned int l;
374 isc_region_t region;
376 isc_buffer_availableregion(target, &region);
377 l = strlen(source);
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);
387 static isc_result_t
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;
392 dns_rdataset_t rds;
393 dns_name_t name;
395 dns_rdataset_init(&rds);
396 dns_name_init(&name, NULL);
398 do {
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));
411 } else {
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;
426 cleanup:
427 if (dns_rdataset_isassociated(&rds))
428 dns_rdataset_disassociate(&rds);
430 return (result);
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
437 * one label.
440 static isc_result_t
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)
447 isc_result_t result;
448 unsigned int column;
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) {
464 column = 0;
467 * Comment?
469 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0)
470 RETERR(str_totext(";", target));
473 * Owner name.
475 if (owner_name != NULL &&
476 ! ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0 &&
477 !first))
479 unsigned int name_start = target->used;
480 RETERR(dns_name_totext(owner_name,
481 omit_final_dot,
482 target));
483 column += target->used - name_start;
487 * TTL.
489 if ((ctx->style.flags & DNS_STYLEFLAG_NO_TTL) == 0 &&
490 !((ctx->style.flags & DNS_STYLEFLAG_OMIT_TTL) != 0 &&
491 current_ttl_valid &&
492 rdataset->ttl == current_ttl))
494 char ttlbuf[64];
495 isc_region_t r;
496 unsigned int length;
498 INDENT_TO(ttl_column);
499 length = snprintf(ttlbuf, sizeof(ttlbuf), "%u",
500 rdataset->ttl);
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);
507 column += 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;
520 * Class.
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,
530 target);
531 if (result != ISC_R_SUCCESS)
532 return (result);
533 column += (target->used - class_start);
537 * Type.
540 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
541 type = rdataset->covers;
542 } else {
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));
550 switch (type) {
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);
558 break;
560 /* FALLTHROUGH */
561 default:
562 result = dns_rdatatype_totext(type, target);
563 if (result != ISC_R_SUCCESS)
564 return (result);
566 column += (target->used - type_start);
569 * Rdata.
571 INDENT_TO(rdata_column);
572 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
573 if (NXDOMAIN(rdataset))
574 RETERR(str_totext(";-$NXDOMAIN\n", target));
575 else
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,
582 target));
583 break;
584 } else {
585 dns_rdata_t rdata = DNS_RDATA_INIT;
586 isc_region_t r;
588 dns_rdataset_current(rdataset, &rdata);
590 RETERR(dns_rdata_tofmttext(&rdata,
591 ctx->origin,
592 ctx->style.flags,
593 ctx->style.line_length -
594 ctx->style.rdata_column,
595 ctx->style.split_width,
596 ctx->linebreak,
597 target));
599 isc_buffer_availableregion(target, &r);
600 if (r.length < 1)
601 return (ISC_R_NOSPACE);
602 r.base[0] = '\n';
603 isc_buffer_add(target, 1);
606 first = ISC_FALSE;
607 result = dns_rdataset_next(rdataset);
610 if (result != ISC_R_NOMORE)
611 return (result);
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
630 * of a DNS message.
632 static isc_result_t
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)
639 unsigned int column;
640 isc_result_t result;
641 isc_region_t r;
643 REQUIRE(DNS_RDATASET_VALID(rdataset));
644 result = dns_rdataset_first(rdataset);
645 REQUIRE(result == ISC_R_NOMORE);
647 column = 0;
649 /* Owner name */
651 unsigned int name_start = target->used;
652 RETERR(dns_name_totext(owner_name,
653 omit_final_dot,
654 target));
655 column += target->used - name_start;
658 /* Class */
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)
665 return (result);
666 column += (target->used - class_start);
669 /* Type */
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)
676 return (result);
677 column += (target->used - type_start);
680 isc_buffer_availableregion(target, &r);
681 if (r.length < 1)
682 return (ISC_R_NOSPACE);
683 r.base[0] = '\n';
684 isc_buffer_add(target, 1);
686 return (ISC_R_SUCCESS);
689 isc_result_t
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;
697 isc_result_t result;
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
709 * previous one.)
711 if (dns_name_countlabels(owner_name) == 0)
712 owner_name = NULL;
714 if (question)
715 return (question_totext(rdataset, owner_name, &ctx,
716 omit_final_dot, target));
717 else
718 return (rdataset_totext(rdataset, owner_name, &ctx,
719 omit_final_dot, target));
722 isc_result_t
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;
729 isc_result_t result;
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,
738 ISC_FALSE, target));
741 isc_result_t
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;
748 isc_result_t result;
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,
757 ISC_FALSE, target));
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.
767 static isc_result_t
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)
772 isc_region_t r;
773 isc_result_t result;
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,
789 ISC_TRUE, buffer);
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);
794 } else {
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.
808 for (;;) {
809 int newlength;
810 void *newmem;
811 result = rdataset_totext(rdataset, name, ctx,
812 ISC_FALSE, buffer);
813 if (result != ISC_R_NOSPACE)
814 break;
816 newlength = buffer->length * 2;
817 newmem = isc_mem_get(mctx, newlength);
818 if (newmem == NULL)
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)
824 return (result);
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));
836 return (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.
851 static int
852 dump_order(const dns_rdataset_t *rds) {
853 int t;
854 int sig;
855 if (rds->type == dns_rdatatype_rrsig) {
856 t = rds->covers;
857 sig = 1;
858 } else {
859 t = rds->type;
860 sig = 0;
862 switch (t) {
863 case dns_rdatatype_soa:
864 t = 0;
865 break;
866 case dns_rdatatype_ns:
867 t = 1;
868 break;
869 default:
870 t += 2;
871 break;
873 return (t << 1) + sig;
876 static int
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.
892 #define MAXSORT 64
894 static isc_result_t
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;
900 isc_region_t r;
901 dns_rdataset_t rdatasets[MAXSORT];
902 dns_rdataset_t *sorted[MAXSORT];
903 int i, n;
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;
917 again:
918 for (i = 0;
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];
925 n = 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 */
937 } else {
938 isc_result_t result =
939 dump_rdataset(mctx, name, rds, ctx,
940 buffer, f);
941 if (result != ISC_R_SUCCESS)
942 dumpresult = result;
943 if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0)
944 name = NULL;
946 if (ctx->style.flags & DNS_STYLEFLAG_RESIGN &&
947 rds->attributes & DNS_RDATASETATTR_RESIGN) {
948 isc_buffer_t b;
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)
959 return (dumpresult);
962 * If we got more data than could be sorted at once,
963 * go handle the rest.
965 if (itresult == ISC_R_SUCCESS)
966 goto again;
968 if (itresult == ISC_R_NOMORE)
969 itresult = ISC_R_SUCCESS;
971 return (itresult);
975 * Dump given RRsets in the "raw" format.
977 static isc_result_t
978 dump_rdataset_raw(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset,
979 isc_buffer_t *buffer, FILE *f)
981 isc_result_t result;
982 isc_uint32_t totallen;
983 isc_uint16_t dlen;
984 isc_region_t r, r_hdr;
986 REQUIRE(buffer->length > 0);
987 REQUIRE(DNS_RDATASET_VALID(rdataset));
989 rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
990 restart:
991 totallen = 0;
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;
1021 do {
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
1033 * continue?).
1035 if (isc_buffer_availablelength(buffer) <
1036 sizeof(dlen) + r.length) {
1037 int newlength;
1038 void *newmem;
1040 newlength = buffer->length * 2;
1041 newmem = isc_mem_get(mctx, newlength);
1042 if (newmem == NULL)
1043 return (ISC_R_NOMEMORY);
1044 isc_mem_put(mctx, buffer->base, buffer->length);
1045 isc_buffer_init(buffer, newmem, newlength);
1046 goto restart;
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)
1056 return (result);
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));
1078 return (result);
1081 return (result);
1084 static isc_result_t
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 */
1102 } else {
1103 result = dump_rdataset_raw(mctx, name, &rdataset,
1104 buffer, f);
1106 dns_rdataset_disassociate(&rdataset);
1107 if (result != ISC_R_SUCCESS)
1108 return (result);
1111 if (result == ISC_R_NOMORE)
1112 result = ISC_R_SUCCESS;
1114 return (result);
1117 static isc_result_t
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)
1122 UNUSED(mctx);
1123 UNUSED(name);
1124 UNUSED(rdsiter);
1125 UNUSED(ctx);
1126 UNUSED(buffer);
1127 UNUSED(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;
1144 static isc_result_t
1145 dumptostreaminc(dns_dumpctx_t *dctx);
1147 static void
1148 dumpctx_destroy(dns_dumpctx_t *dctx) {
1150 dctx->magic = 0;
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));
1165 void
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);
1177 *target = source;
1180 void
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);
1186 dctx = *dctxp;
1187 REQUIRE(DNS_DCTX_VALID(dctx));
1189 *dctxp = NULL;
1191 LOCK(&dctx->lock);
1192 INSIST(dctx->references != 0);
1193 dctx->references--;
1194 if (dctx->references == 0)
1195 need_destroy = ISC_TRUE;
1196 UNLOCK(&dctx->lock);
1197 if (need_destroy)
1198 dumpctx_destroy(dctx);
1201 dns_dbversion_t *
1202 dns_dumpctx_version(dns_dumpctx_t *dctx) {
1203 REQUIRE(DNS_DCTX_VALID(dctx));
1204 return (dctx->version);
1207 dns_db_t *
1208 dns_dumpctx_db(dns_dumpctx_t *dctx) {
1209 REQUIRE(DNS_DCTX_VALID(dctx));
1210 return (dctx->db);
1213 void
1214 dns_dumpctx_cancel(dns_dumpctx_t *dctx) {
1215 REQUIRE(DNS_DCTX_VALID(dctx));
1217 LOCK(&dctx->lock);
1218 dctx->canceled = ISC_TRUE;
1219 UNLOCK(&dctx->lock);
1222 static isc_result_t
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) {
1229 if (temp != NULL)
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));
1234 else
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));
1239 logit = ISC_FALSE;
1242 if (result == ISC_R_SUCCESS)
1243 result = isc_stdio_sync(f);
1244 if (result != ISC_R_SUCCESS && logit) {
1245 if (temp != NULL)
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));
1250 else
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));
1256 return (result);
1259 static isc_result_t
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)
1267 logit = ISC_FALSE;
1269 tresult = isc_stdio_close(f);
1270 if (result == ISC_R_SUCCESS)
1271 result = tresult;
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));
1277 logit = ISC_FALSE;
1279 if (result == ISC_R_SUCCESS)
1280 result = isc_file_rename(temp, file);
1281 else
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));
1289 return (result);
1292 static void
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));
1301 if (dctx->canceled)
1302 result = ISC_R_CANCELED;
1303 else
1304 result = dumptostreaminc(dctx);
1305 if (result == DNS_R_CONTINUE) {
1306 event->ev_arg = dctx;
1307 isc_task_send(task, &event);
1308 return;
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)
1315 result = tresult;
1316 } else
1317 result = flushandsync(dctx->f, result, NULL);
1318 (dctx->done)(dctx->done_arg, result);
1319 isc_event_free(&event);
1320 dns_dumpctx_detach(&dctx);
1323 static isc_result_t
1324 task_send(dns_dumpctx_t *dctx) {
1325 isc_event_t *event;
1327 event = isc_event_allocate(dctx->mctx, NULL, DNS_EVENT_DUMPQUANTUM,
1328 dump_quantum, dctx, sizeof(*event));
1329 if (event == NULL)
1330 return (ISC_R_NOMEMORY);
1331 isc_task_send(dctx->task, &event);
1332 return (ISC_R_SUCCESS);
1335 static isc_result_t
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));
1345 if (dctx == NULL)
1346 return (ISC_R_NOMEMORY);
1348 dctx->mctx = NULL;
1349 dctx->f = f;
1350 dctx->dbiter = NULL;
1351 dctx->db = NULL;
1352 dctx->version = NULL;
1353 dctx->done = NULL;
1354 dctx->done_arg = NULL;
1355 dctx->task = NULL;
1356 dctx->nodes = 0;
1357 dctx->first = ISC_TRUE;
1358 dctx->canceled = ISC_FALSE;
1359 dctx->file = NULL;
1360 dctx->tmpfile = NULL;
1361 dctx->format = format;
1362 if (header == NULL)
1363 dns_master_initrawheader(&dctx->header);
1364 else
1365 dctx->header = *header;
1367 switch (format) {
1368 case dns_masterformat_text:
1369 dctx->dumpsets = dump_rdatasets_text;
1370 break;
1371 case dns_masterformat_raw:
1372 dctx->dumpsets = dump_rdatasets_raw;
1373 break;
1374 case dns_masterformat_map:
1375 dctx->dumpsets = dump_rdatasets_map;
1376 break;
1377 default:
1378 INSIST(0);
1379 break;
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");
1386 goto cleanup;
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;
1397 } else
1398 options = 0;
1399 result = dns_db_createiterator(dctx->db, options, &dctx->dbiter);
1400 if (result != ISC_R_SUCCESS)
1401 goto cleanup;
1403 result = isc_mutex_init(&dctx->lock);
1404 if (result != ISC_R_SUCCESS)
1405 goto cleanup;
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;
1413 *dctxp = dctx;
1414 return (ISC_R_SUCCESS);
1416 cleanup:
1417 if (dctx->dbiter != NULL)
1418 dns_dbiterator_destroy(&dctx->dbiter);
1419 if (dctx->db != NULL)
1420 dns_db_detach(&dctx->db);
1421 if (dctx != NULL)
1422 isc_mem_put(mctx, dctx, sizeof(*dctx));
1423 return (result);
1426 static isc_result_t
1427 writeheader(dns_dumpctx_t *dctx) {
1428 isc_result_t result = ISC_R_SUCCESS;
1429 isc_buffer_t buffer;
1430 char *bufmem;
1431 isc_region_t r;
1432 dns_masterrawheader_t rawheader;
1433 isc_uint32_t rawversion, now32;
1435 bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
1436 if (bufmem == NULL)
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);
1458 break;
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
1470 * header format.
1472 isc_log_write(dns_lctx,
1473 ISC_LOGCATEGORY_GENERAL,
1474 DNS_LOGMODULE_MASTERDUMP,
1475 ISC_LOG_INFO,
1476 "dumping master file in raw "
1477 "format: stdtime is not 32bits");
1478 now32 = 0;
1479 #else
1480 now32 = dctx->now;
1481 #endif
1482 rawversion = 1;
1483 if ((dctx->header.flags & DNS_MASTERRAW_COMPAT) != 0)
1484 rawversion = 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),
1500 dctx->f, NULL);
1501 if (result != ISC_R_SUCCESS)
1502 break;
1504 break;
1505 default:
1506 INSIST(0);
1509 isc_mem_put(dctx->mctx, buffer.base, buffer.length);
1510 return (result);
1513 static isc_result_t
1514 dumptostreaminc(dns_dumpctx_t *dctx) {
1515 isc_result_t result = ISC_R_SUCCESS;
1516 isc_buffer_t buffer;
1517 char *bufmem;
1518 dns_name_t *name;
1519 dns_fixedname_t fixname;
1520 unsigned int nodes;
1521 isc_time_t start;
1523 bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
1524 if (bufmem == NULL)
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);
1532 if (dctx->first) {
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,
1543 dctx->f);
1544 goto cleanup;
1547 result = dns_dbiterator_first(dctx->dbiter);
1548 if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
1549 goto cleanup;
1551 dctx->first = ISC_FALSE;
1552 } else
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)
1563 break;
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);
1578 goto cleanup;
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);
1585 goto cleanup;
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
1595 * next iteration.
1597 if (dctx->nodes != 0 && result == ISC_R_SUCCESS) {
1598 unsigned int pps = dns_pps; /* packets per second */
1599 unsigned int interval;
1600 isc_uint64_t usecs;
1601 isc_time_t end;
1603 isc_time_now(&end);
1604 if (pps < 100)
1605 pps = 100;
1606 interval = 1000000 / pps; /* interval in usecs */
1607 if (interval == 0)
1608 interval = 1;
1609 usecs = isc_time_microdiff(&end, &start);
1610 if (usecs == 0) {
1611 dctx->nodes = dctx->nodes * 2;
1612 if (dctx->nodes > 1000)
1613 dctx->nodes = 1000;
1614 } else {
1615 nodes = dctx->nodes * interval;
1616 nodes /= (unsigned int)usecs;
1617 if (nodes == 0)
1618 nodes = 1;
1619 else if (nodes > 1000)
1620 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,
1627 ISC_LOG_DEBUG(1),
1628 "dumptostreaminc(%p) new nodes -> %d\n",
1629 dctx, dctx->nodes);
1631 result = DNS_R_CONTINUE;
1632 } else if (result == ISC_R_NOMORE)
1633 result = ISC_R_SUCCESS;
1634 cleanup:
1635 RUNTIME_CHECK(dns_dbiterator_pause(dctx->dbiter) == ISC_R_SUCCESS);
1636 isc_mem_put(dctx->mctx, buffer.base, buffer.length);
1637 return (result);
1640 isc_result_t
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);
1652 REQUIRE(f != 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)
1658 return (result);
1659 isc_task_attach(task, &dctx->task);
1660 dctx->done = done;
1661 dctx->done_arg = done_arg;
1662 dctx->nodes = 100;
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);
1671 return (result);
1675 * Dump an entire database into a master file.
1677 isc_result_t
1678 dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db,
1679 dns_dbversion_t *version,
1680 const dns_master_style_t *style,
1681 FILE *f)
1683 return (dns_master_dumptostream3(mctx, db, version, style,
1684 dns_masterformat_text, NULL, f));
1687 isc_result_t
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,
1694 format, NULL, f));
1697 isc_result_t
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,
1708 format, header);
1709 if (result != ISC_R_SUCCESS)
1710 return (result);
1712 result = dumptostreaminc(dctx);
1713 INSIST(result != DNS_R_CONTINUE);
1714 dns_dumpctx_detach(&dctx);
1716 result = flushandsync(f, result, NULL);
1717 return (result);
1720 static isc_result_t
1721 opentmp(isc_mem_t *mctx, dns_masterformat_t format, const char *file,
1722 char **tempp, FILE **fp) {
1723 FILE *f = NULL;
1724 isc_result_t result;
1725 char *tempname = NULL;
1726 int tempnamelen;
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)
1735 goto cleanup;
1737 if (format == dns_masterformat_text)
1738 result = isc_file_openunique(tempname, &f);
1739 else
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));
1746 goto cleanup;
1748 *tempp = tempname;
1749 *fp = f;
1750 return (ISC_R_SUCCESS);
1752 cleanup:
1753 isc_mem_free(mctx, tempname);
1754 return (result);
1757 isc_result_t
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));
1768 isc_result_t
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));
1778 isc_result_t
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)
1785 FILE *f = NULL;
1786 isc_result_t result;
1787 char *tempname = NULL;
1788 char *file = NULL;
1789 dns_dumpctx_t *dctx = NULL;
1791 file = isc_mem_strdup(mctx, filename);
1792 if (file == NULL)
1793 return (ISC_R_NOMEMORY);
1795 result = opentmp(mctx, format, filename, &tempname, &f);
1796 if (result != ISC_R_SUCCESS)
1797 goto cleanup;
1799 result = dumpctx_create(mctx, db, version, style, f, &dctx,
1800 format, header);
1801 if (result != ISC_R_SUCCESS) {
1802 (void)isc_stdio_close(f);
1803 (void)isc_file_remove(tempname);
1804 goto cleanup;
1807 isc_task_attach(task, &dctx->task);
1808 dctx->done = done;
1809 dctx->done_arg = done_arg;
1810 dctx->nodes = 100;
1811 dctx->file = file;
1812 file = NULL;
1813 dctx->tmpfile = tempname;
1814 tempname = NULL;
1816 result = task_send(dctx);
1817 if (result == ISC_R_SUCCESS) {
1818 dns_dumpctx_attach(dctx, dctxp);
1819 return (DNS_R_CONTINUE);
1822 cleanup:
1823 if (dctx != NULL)
1824 dns_dumpctx_detach(&dctx);
1825 if (file != NULL)
1826 isc_mem_free(mctx, file);
1827 if (tempname != NULL)
1828 isc_mem_free(mctx, tempname);
1829 return (result);
1832 isc_result_t
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));
1840 isc_result_t
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,
1846 format, NULL));
1849 isc_result_t
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)
1854 FILE *f = NULL;
1855 isc_result_t result;
1856 char *tempname;
1857 dns_dumpctx_t *dctx = NULL;
1859 result = opentmp(mctx, format, filename, &tempname, &f);
1860 if (result != ISC_R_SUCCESS)
1861 return (result);
1863 result = dumpctx_create(mctx, db, version, style, f, &dctx,
1864 format, header);
1865 if (result != ISC_R_SUCCESS)
1866 goto cleanup;
1868 result = dumptostreaminc(dctx);
1869 INSIST(result != DNS_R_CONTINUE);
1870 dns_dumpctx_detach(&dctx);
1872 result = closeandrename(f, result, tempname, filename);
1874 cleanup:
1875 isc_mem_free(mctx, tempname);
1876 return (result);
1880 * Dump a database node into a master file.
1881 * XXX: this function assumes the text format.
1883 isc_result_t
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,
1888 FILE *f)
1890 isc_result_t result;
1891 isc_buffer_t buffer;
1892 char *bufmem;
1893 isc_stdtime_t now;
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);
1907 if (bufmem == NULL)
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)
1914 goto failure;
1915 result = dump_rdatasets_text(mctx, name, rdsiter, &ctx, &buffer, f);
1916 if (result != ISC_R_SUCCESS)
1917 goto failure;
1918 dns_rdatasetiter_destroy(&rdsiter);
1920 result = ISC_R_SUCCESS;
1922 failure:
1923 isc_mem_put(mctx, buffer.base, buffer.length);
1924 return (result);
1927 isc_result_t
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)
1932 FILE *f = NULL;
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,
1945 style, f);
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);
1964 return (result);
1967 isc_result_t
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,
1972 isc_mem_t *mctx)
1974 return (dns_master_stylecreate2(stylep, flags, ttl_column,
1975 class_column, type_column,
1976 rdata_column, line_length,
1977 tab_width, 0xffffffff, mctx));
1980 isc_result_t
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));
1991 if (style == NULL)
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;
2003 *stylep = style;
2004 return (ISC_R_SUCCESS);
2007 void
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);
2012 style = *stylep;
2013 *stylep = NULL;
2014 isc_mem_put(mctx, style, sizeof(*style));