masterdump.c revision 1.2 1 /* $NetBSD: masterdump.c,v 1.2 2018/08/12 13:02:35 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 */
13
14 /*! \file */
15
16 #include <config.h>
17
18 #include <stdlib.h>
19
20 #include <isc/buffer.h>
21 #include <isc/event.h>
22 #include <isc/file.h>
23 #include <isc/magic.h>
24 #include <isc/mem.h>
25 #include <isc/print.h>
26 #include <isc/stdio.h>
27 #include <isc/string.h>
28 #include <isc/task.h>
29 #include <isc/time.h>
30 #include <isc/types.h>
31 #include <isc/util.h>
32
33 #include <dns/db.h>
34 #include <dns/dbiterator.h>
35 #include <dns/events.h>
36 #include <dns/fixedname.h>
37 #include <dns/lib.h>
38 #include <dns/log.h>
39 #include <dns/master.h>
40 #include <dns/masterdump.h>
41 #include <dns/ncache.h>
42 #include <dns/rdata.h>
43 #include <dns/rdataclass.h>
44 #include <dns/rdataset.h>
45 #include <dns/rdatasetiter.h>
46 #include <dns/rdatatype.h>
47 #include <dns/result.h>
48 #include <dns/time.h>
49 #include <dns/ttl.h>
50
51 #define DNS_DCTX_MAGIC ISC_MAGIC('D', 'c', 't', 'x')
52 #define DNS_DCTX_VALID(d) ISC_MAGIC_VALID(d, DNS_DCTX_MAGIC)
53
54 #define RETERR(x) do { \
55 isc_result_t _r = (x); \
56 if (_r != ISC_R_SUCCESS) \
57 return (_r); \
58 } while (/*CONSTCOND*/0)
59
60 #define CHECK(x) do { \
61 if ((x) != ISC_R_SUCCESS) \
62 goto cleanup; \
63 } while (/*CONSTCOND*/0)
64
65 struct dns_master_style {
66 dns_masterstyle_flags_t flags; /* DNS_STYLEFLAG_* */
67 unsigned int ttl_column;
68 unsigned int class_column;
69 unsigned int type_column;
70 unsigned int rdata_column;
71 unsigned int line_length;
72 unsigned int tab_width;
73 unsigned int split_width;
74 };
75
76 /*%
77 * The maximum length of the newline+indentation that is output
78 * when inserting a line break in an RR. This effectively puts an
79 * upper limits on the value of "rdata_column", because if it is
80 * very large, the tabs and spaces needed to reach it will not fit.
81 */
82 #define DNS_TOTEXT_LINEBREAK_MAXLEN 100
83
84 /*%
85 * Context structure for a masterfile dump in progress.
86 */
87 typedef struct dns_totext_ctx {
88 dns_master_style_t style;
89 isc_boolean_t class_printed;
90 char * linebreak;
91 char linebreak_buf[DNS_TOTEXT_LINEBREAK_MAXLEN];
92 dns_name_t * origin;
93 dns_name_t * neworigin;
94 dns_fixedname_t origin_fixname;
95 isc_uint32_t current_ttl;
96 isc_boolean_t current_ttl_valid;
97 dns_ttl_t serve_stale_ttl;
98 } dns_totext_ctx_t;
99
100 LIBDNS_EXTERNAL_DATA const dns_master_style_t
101 dns_master_style_keyzone = {
102 DNS_STYLEFLAG_OMIT_OWNER |
103 DNS_STYLEFLAG_OMIT_CLASS |
104 DNS_STYLEFLAG_REL_OWNER |
105 DNS_STYLEFLAG_REL_DATA |
106 DNS_STYLEFLAG_OMIT_TTL |
107 DNS_STYLEFLAG_TTL |
108 DNS_STYLEFLAG_COMMENT |
109 DNS_STYLEFLAG_RRCOMMENT |
110 DNS_STYLEFLAG_MULTILINE |
111 DNS_STYLEFLAG_KEYDATA,
112 24, 24, 24, 32, 80, 8, UINT_MAX
113 };
114
115 LIBDNS_EXTERNAL_DATA const dns_master_style_t
116 dns_master_style_default = {
117 DNS_STYLEFLAG_OMIT_OWNER |
118 DNS_STYLEFLAG_OMIT_CLASS |
119 DNS_STYLEFLAG_REL_OWNER |
120 DNS_STYLEFLAG_REL_DATA |
121 DNS_STYLEFLAG_OMIT_TTL |
122 DNS_STYLEFLAG_TTL |
123 DNS_STYLEFLAG_COMMENT |
124 DNS_STYLEFLAG_RRCOMMENT |
125 DNS_STYLEFLAG_MULTILINE,
126 24, 24, 24, 32, 80, 8, UINT_MAX
127 };
128
129 LIBDNS_EXTERNAL_DATA const dns_master_style_t
130 dns_master_style_full = {
131 DNS_STYLEFLAG_COMMENT |
132 DNS_STYLEFLAG_RESIGN,
133 46, 46, 46, 64, 120, 8, UINT_MAX
134 };
135
136 LIBDNS_EXTERNAL_DATA const dns_master_style_t
137 dns_master_style_explicitttl = {
138 DNS_STYLEFLAG_OMIT_OWNER |
139 DNS_STYLEFLAG_OMIT_CLASS |
140 DNS_STYLEFLAG_REL_OWNER |
141 DNS_STYLEFLAG_REL_DATA |
142 DNS_STYLEFLAG_COMMENT |
143 DNS_STYLEFLAG_RRCOMMENT |
144 DNS_STYLEFLAG_MULTILINE,
145 24, 32, 32, 40, 80, 8, UINT_MAX
146 };
147
148 LIBDNS_EXTERNAL_DATA const dns_master_style_t
149 dns_master_style_cache = {
150 DNS_STYLEFLAG_OMIT_OWNER |
151 DNS_STYLEFLAG_OMIT_CLASS |
152 DNS_STYLEFLAG_MULTILINE |
153 DNS_STYLEFLAG_RRCOMMENT |
154 DNS_STYLEFLAG_TRUST |
155 DNS_STYLEFLAG_NCACHE,
156 24, 32, 32, 40, 80, 8, UINT_MAX
157 };
158
159 LIBDNS_EXTERNAL_DATA const dns_master_style_t
160 dns_master_style_simple = {
161 0,
162 24, 32, 32, 40, 80, 8, UINT_MAX
163 };
164
165 /*%
166 * A style suitable for dns_rdataset_totext().
167 */
168 LIBDNS_EXTERNAL_DATA const dns_master_style_t
169 dns_master_style_debug = {
170 DNS_STYLEFLAG_REL_OWNER,
171 24, 32, 40, 48, 80, 8, UINT_MAX
172 };
173
174 /*%
175 * Similar, but indented (i.e., prepended with dns_master_indentstr).
176 */
177 LIBDNS_EXTERNAL_DATA const dns_master_style_t
178 dns_master_style_indent = {
179 DNS_STYLEFLAG_REL_OWNER |
180 DNS_STYLEFLAG_INDENT,
181 24, 32, 40, 48, 80, 8, UINT_MAX
182 };
183
184 /*%
185 * Similar, but with each line commented out.
186 */
187 LIBDNS_EXTERNAL_DATA const dns_master_style_t
188 dns_master_style_comment = {
189 DNS_STYLEFLAG_REL_OWNER |
190 DNS_STYLEFLAG_MULTILINE |
191 DNS_STYLEFLAG_RRCOMMENT |
192 DNS_STYLEFLAG_COMMENTDATA,
193 24, 32, 40, 48, 80, 8, UINT_MAX
194 };
195
196 /*%
197 * YAML style
198 */
199 LIBDNS_EXTERNAL_DATA const dns_master_style_t
200 dns_master_style_yaml = {
201 DNS_STYLEFLAG_YAML |
202 DNS_STYLEFLAG_REL_OWNER |
203 DNS_STYLEFLAG_INDENT,
204 24, 32, 40, 48, 80, 8, UINT_MAX
205 };
206
207 /*%
208 * Default indent string.
209 */
210 LIBDNS_EXTERNAL_DATA const char *dns_master_indentstr = "\t";
211 LIBDNS_EXTERNAL_DATA unsigned int dns_master_indent = 1;
212
213 #define N_SPACES 10
214 static char spaces[N_SPACES+1] = " ";
215
216 #define N_TABS 10
217 static char tabs[N_TABS+1] = "\t\t\t\t\t\t\t\t\t\t";
218
219 struct dns_dumpctx {
220 unsigned int magic;
221 isc_mem_t *mctx;
222 isc_mutex_t lock;
223 unsigned int references;
224 isc_boolean_t canceled;
225 isc_boolean_t first;
226 isc_boolean_t do_date;
227 isc_stdtime_t now;
228 FILE *f;
229 dns_db_t *db;
230 dns_dbversion_t *version;
231 dns_dbiterator_t *dbiter;
232 dns_totext_ctx_t tctx;
233 isc_task_t *task;
234 dns_dumpdonefunc_t done;
235 void *done_arg;
236 unsigned int nodes;
237 /* dns_master_dumpinc() */
238 char *file;
239 char *tmpfile;
240 dns_masterformat_t format;
241 dns_masterrawheader_t header;
242 isc_result_t (*dumpsets)(isc_mem_t *mctx,
243 const dns_name_t *name,
244 dns_rdatasetiter_t *rdsiter,
245 dns_totext_ctx_t *ctx,
246 isc_buffer_t *buffer, FILE *f);
247 };
248
249 #define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
250
251 /*%
252 * Output tabs and spaces to go from column '*current' to
253 * column 'to', and update '*current' to reflect the new
254 * current column.
255 */
256 static isc_result_t
257 indent(unsigned int *current, unsigned int to, int tabwidth,
258 isc_buffer_t *target)
259 {
260 isc_region_t r;
261 unsigned char *p;
262 unsigned int from;
263 int ntabs, nspaces, t;
264
265 from = *current;
266
267 if (to < from + 1)
268 to = from + 1;
269
270 ntabs = to / tabwidth - from / tabwidth;
271 if (ntabs < 0)
272 ntabs = 0;
273
274 if (ntabs > 0) {
275 isc_buffer_availableregion(target, &r);
276 if (r.length < (unsigned) ntabs)
277 return (ISC_R_NOSPACE);
278 p = r.base;
279
280 t = ntabs;
281 while (t) {
282 int n = t;
283 if (n > N_TABS)
284 n = N_TABS;
285 memmove(p, tabs, n);
286 p += n;
287 t -= n;
288 }
289 isc_buffer_add(target, ntabs);
290 from = (to / tabwidth) * tabwidth;
291 }
292
293 nspaces = to - from;
294 INSIST(nspaces >= 0);
295
296 isc_buffer_availableregion(target, &r);
297 if (r.length < (unsigned) nspaces)
298 return (ISC_R_NOSPACE);
299 p = r.base;
300
301 t = nspaces;
302 while (t) {
303 int n = t;
304 if (n > N_SPACES)
305 n = N_SPACES;
306 memmove(p, spaces, n);
307 p += n;
308 t -= n;
309 }
310 isc_buffer_add(target, nspaces);
311
312 *current = to;
313 return (ISC_R_SUCCESS);
314 }
315
316 static isc_result_t
317 totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) {
318 isc_result_t result;
319
320 REQUIRE(style->tab_width != 0);
321
322 ctx->style = *style;
323 ctx->class_printed = ISC_FALSE;
324
325 dns_fixedname_init(&ctx->origin_fixname);
326
327 /*
328 * Set up the line break string if needed.
329 */
330 if ((ctx->style.flags & DNS_STYLEFLAG_MULTILINE) != 0) {
331 isc_buffer_t buf;
332 isc_region_t r;
333 unsigned int col = 0;
334
335 isc_buffer_init(&buf, ctx->linebreak_buf,
336 sizeof(ctx->linebreak_buf));
337
338 isc_buffer_availableregion(&buf, &r);
339 if (r.length < 1)
340 return (DNS_R_TEXTTOOLONG);
341 r.base[0] = '\n';
342 isc_buffer_add(&buf, 1);
343
344 if ((ctx->style.flags & DNS_STYLEFLAG_INDENT) != 0 ||
345 (ctx->style.flags & DNS_STYLEFLAG_YAML) != 0)
346 {
347 unsigned int i, len = strlen(dns_master_indentstr);
348 for (i = 0; i < dns_master_indent; i++) {
349 if (isc_buffer_availablelength(&buf) < len)
350 return (DNS_R_TEXTTOOLONG);
351 isc_buffer_putstr(&buf, dns_master_indentstr);
352 }
353 }
354
355 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0) {
356 isc_buffer_availableregion(&buf, &r);
357 if (r.length < 1)
358 return (DNS_R_TEXTTOOLONG);
359 r.base[0] = ';';
360 isc_buffer_add(&buf, 1);
361 }
362
363 result = indent(&col, ctx->style.rdata_column,
364 ctx->style.tab_width, &buf);
365 /*
366 * Do not return ISC_R_NOSPACE if the line break string
367 * buffer is too small, because that would just make
368 * dump_rdataset() retry indefinitely with ever
369 * bigger target buffers. That's a different buffer,
370 * so it won't help. Use DNS_R_TEXTTOOLONG as a substitute.
371 */
372 if (result == ISC_R_NOSPACE)
373 return (DNS_R_TEXTTOOLONG);
374 if (result != ISC_R_SUCCESS)
375 return (result);
376
377 isc_buffer_availableregion(&buf, &r);
378 if (r.length < 1)
379 return (DNS_R_TEXTTOOLONG);
380 r.base[0] = '\0';
381 isc_buffer_add(&buf, 1);
382 ctx->linebreak = ctx->linebreak_buf;
383 } else {
384 ctx->linebreak = NULL;
385 }
386
387 ctx->origin = NULL;
388 ctx->neworigin = NULL;
389 ctx->current_ttl = 0;
390 ctx->current_ttl_valid = ISC_FALSE;
391 ctx->serve_stale_ttl = 0;
392
393 return (ISC_R_SUCCESS);
394 }
395
396 #define INDENT_TO(col) \
397 do { \
398 if ((ctx->style.flags & DNS_STYLEFLAG_YAML) != 0) { \
399 if ((result = str_totext(" ", target)) \
400 != ISC_R_SUCCESS) \
401 return (result); \
402 } else if ((result = indent(&column, ctx->style.col, \
403 ctx->style.tab_width, target)) \
404 != ISC_R_SUCCESS) \
405 return (result); \
406 } while (/*CONSTCOND*/0)
407
408
409 static isc_result_t
410 str_totext(const char *source, isc_buffer_t *target) {
411 unsigned int l;
412 isc_region_t region;
413
414 isc_buffer_availableregion(target, ®ion);
415 l = strlen(source);
416
417 if (l > region.length)
418 return (ISC_R_NOSPACE);
419
420 memmove(region.base, source, l);
421 isc_buffer_add(target, l);
422 return (ISC_R_SUCCESS);
423 }
424
425 static isc_result_t
426 ncache_summary(dns_rdataset_t *rdataset, isc_boolean_t omit_final_dot,
427 isc_buffer_t *target)
428 {
429 isc_result_t result = ISC_R_SUCCESS;
430 dns_rdataset_t rds;
431 dns_name_t name;
432
433 dns_rdataset_init(&rds);
434 dns_name_init(&name, NULL);
435
436 do {
437 dns_ncache_current(rdataset, &name, &rds);
438 for (result = dns_rdataset_first(&rds);
439 result == ISC_R_SUCCESS;
440 result = dns_rdataset_next(&rds)) {
441 CHECK(str_totext("; ", target));
442 CHECK(dns_name_totext(&name, omit_final_dot, target));
443 CHECK(str_totext(" ", target));
444 CHECK(dns_rdatatype_totext(rds.type, target));
445 if (rds.type == dns_rdatatype_rrsig) {
446 CHECK(str_totext(" ", target));
447 CHECK(dns_rdatatype_totext(rds.covers, target));
448 CHECK(str_totext(" ...\n", target));
449 } else {
450 dns_rdata_t rdata = DNS_RDATA_INIT;
451 dns_rdataset_current(&rds, &rdata);
452 CHECK(str_totext(" ", target));
453 CHECK(dns_rdata_tofmttext(&rdata, dns_rootname,
454 0, 0, 0, " ", target));
455 CHECK(str_totext("\n", target));
456 }
457 }
458 dns_rdataset_disassociate(&rds);
459 result = dns_rdataset_next(rdataset);
460 } while (result == ISC_R_SUCCESS);
461
462 if (result == ISC_R_NOMORE)
463 result = ISC_R_SUCCESS;
464 cleanup:
465 if (dns_rdataset_isassociated(&rds))
466 dns_rdataset_disassociate(&rds);
467
468 return (result);
469 }
470
471 /*
472 * Convert 'rdataset' to master file text format according to 'ctx',
473 * storing the result in 'target'. If 'owner_name' is NULL, it
474 * is omitted; otherwise 'owner_name' must be valid and have at least
475 * one label.
476 */
477
478 static isc_result_t
479 rdataset_totext(dns_rdataset_t *rdataset,
480 const dns_name_t *owner_name,
481 dns_totext_ctx_t *ctx,
482 isc_boolean_t omit_final_dot,
483 isc_buffer_t *target)
484 {
485 isc_result_t result;
486 unsigned int column;
487 isc_boolean_t first = ISC_TRUE;
488 isc_uint32_t current_ttl;
489 isc_boolean_t current_ttl_valid;
490 dns_rdatatype_t type;
491 unsigned int type_start;
492 dns_fixedname_t fixed;
493 dns_name_t *name = NULL;
494 unsigned int i;
495
496 REQUIRE(DNS_RDATASET_VALID(rdataset));
497
498 rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
499 result = dns_rdataset_first(rdataset);
500
501 current_ttl = ctx->current_ttl;
502 current_ttl_valid = ctx->current_ttl_valid;
503
504 if (owner_name != NULL) {
505 name = dns_fixedname_initname(&fixed);
506 dns_name_copy(owner_name, name, NULL);
507 dns_rdataset_getownercase(rdataset, name);
508 }
509
510 while (result == ISC_R_SUCCESS) {
511 column = 0;
512
513 /*
514 * Indent?
515 */
516 if ((ctx->style.flags & DNS_STYLEFLAG_INDENT) != 0 ||
517 (ctx->style.flags & DNS_STYLEFLAG_YAML) != 0)
518 for (i = 0; i < dns_master_indent; i++)
519 RETERR(str_totext(dns_master_indentstr,
520 target));
521
522 /*
523 * YAML enumerator?
524 */
525 if ((ctx->style.flags & DNS_STYLEFLAG_YAML) != 0) {
526 RETERR(str_totext("- ", target));
527 }
528
529 /*
530 * Comment?
531 */
532 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0)
533 RETERR(str_totext(";", target));
534
535 /*
536 * Owner name.
537 */
538 if (name != NULL &&
539 ! ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0 &&
540 !first))
541 {
542 unsigned int name_start = target->used;
543 RETERR(dns_name_totext(name, omit_final_dot, target));
544 column += target->used - name_start;
545 }
546
547 /*
548 * TTL.
549 */
550 if ((ctx->style.flags & DNS_STYLEFLAG_NO_TTL) == 0 &&
551 !((ctx->style.flags & DNS_STYLEFLAG_OMIT_TTL) != 0 &&
552 current_ttl_valid &&
553 rdataset->ttl == current_ttl))
554 {
555 char ttlbuf[64];
556 isc_region_t r;
557 unsigned int length;
558
559 INDENT_TO(ttl_column);
560 if ((ctx->style.flags & DNS_STYLEFLAG_TTL_UNITS) != 0) {
561 length = target->used;
562 result = dns_ttl_totext2(rdataset->ttl,
563 ISC_FALSE, ISC_FALSE,
564 target);
565 if (result != ISC_R_SUCCESS)
566 return (result);
567 column += target->used - length;
568 } else {
569 length = snprintf(ttlbuf, sizeof(ttlbuf), "%u",
570 rdataset->ttl);
571 INSIST(length <= sizeof(ttlbuf));
572 isc_buffer_availableregion(target, &r);
573 if (r.length < length)
574 return (ISC_R_NOSPACE);
575 memmove(r.base, ttlbuf, length);
576 isc_buffer_add(target, length);
577 column += length;
578 }
579
580 /*
581 * If the $TTL directive is not in use, the TTL we
582 * just printed becomes the default for subsequent RRs.
583 */
584 if ((ctx->style.flags & DNS_STYLEFLAG_TTL) == 0) {
585 current_ttl = rdataset->ttl;
586 current_ttl_valid = ISC_TRUE;
587 }
588 }
589
590 /*
591 * Class.
592 */
593 if ((ctx->style.flags & DNS_STYLEFLAG_NO_CLASS) == 0 &&
594 ((ctx->style.flags & DNS_STYLEFLAG_OMIT_CLASS) == 0 ||
595 ctx->class_printed == ISC_FALSE))
596 {
597 unsigned int class_start;
598 INDENT_TO(class_column);
599 class_start = target->used;
600 if ((ctx->style.flags & DNS_STYLEFLAG_UNKNOWNFORMAT) != 0)
601 result = dns_rdataclass_tounknowntext
602 (rdataset->rdclass, target);
603 else
604 result = dns_rdataclass_totext
605 (rdataset->rdclass, target);
606 if (result != ISC_R_SUCCESS)
607 return (result);
608 column += (target->used - class_start);
609 }
610
611 /*
612 * Type.
613 */
614
615 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
616 type = rdataset->covers;
617 } else {
618 type = rdataset->type;
619 }
620
621 INDENT_TO(type_column);
622 type_start = target->used;
623 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
624 RETERR(str_totext("\\-", target));
625 switch (type) {
626 case dns_rdatatype_keydata:
627 #define KEYDATA "KEYDATA"
628 if ((ctx->style.flags & DNS_STYLEFLAG_KEYDATA) != 0) {
629 if (isc_buffer_availablelength(target) <
630 (sizeof(KEYDATA) - 1))
631 return (ISC_R_NOSPACE);
632 isc_buffer_putstr(target, KEYDATA);
633 break;
634 }
635 /* FALLTHROUGH */
636 default:
637 if ((ctx->style.flags & DNS_STYLEFLAG_UNKNOWNFORMAT) != 0)
638 result = dns_rdatatype_tounknowntext(type, target);
639 else
640 result = dns_rdatatype_totext(type, target);
641 if (result != ISC_R_SUCCESS)
642 return (result);
643 }
644 column += (target->used - type_start);
645
646 /*
647 * Rdata.
648 */
649 INDENT_TO(rdata_column);
650 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
651 if ((ctx->style.flags & DNS_STYLEFLAG_INDENT) != 0 ||
652 (ctx->style.flags & DNS_STYLEFLAG_YAML) != 0)
653 {
654 for (i = 0; i < dns_master_indent; i++)
655 RETERR(str_totext(dns_master_indentstr,
656 target));
657 }
658 if (NXDOMAIN(rdataset))
659 RETERR(str_totext(";-$NXDOMAIN\n", target));
660 else
661 RETERR(str_totext(";-$NXRRSET\n", target));
662 /*
663 * Print a summary of the cached records which make
664 * up the negative response.
665 */
666 RETERR(ncache_summary(rdataset, omit_final_dot,
667 target));
668 break;
669 } else {
670 dns_rdata_t rdata = DNS_RDATA_INIT;
671 isc_region_t r;
672
673 dns_rdataset_current(rdataset, &rdata);
674
675 RETERR(dns_rdata_tofmttext(&rdata,
676 ctx->origin,
677 ctx->style.flags,
678 ctx->style.line_length -
679 ctx->style.rdata_column,
680 ctx->style.split_width,
681 ctx->linebreak,
682 target));
683
684 isc_buffer_availableregion(target, &r);
685 if (r.length < 1)
686 return (ISC_R_NOSPACE);
687 r.base[0] = '\n';
688 isc_buffer_add(target, 1);
689 }
690
691 first = ISC_FALSE;
692 result = dns_rdataset_next(rdataset);
693 }
694
695 if (result != ISC_R_NOMORE)
696 return (result);
697
698 /*
699 * Update the ctx state to reflect what we just printed.
700 * This is done last, only when we are sure we will return
701 * success, because this function may be called multiple
702 * times with increasing buffer sizes until it succeeds,
703 * and failed attempts must not update the state prematurely.
704 */
705 ctx->class_printed = ISC_TRUE;
706 ctx->current_ttl= current_ttl;
707 ctx->current_ttl_valid = current_ttl_valid;
708
709 return (ISC_R_SUCCESS);
710 }
711
712 /*
713 * Print the name, type, and class of an empty rdataset,
714 * such as those used to represent the question section
715 * of a DNS message.
716 */
717 static isc_result_t
718 question_totext(dns_rdataset_t *rdataset,
719 const dns_name_t *owner_name,
720 dns_totext_ctx_t *ctx,
721 isc_boolean_t omit_final_dot,
722 isc_buffer_t *target)
723 {
724 unsigned int column;
725 isc_result_t result;
726 isc_region_t r;
727
728 REQUIRE(DNS_RDATASET_VALID(rdataset));
729 result = dns_rdataset_first(rdataset);
730 REQUIRE(result == ISC_R_NOMORE);
731
732 column = 0;
733
734 /* Owner name */
735 {
736 unsigned int name_start = target->used;
737 RETERR(dns_name_totext(owner_name,
738 omit_final_dot,
739 target));
740 column += target->used - name_start;
741 }
742
743 /* Class */
744 {
745 unsigned int class_start;
746 INDENT_TO(class_column);
747 class_start = target->used;
748 if ((ctx->style.flags & DNS_STYLEFLAG_UNKNOWNFORMAT) != 0)
749 result = dns_rdataclass_tounknowntext(rdataset->rdclass,
750 target);
751 else
752 result = dns_rdataclass_totext(rdataset->rdclass,
753 target);
754 if (result != ISC_R_SUCCESS)
755 return (result);
756 column += (target->used - class_start);
757 }
758
759 /* Type */
760 {
761 unsigned int type_start;
762 INDENT_TO(type_column);
763 type_start = target->used;
764 if ((ctx->style.flags & DNS_STYLEFLAG_UNKNOWNFORMAT) != 0)
765 result = dns_rdatatype_tounknowntext(rdataset->type,
766 target);
767 else
768 result = dns_rdatatype_totext(rdataset->type,
769 target);
770 if (result != ISC_R_SUCCESS)
771 return (result);
772 column += (target->used - type_start);
773 }
774
775 isc_buffer_availableregion(target, &r);
776 if (r.length < 1)
777 return (ISC_R_NOSPACE);
778 r.base[0] = '\n';
779 isc_buffer_add(target, 1);
780
781 return (ISC_R_SUCCESS);
782 }
783
784 isc_result_t
785 dns_rdataset_totext(dns_rdataset_t *rdataset,
786 const dns_name_t *owner_name,
787 isc_boolean_t omit_final_dot,
788 isc_boolean_t question,
789 isc_buffer_t *target)
790 {
791 dns_totext_ctx_t ctx;
792 isc_result_t result;
793 result = totext_ctx_init(&dns_master_style_debug, &ctx);
794 if (result != ISC_R_SUCCESS) {
795 UNEXPECTED_ERROR(__FILE__, __LINE__,
796 "could not set master file style");
797 return (ISC_R_UNEXPECTED);
798 }
799
800 /*
801 * The caller might want to give us an empty owner
802 * name (e.g. if they are outputting into a master
803 * file and this rdataset has the same name as the
804 * previous one.)
805 */
806 if (dns_name_countlabels(owner_name) == 0)
807 owner_name = NULL;
808
809 if (question)
810 return (question_totext(rdataset, owner_name, &ctx,
811 omit_final_dot, target));
812 else
813 return (rdataset_totext(rdataset, owner_name, &ctx,
814 omit_final_dot, target));
815 }
816
817 isc_result_t
818 dns_master_rdatasettotext(const dns_name_t *owner_name,
819 dns_rdataset_t *rdataset,
820 const dns_master_style_t *style,
821 isc_buffer_t *target)
822 {
823 dns_totext_ctx_t ctx;
824 isc_result_t result;
825 result = totext_ctx_init(style, &ctx);
826 if (result != ISC_R_SUCCESS) {
827 UNEXPECTED_ERROR(__FILE__, __LINE__,
828 "could not set master file style");
829 return (ISC_R_UNEXPECTED);
830 }
831
832 return (rdataset_totext(rdataset, owner_name, &ctx,
833 ISC_FALSE, target));
834 }
835
836 isc_result_t
837 dns_master_questiontotext(const dns_name_t *owner_name,
838 dns_rdataset_t *rdataset,
839 const dns_master_style_t *style,
840 isc_buffer_t *target)
841 {
842 dns_totext_ctx_t ctx;
843 isc_result_t result;
844 result = totext_ctx_init(style, &ctx);
845 if (result != ISC_R_SUCCESS) {
846 UNEXPECTED_ERROR(__FILE__, __LINE__,
847 "could not set master file style");
848 return (ISC_R_UNEXPECTED);
849 }
850
851 return (question_totext(rdataset, owner_name, &ctx,
852 ISC_FALSE, target));
853 }
854
855 /*
856 * Print an rdataset. 'buffer' is a scratch buffer, which must have been
857 * dynamically allocated by the caller. It must be large enough to
858 * hold the result from dns_ttl_totext(). If more than that is needed,
859 * the buffer will be grown automatically.
860 */
861
862 static isc_result_t
863 dump_rdataset(isc_mem_t *mctx, const dns_name_t *name,
864 dns_rdataset_t *rdataset, dns_totext_ctx_t *ctx,
865 isc_buffer_t *buffer, FILE *f)
866 {
867 isc_region_t r;
868 isc_result_t result;
869
870 REQUIRE(buffer->length > 0);
871
872 /*
873 * Output a $TTL directive if needed.
874 */
875
876 if ((ctx->style.flags & DNS_STYLEFLAG_TTL) != 0) {
877 if (ctx->current_ttl_valid == ISC_FALSE ||
878 ctx->current_ttl != rdataset->ttl)
879 {
880 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENT) != 0)
881 {
882 isc_buffer_clear(buffer);
883 result = dns_ttl_totext(rdataset->ttl,
884 ISC_TRUE, buffer);
885 INSIST(result == ISC_R_SUCCESS);
886 isc_buffer_usedregion(buffer, &r);
887 fprintf(f, "$TTL %u\t; %.*s\n", rdataset->ttl,
888 (int) r.length, (char *) r.base);
889 } else {
890 fprintf(f, "$TTL %u\n", rdataset->ttl);
891 }
892 ctx->current_ttl = rdataset->ttl;
893 ctx->current_ttl_valid = ISC_TRUE;
894 }
895 }
896
897 isc_buffer_clear(buffer);
898
899 /*
900 * Generate the text representation of the rdataset into
901 * the buffer. If the buffer is too small, grow it.
902 */
903 for (;;) {
904 int newlength;
905 void *newmem;
906 result = rdataset_totext(rdataset, name, ctx,
907 ISC_FALSE, buffer);
908 if (result != ISC_R_NOSPACE)
909 break;
910
911 newlength = buffer->length * 2;
912 newmem = isc_mem_get(mctx, newlength);
913 if (newmem == NULL)
914 return (ISC_R_NOMEMORY);
915 isc_mem_put(mctx, buffer->base, buffer->length);
916 isc_buffer_init(buffer, newmem, newlength);
917 }
918 if (result != ISC_R_SUCCESS)
919 return (result);
920
921 /*
922 * Write the buffer contents to the master file.
923 */
924 isc_buffer_usedregion(buffer, &r);
925 result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL);
926
927 if (result != ISC_R_SUCCESS) {
928 UNEXPECTED_ERROR(__FILE__, __LINE__,
929 "master file write failed: %s",
930 isc_result_totext(result));
931 return (result);
932 }
933
934 return (ISC_R_SUCCESS);
935 }
936
937 /*
938 * Define the order in which rdatasets should be printed in zone
939 * files. We will print SOA and NS records before others, SIGs
940 * immediately following the things they sign, and order everything
941 * else by RR number. This is all just for aesthetics and
942 * compatibility with buggy software that expects the SOA to be first;
943 * the DNS specifications allow any order.
944 */
945
946 static int
947 dump_order(const dns_rdataset_t *rds) {
948 int t;
949 int sig;
950 if (rds->type == dns_rdatatype_rrsig) {
951 t = rds->covers;
952 sig = 1;
953 } else {
954 t = rds->type;
955 sig = 0;
956 }
957 switch (t) {
958 case dns_rdatatype_soa:
959 t = 0;
960 break;
961 case dns_rdatatype_ns:
962 t = 1;
963 break;
964 default:
965 t += 2;
966 break;
967 }
968 return (t << 1) + sig;
969 }
970
971 static int
972 dump_order_compare(const void *a, const void *b) {
973 return (dump_order(*((const dns_rdataset_t * const *) a)) -
974 dump_order(*((const dns_rdataset_t * const *) b)));
975 }
976
977 /*
978 * Dump all the rdatasets of a domain name to a master file. We make
979 * a "best effort" attempt to sort the RRsets in a nice order, but if
980 * there are more than MAXSORT RRsets, we punt and only sort them in
981 * groups of MAXSORT. This is not expected to ever happen in practice
982 * since much less than 64 RR types have been registered with the
983 * IANA, so far, and the output will be correct (though not
984 * aesthetically pleasing) even if it does happen.
985 */
986
987 #define MAXSORT 64
988
989 static isc_result_t
990 dump_rdatasets_text(isc_mem_t *mctx, const dns_name_t *name,
991 dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
992 isc_buffer_t *buffer, FILE *f)
993 {
994 isc_result_t itresult, dumpresult;
995 isc_region_t r;
996 dns_rdataset_t rdatasets[MAXSORT];
997 dns_rdataset_t *sorted[MAXSORT];
998 int i, n;
999
1000 itresult = dns_rdatasetiter_first(rdsiter);
1001 dumpresult = ISC_R_SUCCESS;
1002
1003 if (itresult == ISC_R_SUCCESS && ctx->neworigin != NULL) {
1004 isc_buffer_clear(buffer);
1005 itresult = dns_name_totext(ctx->neworigin, ISC_FALSE, buffer);
1006 RUNTIME_CHECK(itresult == ISC_R_SUCCESS);
1007 isc_buffer_usedregion(buffer, &r);
1008 fprintf(f, "$ORIGIN %.*s\n", (int) r.length, (char *) r.base);
1009 ctx->neworigin = NULL;
1010 }
1011
1012 again:
1013 for (i = 0;
1014 itresult == ISC_R_SUCCESS && i < MAXSORT;
1015 itresult = dns_rdatasetiter_next(rdsiter), i++) {
1016 dns_rdataset_init(&rdatasets[i]);
1017 dns_rdatasetiter_current(rdsiter, &rdatasets[i]);
1018 sorted[i] = &rdatasets[i];
1019 }
1020 n = i;
1021 INSIST(n <= MAXSORT);
1022
1023 qsort(sorted, n, sizeof(sorted[0]), dump_order_compare);
1024
1025 for (i = 0; i < n; i++) {
1026 dns_rdataset_t *rds = sorted[i];
1027 if (ctx->style.flags & DNS_STYLEFLAG_TRUST) {
1028 if ((ctx->style.flags & DNS_STYLEFLAG_INDENT) != 0 ||
1029 (ctx->style.flags & DNS_STYLEFLAG_YAML) != 0)
1030 {
1031 unsigned int j;
1032 for (j = 0; j < dns_master_indent; j++)
1033 fprintf(f, "%s", dns_master_indentstr);
1034 }
1035 fprintf(f, "; %s\n", dns_trust_totext(rds->trust));
1036 }
1037 if (((rds->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) &&
1038 (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
1039 /* Omit negative cache entries */
1040 } else {
1041 isc_result_t result;
1042 if (rds->ttl < ctx->serve_stale_ttl)
1043 fprintf(f, "; stale\n");
1044 result = dump_rdataset(mctx, name, rds, ctx, buffer, f);
1045 if (result != ISC_R_SUCCESS)
1046 dumpresult = result;
1047 if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0)
1048 name = NULL;
1049 }
1050 if (ctx->style.flags & DNS_STYLEFLAG_RESIGN &&
1051 rds->attributes & DNS_RDATASETATTR_RESIGN) {
1052 isc_buffer_t b;
1053 char buf[sizeof("YYYYMMDDHHMMSS")];
1054 memset(buf, 0, sizeof(buf));
1055 isc_buffer_init(&b, buf, sizeof(buf) - 1);
1056 dns_time64_totext((isc_uint64_t)rds->resign, &b);
1057 if ((ctx->style.flags & DNS_STYLEFLAG_INDENT) != 0 ||
1058 (ctx->style.flags & DNS_STYLEFLAG_YAML) != 0)
1059 {
1060 unsigned int j;
1061 for (j = 0; j < dns_master_indent; j++)
1062 fprintf(f, "%s", dns_master_indentstr);
1063 }
1064 fprintf(f, "; resign=%s\n", buf);
1065 }
1066 dns_rdataset_disassociate(rds);
1067 }
1068
1069 if (dumpresult != ISC_R_SUCCESS)
1070 return (dumpresult);
1071
1072 /*
1073 * If we got more data than could be sorted at once,
1074 * go handle the rest.
1075 */
1076 if (itresult == ISC_R_SUCCESS)
1077 goto again;
1078
1079 if (itresult == ISC_R_NOMORE)
1080 itresult = ISC_R_SUCCESS;
1081
1082 return (itresult);
1083 }
1084
1085 /*
1086 * Dump given RRsets in the "raw" format.
1087 */
1088 static isc_result_t
1089 dump_rdataset_raw(isc_mem_t *mctx, const dns_name_t *name,
1090 dns_rdataset_t *rdataset, isc_buffer_t *buffer, FILE *f)
1091 {
1092 isc_result_t result;
1093 isc_uint32_t totallen;
1094 isc_uint16_t dlen;
1095 isc_region_t r, r_hdr;
1096
1097 REQUIRE(buffer->length > 0);
1098 REQUIRE(DNS_RDATASET_VALID(rdataset));
1099
1100 rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
1101 restart:
1102 totallen = 0;
1103 result = dns_rdataset_first(rdataset);
1104 REQUIRE(result == ISC_R_SUCCESS);
1105
1106 isc_buffer_clear(buffer);
1107
1108 /*
1109 * Common header and owner name (length followed by name)
1110 * These fields should be in a moderate length, so we assume we
1111 * can store all of them in the initial buffer.
1112 */
1113 isc_buffer_availableregion(buffer, &r_hdr);
1114 INSIST(r_hdr.length >= sizeof(dns_masterrawrdataset_t));
1115 isc_buffer_putuint32(buffer, totallen); /* XXX: leave space */
1116 isc_buffer_putuint16(buffer, rdataset->rdclass); /* 16-bit class */
1117 isc_buffer_putuint16(buffer, rdataset->type); /* 16-bit type */
1118 isc_buffer_putuint16(buffer, rdataset->covers); /* same as type */
1119 isc_buffer_putuint32(buffer, rdataset->ttl); /* 32-bit TTL */
1120 isc_buffer_putuint32(buffer, dns_rdataset_count(rdataset));
1121 totallen = isc_buffer_usedlength(buffer);
1122 INSIST(totallen <= sizeof(dns_masterrawrdataset_t));
1123
1124 dns_name_toregion(name, &r);
1125 INSIST(isc_buffer_availablelength(buffer) >=
1126 (sizeof(dlen) + r.length));
1127 dlen = (isc_uint16_t)r.length;
1128 isc_buffer_putuint16(buffer, dlen);
1129 isc_buffer_copyregion(buffer, &r);
1130 totallen += sizeof(dlen) + r.length;
1131
1132 do {
1133 dns_rdata_t rdata = DNS_RDATA_INIT;
1134
1135 dns_rdataset_current(rdataset, &rdata);
1136 dns_rdata_toregion(&rdata, &r);
1137 INSIST(r.length <= 0xffffU);
1138 dlen = (isc_uint16_t)r.length;
1139
1140 /*
1141 * Copy the rdata into the buffer. If the buffer is too small,
1142 * grow it. This should be rare, so we'll simply restart the
1143 * entire procedure (or should we copy the old data and
1144 * continue?).
1145 */
1146 if (isc_buffer_availablelength(buffer) <
1147 sizeof(dlen) + r.length) {
1148 int newlength;
1149 void *newmem;
1150
1151 newlength = buffer->length * 2;
1152 newmem = isc_mem_get(mctx, newlength);
1153 if (newmem == NULL)
1154 return (ISC_R_NOMEMORY);
1155 isc_mem_put(mctx, buffer->base, buffer->length);
1156 isc_buffer_init(buffer, newmem, newlength);
1157 goto restart;
1158 }
1159 isc_buffer_putuint16(buffer, dlen);
1160 isc_buffer_copyregion(buffer, &r);
1161 totallen += sizeof(dlen) + r.length;
1162
1163 result = dns_rdataset_next(rdataset);
1164 } while (result == ISC_R_SUCCESS);
1165
1166 if (result != ISC_R_NOMORE)
1167 return (result);
1168
1169 /*
1170 * Fill in the total length field.
1171 * XXX: this is a bit tricky. Since we have already "used" the space
1172 * for the total length in the buffer, we first remember the entire
1173 * buffer length in the region, "rewind", and then write the value.
1174 */
1175 isc_buffer_usedregion(buffer, &r);
1176 isc_buffer_clear(buffer);
1177 isc_buffer_putuint32(buffer, totallen);
1178 INSIST(isc_buffer_usedlength(buffer) < totallen);
1179
1180 /*
1181 * Write the buffer contents to the raw master file.
1182 */
1183 result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL);
1184
1185 if (result != ISC_R_SUCCESS) {
1186 UNEXPECTED_ERROR(__FILE__, __LINE__,
1187 "raw master file write failed: %s",
1188 isc_result_totext(result));
1189 return (result);
1190 }
1191
1192 return (result);
1193 }
1194
1195 static isc_result_t
1196 dump_rdatasets_raw(isc_mem_t *mctx, const dns_name_t *name,
1197 dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
1198 isc_buffer_t *buffer, FILE *f)
1199 {
1200 isc_result_t result;
1201 dns_rdataset_t rdataset;
1202
1203 for (result = dns_rdatasetiter_first(rdsiter);
1204 result == ISC_R_SUCCESS;
1205 result = dns_rdatasetiter_next(rdsiter)) {
1206
1207 dns_rdataset_init(&rdataset);
1208 dns_rdatasetiter_current(rdsiter, &rdataset);
1209
1210 if (((rdataset.attributes & DNS_RDATASETATTR_NEGATIVE) != 0) &&
1211 (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
1212 /* Omit negative cache entries */
1213 } else {
1214 result = dump_rdataset_raw(mctx, name, &rdataset,
1215 buffer, f);
1216 }
1217 dns_rdataset_disassociate(&rdataset);
1218 if (result != ISC_R_SUCCESS)
1219 return (result);
1220 }
1221
1222 if (result == ISC_R_NOMORE)
1223 result = ISC_R_SUCCESS;
1224
1225 return (result);
1226 }
1227
1228 static isc_result_t
1229 dump_rdatasets_map(isc_mem_t *mctx, const dns_name_t *name,
1230 dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
1231 isc_buffer_t *buffer, FILE *f)
1232 {
1233 UNUSED(mctx);
1234 UNUSED(name);
1235 UNUSED(rdsiter);
1236 UNUSED(ctx);
1237 UNUSED(buffer);
1238 UNUSED(f);
1239
1240 return (ISC_R_NOTIMPLEMENTED);
1241 }
1242
1243 /*
1244 * Initial size of text conversion buffer. The buffer is used
1245 * for several purposes: converting origin names, rdatasets,
1246 * $DATE timestamps, and comment strings for $TTL directives.
1247 *
1248 * When converting rdatasets, it is dynamically resized, but
1249 * when converting origins, timestamps, etc it is not. Therefore,
1250 * the initial size must large enough to hold the longest possible
1251 * text representation of any domain name (for $ORIGIN).
1252 */
1253 static const int initial_buffer_length = 1200;
1254
1255 static isc_result_t
1256 dumptostreaminc(dns_dumpctx_t *dctx);
1257
1258 static void
1259 dumpctx_destroy(dns_dumpctx_t *dctx) {
1260
1261 dctx->magic = 0;
1262 DESTROYLOCK(&dctx->lock);
1263 dns_dbiterator_destroy(&dctx->dbiter);
1264 if (dctx->version != NULL)
1265 dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
1266 dns_db_detach(&dctx->db);
1267 if (dctx->task != NULL)
1268 isc_task_detach(&dctx->task);
1269 if (dctx->file != NULL)
1270 isc_mem_free(dctx->mctx, dctx->file);
1271 if (dctx->tmpfile != NULL)
1272 isc_mem_free(dctx->mctx, dctx->tmpfile);
1273 isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(*dctx));
1274 }
1275
1276 void
1277 dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target) {
1278
1279 REQUIRE(DNS_DCTX_VALID(source));
1280 REQUIRE(target != NULL && *target == NULL);
1281
1282 LOCK(&source->lock);
1283 INSIST(source->references > 0);
1284 source->references++;
1285 INSIST(source->references != 0); /* Overflow? */
1286 UNLOCK(&source->lock);
1287
1288 *target = source;
1289 }
1290
1291 void
1292 dns_dumpctx_detach(dns_dumpctx_t **dctxp) {
1293 dns_dumpctx_t *dctx;
1294 isc_boolean_t need_destroy = ISC_FALSE;
1295
1296 REQUIRE(dctxp != NULL);
1297 dctx = *dctxp;
1298 REQUIRE(DNS_DCTX_VALID(dctx));
1299
1300 *dctxp = NULL;
1301
1302 LOCK(&dctx->lock);
1303 INSIST(dctx->references != 0);
1304 dctx->references--;
1305 if (dctx->references == 0)
1306 need_destroy = ISC_TRUE;
1307 UNLOCK(&dctx->lock);
1308 if (need_destroy)
1309 dumpctx_destroy(dctx);
1310 }
1311
1312 dns_dbversion_t *
1313 dns_dumpctx_version(dns_dumpctx_t *dctx) {
1314 REQUIRE(DNS_DCTX_VALID(dctx));
1315 return (dctx->version);
1316 }
1317
1318 dns_db_t *
1319 dns_dumpctx_db(dns_dumpctx_t *dctx) {
1320 REQUIRE(DNS_DCTX_VALID(dctx));
1321 return (dctx->db);
1322 }
1323
1324 void
1325 dns_dumpctx_cancel(dns_dumpctx_t *dctx) {
1326 REQUIRE(DNS_DCTX_VALID(dctx));
1327
1328 LOCK(&dctx->lock);
1329 dctx->canceled = ISC_TRUE;
1330 UNLOCK(&dctx->lock);
1331 }
1332
1333 static isc_result_t
1334 flushandsync(FILE *f, isc_result_t result, const char *temp) {
1335 isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS);
1336
1337 if (result == ISC_R_SUCCESS)
1338 result = isc_stdio_flush(f);
1339 if (result != ISC_R_SUCCESS && logit) {
1340 if (temp != NULL)
1341 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1342 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1343 "dumping to master file: %s: flush: %s",
1344 temp, isc_result_totext(result));
1345 else
1346 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1347 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1348 "dumping to stream: flush: %s",
1349 isc_result_totext(result));
1350 logit = ISC_FALSE;
1351 }
1352
1353 if (result == ISC_R_SUCCESS)
1354 result = isc_stdio_sync(f);
1355 if (result != ISC_R_SUCCESS && logit) {
1356 if (temp != NULL)
1357 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1358 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1359 "dumping to master file: %s: fsync: %s",
1360 temp, isc_result_totext(result));
1361 else
1362 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1363 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1364 "dumping to stream: fsync: %s",
1365 isc_result_totext(result));
1366 }
1367 return (result);
1368 }
1369
1370 static isc_result_t
1371 closeandrename(FILE *f, isc_result_t result, const char *temp, const char *file)
1372 {
1373 isc_result_t tresult;
1374 isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS);
1375
1376 result = flushandsync(f, result, temp);
1377 if (result != ISC_R_SUCCESS)
1378 logit = ISC_FALSE;
1379
1380 tresult = isc_stdio_close(f);
1381 if (result == ISC_R_SUCCESS)
1382 result = tresult;
1383 if (result != ISC_R_SUCCESS && logit) {
1384 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1385 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1386 "dumping master file: %s: fclose: %s",
1387 temp, isc_result_totext(result));
1388 logit = ISC_FALSE;
1389 }
1390 if (result == ISC_R_SUCCESS)
1391 result = isc_file_rename(temp, file);
1392 else
1393 (void)isc_file_remove(temp);
1394 if (result != ISC_R_SUCCESS && logit) {
1395 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1396 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1397 "dumping master file: rename: %s: %s",
1398 file, isc_result_totext(result));
1399 }
1400 return (result);
1401 }
1402
1403 static void
1404 dump_quantum(isc_task_t *task, isc_event_t *event) {
1405 isc_result_t result;
1406 isc_result_t tresult;
1407 dns_dumpctx_t *dctx;
1408
1409 REQUIRE(event != NULL);
1410 dctx = event->ev_arg;
1411 REQUIRE(DNS_DCTX_VALID(dctx));
1412 if (dctx->canceled)
1413 result = ISC_R_CANCELED;
1414 else
1415 result = dumptostreaminc(dctx);
1416 if (result == DNS_R_CONTINUE) {
1417 event->ev_arg = dctx;
1418 isc_task_send(task, &event);
1419 return;
1420 }
1421
1422 if (dctx->file != NULL) {
1423 tresult = closeandrename(dctx->f, result,
1424 dctx->tmpfile, dctx->file);
1425 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1426 result = tresult;
1427 } else
1428 result = flushandsync(dctx->f, result, NULL);
1429 (dctx->done)(dctx->done_arg, result);
1430 isc_event_free(&event);
1431 dns_dumpctx_detach(&dctx);
1432 }
1433
1434 static isc_result_t
1435 task_send(dns_dumpctx_t *dctx) {
1436 isc_event_t *event;
1437
1438 event = isc_event_allocate(dctx->mctx, NULL, DNS_EVENT_DUMPQUANTUM,
1439 dump_quantum, dctx, sizeof(*event));
1440 if (event == NULL)
1441 return (ISC_R_NOMEMORY);
1442 isc_task_send(dctx->task, &event);
1443 return (ISC_R_SUCCESS);
1444 }
1445
1446 static isc_result_t
1447 dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1448 const dns_master_style_t *style, FILE *f, dns_dumpctx_t **dctxp,
1449 dns_masterformat_t format, dns_masterrawheader_t *header)
1450 {
1451 dns_dumpctx_t *dctx;
1452 isc_result_t result;
1453 unsigned int options;
1454
1455 dctx = isc_mem_get(mctx, sizeof(*dctx));
1456 if (dctx == NULL)
1457 return (ISC_R_NOMEMORY);
1458
1459 dctx->mctx = NULL;
1460 dctx->f = f;
1461 dctx->dbiter = NULL;
1462 dctx->db = NULL;
1463 dctx->version = NULL;
1464 dctx->done = NULL;
1465 dctx->done_arg = NULL;
1466 dctx->task = NULL;
1467 dctx->nodes = 0;
1468 dctx->first = ISC_TRUE;
1469 dctx->canceled = ISC_FALSE;
1470 dctx->file = NULL;
1471 dctx->tmpfile = NULL;
1472 dctx->format = format;
1473 if (header == NULL)
1474 dns_master_initrawheader(&dctx->header);
1475 else
1476 dctx->header = *header;
1477
1478 switch (format) {
1479 case dns_masterformat_text:
1480 dctx->dumpsets = dump_rdatasets_text;
1481 break;
1482 case dns_masterformat_raw:
1483 dctx->dumpsets = dump_rdatasets_raw;
1484 break;
1485 case dns_masterformat_map:
1486 dctx->dumpsets = dump_rdatasets_map;
1487 break;
1488 default:
1489 INSIST(0);
1490 break;
1491 }
1492
1493 result = totext_ctx_init(style, &dctx->tctx);
1494 if (result != ISC_R_SUCCESS) {
1495 UNEXPECTED_ERROR(__FILE__, __LINE__,
1496 "could not set master file style");
1497 goto cleanup;
1498 }
1499
1500 isc_stdtime_get(&dctx->now);
1501 dns_db_attach(db, &dctx->db);
1502
1503 dctx->do_date = dns_db_iscache(dctx->db);
1504 if (dctx->do_date) {
1505 /*
1506 * Adjust the date backwards by the serve-stale TTL, if any.
1507 * This is so the TTL will be loaded correctly when next started.
1508 */
1509 (void)dns_db_getservestalettl(dctx->db,
1510 &dctx->tctx.serve_stale_ttl);
1511 dctx->now -= dctx->tctx.serve_stale_ttl;
1512 }
1513
1514 if (dctx->format == dns_masterformat_text &&
1515 (dctx->tctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) {
1516 options = DNS_DB_RELATIVENAMES;
1517 } else
1518 options = 0;
1519 result = dns_db_createiterator(dctx->db, options, &dctx->dbiter);
1520 if (result != ISC_R_SUCCESS)
1521 goto cleanup;
1522
1523 result = isc_mutex_init(&dctx->lock);
1524 if (result != ISC_R_SUCCESS)
1525 goto cleanup;
1526 if (version != NULL)
1527 dns_db_attachversion(dctx->db, version, &dctx->version);
1528 else if (!dns_db_iscache(db))
1529 dns_db_currentversion(dctx->db, &dctx->version);
1530 isc_mem_attach(mctx, &dctx->mctx);
1531 dctx->references = 1;
1532 dctx->magic = DNS_DCTX_MAGIC;
1533 *dctxp = dctx;
1534 return (ISC_R_SUCCESS);
1535
1536 cleanup:
1537 if (dctx->dbiter != NULL)
1538 dns_dbiterator_destroy(&dctx->dbiter);
1539 if (dctx->db != NULL)
1540 dns_db_detach(&dctx->db);
1541 if (dctx != NULL)
1542 isc_mem_put(mctx, dctx, sizeof(*dctx));
1543 return (result);
1544 }
1545
1546 static isc_result_t
1547 writeheader(dns_dumpctx_t *dctx) {
1548 isc_result_t result = ISC_R_SUCCESS;
1549 isc_buffer_t buffer;
1550 char *bufmem;
1551 isc_region_t r;
1552 dns_masterrawheader_t rawheader;
1553 isc_uint32_t rawversion, now32;
1554
1555 bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
1556 if (bufmem == NULL)
1557 return (ISC_R_NOMEMORY);
1558
1559 isc_buffer_init(&buffer, bufmem, initial_buffer_length);
1560
1561 switch (dctx->format) {
1562 case dns_masterformat_text:
1563 /*
1564 * If the database has cache semantics, output an
1565 * RFC2540 $DATE directive so that the TTLs can be
1566 * adjusted when it is reloaded. For zones it is not
1567 * really needed, and it would make the file
1568 * incompatible with pre-RFC2540 software, so we omit
1569 * it in the zone case.
1570 */
1571 if (dctx->do_date) {
1572 fprintf(dctx->f,
1573 "; using a %u second stale ttl\n",
1574 dctx->tctx.serve_stale_ttl);
1575 result = dns_time32_totext(dctx->now, &buffer);
1576 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1577 isc_buffer_usedregion(&buffer, &r);
1578 fprintf(dctx->f, "$DATE %.*s\n",
1579 (int) r.length, (char *) r.base);
1580 }
1581 break;
1582 case dns_masterformat_raw:
1583 case dns_masterformat_map:
1584 r.base = (unsigned char *)&rawheader;
1585 r.length = sizeof(rawheader);
1586 isc_buffer_region(&buffer, &r);
1587 #if !defined(STDTIME_ON_32BITS) || (STDTIME_ON_32BITS + 0) != 1
1588 /*
1589 * We assume isc_stdtime_t is a 32-bit integer,
1590 * which should be the case on most platforms.
1591 * If it turns out to be uncommon, we'll need
1592 * to bump the version number and revise the
1593 * header format.
1594 */
1595 isc_log_write(dns_lctx,
1596 ISC_LOGCATEGORY_GENERAL,
1597 DNS_LOGMODULE_MASTERDUMP,
1598 ISC_LOG_INFO,
1599 "dumping master file in raw "
1600 "format: stdtime is not 32bits");
1601 now32 = 0;
1602 #else
1603 now32 = dctx->now;
1604 #endif
1605 rawversion = 1;
1606 if ((dctx->header.flags & DNS_MASTERRAW_COMPAT) != 0)
1607 rawversion = 0;
1608
1609 isc_buffer_putuint32(&buffer, dctx->format);
1610 isc_buffer_putuint32(&buffer, rawversion);
1611 isc_buffer_putuint32(&buffer, now32);
1612
1613 if (rawversion == 1) {
1614 isc_buffer_putuint32(&buffer, dctx->header.flags);
1615 isc_buffer_putuint32(&buffer,
1616 dctx->header.sourceserial);
1617 isc_buffer_putuint32(&buffer, dctx->header.lastxfrin);
1618 }
1619
1620 INSIST(isc_buffer_usedlength(&buffer) <= sizeof(rawheader));
1621 result = isc_stdio_write(buffer.base, 1,
1622 isc_buffer_usedlength(&buffer),
1623 dctx->f, NULL);
1624 if (result != ISC_R_SUCCESS)
1625 break;
1626
1627 break;
1628 default:
1629 INSIST(0);
1630 }
1631
1632 isc_mem_put(dctx->mctx, buffer.base, buffer.length);
1633 return (result);
1634 }
1635
1636 static isc_result_t
1637 dumptostreaminc(dns_dumpctx_t *dctx) {
1638 isc_result_t result = ISC_R_SUCCESS;
1639 isc_buffer_t buffer;
1640 char *bufmem;
1641 dns_name_t *name;
1642 dns_fixedname_t fixname;
1643 unsigned int nodes;
1644 isc_time_t start;
1645
1646 bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
1647 if (bufmem == NULL)
1648 return (ISC_R_NOMEMORY);
1649
1650 isc_buffer_init(&buffer, bufmem, initial_buffer_length);
1651
1652 name = dns_fixedname_initname(&fixname);
1653
1654 if (dctx->first) {
1655 CHECK(writeheader(dctx));
1656
1657 /*
1658 * Fast format is not currently written incrementally,
1659 * so we make the call to dns_db_serialize() here.
1660 * If the database is anything other than an rbtdb,
1661 * this should result in not implemented
1662 */
1663 if (dctx->format == dns_masterformat_map) {
1664 result = dns_db_serialize(dctx->db, dctx->version,
1665 dctx->f);
1666 goto cleanup;
1667 }
1668
1669 result = dns_dbiterator_first(dctx->dbiter);
1670 if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
1671 goto cleanup;
1672
1673 dctx->first = ISC_FALSE;
1674 } else
1675 result = ISC_R_SUCCESS;
1676
1677 nodes = dctx->nodes;
1678 isc_time_now(&start);
1679 while (result == ISC_R_SUCCESS && (dctx->nodes == 0 || nodes--)) {
1680 dns_rdatasetiter_t *rdsiter = NULL;
1681 dns_dbnode_t *node = NULL;
1682
1683 result = dns_dbiterator_current(dctx->dbiter, &node, name);
1684 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
1685 break;
1686 if (result == DNS_R_NEWORIGIN) {
1687 dns_name_t *origin =
1688 dns_fixedname_name(&dctx->tctx.origin_fixname);
1689 result = dns_dbiterator_origin(dctx->dbiter, origin);
1690 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1691 if ((dctx->tctx.style.flags &
1692 DNS_STYLEFLAG_REL_DATA) != 0)
1693 dctx->tctx.origin = origin;
1694 dctx->tctx.neworigin = origin;
1695 }
1696 result = dns_db_allrdatasets(dctx->db, node, dctx->version,
1697 dctx->now, &rdsiter);
1698 if (result != ISC_R_SUCCESS) {
1699 dns_db_detachnode(dctx->db, &node);
1700 goto cleanup;
1701 }
1702 result = (dctx->dumpsets)(dctx->mctx, name, rdsiter,
1703 &dctx->tctx, &buffer, dctx->f);
1704 dns_rdatasetiter_destroy(&rdsiter);
1705 if (result != ISC_R_SUCCESS) {
1706 dns_db_detachnode(dctx->db, &node);
1707 goto cleanup;
1708 }
1709 dns_db_detachnode(dctx->db, &node);
1710 result = dns_dbiterator_next(dctx->dbiter);
1711 }
1712
1713 /*
1714 * Work out how many nodes can be written in the time between
1715 * two requests to the nameserver. Smooth the resulting number and
1716 * use it as a estimate for the number of nodes to be written in the
1717 * next iteration.
1718 */
1719 if (dctx->nodes != 0 && result == ISC_R_SUCCESS) {
1720 unsigned int pps = dns_pps; /* packets per second */
1721 unsigned int interval;
1722 isc_uint64_t usecs;
1723 isc_time_t end;
1724
1725 isc_time_now(&end);
1726 if (pps < 100)
1727 pps = 100;
1728 interval = 1000000 / pps; /* interval in usecs */
1729 if (interval == 0)
1730 interval = 1;
1731 usecs = isc_time_microdiff(&end, &start);
1732 if (usecs == 0) {
1733 dctx->nodes = dctx->nodes * 2;
1734 if (dctx->nodes > 1000)
1735 dctx->nodes = 1000;
1736 } else {
1737 nodes = dctx->nodes * interval;
1738 nodes /= (unsigned int)usecs;
1739 if (nodes == 0)
1740 nodes = 1;
1741 else if (nodes > 1000)
1742 nodes = 1000;
1743
1744 /* Smooth and assign. */
1745 dctx->nodes = (nodes + dctx->nodes * 7) / 8;
1746
1747 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1748 DNS_LOGMODULE_MASTERDUMP,
1749 ISC_LOG_DEBUG(1),
1750 "dumptostreaminc(%p) new nodes -> %d",
1751 dctx, dctx->nodes);
1752 }
1753 result = DNS_R_CONTINUE;
1754 } else if (result == ISC_R_NOMORE)
1755 result = ISC_R_SUCCESS;
1756 cleanup:
1757 RUNTIME_CHECK(dns_dbiterator_pause(dctx->dbiter) == ISC_R_SUCCESS);
1758 isc_mem_put(dctx->mctx, buffer.base, buffer.length);
1759 return (result);
1760 }
1761
1762 isc_result_t
1763 dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db,
1764 dns_dbversion_t *version,
1765 const dns_master_style_t *style,
1766 FILE *f, isc_task_t *task,
1767 dns_dumpdonefunc_t done, void *done_arg,
1768 dns_dumpctx_t **dctxp)
1769 {
1770 dns_dumpctx_t *dctx = NULL;
1771 isc_result_t result;
1772
1773 REQUIRE(task != NULL);
1774 REQUIRE(f != NULL);
1775 REQUIRE(done != NULL);
1776
1777 result = dumpctx_create(mctx, db, version, style, f, &dctx,
1778 dns_masterformat_text, NULL);
1779 if (result != ISC_R_SUCCESS)
1780 return (result);
1781 isc_task_attach(task, &dctx->task);
1782 dctx->done = done;
1783 dctx->done_arg = done_arg;
1784 dctx->nodes = 100;
1785
1786 result = task_send(dctx);
1787 if (result == ISC_R_SUCCESS) {
1788 dns_dumpctx_attach(dctx, dctxp);
1789 return (DNS_R_CONTINUE);
1790 }
1791
1792 dns_dumpctx_detach(&dctx);
1793 return (result);
1794 }
1795
1796 /*
1797 * Dump an entire database into a master file.
1798 */
1799 isc_result_t
1800 dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db,
1801 dns_dbversion_t *version,
1802 const dns_master_style_t *style,
1803 FILE *f)
1804 {
1805 return (dns_master_dumptostream3(mctx, db, version, style,
1806 dns_masterformat_text, NULL, f));
1807 }
1808
1809 isc_result_t
1810 dns_master_dumptostream2(isc_mem_t *mctx, dns_db_t *db,
1811 dns_dbversion_t *version,
1812 const dns_master_style_t *style,
1813 dns_masterformat_t format, FILE *f)
1814 {
1815 return (dns_master_dumptostream3(mctx, db, version, style,
1816 format, NULL, f));
1817 }
1818
1819 isc_result_t
1820 dns_master_dumptostream3(isc_mem_t *mctx, dns_db_t *db,
1821 dns_dbversion_t *version,
1822 const dns_master_style_t *style,
1823 dns_masterformat_t format,
1824 dns_masterrawheader_t *header, FILE *f)
1825 {
1826 dns_dumpctx_t *dctx = NULL;
1827 isc_result_t result;
1828
1829 result = dumpctx_create(mctx, db, version, style, f, &dctx,
1830 format, header);
1831 if (result != ISC_R_SUCCESS)
1832 return (result);
1833
1834 result = dumptostreaminc(dctx);
1835 INSIST(result != DNS_R_CONTINUE);
1836 dns_dumpctx_detach(&dctx);
1837
1838 result = flushandsync(f, result, NULL);
1839 return (result);
1840 }
1841
1842 static isc_result_t
1843 opentmp(isc_mem_t *mctx, dns_masterformat_t format, const char *file,
1844 char **tempp, FILE **fp) {
1845 FILE *f = NULL;
1846 isc_result_t result;
1847 char *tempname = NULL;
1848 int tempnamelen;
1849
1850 tempnamelen = strlen(file) + 20;
1851 tempname = isc_mem_allocate(mctx, tempnamelen);
1852 if (tempname == NULL)
1853 return (ISC_R_NOMEMORY);
1854
1855 result = isc_file_mktemplate(file, tempname, tempnamelen);
1856 if (result != ISC_R_SUCCESS)
1857 goto cleanup;
1858
1859 if (format == dns_masterformat_text)
1860 result = isc_file_openunique(tempname, &f);
1861 else
1862 result = isc_file_bopenunique(tempname, &f);
1863 if (result != ISC_R_SUCCESS) {
1864 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1865 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1866 "dumping master file: %s: open: %s",
1867 tempname, isc_result_totext(result));
1868 goto cleanup;
1869 }
1870 *tempp = tempname;
1871 *fp = f;
1872 return (ISC_R_SUCCESS);
1873
1874 cleanup:
1875 isc_mem_free(mctx, tempname);
1876 return (result);
1877 }
1878
1879 isc_result_t
1880 dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1881 const dns_master_style_t *style, const char *filename,
1882 isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
1883 dns_dumpctx_t **dctxp)
1884 {
1885 return (dns_master_dumpinc3(mctx, db, version, style, filename, task,
1886 done, done_arg, dctxp,
1887 dns_masterformat_text, NULL));
1888 }
1889
1890 isc_result_t
1891 dns_master_dumpinc2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1892 const dns_master_style_t *style, const char *filename,
1893 isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
1894 dns_dumpctx_t **dctxp, dns_masterformat_t format)
1895 {
1896 return (dns_master_dumpinc3(mctx, db, version, style, filename, task,
1897 done, done_arg, dctxp, format, NULL));
1898 }
1899
1900 isc_result_t
1901 dns_master_dumpinc3(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1902 const dns_master_style_t *style, const char *filename,
1903 isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
1904 dns_dumpctx_t **dctxp, dns_masterformat_t format,
1905 dns_masterrawheader_t *header)
1906 {
1907 FILE *f = NULL;
1908 isc_result_t result;
1909 char *tempname = NULL;
1910 char *file = NULL;
1911 dns_dumpctx_t *dctx = NULL;
1912
1913 file = isc_mem_strdup(mctx, filename);
1914 if (file == NULL)
1915 return (ISC_R_NOMEMORY);
1916
1917 result = opentmp(mctx, format, filename, &tempname, &f);
1918 if (result != ISC_R_SUCCESS)
1919 goto cleanup;
1920
1921 result = dumpctx_create(mctx, db, version, style, f, &dctx,
1922 format, header);
1923 if (result != ISC_R_SUCCESS) {
1924 (void)isc_stdio_close(f);
1925 (void)isc_file_remove(tempname);
1926 goto cleanup;
1927 }
1928
1929 isc_task_attach(task, &dctx->task);
1930 dctx->done = done;
1931 dctx->done_arg = done_arg;
1932 dctx->nodes = 100;
1933 dctx->file = file;
1934 file = NULL;
1935 dctx->tmpfile = tempname;
1936 tempname = NULL;
1937
1938 result = task_send(dctx);
1939 if (result == ISC_R_SUCCESS) {
1940 dns_dumpctx_attach(dctx, dctxp);
1941 return (DNS_R_CONTINUE);
1942 }
1943
1944 cleanup:
1945 if (dctx != NULL)
1946 dns_dumpctx_detach(&dctx);
1947 if (file != NULL)
1948 isc_mem_free(mctx, file);
1949 if (tempname != NULL)
1950 isc_mem_free(mctx, tempname);
1951 return (result);
1952 }
1953
1954 isc_result_t
1955 dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1956 const dns_master_style_t *style, const char *filename)
1957 {
1958 return (dns_master_dump3(mctx, db, version, style, filename,
1959 dns_masterformat_text, NULL));
1960 }
1961
1962 isc_result_t
1963 dns_master_dump2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1964 const dns_master_style_t *style, const char *filename,
1965 dns_masterformat_t format)
1966 {
1967 return (dns_master_dump3(mctx, db, version, style, filename,
1968 format, NULL));
1969 }
1970
1971 isc_result_t
1972 dns_master_dump3(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1973 const dns_master_style_t *style, const char *filename,
1974 dns_masterformat_t format, dns_masterrawheader_t *header)
1975 {
1976 FILE *f = NULL;
1977 isc_result_t result;
1978 char *tempname;
1979 dns_dumpctx_t *dctx = NULL;
1980
1981 result = opentmp(mctx, format, filename, &tempname, &f);
1982 if (result != ISC_R_SUCCESS)
1983 return (result);
1984
1985 result = dumpctx_create(mctx, db, version, style, f, &dctx,
1986 format, header);
1987 if (result != ISC_R_SUCCESS)
1988 goto cleanup;
1989
1990 result = dumptostreaminc(dctx);
1991 INSIST(result != DNS_R_CONTINUE);
1992 dns_dumpctx_detach(&dctx);
1993
1994 result = closeandrename(f, result, tempname, filename);
1995
1996 cleanup:
1997 isc_mem_free(mctx, tempname);
1998 return (result);
1999 }
2000
2001 /*
2002 * Dump a database node into a master file.
2003 * XXX: this function assumes the text format.
2004 */
2005 isc_result_t
2006 dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db,
2007 dns_dbversion_t *version,
2008 dns_dbnode_t *node, const dns_name_t *name,
2009 const dns_master_style_t *style,
2010 FILE *f)
2011 {
2012 isc_result_t result;
2013 isc_buffer_t buffer;
2014 char *bufmem;
2015 isc_stdtime_t now;
2016 dns_totext_ctx_t ctx;
2017 dns_rdatasetiter_t *rdsiter = NULL;
2018
2019 result = totext_ctx_init(style, &ctx);
2020 if (result != ISC_R_SUCCESS) {
2021 UNEXPECTED_ERROR(__FILE__, __LINE__,
2022 "could not set master file style");
2023 return (ISC_R_UNEXPECTED);
2024 }
2025
2026 isc_stdtime_get(&now);
2027
2028 bufmem = isc_mem_get(mctx, initial_buffer_length);
2029 if (bufmem == NULL)
2030 return (ISC_R_NOMEMORY);
2031
2032 isc_buffer_init(&buffer, bufmem, initial_buffer_length);
2033
2034 result = dns_db_allrdatasets(db, node, version, now, &rdsiter);
2035 if (result != ISC_R_SUCCESS)
2036 goto failure;
2037 result = dump_rdatasets_text(mctx, name, rdsiter, &ctx, &buffer, f);
2038 if (result != ISC_R_SUCCESS)
2039 goto failure;
2040 dns_rdatasetiter_destroy(&rdsiter);
2041
2042 result = ISC_R_SUCCESS;
2043
2044 failure:
2045 isc_mem_put(mctx, buffer.base, buffer.length);
2046 return (result);
2047 }
2048
2049 isc_result_t
2050 dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
2051 dns_dbnode_t *node, const dns_name_t *name,
2052 const dns_master_style_t *style, const char *filename)
2053 {
2054 FILE *f = NULL;
2055 isc_result_t result;
2056
2057 result = isc_stdio_open(filename, "w", &f);
2058 if (result != ISC_R_SUCCESS) {
2059 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
2060 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
2061 "dumping node to file: %s: open: %s", filename,
2062 isc_result_totext(result));
2063 return (ISC_R_UNEXPECTED);
2064 }
2065
2066 result = dns_master_dumpnodetostream(mctx, db, version, node, name,
2067 style, f);
2068 if (result != ISC_R_SUCCESS) {
2069 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
2070 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
2071 "dumping master file: %s: dump: %s", filename,
2072 isc_result_totext(result));
2073 (void)isc_stdio_close(f);
2074 return (ISC_R_UNEXPECTED);
2075 }
2076
2077 result = isc_stdio_close(f);
2078 if (result != ISC_R_SUCCESS) {
2079 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
2080 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
2081 "dumping master file: %s: close: %s", filename,
2082 isc_result_totext(result));
2083 return (ISC_R_UNEXPECTED);
2084 }
2085
2086 return (result);
2087 }
2088
2089 dns_masterstyle_flags_t
2090 dns_master_styleflags(const dns_master_style_t *style) {
2091 REQUIRE(style != NULL);
2092 return (style->flags);
2093 }
2094
2095 isc_result_t
2096 dns_master_stylecreate(dns_master_style_t **stylep,
2097 dns_masterstyle_flags_t flags,
2098 unsigned int ttl_column, unsigned int class_column,
2099 unsigned int type_column, unsigned int rdata_column,
2100 unsigned int line_length, unsigned int tab_width,
2101 isc_mem_t *mctx)
2102 {
2103 return (dns_master_stylecreate2(stylep, flags, ttl_column,
2104 class_column, type_column,
2105 rdata_column, line_length,
2106 tab_width, 0xffffffff, mctx));
2107 }
2108
2109 isc_result_t
2110 dns_master_stylecreate2(dns_master_style_t **stylep,
2111 dns_masterstyle_flags_t flags,
2112 unsigned int ttl_column, unsigned int class_column,
2113 unsigned int type_column, unsigned int rdata_column,
2114 unsigned int line_length, unsigned int tab_width,
2115 unsigned int split_width, isc_mem_t *mctx)
2116 {
2117 dns_master_style_t *style;
2118
2119 REQUIRE(stylep != NULL && *stylep == NULL);
2120 style = isc_mem_get(mctx, sizeof(*style));
2121 if (style == NULL)
2122 return (ISC_R_NOMEMORY);
2123
2124 style->flags = flags;
2125 style->ttl_column = ttl_column;
2126 style->class_column = class_column;
2127 style->type_column = type_column;
2128 style->rdata_column = rdata_column;
2129 style->line_length = line_length;
2130 style->tab_width = tab_width;
2131 style->split_width = split_width;
2132 *stylep = style;
2133 return (ISC_R_SUCCESS);
2134 }
2135
2136 void
2137 dns_master_styledestroy(dns_master_style_t **stylep, isc_mem_t *mctx) {
2138 dns_master_style_t *style;
2139
2140 REQUIRE(stylep != NULL && *stylep != NULL);
2141 style = *stylep;
2142 *stylep = NULL;
2143 isc_mem_put(mctx, style, sizeof(*style));
2144 }
2145