masterdump.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2009, 2011-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <stdlib.h>
00025 
00026 #include <isc/event.h>
00027 #include <isc/file.h>
00028 #include <isc/magic.h>
00029 #include <isc/mem.h>
00030 #include <isc/print.h>
00031 #include <isc/stdio.h>
00032 #include <isc/string.h>
00033 #include <isc/task.h>
00034 #include <isc/time.h>
00035 #include <isc/util.h>
00036 
00037 #include <dns/db.h>
00038 #include <dns/dbiterator.h>
00039 #include <dns/events.h>
00040 #include <dns/fixedname.h>
00041 #include <dns/lib.h>
00042 #include <dns/log.h>
00043 #include <dns/master.h>
00044 #include <dns/masterdump.h>
00045 #include <dns/ncache.h>
00046 #include <dns/rdata.h>
00047 #include <dns/rdataclass.h>
00048 #include <dns/rdataset.h>
00049 #include <dns/rdatasetiter.h>
00050 #include <dns/rdatatype.h>
00051 #include <dns/result.h>
00052 #include <dns/time.h>
00053 #include <dns/ttl.h>
00054 
00055 #define DNS_DCTX_MAGIC          ISC_MAGIC('D', 'c', 't', 'x')
00056 #define DNS_DCTX_VALID(d)       ISC_MAGIC_VALID(d, DNS_DCTX_MAGIC)
00057 
00058 #define RETERR(x) do { \
00059         isc_result_t _r = (x); \
00060         if (_r != ISC_R_SUCCESS) \
00061                 return (_r); \
00062         } while (0)
00063 
00064 #define CHECK(x) do { \
00065         if ((x) != ISC_R_SUCCESS) \
00066                 goto cleanup; \
00067         } while (0)
00068 
00069 struct dns_master_style {
00070         unsigned int flags;             /* DNS_STYLEFLAG_* */
00071         unsigned int ttl_column;
00072         unsigned int class_column;
00073         unsigned int type_column;
00074         unsigned int rdata_column;
00075         unsigned int line_length;
00076         unsigned int tab_width;
00077         unsigned int split_width;
00078 };
00079 
00080 /*%
00081  * The maximum length of the newline+indentation that is output
00082  * when inserting a line break in an RR.  This effectively puts an
00083  * upper limits on the value of "rdata_column", because if it is
00084  * very large, the tabs and spaces needed to reach it will not fit.
00085  */
00086 #define DNS_TOTEXT_LINEBREAK_MAXLEN 100
00087 
00088 /*%
00089  * Context structure for a masterfile dump in progress.
00090  */
00091 typedef struct dns_totext_ctx {
00092         dns_master_style_t      style;
00093         isc_boolean_t           class_printed;
00094         char *                  linebreak;
00095         char                    linebreak_buf[DNS_TOTEXT_LINEBREAK_MAXLEN];
00096         dns_name_t *            origin;
00097         dns_name_t *            neworigin;
00098         dns_fixedname_t         origin_fixname;
00099         isc_uint32_t            current_ttl;
00100         isc_boolean_t           current_ttl_valid;
00101 } dns_totext_ctx_t;
00102 
00103 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00104 dns_master_style_keyzone = {
00105         DNS_STYLEFLAG_OMIT_OWNER |
00106         DNS_STYLEFLAG_OMIT_CLASS |
00107         DNS_STYLEFLAG_REL_OWNER |
00108         DNS_STYLEFLAG_REL_DATA |
00109         DNS_STYLEFLAG_OMIT_TTL |
00110         DNS_STYLEFLAG_TTL |
00111         DNS_STYLEFLAG_COMMENT |
00112         DNS_STYLEFLAG_RRCOMMENT |
00113         DNS_STYLEFLAG_MULTILINE |
00114         DNS_STYLEFLAG_KEYDATA,
00115         24, 24, 24, 32, 80, 8, UINT_MAX
00116 };
00117 
00118 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00119 dns_master_style_default = {
00120         DNS_STYLEFLAG_OMIT_OWNER |
00121         DNS_STYLEFLAG_OMIT_CLASS |
00122         DNS_STYLEFLAG_REL_OWNER |
00123         DNS_STYLEFLAG_REL_DATA |
00124         DNS_STYLEFLAG_OMIT_TTL |
00125         DNS_STYLEFLAG_TTL |
00126         DNS_STYLEFLAG_COMMENT |
00127         DNS_STYLEFLAG_RRCOMMENT |
00128         DNS_STYLEFLAG_MULTILINE,
00129         24, 24, 24, 32, 80, 8, UINT_MAX
00130 };
00131 
00132 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00133 dns_master_style_full = {
00134         DNS_STYLEFLAG_COMMENT |
00135         DNS_STYLEFLAG_RESIGN,
00136         46, 46, 46, 64, 120, 8, UINT_MAX
00137 };
00138 
00139 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00140 dns_master_style_explicitttl = {
00141         DNS_STYLEFLAG_OMIT_OWNER |
00142         DNS_STYLEFLAG_OMIT_CLASS |
00143         DNS_STYLEFLAG_REL_OWNER |
00144         DNS_STYLEFLAG_REL_DATA |
00145         DNS_STYLEFLAG_COMMENT |
00146         DNS_STYLEFLAG_RRCOMMENT |
00147         DNS_STYLEFLAG_MULTILINE,
00148         24, 32, 32, 40, 80, 8, UINT_MAX
00149 };
00150 
00151 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00152 dns_master_style_cache = {
00153         DNS_STYLEFLAG_OMIT_OWNER |
00154         DNS_STYLEFLAG_OMIT_CLASS |
00155         DNS_STYLEFLAG_MULTILINE |
00156         DNS_STYLEFLAG_RRCOMMENT |
00157         DNS_STYLEFLAG_TRUST |
00158         DNS_STYLEFLAG_NCACHE,
00159         24, 32, 32, 40, 80, 8, UINT_MAX
00160 };
00161 
00162 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00163 dns_master_style_simple = {
00164         0,
00165         24, 32, 32, 40, 80, 8, UINT_MAX
00166 };
00167 
00168 /*%
00169  * A style suitable for dns_rdataset_totext().
00170  */
00171 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00172 dns_master_style_debug = {
00173         DNS_STYLEFLAG_REL_OWNER,
00174         24, 32, 40, 48, 80, 8, UINT_MAX
00175 };
00176 
00177 /*%
00178  * Similar, but with each line commented out.
00179  */
00180 LIBDNS_EXTERNAL_DATA const dns_master_style_t
00181 dns_master_style_comment = {
00182         DNS_STYLEFLAG_REL_OWNER |
00183         DNS_STYLEFLAG_MULTILINE |
00184         DNS_STYLEFLAG_RRCOMMENT |
00185         DNS_STYLEFLAG_COMMENTDATA,
00186         24, 32, 40, 48, 80, 8, UINT_MAX
00187 };
00188 
00189 
00190 #define N_SPACES 10
00191 static char spaces[N_SPACES+1] = "          ";
00192 
00193 #define N_TABS 10
00194 static char tabs[N_TABS+1] = "\t\t\t\t\t\t\t\t\t\t";
00195 
00196 struct dns_dumpctx {
00197         unsigned int            magic;
00198         isc_mem_t               *mctx;
00199         isc_mutex_t             lock;
00200         unsigned int            references;
00201         isc_boolean_t           canceled;
00202         isc_boolean_t           first;
00203         isc_boolean_t           do_date;
00204         isc_stdtime_t           now;
00205         FILE                    *f;
00206         dns_db_t                *db;
00207         dns_dbversion_t         *version;
00208         dns_dbiterator_t        *dbiter;
00209         dns_totext_ctx_t        tctx;
00210         isc_task_t              *task;
00211         dns_dumpdonefunc_t      done;
00212         void                    *done_arg;
00213         unsigned int            nodes;
00214         /* dns_master_dumpinc() */
00215         char                    *file;
00216         char                    *tmpfile;
00217         dns_masterformat_t      format;
00218         dns_masterrawheader_t   header;
00219         isc_result_t            (*dumpsets)(isc_mem_t *mctx, dns_name_t *name,
00220                                             dns_rdatasetiter_t *rdsiter,
00221                                             dns_totext_ctx_t *ctx,
00222                                             isc_buffer_t *buffer, FILE *f);
00223 };
00224 
00225 #define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
00226 
00227 /*%
00228  * Output tabs and spaces to go from column '*current' to
00229  * column 'to', and update '*current' to reflect the new
00230  * current column.
00231  */
00232 static isc_result_t
00233 indent(unsigned int *current, unsigned int to, int tabwidth,
00234        isc_buffer_t *target)
00235 {
00236         isc_region_t r;
00237         unsigned char *p;
00238         unsigned int from;
00239         int ntabs, nspaces, t;
00240 
00241         from = *current;
00242 
00243         if (to < from + 1)
00244                 to = from + 1;
00245 
00246         ntabs = to / tabwidth - from / tabwidth;
00247         if (ntabs < 0)
00248                 ntabs = 0;
00249 
00250         if (ntabs > 0) {
00251                 isc_buffer_availableregion(target, &r);
00252                 if (r.length < (unsigned) ntabs)
00253                         return (ISC_R_NOSPACE);
00254                 p = r.base;
00255 
00256                 t = ntabs;
00257                 while (t) {
00258                         int n = t;
00259                         if (n > N_TABS)
00260                                 n = N_TABS;
00261                         memmove(p, tabs, n);
00262                         p += n;
00263                         t -= n;
00264                 }
00265                 isc_buffer_add(target, ntabs);
00266                 from = (to / tabwidth) * tabwidth;
00267         }
00268 
00269         nspaces = to - from;
00270         INSIST(nspaces >= 0);
00271 
00272         isc_buffer_availableregion(target, &r);
00273         if (r.length < (unsigned) nspaces)
00274                 return (ISC_R_NOSPACE);
00275         p = r.base;
00276 
00277         t = nspaces;
00278         while (t) {
00279                 int n = t;
00280                 if (n > N_SPACES)
00281                         n = N_SPACES;
00282                 memmove(p, spaces, n);
00283                 p += n;
00284                 t -= n;
00285         }
00286         isc_buffer_add(target, nspaces);
00287 
00288         *current = to;
00289         return (ISC_R_SUCCESS);
00290 }
00291 
00292 static isc_result_t
00293 totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) {
00294         isc_result_t result;
00295 
00296         REQUIRE(style->tab_width != 0);
00297 
00298         ctx->style = *style;
00299         ctx->class_printed = ISC_FALSE;
00300 
00301         dns_fixedname_init(&ctx->origin_fixname);
00302 
00303         /*
00304          * Set up the line break string if needed.
00305          */
00306         if ((ctx->style.flags & DNS_STYLEFLAG_MULTILINE) != 0) {
00307                 isc_buffer_t buf;
00308                 isc_region_t r;
00309                 unsigned int col = 0;
00310 
00311                 isc_buffer_init(&buf, ctx->linebreak_buf,
00312                                 sizeof(ctx->linebreak_buf));
00313 
00314                 isc_buffer_availableregion(&buf, &r);
00315                 if (r.length < 1)
00316                         return (DNS_R_TEXTTOOLONG);
00317                 r.base[0] = '\n';
00318                 isc_buffer_add(&buf, 1);
00319 
00320                 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0) {
00321                         isc_buffer_availableregion(&buf, &r);
00322                         if (r.length < 1)
00323                                 return (DNS_R_TEXTTOOLONG);
00324                         r.base[0] = ';';
00325                         isc_buffer_add(&buf, 1);
00326                 }
00327 
00328                 result = indent(&col, ctx->style.rdata_column,
00329                                 ctx->style.tab_width, &buf);
00330                 /*
00331                  * Do not return ISC_R_NOSPACE if the line break string
00332                  * buffer is too small, because that would just make
00333                  * dump_rdataset() retry indefinitely with ever
00334                  * bigger target buffers.  That's a different buffer,
00335                  * so it won't help.  Use DNS_R_TEXTTOOLONG as a substitute.
00336                  */
00337                 if (result == ISC_R_NOSPACE)
00338                         return (DNS_R_TEXTTOOLONG);
00339                 if (result != ISC_R_SUCCESS)
00340                         return (result);
00341 
00342                 isc_buffer_availableregion(&buf, &r);
00343                 if (r.length < 1)
00344                         return (DNS_R_TEXTTOOLONG);
00345                 r.base[0] = '\0';
00346                 isc_buffer_add(&buf, 1);
00347                 ctx->linebreak = ctx->linebreak_buf;
00348         } else {
00349                 ctx->linebreak = NULL;
00350         }
00351 
00352         ctx->origin = NULL;
00353         ctx->neworigin = NULL;
00354         ctx->current_ttl = 0;
00355         ctx->current_ttl_valid = ISC_FALSE;
00356 
00357         return (ISC_R_SUCCESS);
00358 }
00359 
00360 #define INDENT_TO(col) \
00361         do { \
00362                  if ((result = indent(&column, ctx->style.col, \
00363                                       ctx->style.tab_width, target)) \
00364                      != ISC_R_SUCCESS) \
00365                             return (result); \
00366         } while (0)
00367 
00368 
00369 static isc_result_t
00370 str_totext(const char *source, isc_buffer_t *target) {
00371         unsigned int l;
00372         isc_region_t region;
00373 
00374         isc_buffer_availableregion(target, &region);
00375         l = strlen(source);
00376 
00377         if (l > region.length)
00378                 return (ISC_R_NOSPACE);
00379 
00380         memmove(region.base, source, l);
00381         isc_buffer_add(target, l);
00382         return (ISC_R_SUCCESS);
00383 }
00384 
00385 static isc_result_t
00386 ncache_summary(dns_rdataset_t *rdataset, isc_boolean_t omit_final_dot,
00387                isc_buffer_t *target)
00388 {
00389         isc_result_t result = ISC_R_SUCCESS;
00390         dns_rdataset_t rds;
00391         dns_name_t name;
00392 
00393         dns_rdataset_init(&rds);
00394         dns_name_init(&name, NULL);
00395 
00396         do {
00397                 dns_ncache_current(rdataset, &name, &rds);
00398                 for (result = dns_rdataset_first(&rds);
00399                      result == ISC_R_SUCCESS;
00400                      result = dns_rdataset_next(&rds)) {
00401                         CHECK(str_totext("; ", target));
00402                         CHECK(dns_name_totext(&name, omit_final_dot, target));
00403                         CHECK(str_totext(" ", target));
00404                         CHECK(dns_rdatatype_totext(rds.type, target));
00405                         if (rds.type == dns_rdatatype_rrsig) {
00406                                 CHECK(str_totext(" ", target));
00407                                 CHECK(dns_rdatatype_totext(rds.covers, target));
00408                                 CHECK(str_totext(" ...\n", target));
00409                         } else {
00410                                 dns_rdata_t rdata = DNS_RDATA_INIT;
00411                                 dns_rdataset_current(&rds, &rdata);
00412                                 CHECK(str_totext(" ", target));
00413                                 CHECK(dns_rdata_tofmttext(&rdata, dns_rootname,
00414                                                           0, 0, 0, " ", target));
00415                                 CHECK(str_totext("\n", target));
00416                         }
00417                 }
00418                 dns_rdataset_disassociate(&rds);
00419                 result = dns_rdataset_next(rdataset);
00420         } while (result == ISC_R_SUCCESS);
00421 
00422         if (result == ISC_R_NOMORE)
00423                 result = ISC_R_SUCCESS;
00424  cleanup:
00425         if (dns_rdataset_isassociated(&rds))
00426                 dns_rdataset_disassociate(&rds);
00427 
00428         return (result);
00429 }
00430 
00431 /*
00432  * Convert 'rdataset' to master file text format according to 'ctx',
00433  * storing the result in 'target'.  If 'owner_name' is NULL, it
00434  * is omitted; otherwise 'owner_name' must be valid and have at least
00435  * one label.
00436  */
00437 
00438 static isc_result_t
00439 rdataset_totext(dns_rdataset_t *rdataset,
00440                 dns_name_t *owner_name,
00441                 dns_totext_ctx_t *ctx,
00442                 isc_boolean_t omit_final_dot,
00443                 isc_buffer_t *target)
00444 {
00445         isc_result_t result;
00446         unsigned int column;
00447         isc_boolean_t first = ISC_TRUE;
00448         isc_uint32_t current_ttl;
00449         isc_boolean_t current_ttl_valid;
00450         dns_rdatatype_t type;
00451         unsigned int type_start;
00452         dns_fixedname_t fixed;
00453         dns_name_t *name = NULL;
00454 
00455         REQUIRE(DNS_RDATASET_VALID(rdataset));
00456 
00457         rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
00458         result = dns_rdataset_first(rdataset);
00459 
00460         current_ttl = ctx->current_ttl;
00461         current_ttl_valid = ctx->current_ttl_valid;
00462 
00463         if (owner_name != NULL) {
00464                 dns_fixedname_init(&fixed);
00465                 name = dns_fixedname_name(&fixed);
00466                 dns_name_copy(owner_name, name, NULL);
00467                 dns_rdataset_getownercase(rdataset, name);
00468         }
00469 
00470         while (result == ISC_R_SUCCESS) {
00471                 column = 0;
00472 
00473                 /*
00474                  * Comment?
00475                  */
00476                 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0)
00477                         RETERR(str_totext(";", target));
00478 
00479                 /*
00480                  * Owner name.
00481                  */
00482                 if (name != NULL &&
00483                     ! ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0 &&
00484                        !first))
00485                 {
00486                         unsigned int name_start = target->used;
00487                         RETERR(dns_name_totext(name, omit_final_dot, target));
00488                         column += target->used - name_start;
00489                 }
00490 
00491                 /*
00492                  * TTL.
00493                  */
00494                 if ((ctx->style.flags & DNS_STYLEFLAG_NO_TTL) == 0 &&
00495                     !((ctx->style.flags & DNS_STYLEFLAG_OMIT_TTL) != 0 &&
00496                       current_ttl_valid &&
00497                       rdataset->ttl == current_ttl))
00498                 {
00499                         char ttlbuf[64];
00500                         isc_region_t r;
00501                         unsigned int length;
00502 
00503                         INDENT_TO(ttl_column);
00504                         if ((ctx->style.flags & DNS_STYLEFLAG_TTL_UNITS) != 0) {
00505                                 length = target->used;
00506                                 result = dns_ttl_totext2(rdataset->ttl,
00507                                                         ISC_FALSE, ISC_FALSE,
00508                                                         target);
00509                                 if (result != ISC_R_SUCCESS)
00510                                         return (result);
00511                                 column += target->used - length;
00512                         } else {
00513                                 length = snprintf(ttlbuf, sizeof(ttlbuf), "%u",
00514                                                   rdataset->ttl);
00515                                 INSIST(length <= sizeof(ttlbuf));
00516                                 isc_buffer_availableregion(target, &r);
00517                                 if (r.length < length)
00518                                         return (ISC_R_NOSPACE);
00519                                 memmove(r.base, ttlbuf, length);
00520                                 isc_buffer_add(target, length);
00521                                 column += length;
00522                         }
00523 
00524                         /*
00525                          * If the $TTL directive is not in use, the TTL we
00526                          * just printed becomes the default for subsequent RRs.
00527                          */
00528                         if ((ctx->style.flags & DNS_STYLEFLAG_TTL) == 0) {
00529                                 current_ttl = rdataset->ttl;
00530                                 current_ttl_valid = ISC_TRUE;
00531                         }
00532                 }
00533 
00534                 /*
00535                  * Class.
00536                  */
00537                 if ((ctx->style.flags & DNS_STYLEFLAG_NO_CLASS) == 0 &&
00538                     ((ctx->style.flags & DNS_STYLEFLAG_OMIT_CLASS) == 0 ||
00539                      ctx->class_printed == ISC_FALSE))
00540                 {
00541                         unsigned int class_start;
00542                         INDENT_TO(class_column);
00543                         class_start = target->used;
00544                         result = dns_rdataclass_totext(rdataset->rdclass,
00545                                                        target);
00546                         if (result != ISC_R_SUCCESS)
00547                                 return (result);
00548                         column += (target->used - class_start);
00549                 }
00550 
00551                 /*
00552                  * Type.
00553                  */
00554 
00555                 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
00556                         type = rdataset->covers;
00557                 } else {
00558                         type = rdataset->type;
00559                 }
00560 
00561                 INDENT_TO(type_column);
00562                 type_start = target->used;
00563                 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
00564                         RETERR(str_totext("\\-", target));
00565                 switch (type) {
00566                 case dns_rdatatype_keydata:
00567 #define KEYDATA "KEYDATA"
00568                         if ((ctx->style.flags & DNS_STYLEFLAG_KEYDATA) != 0) {
00569                                 if (isc_buffer_availablelength(target) <
00570                                     (sizeof(KEYDATA) - 1))
00571                                         return (ISC_R_NOSPACE);
00572                                 isc_buffer_putstr(target, KEYDATA);
00573                                 break;
00574                         }
00575                         /* FALLTHROUGH */
00576                 default:
00577                         result = dns_rdatatype_totext(type, target);
00578                         if (result != ISC_R_SUCCESS)
00579                                 return (result);
00580                 }
00581                 column += (target->used - type_start);
00582 
00583                 /*
00584                  * Rdata.
00585                  */
00586                 INDENT_TO(rdata_column);
00587                 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
00588                         if (NXDOMAIN(rdataset))
00589                                 RETERR(str_totext(";-$NXDOMAIN\n", target));
00590                         else
00591                                 RETERR(str_totext(";-$NXRRSET\n", target));
00592                         /*
00593                          * Print a summary of the cached records which make
00594                          * up the negative response.
00595                          */
00596                         RETERR(ncache_summary(rdataset, omit_final_dot,
00597                                               target));
00598                         break;
00599                 } else {
00600                         dns_rdata_t rdata = DNS_RDATA_INIT;
00601                         isc_region_t r;
00602 
00603                         dns_rdataset_current(rdataset, &rdata);
00604 
00605                         RETERR(dns_rdata_tofmttext(&rdata,
00606                                                    ctx->origin,
00607                                                    ctx->style.flags,
00608                                                    ctx->style.line_length -
00609                                                        ctx->style.rdata_column,
00610                                                    ctx->style.split_width,
00611                                                    ctx->linebreak,
00612                                                    target));
00613 
00614                         isc_buffer_availableregion(target, &r);
00615                         if (r.length < 1)
00616                                 return (ISC_R_NOSPACE);
00617                         r.base[0] = '\n';
00618                         isc_buffer_add(target, 1);
00619                 }
00620 
00621                 first = ISC_FALSE;
00622                 result = dns_rdataset_next(rdataset);
00623         }
00624 
00625         if (result != ISC_R_NOMORE)
00626                 return (result);
00627 
00628         /*
00629          * Update the ctx state to reflect what we just printed.
00630          * This is done last, only when we are sure we will return
00631          * success, because this function may be called multiple
00632          * times with increasing buffer sizes until it succeeds,
00633          * and failed attempts must not update the state prematurely.
00634          */
00635         ctx->class_printed = ISC_TRUE;
00636         ctx->current_ttl= current_ttl;
00637         ctx->current_ttl_valid = current_ttl_valid;
00638 
00639         return (ISC_R_SUCCESS);
00640 }
00641 
00642 /*
00643  * Print the name, type, and class of an empty rdataset,
00644  * such as those used to represent the question section
00645  * of a DNS message.
00646  */
00647 static isc_result_t
00648 question_totext(dns_rdataset_t *rdataset,
00649                 dns_name_t *owner_name,
00650                 dns_totext_ctx_t *ctx,
00651                 isc_boolean_t omit_final_dot,
00652                 isc_buffer_t *target)
00653 {
00654         unsigned int column;
00655         isc_result_t result;
00656         isc_region_t r;
00657 
00658         REQUIRE(DNS_RDATASET_VALID(rdataset));
00659         result = dns_rdataset_first(rdataset);
00660         REQUIRE(result == ISC_R_NOMORE);
00661 
00662         column = 0;
00663 
00664         /* Owner name */
00665         {
00666                 unsigned int name_start = target->used;
00667                 RETERR(dns_name_totext(owner_name,
00668                                        omit_final_dot,
00669                                        target));
00670                 column += target->used - name_start;
00671         }
00672 
00673         /* Class */
00674         {
00675                 unsigned int class_start;
00676                 INDENT_TO(class_column);
00677                 class_start = target->used;
00678                 result = dns_rdataclass_totext(rdataset->rdclass, target);
00679                 if (result != ISC_R_SUCCESS)
00680                         return (result);
00681                 column += (target->used - class_start);
00682         }
00683 
00684         /* Type */
00685         {
00686                 unsigned int type_start;
00687                 INDENT_TO(type_column);
00688                 type_start = target->used;
00689                 result = dns_rdatatype_totext(rdataset->type, target);
00690                 if (result != ISC_R_SUCCESS)
00691                         return (result);
00692                 column += (target->used - type_start);
00693         }
00694 
00695         isc_buffer_availableregion(target, &r);
00696         if (r.length < 1)
00697                 return (ISC_R_NOSPACE);
00698         r.base[0] = '\n';
00699         isc_buffer_add(target, 1);
00700 
00701         return (ISC_R_SUCCESS);
00702 }
00703 
00704 isc_result_t
00705 dns_rdataset_totext(dns_rdataset_t *rdataset,
00706                     dns_name_t *owner_name,
00707                     isc_boolean_t omit_final_dot,
00708                     isc_boolean_t question,
00709                     isc_buffer_t *target)
00710 {
00711         dns_totext_ctx_t ctx;
00712         isc_result_t result;
00713         result = totext_ctx_init(&dns_master_style_debug, &ctx);
00714         if (result != ISC_R_SUCCESS) {
00715                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00716                                  "could not set master file style");
00717                 return (ISC_R_UNEXPECTED);
00718         }
00719 
00720         /*
00721          * The caller might want to give us an empty owner
00722          * name (e.g. if they are outputting into a master
00723          * file and this rdataset has the same name as the
00724          * previous one.)
00725          */
00726         if (dns_name_countlabels(owner_name) == 0)
00727                 owner_name = NULL;
00728 
00729         if (question)
00730                 return (question_totext(rdataset, owner_name, &ctx,
00731                                         omit_final_dot, target));
00732         else
00733                 return (rdataset_totext(rdataset, owner_name, &ctx,
00734                                         omit_final_dot, target));
00735 }
00736 
00737 isc_result_t
00738 dns_master_rdatasettotext(dns_name_t *owner_name,
00739                           dns_rdataset_t *rdataset,
00740                           const dns_master_style_t *style,
00741                           isc_buffer_t *target)
00742 {
00743         dns_totext_ctx_t ctx;
00744         isc_result_t result;
00745         result = totext_ctx_init(style, &ctx);
00746         if (result != ISC_R_SUCCESS) {
00747                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00748                                  "could not set master file style");
00749                 return (ISC_R_UNEXPECTED);
00750         }
00751 
00752         return (rdataset_totext(rdataset, owner_name, &ctx,
00753                                 ISC_FALSE, target));
00754 }
00755 
00756 isc_result_t
00757 dns_master_questiontotext(dns_name_t *owner_name,
00758                           dns_rdataset_t *rdataset,
00759                           const dns_master_style_t *style,
00760                           isc_buffer_t *target)
00761 {
00762         dns_totext_ctx_t ctx;
00763         isc_result_t result;
00764         result = totext_ctx_init(style, &ctx);
00765         if (result != ISC_R_SUCCESS) {
00766                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00767                                  "could not set master file style");
00768                 return (ISC_R_UNEXPECTED);
00769         }
00770 
00771         return (question_totext(rdataset, owner_name, &ctx,
00772                                 ISC_FALSE, target));
00773 }
00774 
00775 /*
00776  * Print an rdataset.  'buffer' is a scratch buffer, which must have been
00777  * dynamically allocated by the caller.  It must be large enough to
00778  * hold the result from dns_ttl_totext().  If more than that is needed,
00779  * the buffer will be grown automatically.
00780  */
00781 
00782 static isc_result_t
00783 dump_rdataset(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset,
00784               dns_totext_ctx_t *ctx,
00785               isc_buffer_t *buffer, FILE *f)
00786 {
00787         isc_region_t r;
00788         isc_result_t result;
00789 
00790         REQUIRE(buffer->length > 0);
00791 
00792         /*
00793          * Output a $TTL directive if needed.
00794          */
00795 
00796         if ((ctx->style.flags & DNS_STYLEFLAG_TTL) != 0) {
00797                 if (ctx->current_ttl_valid == ISC_FALSE ||
00798                     ctx->current_ttl != rdataset->ttl)
00799                 {
00800                         if ((ctx->style.flags & DNS_STYLEFLAG_COMMENT) != 0)
00801                         {
00802                                 isc_buffer_clear(buffer);
00803                                 result = dns_ttl_totext(rdataset->ttl,
00804                                                         ISC_TRUE, buffer);
00805                                 INSIST(result == ISC_R_SUCCESS);
00806                                 isc_buffer_usedregion(buffer, &r);
00807                                 fprintf(f, "$TTL %u\t; %.*s\n", rdataset->ttl,
00808                                         (int) r.length, (char *) r.base);
00809                         } else {
00810                                 fprintf(f, "$TTL %u\n", rdataset->ttl);
00811                         }
00812                         ctx->current_ttl = rdataset->ttl;
00813                         ctx->current_ttl_valid = ISC_TRUE;
00814                 }
00815         }
00816 
00817         isc_buffer_clear(buffer);
00818 
00819         /*
00820          * Generate the text representation of the rdataset into
00821          * the buffer.  If the buffer is too small, grow it.
00822          */
00823         for (;;) {
00824                 int newlength;
00825                 void *newmem;
00826                 result = rdataset_totext(rdataset, name, ctx,
00827                                          ISC_FALSE, buffer);
00828                 if (result != ISC_R_NOSPACE)
00829                         break;
00830 
00831                 newlength = buffer->length * 2;
00832                 newmem = isc_mem_get(mctx, newlength);
00833                 if (newmem == NULL)
00834                         return (ISC_R_NOMEMORY);
00835                 isc_mem_put(mctx, buffer->base, buffer->length);
00836                 isc_buffer_init(buffer, newmem, newlength);
00837         }
00838         if (result != ISC_R_SUCCESS)
00839                 return (result);
00840 
00841         /*
00842          * Write the buffer contents to the master file.
00843          */
00844         isc_buffer_usedregion(buffer, &r);
00845         result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL);
00846 
00847         if (result != ISC_R_SUCCESS) {
00848                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00849                                  "master file write failed: %s",
00850                                  isc_result_totext(result));
00851                 return (result);
00852         }
00853 
00854         return (ISC_R_SUCCESS);
00855 }
00856 
00857 /*
00858  * Define the order in which rdatasets should be printed in zone
00859  * files.  We will print SOA and NS records before others, SIGs
00860  * immediately following the things they sign, and order everything
00861  * else by RR number.  This is all just for aesthetics and
00862  * compatibility with buggy software that expects the SOA to be first;
00863  * the DNS specifications allow any order.
00864  */
00865 
00866 static int
00867 dump_order(const dns_rdataset_t *rds) {
00868         int t;
00869         int sig;
00870         if (rds->type == dns_rdatatype_rrsig) {
00871                 t = rds->covers;
00872                 sig = 1;
00873         } else {
00874                 t = rds->type;
00875                 sig = 0;
00876         }
00877         switch (t) {
00878         case dns_rdatatype_soa:
00879                 t = 0;
00880                 break;
00881         case dns_rdatatype_ns:
00882                 t = 1;
00883                 break;
00884         default:
00885                 t += 2;
00886                 break;
00887         }
00888         return (t << 1) + sig;
00889 }
00890 
00891 static int
00892 dump_order_compare(const void *a, const void *b) {
00893         return (dump_order(*((const dns_rdataset_t * const *) a)) -
00894                 dump_order(*((const dns_rdataset_t * const *) b)));
00895 }
00896 
00897 /*
00898  * Dump all the rdatasets of a domain name to a master file.  We make
00899  * a "best effort" attempt to sort the RRsets in a nice order, but if
00900  * there are more than MAXSORT RRsets, we punt and only sort them in
00901  * groups of MAXSORT.  This is not expected to ever happen in practice
00902  * since much less than 64 RR types have been registered with the
00903  * IANA, so far, and the output will be correct (though not
00904  * aesthetically pleasing) even if it does happen.
00905  */
00906 
00907 #define MAXSORT 64
00908 
00909 static isc_result_t
00910 dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name,
00911                     dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
00912                     isc_buffer_t *buffer, FILE *f)
00913 {
00914         isc_result_t itresult, dumpresult;
00915         isc_region_t r;
00916         dns_rdataset_t rdatasets[MAXSORT];
00917         dns_rdataset_t *sorted[MAXSORT];
00918         int i, n;
00919 
00920         itresult = dns_rdatasetiter_first(rdsiter);
00921         dumpresult = ISC_R_SUCCESS;
00922 
00923         if (itresult == ISC_R_SUCCESS && ctx->neworigin != NULL) {
00924                 isc_buffer_clear(buffer);
00925                 itresult = dns_name_totext(ctx->neworigin, ISC_FALSE, buffer);
00926                 RUNTIME_CHECK(itresult == ISC_R_SUCCESS);
00927                 isc_buffer_usedregion(buffer, &r);
00928                 fprintf(f, "$ORIGIN %.*s\n", (int) r.length, (char *) r.base);
00929                 ctx->neworigin = NULL;
00930         }
00931 
00932  again:
00933         for (i = 0;
00934              itresult == ISC_R_SUCCESS && i < MAXSORT;
00935              itresult = dns_rdatasetiter_next(rdsiter), i++) {
00936                 dns_rdataset_init(&rdatasets[i]);
00937                 dns_rdatasetiter_current(rdsiter, &rdatasets[i]);
00938                 sorted[i] = &rdatasets[i];
00939         }
00940         n = i;
00941         INSIST(n <= MAXSORT);
00942 
00943         qsort(sorted, n, sizeof(sorted[0]), dump_order_compare);
00944 
00945         for (i = 0; i < n; i++) {
00946                 dns_rdataset_t *rds = sorted[i];
00947                 if (ctx->style.flags & DNS_STYLEFLAG_TRUST)
00948                         fprintf(f, "; %s\n", dns_trust_totext(rds->trust));
00949                 if (((rds->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) &&
00950                     (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
00951                         /* Omit negative cache entries */
00952                 } else {
00953                         isc_result_t result =
00954                                 dump_rdataset(mctx, name, rds, ctx,
00955                                                buffer, f);
00956                         if (result != ISC_R_SUCCESS)
00957                                 dumpresult = result;
00958                         if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0)
00959                                 name = NULL;
00960                 }
00961                 if (ctx->style.flags & DNS_STYLEFLAG_RESIGN &&
00962                     rds->attributes & DNS_RDATASETATTR_RESIGN) {
00963                         isc_buffer_t b;
00964                         char buf[sizeof("YYYYMMDDHHMMSS")];
00965                         memset(buf, 0, sizeof(buf));
00966                         isc_buffer_init(&b, buf, sizeof(buf) - 1);
00967                         dns_time64_totext((isc_uint64_t)rds->resign, &b);
00968                         fprintf(f, "; resign=%s\n", buf);
00969                 }
00970                 dns_rdataset_disassociate(rds);
00971         }
00972 
00973         if (dumpresult != ISC_R_SUCCESS)
00974                 return (dumpresult);
00975 
00976         /*
00977          * If we got more data than could be sorted at once,
00978          * go handle the rest.
00979          */
00980         if (itresult == ISC_R_SUCCESS)
00981                 goto again;
00982 
00983         if (itresult == ISC_R_NOMORE)
00984                 itresult = ISC_R_SUCCESS;
00985 
00986         return (itresult);
00987 }
00988 
00989 /*
00990  * Dump given RRsets in the "raw" format.
00991  */
00992 static isc_result_t
00993 dump_rdataset_raw(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset,
00994                   isc_buffer_t *buffer, FILE *f)
00995 {
00996         isc_result_t result;
00997         isc_uint32_t totallen;
00998         isc_uint16_t dlen;
00999         isc_region_t r, r_hdr;
01000 
01001         REQUIRE(buffer->length > 0);
01002         REQUIRE(DNS_RDATASET_VALID(rdataset));
01003 
01004         rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
01005  restart:
01006         totallen = 0;
01007         result = dns_rdataset_first(rdataset);
01008         REQUIRE(result == ISC_R_SUCCESS);
01009 
01010         isc_buffer_clear(buffer);
01011 
01012         /*
01013          * Common header and owner name (length followed by name)
01014          * These fields should be in a moderate length, so we assume we
01015          * can store all of them in the initial buffer.
01016          */
01017         isc_buffer_availableregion(buffer, &r_hdr);
01018         INSIST(r_hdr.length >= sizeof(dns_masterrawrdataset_t));
01019         isc_buffer_putuint32(buffer, totallen); /* XXX: leave space */
01020         isc_buffer_putuint16(buffer, rdataset->rdclass); /* 16-bit class */
01021         isc_buffer_putuint16(buffer, rdataset->type); /* 16-bit type */
01022         isc_buffer_putuint16(buffer, rdataset->covers); /* same as type */
01023         isc_buffer_putuint32(buffer, rdataset->ttl); /* 32-bit TTL */
01024         isc_buffer_putuint32(buffer, dns_rdataset_count(rdataset));
01025         totallen = isc_buffer_usedlength(buffer);
01026         INSIST(totallen <= sizeof(dns_masterrawrdataset_t));
01027 
01028         dns_name_toregion(name, &r);
01029         INSIST(isc_buffer_availablelength(buffer) >=
01030                (sizeof(dlen) + r.length));
01031         dlen = (isc_uint16_t)r.length;
01032         isc_buffer_putuint16(buffer, dlen);
01033         isc_buffer_copyregion(buffer, &r);
01034         totallen += sizeof(dlen) + r.length;
01035 
01036         do {
01037                 dns_rdata_t rdata = DNS_RDATA_INIT;
01038 
01039                 dns_rdataset_current(rdataset, &rdata);
01040                 dns_rdata_toregion(&rdata, &r);
01041                 INSIST(r.length <= 0xffffU);
01042                 dlen = (isc_uint16_t)r.length;
01043 
01044                 /*
01045                  * Copy the rdata into the buffer.  If the buffer is too small,
01046                  * grow it.  This should be rare, so we'll simply restart the
01047                  * entire procedure (or should we copy the old data and
01048                  * continue?).
01049                  */
01050                 if (isc_buffer_availablelength(buffer) <
01051                                                  sizeof(dlen) + r.length) {
01052                         int newlength;
01053                         void *newmem;
01054 
01055                         newlength = buffer->length * 2;
01056                         newmem = isc_mem_get(mctx, newlength);
01057                         if (newmem == NULL)
01058                                 return (ISC_R_NOMEMORY);
01059                         isc_mem_put(mctx, buffer->base, buffer->length);
01060                         isc_buffer_init(buffer, newmem, newlength);
01061                         goto restart;
01062                 }
01063                 isc_buffer_putuint16(buffer, dlen);
01064                 isc_buffer_copyregion(buffer, &r);
01065                 totallen += sizeof(dlen) + r.length;
01066 
01067                 result = dns_rdataset_next(rdataset);
01068         } while (result == ISC_R_SUCCESS);
01069 
01070         if (result != ISC_R_NOMORE)
01071                 return (result);
01072 
01073         /*
01074          * Fill in the total length field.
01075          * XXX: this is a bit tricky.  Since we have already "used" the space
01076          * for the total length in the buffer, we first remember the entire
01077          * buffer length in the region, "rewind", and then write the value.
01078          */
01079         isc_buffer_usedregion(buffer, &r);
01080         isc_buffer_clear(buffer);
01081         isc_buffer_putuint32(buffer, totallen);
01082         INSIST(isc_buffer_usedlength(buffer) < totallen);
01083 
01084         /*
01085          * Write the buffer contents to the raw master file.
01086          */
01087         result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL);
01088 
01089         if (result != ISC_R_SUCCESS) {
01090                 UNEXPECTED_ERROR(__FILE__, __LINE__,
01091                                  "raw master file write failed: %s",
01092                                  isc_result_totext(result));
01093                 return (result);
01094         }
01095 
01096         return (result);
01097 }
01098 
01099 static isc_result_t
01100 dump_rdatasets_raw(isc_mem_t *mctx, dns_name_t *name,
01101                    dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
01102                    isc_buffer_t *buffer, FILE *f)
01103 {
01104         isc_result_t result;
01105         dns_rdataset_t rdataset;
01106 
01107         for (result = dns_rdatasetiter_first(rdsiter);
01108              result == ISC_R_SUCCESS;
01109              result = dns_rdatasetiter_next(rdsiter)) {
01110 
01111                 dns_rdataset_init(&rdataset);
01112                 dns_rdatasetiter_current(rdsiter, &rdataset);
01113 
01114                 if (((rdataset.attributes & DNS_RDATASETATTR_NEGATIVE) != 0) &&
01115                     (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
01116                         /* Omit negative cache entries */
01117                 } else {
01118                         result = dump_rdataset_raw(mctx, name, &rdataset,
01119                                                    buffer, f);
01120                 }
01121                 dns_rdataset_disassociate(&rdataset);
01122                 if (result != ISC_R_SUCCESS)
01123                         return (result);
01124         }
01125 
01126         if (result == ISC_R_NOMORE)
01127                 result = ISC_R_SUCCESS;
01128 
01129         return (result);
01130 }
01131 
01132 static isc_result_t
01133 dump_rdatasets_map(isc_mem_t *mctx, dns_name_t *name,
01134                    dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
01135                    isc_buffer_t *buffer, FILE *f)
01136 {
01137         UNUSED(mctx);
01138         UNUSED(name);
01139         UNUSED(rdsiter);
01140         UNUSED(ctx);
01141         UNUSED(buffer);
01142         UNUSED(f);
01143 
01144         return (ISC_R_NOTIMPLEMENTED);
01145 }
01146 
01147 /*
01148  * Initial size of text conversion buffer.  The buffer is used
01149  * for several purposes: converting origin names, rdatasets,
01150  * $DATE timestamps, and comment strings for $TTL directives.
01151  *
01152  * When converting rdatasets, it is dynamically resized, but
01153  * when converting origins, timestamps, etc it is not.  Therefore,
01154  * the initial size must large enough to hold the longest possible
01155  * text representation of any domain name (for $ORIGIN).
01156  */
01157 static const int initial_buffer_length = 1200;
01158 
01159 static isc_result_t
01160 dumptostreaminc(dns_dumpctx_t *dctx);
01161 
01162 static void
01163 dumpctx_destroy(dns_dumpctx_t *dctx) {
01164 
01165         dctx->magic = 0;
01166         DESTROYLOCK(&dctx->lock);
01167         dns_dbiterator_destroy(&dctx->dbiter);
01168         if (dctx->version != NULL)
01169                 dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
01170         dns_db_detach(&dctx->db);
01171         if (dctx->task != NULL)
01172                 isc_task_detach(&dctx->task);
01173         if (dctx->file != NULL)
01174                 isc_mem_free(dctx->mctx, dctx->file);
01175         if (dctx->tmpfile != NULL)
01176                 isc_mem_free(dctx->mctx, dctx->tmpfile);
01177         isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(*dctx));
01178 }
01179 
01180 void
01181 dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target) {
01182 
01183         REQUIRE(DNS_DCTX_VALID(source));
01184         REQUIRE(target != NULL && *target == NULL);
01185 
01186         LOCK(&source->lock);
01187         INSIST(source->references > 0);
01188         source->references++;
01189         INSIST(source->references != 0);        /* Overflow? */
01190         UNLOCK(&source->lock);
01191 
01192         *target = source;
01193 }
01194 
01195 void
01196 dns_dumpctx_detach(dns_dumpctx_t **dctxp) {
01197         dns_dumpctx_t *dctx;
01198         isc_boolean_t need_destroy = ISC_FALSE;
01199 
01200         REQUIRE(dctxp != NULL);
01201         dctx = *dctxp;
01202         REQUIRE(DNS_DCTX_VALID(dctx));
01203 
01204         *dctxp = NULL;
01205 
01206         LOCK(&dctx->lock);
01207         INSIST(dctx->references != 0);
01208         dctx->references--;
01209         if (dctx->references == 0)
01210                 need_destroy = ISC_TRUE;
01211         UNLOCK(&dctx->lock);
01212         if (need_destroy)
01213                 dumpctx_destroy(dctx);
01214 }
01215 
01216 dns_dbversion_t *
01217 dns_dumpctx_version(dns_dumpctx_t *dctx) {
01218         REQUIRE(DNS_DCTX_VALID(dctx));
01219         return (dctx->version);
01220 }
01221 
01222 dns_db_t *
01223 dns_dumpctx_db(dns_dumpctx_t *dctx) {
01224         REQUIRE(DNS_DCTX_VALID(dctx));
01225         return (dctx->db);
01226 }
01227 
01228 void
01229 dns_dumpctx_cancel(dns_dumpctx_t *dctx) {
01230         REQUIRE(DNS_DCTX_VALID(dctx));
01231 
01232         LOCK(&dctx->lock);
01233         dctx->canceled = ISC_TRUE;
01234         UNLOCK(&dctx->lock);
01235 }
01236 
01237 static isc_result_t
01238 flushandsync(FILE *f, isc_result_t result, const char *temp) {
01239         isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS);
01240 
01241         if (result == ISC_R_SUCCESS)
01242                 result = isc_stdio_flush(f);
01243         if (result != ISC_R_SUCCESS && logit) {
01244                 if (temp != NULL)
01245                         isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01246                                       DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01247                                       "dumping to master file: %s: flush: %s",
01248                                       temp, isc_result_totext(result));
01249                 else
01250                         isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01251                                       DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01252                                       "dumping to stream: flush: %s",
01253                                       isc_result_totext(result));
01254                 logit = ISC_FALSE;
01255         }
01256 
01257         if (result == ISC_R_SUCCESS)
01258                 result = isc_stdio_sync(f);
01259         if (result != ISC_R_SUCCESS && logit) {
01260                 if (temp != NULL)
01261                         isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01262                                       DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01263                                       "dumping to master file: %s: fsync: %s",
01264                                       temp, isc_result_totext(result));
01265                 else
01266                         isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01267                                       DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01268                                       "dumping to stream: fsync: %s",
01269                                       isc_result_totext(result));
01270         }
01271         return (result);
01272 }
01273 
01274 static isc_result_t
01275 closeandrename(FILE *f, isc_result_t result, const char *temp, const char *file)
01276 {
01277         isc_result_t tresult;
01278         isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS);
01279 
01280         result = flushandsync(f, result, temp);
01281         if (result != ISC_R_SUCCESS)
01282                 logit = ISC_FALSE;
01283 
01284         tresult = isc_stdio_close(f);
01285         if (result == ISC_R_SUCCESS)
01286                 result = tresult;
01287         if (result != ISC_R_SUCCESS && logit) {
01288                 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01289                               DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01290                               "dumping master file: %s: fclose: %s",
01291                               temp, isc_result_totext(result));
01292                 logit = ISC_FALSE;
01293         }
01294         if (result == ISC_R_SUCCESS)
01295                 result = isc_file_rename(temp, file);
01296         else
01297                 (void)isc_file_remove(temp);
01298         if (result != ISC_R_SUCCESS && logit) {
01299                 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01300                               DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01301                               "dumping master file: rename: %s: %s",
01302                               file, isc_result_totext(result));
01303         }
01304         return (result);
01305 }
01306 
01307 static void
01308 dump_quantum(isc_task_t *task, isc_event_t *event) {
01309         isc_result_t result;
01310         isc_result_t tresult;
01311         dns_dumpctx_t *dctx;
01312 
01313         REQUIRE(event != NULL);
01314         dctx = event->ev_arg;
01315         REQUIRE(DNS_DCTX_VALID(dctx));
01316         if (dctx->canceled)
01317                 result = ISC_R_CANCELED;
01318         else
01319                 result = dumptostreaminc(dctx);
01320         if (result == DNS_R_CONTINUE) {
01321                 event->ev_arg = dctx;
01322                 isc_task_send(task, &event);
01323                 return;
01324         }
01325 
01326         if (dctx->file != NULL) {
01327                 tresult = closeandrename(dctx->f, result,
01328                                          dctx->tmpfile, dctx->file);
01329                 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
01330                         result = tresult;
01331         } else
01332                 result = flushandsync(dctx->f, result, NULL);
01333         (dctx->done)(dctx->done_arg, result);
01334         isc_event_free(&event);
01335         dns_dumpctx_detach(&dctx);
01336 }
01337 
01338 static isc_result_t
01339 task_send(dns_dumpctx_t *dctx) {
01340         isc_event_t *event;
01341 
01342         event = isc_event_allocate(dctx->mctx, NULL, DNS_EVENT_DUMPQUANTUM,
01343                                    dump_quantum, dctx, sizeof(*event));
01344         if (event == NULL)
01345                 return (ISC_R_NOMEMORY);
01346         isc_task_send(dctx->task, &event);
01347         return (ISC_R_SUCCESS);
01348 }
01349 
01350 static isc_result_t
01351 dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01352                const dns_master_style_t *style, FILE *f, dns_dumpctx_t **dctxp,
01353                dns_masterformat_t format, dns_masterrawheader_t *header)
01354 {
01355         dns_dumpctx_t *dctx;
01356         isc_result_t result;
01357         unsigned int options;
01358 
01359         dctx = isc_mem_get(mctx, sizeof(*dctx));
01360         if (dctx == NULL)
01361                 return (ISC_R_NOMEMORY);
01362 
01363         dctx->mctx = NULL;
01364         dctx->f = f;
01365         dctx->dbiter = NULL;
01366         dctx->db = NULL;
01367         dctx->version = NULL;
01368         dctx->done = NULL;
01369         dctx->done_arg = NULL;
01370         dctx->task = NULL;
01371         dctx->nodes = 0;
01372         dctx->first = ISC_TRUE;
01373         dctx->canceled = ISC_FALSE;
01374         dctx->file = NULL;
01375         dctx->tmpfile = NULL;
01376         dctx->format = format;
01377         if (header == NULL)
01378                 dns_master_initrawheader(&dctx->header);
01379         else
01380                 dctx->header = *header;
01381 
01382         switch (format) {
01383         case dns_masterformat_text:
01384                 dctx->dumpsets = dump_rdatasets_text;
01385                 break;
01386         case dns_masterformat_raw:
01387                 dctx->dumpsets = dump_rdatasets_raw;
01388                 break;
01389         case dns_masterformat_map:
01390                 dctx->dumpsets = dump_rdatasets_map;
01391                 break;
01392         default:
01393                 INSIST(0);
01394                 break;
01395         }
01396 
01397         result = totext_ctx_init(style, &dctx->tctx);
01398         if (result != ISC_R_SUCCESS) {
01399                 UNEXPECTED_ERROR(__FILE__, __LINE__,
01400                                  "could not set master file style");
01401                 goto cleanup;
01402         }
01403 
01404         isc_stdtime_get(&dctx->now);
01405         dns_db_attach(db, &dctx->db);
01406 
01407         dctx->do_date = dns_db_iscache(dctx->db);
01408 
01409         if (dctx->format == dns_masterformat_text &&
01410             (dctx->tctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) {
01411                 options = DNS_DB_RELATIVENAMES;
01412         } else
01413                 options = 0;
01414         result = dns_db_createiterator(dctx->db, options, &dctx->dbiter);
01415         if (result != ISC_R_SUCCESS)
01416                 goto cleanup;
01417 
01418         result = isc_mutex_init(&dctx->lock);
01419         if (result != ISC_R_SUCCESS)
01420                 goto cleanup;
01421         if (version != NULL)
01422                 dns_db_attachversion(dctx->db, version, &dctx->version);
01423         else if (!dns_db_iscache(db))
01424                 dns_db_currentversion(dctx->db, &dctx->version);
01425         isc_mem_attach(mctx, &dctx->mctx);
01426         dctx->references = 1;
01427         dctx->magic = DNS_DCTX_MAGIC;
01428         *dctxp = dctx;
01429         return (ISC_R_SUCCESS);
01430 
01431  cleanup:
01432         if (dctx->dbiter != NULL)
01433                 dns_dbiterator_destroy(&dctx->dbiter);
01434         if (dctx->db != NULL)
01435                 dns_db_detach(&dctx->db);
01436         if (dctx != NULL)
01437                 isc_mem_put(mctx, dctx, sizeof(*dctx));
01438         return (result);
01439 }
01440 
01441 static isc_result_t
01442 writeheader(dns_dumpctx_t *dctx) {
01443         isc_result_t result = ISC_R_SUCCESS;
01444         isc_buffer_t buffer;
01445         char *bufmem;
01446         isc_region_t r;
01447         dns_masterrawheader_t rawheader;
01448         isc_uint32_t rawversion, now32;
01449 
01450         bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
01451         if (bufmem == NULL)
01452                 return (ISC_R_NOMEMORY);
01453 
01454         isc_buffer_init(&buffer, bufmem, initial_buffer_length);
01455 
01456         switch (dctx->format) {
01457         case dns_masterformat_text:
01458                 /*
01459                  * If the database has cache semantics, output an
01460                  * RFC2540 $DATE directive so that the TTLs can be
01461                  * adjusted when it is reloaded.  For zones it is not
01462                  * really needed, and it would make the file
01463                  * incompatible with pre-RFC2540 software, so we omit
01464                  * it in the zone case.
01465                  */
01466                 if (dctx->do_date) {
01467                         result = dns_time32_totext(dctx->now, &buffer);
01468                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
01469                         isc_buffer_usedregion(&buffer, &r);
01470                         fprintf(dctx->f, "$DATE %.*s\n",
01471                                 (int) r.length, (char *) r.base);
01472                 }
01473                 break;
01474         case dns_masterformat_raw:
01475         case dns_masterformat_map:
01476                 r.base = (unsigned char *)&rawheader;
01477                 r.length = sizeof(rawheader);
01478                 isc_buffer_region(&buffer, &r);
01479 #if !defined(STDTIME_ON_32BITS) || (STDTIME_ON_32BITS + 0) != 1
01480                 /*
01481                  * We assume isc_stdtime_t is a 32-bit integer,
01482                  * which should be the case on most platforms.
01483                  * If it turns out to be uncommon, we'll need
01484                  * to bump the version number and revise the
01485                  * header format.
01486                  */
01487                 isc_log_write(dns_lctx,
01488                               ISC_LOGCATEGORY_GENERAL,
01489                               DNS_LOGMODULE_MASTERDUMP,
01490                               ISC_LOG_INFO,
01491                               "dumping master file in raw "
01492                               "format: stdtime is not 32bits");
01493                 now32 = 0;
01494 #else
01495                 now32 = dctx->now;
01496 #endif
01497                 rawversion = 1;
01498                 if ((dctx->header.flags & DNS_MASTERRAW_COMPAT) != 0)
01499                         rawversion = 0;
01500 
01501                 isc_buffer_putuint32(&buffer, dctx->format);
01502                 isc_buffer_putuint32(&buffer, rawversion);
01503                 isc_buffer_putuint32(&buffer, now32);
01504 
01505                 if (rawversion == 1) {
01506                         isc_buffer_putuint32(&buffer, dctx->header.flags);
01507                         isc_buffer_putuint32(&buffer,
01508                                              dctx->header.sourceserial);
01509                         isc_buffer_putuint32(&buffer, dctx->header.lastxfrin);
01510                 }
01511 
01512                 INSIST(isc_buffer_usedlength(&buffer) <= sizeof(rawheader));
01513                 result = isc_stdio_write(buffer.base, 1,
01514                                          isc_buffer_usedlength(&buffer),
01515                                          dctx->f, NULL);
01516                 if (result != ISC_R_SUCCESS)
01517                         break;
01518 
01519                 break;
01520         default:
01521                 INSIST(0);
01522         }
01523 
01524         isc_mem_put(dctx->mctx, buffer.base, buffer.length);
01525         return (result);
01526 }
01527 
01528 static isc_result_t
01529 dumptostreaminc(dns_dumpctx_t *dctx) {
01530         isc_result_t result = ISC_R_SUCCESS;
01531         isc_buffer_t buffer;
01532         char *bufmem;
01533         dns_name_t *name;
01534         dns_fixedname_t fixname;
01535         unsigned int nodes;
01536         isc_time_t start;
01537 
01538         bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
01539         if (bufmem == NULL)
01540                 return (ISC_R_NOMEMORY);
01541 
01542         isc_buffer_init(&buffer, bufmem, initial_buffer_length);
01543 
01544         dns_fixedname_init(&fixname);
01545         name = dns_fixedname_name(&fixname);
01546 
01547         if (dctx->first) {
01548                 CHECK(writeheader(dctx));
01549 
01550                 /*
01551                  * Fast format is not currently written incrementally,
01552                  * so we make the call to dns_db_serialize() here.
01553                  * If the database is anything other than an rbtdb,
01554                  * this should result in not implemented
01555                  */
01556                 if (dctx->format == dns_masterformat_map) {
01557                         result = dns_db_serialize(dctx->db, dctx->version,
01558                                                   dctx->f);
01559                         goto cleanup;
01560                 }
01561 
01562                 result = dns_dbiterator_first(dctx->dbiter);
01563                 if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
01564                         goto cleanup;
01565 
01566                 dctx->first = ISC_FALSE;
01567         } else
01568                 result = ISC_R_SUCCESS;
01569 
01570         nodes = dctx->nodes;
01571         isc_time_now(&start);
01572         while (result == ISC_R_SUCCESS && (dctx->nodes == 0 || nodes--)) {
01573                 dns_rdatasetiter_t *rdsiter = NULL;
01574                 dns_dbnode_t *node = NULL;
01575 
01576                 result = dns_dbiterator_current(dctx->dbiter, &node, name);
01577                 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
01578                         break;
01579                 if (result == DNS_R_NEWORIGIN) {
01580                         dns_name_t *origin =
01581                                 dns_fixedname_name(&dctx->tctx.origin_fixname);
01582                         result = dns_dbiterator_origin(dctx->dbiter, origin);
01583                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
01584                         if ((dctx->tctx.style.flags &
01585                              DNS_STYLEFLAG_REL_DATA) != 0)
01586                                 dctx->tctx.origin = origin;
01587                         dctx->tctx.neworigin = origin;
01588                 }
01589                 result = dns_db_allrdatasets(dctx->db, node, dctx->version,
01590                                              dctx->now, &rdsiter);
01591                 if (result != ISC_R_SUCCESS) {
01592                         dns_db_detachnode(dctx->db, &node);
01593                         goto cleanup;
01594                 }
01595                 result = (dctx->dumpsets)(dctx->mctx, name, rdsiter,
01596                                           &dctx->tctx, &buffer, dctx->f);
01597                 dns_rdatasetiter_destroy(&rdsiter);
01598                 if (result != ISC_R_SUCCESS) {
01599                         dns_db_detachnode(dctx->db, &node);
01600                         goto cleanup;
01601                 }
01602                 dns_db_detachnode(dctx->db, &node);
01603                 result = dns_dbiterator_next(dctx->dbiter);
01604         }
01605 
01606         /*
01607          * Work out how many nodes can be written in the time between
01608          * two requests to the nameserver.  Smooth the resulting number and
01609          * use it as a estimate for the number of nodes to be written in the
01610          * next iteration.
01611          */
01612         if (dctx->nodes != 0 && result == ISC_R_SUCCESS) {
01613                 unsigned int pps = dns_pps;     /* packets per second */
01614                 unsigned int interval;
01615                 isc_uint64_t usecs;
01616                 isc_time_t end;
01617 
01618                 isc_time_now(&end);
01619                 if (pps < 100)
01620                         pps = 100;
01621                 interval = 1000000 / pps;       /* interval in usecs */
01622                 if (interval == 0)
01623                         interval = 1;
01624                 usecs = isc_time_microdiff(&end, &start);
01625                 if (usecs == 0) {
01626                         dctx->nodes = dctx->nodes * 2;
01627                         if (dctx->nodes > 1000)
01628                                 dctx->nodes = 1000;
01629                 } else {
01630                         nodes = dctx->nodes * interval;
01631                         nodes /= (unsigned int)usecs;
01632                         if (nodes == 0)
01633                                 nodes = 1;
01634                         else if (nodes > 1000)
01635                                 nodes = 1000;
01636 
01637                         /* Smooth and assign. */
01638                         dctx->nodes = (nodes + dctx->nodes * 7) / 8;
01639 
01640                         isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01641                                       DNS_LOGMODULE_MASTERDUMP,
01642                                       ISC_LOG_DEBUG(1),
01643                                       "dumptostreaminc(%p) new nodes -> %d\n",
01644                                       dctx, dctx->nodes);
01645                 }
01646                 result = DNS_R_CONTINUE;
01647         } else if (result == ISC_R_NOMORE)
01648                 result = ISC_R_SUCCESS;
01649  cleanup:
01650         RUNTIME_CHECK(dns_dbiterator_pause(dctx->dbiter) == ISC_R_SUCCESS);
01651         isc_mem_put(dctx->mctx, buffer.base, buffer.length);
01652         return (result);
01653 }
01654 
01655 isc_result_t
01656 dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db,
01657                            dns_dbversion_t *version,
01658                            const dns_master_style_t *style,
01659                            FILE *f, isc_task_t *task,
01660                            dns_dumpdonefunc_t done, void *done_arg,
01661                            dns_dumpctx_t **dctxp)
01662 {
01663         dns_dumpctx_t *dctx = NULL;
01664         isc_result_t result;
01665 
01666         REQUIRE(task != NULL);
01667         REQUIRE(f != NULL);
01668         REQUIRE(done != NULL);
01669 
01670         result = dumpctx_create(mctx, db, version, style, f, &dctx,
01671                                 dns_masterformat_text, NULL);
01672         if (result != ISC_R_SUCCESS)
01673                 return (result);
01674         isc_task_attach(task, &dctx->task);
01675         dctx->done = done;
01676         dctx->done_arg = done_arg;
01677         dctx->nodes = 100;
01678 
01679         result = task_send(dctx);
01680         if (result == ISC_R_SUCCESS) {
01681                 dns_dumpctx_attach(dctx, dctxp);
01682                 return (DNS_R_CONTINUE);
01683         }
01684 
01685         dns_dumpctx_detach(&dctx);
01686         return (result);
01687 }
01688 
01689 /*
01690  * Dump an entire database into a master file.
01691  */
01692 isc_result_t
01693 dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db,
01694                         dns_dbversion_t *version,
01695                         const dns_master_style_t *style,
01696                         FILE *f)
01697 {
01698         return (dns_master_dumptostream3(mctx, db, version, style,
01699                                          dns_masterformat_text, NULL, f));
01700 }
01701 
01702 isc_result_t
01703 dns_master_dumptostream2(isc_mem_t *mctx, dns_db_t *db,
01704                          dns_dbversion_t *version,
01705                          const dns_master_style_t *style,
01706                          dns_masterformat_t format, FILE *f)
01707 {
01708         return (dns_master_dumptostream3(mctx, db, version, style,
01709                                          format, NULL, f));
01710 }
01711 
01712 isc_result_t
01713 dns_master_dumptostream3(isc_mem_t *mctx, dns_db_t *db,
01714                          dns_dbversion_t *version,
01715                          const dns_master_style_t *style,
01716                          dns_masterformat_t format,
01717                          dns_masterrawheader_t *header, FILE *f)
01718 {
01719         dns_dumpctx_t *dctx = NULL;
01720         isc_result_t result;
01721 
01722         result = dumpctx_create(mctx, db, version, style, f, &dctx,
01723                                 format, header);
01724         if (result != ISC_R_SUCCESS)
01725                 return (result);
01726 
01727         result = dumptostreaminc(dctx);
01728         INSIST(result != DNS_R_CONTINUE);
01729         dns_dumpctx_detach(&dctx);
01730 
01731         result = flushandsync(f, result, NULL);
01732         return (result);
01733 }
01734 
01735 static isc_result_t
01736 opentmp(isc_mem_t *mctx, dns_masterformat_t format, const char *file,
01737         char **tempp, FILE **fp) {
01738         FILE *f = NULL;
01739         isc_result_t result;
01740         char *tempname = NULL;
01741         int tempnamelen;
01742 
01743         tempnamelen = strlen(file) + 20;
01744         tempname = isc_mem_allocate(mctx, tempnamelen);
01745         if (tempname == NULL)
01746                 return (ISC_R_NOMEMORY);
01747 
01748         result = isc_file_mktemplate(file, tempname, tempnamelen);
01749         if (result != ISC_R_SUCCESS)
01750                 goto cleanup;
01751 
01752         if (format == dns_masterformat_text)
01753                 result = isc_file_openunique(tempname, &f);
01754         else
01755                 result = isc_file_bopenunique(tempname, &f);
01756         if (result != ISC_R_SUCCESS) {
01757                 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01758                               DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01759                               "dumping master file: %s: open: %s",
01760                               tempname, isc_result_totext(result));
01761                 goto cleanup;
01762         }
01763         *tempp = tempname;
01764         *fp = f;
01765         return (ISC_R_SUCCESS);
01766 
01767 cleanup:
01768         isc_mem_free(mctx, tempname);
01769         return (result);
01770 }
01771 
01772 isc_result_t
01773 dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01774                    const dns_master_style_t *style, const char *filename,
01775                    isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
01776                    dns_dumpctx_t **dctxp)
01777 {
01778         return (dns_master_dumpinc3(mctx, db, version, style, filename, task,
01779                                     done, done_arg, dctxp,
01780                                     dns_masterformat_text, NULL));
01781 }
01782 
01783 isc_result_t
01784 dns_master_dumpinc2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01785                     const dns_master_style_t *style, const char *filename,
01786                     isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
01787                     dns_dumpctx_t **dctxp, dns_masterformat_t format)
01788 {
01789         return (dns_master_dumpinc3(mctx, db, version, style, filename, task,
01790                                     done, done_arg, dctxp, format, NULL));
01791 }
01792 
01793 isc_result_t
01794 dns_master_dumpinc3(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01795                     const dns_master_style_t *style, const char *filename,
01796                     isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
01797                     dns_dumpctx_t **dctxp, dns_masterformat_t format,
01798                     dns_masterrawheader_t *header)
01799 {
01800         FILE *f = NULL;
01801         isc_result_t result;
01802         char *tempname = NULL;
01803         char *file = NULL;
01804         dns_dumpctx_t *dctx = NULL;
01805 
01806         file = isc_mem_strdup(mctx, filename);
01807         if (file == NULL)
01808                 return (ISC_R_NOMEMORY);
01809 
01810         result = opentmp(mctx, format, filename, &tempname, &f);
01811         if (result != ISC_R_SUCCESS)
01812                 goto cleanup;
01813 
01814         result = dumpctx_create(mctx, db, version, style, f, &dctx,
01815                                 format, header);
01816         if (result != ISC_R_SUCCESS) {
01817                 (void)isc_stdio_close(f);
01818                 (void)isc_file_remove(tempname);
01819                 goto cleanup;
01820         }
01821 
01822         isc_task_attach(task, &dctx->task);
01823         dctx->done = done;
01824         dctx->done_arg = done_arg;
01825         dctx->nodes = 100;
01826         dctx->file = file;
01827         file = NULL;
01828         dctx->tmpfile = tempname;
01829         tempname = NULL;
01830 
01831         result = task_send(dctx);
01832         if (result == ISC_R_SUCCESS) {
01833                 dns_dumpctx_attach(dctx, dctxp);
01834                 return (DNS_R_CONTINUE);
01835         }
01836 
01837  cleanup:
01838         if (dctx != NULL)
01839                 dns_dumpctx_detach(&dctx);
01840         if (file != NULL)
01841                 isc_mem_free(mctx, file);
01842         if (tempname != NULL)
01843                 isc_mem_free(mctx, tempname);
01844         return (result);
01845 }
01846 
01847 isc_result_t
01848 dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01849                 const dns_master_style_t *style, const char *filename)
01850 {
01851         return (dns_master_dump3(mctx, db, version, style, filename,
01852                                  dns_masterformat_text, NULL));
01853 }
01854 
01855 isc_result_t
01856 dns_master_dump2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01857                  const dns_master_style_t *style, const char *filename,
01858                  dns_masterformat_t format)
01859 {
01860         return (dns_master_dump3(mctx, db, version, style, filename,
01861                                  format, NULL));
01862 }
01863 
01864 isc_result_t
01865 dns_master_dump3(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01866                  const dns_master_style_t *style, const char *filename,
01867                  dns_masterformat_t format, dns_masterrawheader_t *header)
01868 {
01869         FILE *f = NULL;
01870         isc_result_t result;
01871         char *tempname;
01872         dns_dumpctx_t *dctx = NULL;
01873 
01874         result = opentmp(mctx, format, filename, &tempname, &f);
01875         if (result != ISC_R_SUCCESS)
01876                 return (result);
01877 
01878         result = dumpctx_create(mctx, db, version, style, f, &dctx,
01879                                 format, header);
01880         if (result != ISC_R_SUCCESS)
01881                 goto cleanup;
01882 
01883         result = dumptostreaminc(dctx);
01884         INSIST(result != DNS_R_CONTINUE);
01885         dns_dumpctx_detach(&dctx);
01886 
01887         result = closeandrename(f, result, tempname, filename);
01888 
01889  cleanup:
01890         isc_mem_free(mctx, tempname);
01891         return (result);
01892 }
01893 
01894 /*
01895  * Dump a database node into a master file.
01896  * XXX: this function assumes the text format.
01897  */
01898 isc_result_t
01899 dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db,
01900                             dns_dbversion_t *version,
01901                             dns_dbnode_t *node, dns_name_t *name,
01902                             const dns_master_style_t *style,
01903                             FILE *f)
01904 {
01905         isc_result_t result;
01906         isc_buffer_t buffer;
01907         char *bufmem;
01908         isc_stdtime_t now;
01909         dns_totext_ctx_t ctx;
01910         dns_rdatasetiter_t *rdsiter = NULL;
01911 
01912         result = totext_ctx_init(style, &ctx);
01913         if (result != ISC_R_SUCCESS) {
01914                 UNEXPECTED_ERROR(__FILE__, __LINE__,
01915                                  "could not set master file style");
01916                 return (ISC_R_UNEXPECTED);
01917         }
01918 
01919         isc_stdtime_get(&now);
01920 
01921         bufmem = isc_mem_get(mctx, initial_buffer_length);
01922         if (bufmem == NULL)
01923                 return (ISC_R_NOMEMORY);
01924 
01925         isc_buffer_init(&buffer, bufmem, initial_buffer_length);
01926 
01927         result = dns_db_allrdatasets(db, node, version, now, &rdsiter);
01928         if (result != ISC_R_SUCCESS)
01929                 goto failure;
01930         result = dump_rdatasets_text(mctx, name, rdsiter, &ctx, &buffer, f);
01931         if (result != ISC_R_SUCCESS)
01932                 goto failure;
01933         dns_rdatasetiter_destroy(&rdsiter);
01934 
01935         result = ISC_R_SUCCESS;
01936 
01937  failure:
01938         isc_mem_put(mctx, buffer.base, buffer.length);
01939         return (result);
01940 }
01941 
01942 isc_result_t
01943 dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
01944                     dns_dbnode_t *node, dns_name_t *name,
01945                     const dns_master_style_t *style, const char *filename)
01946 {
01947         FILE *f = NULL;
01948         isc_result_t result;
01949 
01950         result = isc_stdio_open(filename, "w", &f);
01951         if (result != ISC_R_SUCCESS) {
01952                 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01953                               DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01954                               "dumping node to file: %s: open: %s", filename,
01955                               isc_result_totext(result));
01956                 return (ISC_R_UNEXPECTED);
01957         }
01958 
01959         result = dns_master_dumpnodetostream(mctx, db, version, node, name,
01960                                              style, f);
01961         if (result != ISC_R_SUCCESS) {
01962                 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01963                               DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01964                               "dumping master file: %s: dump: %s", filename,
01965                               isc_result_totext(result));
01966                 (void)isc_stdio_close(f);
01967                 return (ISC_R_UNEXPECTED);
01968         }
01969 
01970         result = isc_stdio_close(f);
01971         if (result != ISC_R_SUCCESS) {
01972                 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01973                               DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
01974                               "dumping master file: %s: close: %s", filename,
01975                               isc_result_totext(result));
01976                 return (ISC_R_UNEXPECTED);
01977         }
01978 
01979         return (result);
01980 }
01981 
01982 isc_result_t
01983 dns_master_stylecreate(dns_master_style_t **stylep, unsigned int flags,
01984                        unsigned int ttl_column, unsigned int class_column,
01985                        unsigned int type_column, unsigned int rdata_column,
01986                        unsigned int line_length, unsigned int tab_width,
01987                        isc_mem_t *mctx)
01988 {
01989         return (dns_master_stylecreate2(stylep, flags, ttl_column,
01990                                         class_column, type_column,
01991                                         rdata_column, line_length,
01992                                         tab_width, 0xffffffff, mctx));
01993 }
01994 
01995 isc_result_t
01996 dns_master_stylecreate2(dns_master_style_t **stylep, unsigned int flags,
01997                         unsigned int ttl_column, unsigned int class_column,
01998                         unsigned int type_column, unsigned int rdata_column,
01999                         unsigned int line_length, unsigned int tab_width,
02000                         unsigned int split_width, isc_mem_t *mctx)
02001 {
02002         dns_master_style_t *style;
02003 
02004         REQUIRE(stylep != NULL && *stylep == NULL);
02005         style = isc_mem_get(mctx, sizeof(*style));
02006         if (style == NULL)
02007                 return (ISC_R_NOMEMORY);
02008 
02009         style->flags = flags;
02010         style->ttl_column = ttl_column;
02011         style->class_column = class_column;
02012         style->type_column = type_column;
02013         style->rdata_column = rdata_column;
02014         style->line_length = line_length;
02015         style->tab_width = tab_width;
02016         style->split_width = split_width;
02017 
02018         *stylep = style;
02019         return (ISC_R_SUCCESS);
02020 }
02021 
02022 void
02023 dns_master_styledestroy(dns_master_style_t **stylep, isc_mem_t *mctx) {
02024         dns_master_style_t *style;
02025 
02026         REQUIRE(stylep != NULL && *stylep != NULL);
02027         style = *stylep;
02028         *stylep = NULL;
02029         isc_mem_put(mctx, style, sizeof(*style));
02030 }

Generated on Tue Apr 28 17:40:58 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha