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