xref: /openbsd/usr.bin/dig/lib/dns/masterdump.c (revision 4008b4f7)
15185a700Sflorian /*
25185a700Sflorian  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
35185a700Sflorian  *
45185a700Sflorian  * Permission to use, copy, modify, and/or distribute this software for any
55185a700Sflorian  * purpose with or without fee is hereby granted, provided that the above
65185a700Sflorian  * copyright notice and this permission notice appear in all copies.
75185a700Sflorian  *
85185a700Sflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
95185a700Sflorian  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
105185a700Sflorian  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
115185a700Sflorian  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
125185a700Sflorian  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
135185a700Sflorian  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
145185a700Sflorian  * PERFORMANCE OF THIS SOFTWARE.
155185a700Sflorian  */
165185a700Sflorian 
175185a700Sflorian /*! \file */
185185a700Sflorian 
195185a700Sflorian #include <limits.h>
205185a700Sflorian #include <stdlib.h>
215185a700Sflorian #include <string.h>
225185a700Sflorian 
235185a700Sflorian #include <isc/types.h>
245185a700Sflorian #include <isc/util.h>
255185a700Sflorian 
265185a700Sflorian #include <dns/fixedname.h>
275185a700Sflorian #include <dns/masterdump.h>
285185a700Sflorian #include <dns/rdata.h>
295185a700Sflorian #include <dns/rdataclass.h>
305185a700Sflorian #include <dns/rdataset.h>
315185a700Sflorian #include <dns/rdatatype.h>
325185a700Sflorian #include <dns/result.h>
335185a700Sflorian 
345185a700Sflorian #define RETERR(x) do { \
355185a700Sflorian 	isc_result_t _r = (x); \
365185a700Sflorian 	if (_r != ISC_R_SUCCESS) \
375185a700Sflorian 		return (_r); \
385185a700Sflorian 	} while (0)
395185a700Sflorian 
405185a700Sflorian struct dns_master_style {
415185a700Sflorian 	dns_masterstyle_flags_t flags;		/* DNS_STYLEFLAG_* */
425185a700Sflorian 	unsigned int ttl_column;
435185a700Sflorian 	unsigned int class_column;
445185a700Sflorian 	unsigned int type_column;
455185a700Sflorian 	unsigned int rdata_column;
465185a700Sflorian 	unsigned int line_length;
475185a700Sflorian 	unsigned int tab_width;
485185a700Sflorian 	unsigned int split_width;
495185a700Sflorian };
505185a700Sflorian 
515185a700Sflorian /*%
525185a700Sflorian  * The maximum length of the newline+indentation that is output
535185a700Sflorian  * when inserting a line break in an RR.  This effectively puts an
545185a700Sflorian  * upper limits on the value of "rdata_column", because if it is
555185a700Sflorian  * very large, the tabs and spaces needed to reach it will not fit.
565185a700Sflorian  */
575185a700Sflorian #define DNS_TOTEXT_LINEBREAK_MAXLEN 100
585185a700Sflorian 
595185a700Sflorian /*%
605185a700Sflorian  * Context structure for a masterfile dump in progress.
615185a700Sflorian  */
625185a700Sflorian typedef struct dns_totext_ctx {
635185a700Sflorian 	dns_master_style_t	style;
64*1fb015a8Sflorian 	int 		class_printed;
655185a700Sflorian 	char *			linebreak;
665185a700Sflorian 	char 			linebreak_buf[DNS_TOTEXT_LINEBREAK_MAXLEN];
675185a700Sflorian 	dns_name_t *		origin;
685185a700Sflorian 	dns_name_t *		neworigin;
695185a700Sflorian 	dns_fixedname_t		origin_fixname;
705185a700Sflorian 	uint32_t 		current_ttl;
71*1fb015a8Sflorian 	int 		current_ttl_valid;
725185a700Sflorian } dns_totext_ctx_t;
735185a700Sflorian 
745185a700Sflorian /*%
755185a700Sflorian  * A style suitable for dns_rdataset_totext().
765185a700Sflorian  */
775185a700Sflorian const dns_master_style_t
785185a700Sflorian dns_master_style_debug = {
795185a700Sflorian 	DNS_STYLEFLAG_REL_OWNER,
805185a700Sflorian 	24, 32, 40, 48, 80, 8, UINT_MAX
815185a700Sflorian };
825185a700Sflorian 
835185a700Sflorian #define N_SPACES 10
845185a700Sflorian static char spaces[N_SPACES+1] = "          ";
855185a700Sflorian 
865185a700Sflorian #define N_TABS 10
875185a700Sflorian static char tabs[N_TABS+1] = "\t\t\t\t\t\t\t\t\t\t";
885185a700Sflorian 
895185a700Sflorian /*%
905185a700Sflorian  * Output tabs and spaces to go from column '*current' to
915185a700Sflorian  * column 'to', and update '*current' to reflect the new
925185a700Sflorian  * current column.
935185a700Sflorian  */
945185a700Sflorian static isc_result_t
indent(unsigned int * current,unsigned int to,int tabwidth,isc_buffer_t * target)955185a700Sflorian indent(unsigned int *current, unsigned int to, int tabwidth,
965185a700Sflorian        isc_buffer_t *target)
975185a700Sflorian {
985185a700Sflorian 	isc_region_t r;
995185a700Sflorian 	unsigned char *p;
1005185a700Sflorian 	unsigned int from;
1015185a700Sflorian 	int ntabs, nspaces, t;
1025185a700Sflorian 
1035185a700Sflorian 	from = *current;
1045185a700Sflorian 
1055185a700Sflorian 	if (to < from + 1)
1065185a700Sflorian 		to = from + 1;
1075185a700Sflorian 
1085185a700Sflorian 	ntabs = to / tabwidth - from / tabwidth;
1095185a700Sflorian 	if (ntabs < 0)
1105185a700Sflorian 		ntabs = 0;
1115185a700Sflorian 
1125185a700Sflorian 	if (ntabs > 0) {
1135185a700Sflorian 		isc_buffer_availableregion(target, &r);
1145185a700Sflorian 		if (r.length < (unsigned) ntabs)
1155185a700Sflorian 			return (ISC_R_NOSPACE);
1165185a700Sflorian 		p = r.base;
1175185a700Sflorian 
1185185a700Sflorian 		t = ntabs;
1195185a700Sflorian 		while (t) {
1205185a700Sflorian 			int n = t;
1215185a700Sflorian 			if (n > N_TABS)
1225185a700Sflorian 				n = N_TABS;
1235185a700Sflorian 			memmove(p, tabs, n);
1245185a700Sflorian 			p += n;
1255185a700Sflorian 			t -= n;
1265185a700Sflorian 		}
1275185a700Sflorian 		isc_buffer_add(target, ntabs);
1285185a700Sflorian 		from = (to / tabwidth) * tabwidth;
1295185a700Sflorian 	}
1305185a700Sflorian 
1315185a700Sflorian 	nspaces = to - from;
1325185a700Sflorian 	INSIST(nspaces >= 0);
1335185a700Sflorian 
1345185a700Sflorian 	isc_buffer_availableregion(target, &r);
1355185a700Sflorian 	if (r.length < (unsigned) nspaces)
1365185a700Sflorian 		return (ISC_R_NOSPACE);
1375185a700Sflorian 	p = r.base;
1385185a700Sflorian 
1395185a700Sflorian 	t = nspaces;
1405185a700Sflorian 	while (t) {
1415185a700Sflorian 		int n = t;
1425185a700Sflorian 		if (n > N_SPACES)
1435185a700Sflorian 			n = N_SPACES;
1445185a700Sflorian 		memmove(p, spaces, n);
1455185a700Sflorian 		p += n;
1465185a700Sflorian 		t -= n;
1475185a700Sflorian 	}
1485185a700Sflorian 	isc_buffer_add(target, nspaces);
1495185a700Sflorian 
1505185a700Sflorian 	*current = to;
1515185a700Sflorian 	return (ISC_R_SUCCESS);
1525185a700Sflorian }
1535185a700Sflorian 
1545185a700Sflorian static isc_result_t
totext_ctx_init(const dns_master_style_t * style,dns_totext_ctx_t * ctx)1555185a700Sflorian totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) {
1565185a700Sflorian 	isc_result_t result;
1575185a700Sflorian 
1585185a700Sflorian 	REQUIRE(style->tab_width != 0);
1595185a700Sflorian 
1605185a700Sflorian 	ctx->style = *style;
161*1fb015a8Sflorian 	ctx->class_printed = 0;
1625185a700Sflorian 
1635185a700Sflorian 	dns_fixedname_init(&ctx->origin_fixname);
1645185a700Sflorian 
1655185a700Sflorian 	/*
1665185a700Sflorian 	 * Set up the line break string if needed.
1675185a700Sflorian 	 */
1685185a700Sflorian 	if ((ctx->style.flags & DNS_STYLEFLAG_MULTILINE) != 0) {
1695185a700Sflorian 		isc_buffer_t buf;
1705185a700Sflorian 		isc_region_t r;
1715185a700Sflorian 		unsigned int col = 0;
1725185a700Sflorian 
1735185a700Sflorian 		isc_buffer_init(&buf, ctx->linebreak_buf,
1745185a700Sflorian 				sizeof(ctx->linebreak_buf));
1755185a700Sflorian 
1765185a700Sflorian 		isc_buffer_availableregion(&buf, &r);
1775185a700Sflorian 		if (r.length < 1)
1785185a700Sflorian 			return (DNS_R_TEXTTOOLONG);
1795185a700Sflorian 		r.base[0] = '\n';
1805185a700Sflorian 		isc_buffer_add(&buf, 1);
1815185a700Sflorian 
1825185a700Sflorian 		if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0) {
1835185a700Sflorian 			isc_buffer_availableregion(&buf, &r);
1845185a700Sflorian 			if (r.length < 1)
1855185a700Sflorian 				return (DNS_R_TEXTTOOLONG);
1865185a700Sflorian 			r.base[0] = ';';
1875185a700Sflorian 			isc_buffer_add(&buf, 1);
1885185a700Sflorian 		}
1895185a700Sflorian 
1905185a700Sflorian 		result = indent(&col, ctx->style.rdata_column,
1915185a700Sflorian 				ctx->style.tab_width, &buf);
1925185a700Sflorian 		/*
1935185a700Sflorian 		 * Do not return ISC_R_NOSPACE if the line break string
1945185a700Sflorian 		 * buffer is too small, because that would just make
1955185a700Sflorian 		 * dump_rdataset() retry indefinitely with ever
1965185a700Sflorian 		 * bigger target buffers.  That's a different buffer,
1975185a700Sflorian 		 * so it won't help.  Use DNS_R_TEXTTOOLONG as a substitute.
1985185a700Sflorian 		 */
1995185a700Sflorian 		if (result == ISC_R_NOSPACE)
2005185a700Sflorian 			return (DNS_R_TEXTTOOLONG);
2015185a700Sflorian 		if (result != ISC_R_SUCCESS)
2025185a700Sflorian 			return (result);
2035185a700Sflorian 
2045185a700Sflorian 		isc_buffer_availableregion(&buf, &r);
2055185a700Sflorian 		if (r.length < 1)
2065185a700Sflorian 			return (DNS_R_TEXTTOOLONG);
2075185a700Sflorian 		r.base[0] = '\0';
2085185a700Sflorian 		isc_buffer_add(&buf, 1);
2095185a700Sflorian 		ctx->linebreak = ctx->linebreak_buf;
2105185a700Sflorian 	} else {
2115185a700Sflorian 		ctx->linebreak = NULL;
2125185a700Sflorian 	}
2135185a700Sflorian 
2145185a700Sflorian 	ctx->origin = NULL;
2155185a700Sflorian 	ctx->neworigin = NULL;
2165185a700Sflorian 	ctx->current_ttl = 0;
217*1fb015a8Sflorian 	ctx->current_ttl_valid = 0;
2185185a700Sflorian 
2195185a700Sflorian 	return (ISC_R_SUCCESS);
2205185a700Sflorian }
2215185a700Sflorian 
2225185a700Sflorian #define INDENT_TO(col) \
2235185a700Sflorian 	do { \
2245185a700Sflorian 		 if ((result = indent(&column, ctx->style.col, \
2255185a700Sflorian 				      ctx->style.tab_width, target)) \
2265185a700Sflorian 		     != ISC_R_SUCCESS) \
2275185a700Sflorian 			    return (result); \
2285185a700Sflorian 	} while (0)
2295185a700Sflorian 
2305185a700Sflorian /*
2315185a700Sflorian  * Convert 'rdataset' to master file text format according to 'ctx',
2325185a700Sflorian  * storing the result in 'target'.  If 'owner_name' is NULL, it
2335185a700Sflorian  * is omitted; otherwise 'owner_name' must be valid and have at least
2345185a700Sflorian  * one label.
2355185a700Sflorian  */
2365185a700Sflorian 
2375185a700Sflorian static isc_result_t
rdataset_totext(dns_rdataset_t * rdataset,dns_name_t * owner_name,dns_totext_ctx_t * ctx,int omit_final_dot,isc_buffer_t * target)2385185a700Sflorian rdataset_totext(dns_rdataset_t *rdataset,
2395185a700Sflorian 		dns_name_t *owner_name,
2405185a700Sflorian 		dns_totext_ctx_t *ctx,
241*1fb015a8Sflorian 		int omit_final_dot,
2425185a700Sflorian 		isc_buffer_t *target)
2435185a700Sflorian {
2445185a700Sflorian 	isc_result_t result;
2455185a700Sflorian 	unsigned int column;
246*1fb015a8Sflorian 	int first = 1;
2475185a700Sflorian 	uint32_t current_ttl;
248*1fb015a8Sflorian 	int current_ttl_valid;
2495185a700Sflorian 	dns_rdatatype_t type;
2505185a700Sflorian 	unsigned int type_start;
2515185a700Sflorian 
2525185a700Sflorian 	result = dns_rdataset_first(rdataset);
2535185a700Sflorian 
2545185a700Sflorian 	current_ttl = ctx->current_ttl;
2555185a700Sflorian 	current_ttl_valid = ctx->current_ttl_valid;
2565185a700Sflorian 
2575185a700Sflorian 	while (result == ISC_R_SUCCESS) {
2585185a700Sflorian 		column = 0;
2595185a700Sflorian 
2605185a700Sflorian 		/*
2615185a700Sflorian 		 * Comment?
2625185a700Sflorian 		 */
2635185a700Sflorian 		if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0)
264873f12b9Sflorian 			RETERR(isc_str_tobuffer(";", target));
2655185a700Sflorian 
2665185a700Sflorian 		/*
2675185a700Sflorian 		 * Owner name.
2685185a700Sflorian 		 */
2695185a700Sflorian 		if (owner_name != NULL &&
2705185a700Sflorian 		    ! ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0 &&
2715185a700Sflorian 		       !first))
2725185a700Sflorian 		{
2735185a700Sflorian 			unsigned int name_start = target->used;
2745185a700Sflorian 			RETERR(dns_name_totext(owner_name,
2755185a700Sflorian 					       omit_final_dot,
2765185a700Sflorian 					       target));
2775185a700Sflorian 			column += target->used - name_start;
2785185a700Sflorian 		}
2795185a700Sflorian 
2805185a700Sflorian 		/*
2815185a700Sflorian 		 * TTL.
2825185a700Sflorian 		 */
2835185a700Sflorian 		if ((ctx->style.flags & DNS_STYLEFLAG_NO_TTL) == 0 &&
2845185a700Sflorian 		    !((ctx->style.flags & DNS_STYLEFLAG_OMIT_TTL) != 0 &&
2855185a700Sflorian 		      current_ttl_valid &&
2865185a700Sflorian 		      rdataset->ttl == current_ttl))
2875185a700Sflorian 		{
2885185a700Sflorian 			char ttlbuf[64];
2895185a700Sflorian 			isc_region_t r;
2905185a700Sflorian 			unsigned int length;
2915185a700Sflorian 
2925185a700Sflorian 			INDENT_TO(ttl_column);
2935185a700Sflorian 			length = snprintf(ttlbuf, sizeof(ttlbuf), "%u",
2945185a700Sflorian 					  rdataset->ttl);
2955185a700Sflorian 			INSIST(length <= sizeof(ttlbuf));
2965185a700Sflorian 			isc_buffer_availableregion(target, &r);
2975185a700Sflorian 			if (r.length < length)
2985185a700Sflorian 				return (ISC_R_NOSPACE);
2995185a700Sflorian 			memmove(r.base, ttlbuf, length);
3005185a700Sflorian 			isc_buffer_add(target, length);
3015185a700Sflorian 			column += length;
3025185a700Sflorian 
3035185a700Sflorian 			/*
3045185a700Sflorian 			 * If the $TTL directive is not in use, the TTL we
3055185a700Sflorian 			 * just printed becomes the default for subsequent RRs.
3065185a700Sflorian 			 */
3075185a700Sflorian 			if ((ctx->style.flags & DNS_STYLEFLAG_TTL) == 0) {
3085185a700Sflorian 				current_ttl = rdataset->ttl;
309*1fb015a8Sflorian 				current_ttl_valid = 1;
3105185a700Sflorian 			}
3115185a700Sflorian 		}
3125185a700Sflorian 
3135185a700Sflorian 		/*
3145185a700Sflorian 		 * Class.
3155185a700Sflorian 		 */
3165185a700Sflorian 		if ((ctx->style.flags & DNS_STYLEFLAG_NO_CLASS) == 0 &&
3175185a700Sflorian 		    ((ctx->style.flags & DNS_STYLEFLAG_OMIT_CLASS) == 0 ||
318*1fb015a8Sflorian 		     !ctx->class_printed))
3195185a700Sflorian 		{
3205185a700Sflorian 			unsigned int class_start;
3215185a700Sflorian 			INDENT_TO(class_column);
3225185a700Sflorian 			class_start = target->used;
3235185a700Sflorian 			result = dns_rdataclass_totext(rdataset->rdclass,
3245185a700Sflorian 						       target);
3255185a700Sflorian 			if (result != ISC_R_SUCCESS)
3265185a700Sflorian 				return (result);
3275185a700Sflorian 			column += (target->used - class_start);
3285185a700Sflorian 		}
3295185a700Sflorian 
3305185a700Sflorian 		/*
3315185a700Sflorian 		 * Type.
3325185a700Sflorian 		 */
3335185a700Sflorian 
3345185a700Sflorian 		type = rdataset->type;
3355185a700Sflorian 
3365185a700Sflorian 		INDENT_TO(type_column);
3375185a700Sflorian 		type_start = target->used;
3385185a700Sflorian 		switch (type) {
3395185a700Sflorian 		case dns_rdatatype_keydata:
3405185a700Sflorian #define KEYDATA "KEYDATA"
3415185a700Sflorian 			if ((ctx->style.flags & DNS_STYLEFLAG_KEYDATA) != 0) {
3425185a700Sflorian 				if (isc_buffer_availablelength(target) <
3435185a700Sflorian 				    (sizeof(KEYDATA) - 1))
3445185a700Sflorian 					return (ISC_R_NOSPACE);
3455185a700Sflorian 				isc_buffer_putstr(target, KEYDATA);
3465185a700Sflorian 				break;
3475185a700Sflorian 			}
3485185a700Sflorian 			/* FALLTHROUGH */
3495185a700Sflorian 		default:
3505185a700Sflorian 			result = dns_rdatatype_totext(type, target);
3515185a700Sflorian 			if (result != ISC_R_SUCCESS)
3525185a700Sflorian 				return (result);
3535185a700Sflorian 		}
3545185a700Sflorian 		column += (target->used - type_start);
3555185a700Sflorian 
3565185a700Sflorian 		/*
3575185a700Sflorian 		 * Rdata.
3585185a700Sflorian 		 */
3595185a700Sflorian 		INDENT_TO(rdata_column);
3605185a700Sflorian 		{
3615185a700Sflorian 			dns_rdata_t rdata = DNS_RDATA_INIT;
3625185a700Sflorian 			isc_region_t r;
3635185a700Sflorian 
3645185a700Sflorian 			dns_rdataset_current(rdataset, &rdata);
3655185a700Sflorian 
3665185a700Sflorian 			RETERR(dns_rdata_tofmttext(&rdata,
3675185a700Sflorian 						   ctx->origin,
3685185a700Sflorian 						   (unsigned int)
3695185a700Sflorian 						   ctx->style.flags,
3705185a700Sflorian 						   ctx->style.line_length -
3715185a700Sflorian 						       ctx->style.rdata_column,
3725185a700Sflorian 						   ctx->style.split_width,
3735185a700Sflorian 						   ctx->linebreak,
3745185a700Sflorian 						   target));
3755185a700Sflorian 
3765185a700Sflorian 			isc_buffer_availableregion(target, &r);
3775185a700Sflorian 			if (r.length < 1)
3785185a700Sflorian 				return (ISC_R_NOSPACE);
3795185a700Sflorian 			r.base[0] = '\n';
3805185a700Sflorian 			isc_buffer_add(target, 1);
3815185a700Sflorian 		}
3825185a700Sflorian 
383*1fb015a8Sflorian 		first = 0;
3845185a700Sflorian 		result = dns_rdataset_next(rdataset);
3855185a700Sflorian 	}
3865185a700Sflorian 
3875185a700Sflorian 	if (result != ISC_R_NOMORE)
3885185a700Sflorian 		return (result);
3895185a700Sflorian 
3905185a700Sflorian 	/*
3915185a700Sflorian 	 * Update the ctx state to reflect what we just printed.
3925185a700Sflorian 	 * This is done last, only when we are sure we will return
3935185a700Sflorian 	 * success, because this function may be called multiple
3945185a700Sflorian 	 * times with increasing buffer sizes until it succeeds,
3955185a700Sflorian 	 * and failed attempts must not update the state prematurely.
3965185a700Sflorian 	 */
397*1fb015a8Sflorian 	ctx->class_printed = 1;
3985185a700Sflorian 	ctx->current_ttl= current_ttl;
3995185a700Sflorian 	ctx->current_ttl_valid = current_ttl_valid;
4005185a700Sflorian 
4015185a700Sflorian 	return (ISC_R_SUCCESS);
4025185a700Sflorian }
4035185a700Sflorian 
4045185a700Sflorian /*
4055185a700Sflorian  * Print the name, type, and class of an empty rdataset,
4065185a700Sflorian  * such as those used to represent the question section
4075185a700Sflorian  * of a DNS message.
4085185a700Sflorian  */
4095185a700Sflorian static isc_result_t
question_totext(dns_rdataset_t * rdataset,dns_name_t * owner_name,dns_totext_ctx_t * ctx,int omit_final_dot,isc_buffer_t * target)4105185a700Sflorian question_totext(dns_rdataset_t *rdataset,
4115185a700Sflorian 		dns_name_t *owner_name,
4125185a700Sflorian 		dns_totext_ctx_t *ctx,
413*1fb015a8Sflorian 		int omit_final_dot,
4145185a700Sflorian 		isc_buffer_t *target)
4155185a700Sflorian {
4165185a700Sflorian 	unsigned int column;
4175185a700Sflorian 	isc_result_t result;
4185185a700Sflorian 	isc_region_t r;
4195185a700Sflorian 
4205185a700Sflorian 	result = dns_rdataset_first(rdataset);
4215185a700Sflorian 	REQUIRE(result == ISC_R_NOMORE);
4225185a700Sflorian 
4235185a700Sflorian 	column = 0;
4245185a700Sflorian 
4255185a700Sflorian 	/* Owner name */
4265185a700Sflorian 	{
4275185a700Sflorian 		unsigned int name_start = target->used;
4285185a700Sflorian 		RETERR(dns_name_totext(owner_name,
4295185a700Sflorian 				       omit_final_dot,
4305185a700Sflorian 				       target));
4315185a700Sflorian 		column += target->used - name_start;
4325185a700Sflorian 	}
4335185a700Sflorian 
4345185a700Sflorian 	/* Class */
4355185a700Sflorian 	{
4365185a700Sflorian 		unsigned int class_start;
4375185a700Sflorian 		INDENT_TO(class_column);
4385185a700Sflorian 		class_start = target->used;
4395185a700Sflorian 		result = dns_rdataclass_totext(rdataset->rdclass, target);
4405185a700Sflorian 		if (result != ISC_R_SUCCESS)
4415185a700Sflorian 			return (result);
4425185a700Sflorian 		column += (target->used - class_start);
4435185a700Sflorian 	}
4445185a700Sflorian 
4455185a700Sflorian 	/* Type */
4465185a700Sflorian 	{
4475185a700Sflorian 		unsigned int type_start;
4485185a700Sflorian 		INDENT_TO(type_column);
4495185a700Sflorian 		type_start = target->used;
4505185a700Sflorian 		result = dns_rdatatype_totext(rdataset->type, target);
4515185a700Sflorian 		if (result != ISC_R_SUCCESS)
4525185a700Sflorian 			return (result);
4535185a700Sflorian 		column += (target->used - type_start);
4545185a700Sflorian 	}
4555185a700Sflorian 
4565185a700Sflorian 	isc_buffer_availableregion(target, &r);
4575185a700Sflorian 	if (r.length < 1)
4585185a700Sflorian 		return (ISC_R_NOSPACE);
4595185a700Sflorian 	r.base[0] = '\n';
4605185a700Sflorian 	isc_buffer_add(target, 1);
4615185a700Sflorian 
4625185a700Sflorian 	return (ISC_R_SUCCESS);
4635185a700Sflorian }
4645185a700Sflorian 
4655185a700Sflorian isc_result_t
dns_rdataset_totext(dns_rdataset_t * rdataset,dns_name_t * owner_name,int omit_final_dot,int question,isc_buffer_t * target)4665185a700Sflorian dns_rdataset_totext(dns_rdataset_t *rdataset,
4675185a700Sflorian 		    dns_name_t *owner_name,
468*1fb015a8Sflorian 		    int omit_final_dot,
469*1fb015a8Sflorian 		    int question,
4705185a700Sflorian 		    isc_buffer_t *target)
4715185a700Sflorian {
4725185a700Sflorian 	dns_totext_ctx_t ctx;
4735185a700Sflorian 	isc_result_t result;
4745185a700Sflorian 	result = totext_ctx_init(&dns_master_style_debug, &ctx);
4755185a700Sflorian 	if (result != ISC_R_SUCCESS) {
4765185a700Sflorian 		UNEXPECTED_ERROR(__FILE__, __LINE__,
4775185a700Sflorian 				 "could not set master file style");
4785185a700Sflorian 		return (ISC_R_UNEXPECTED);
4795185a700Sflorian 	}
4805185a700Sflorian 
4815185a700Sflorian 	/*
4825185a700Sflorian 	 * The caller might want to give us an empty owner
4835185a700Sflorian 	 * name (e.g. if they are outputting into a master
4845185a700Sflorian 	 * file and this rdataset has the same name as the
4855185a700Sflorian 	 * previous one.)
4865185a700Sflorian 	 */
4875185a700Sflorian 	if (dns_name_countlabels(owner_name) == 0)
4885185a700Sflorian 		owner_name = NULL;
4895185a700Sflorian 
4905185a700Sflorian 	if (question)
4915185a700Sflorian 		return (question_totext(rdataset, owner_name, &ctx,
4925185a700Sflorian 					omit_final_dot, target));
4935185a700Sflorian 	else
4945185a700Sflorian 		return (rdataset_totext(rdataset, owner_name, &ctx,
4955185a700Sflorian 					omit_final_dot, target));
4965185a700Sflorian }
4975185a700Sflorian 
4985185a700Sflorian isc_result_t
dns_master_rdatasettotext(dns_name_t * owner_name,dns_rdataset_t * rdataset,const dns_master_style_t * style,isc_buffer_t * target)4995185a700Sflorian dns_master_rdatasettotext(dns_name_t *owner_name,
5005185a700Sflorian 			  dns_rdataset_t *rdataset,
5015185a700Sflorian 			  const dns_master_style_t *style,
5025185a700Sflorian 			  isc_buffer_t *target)
5035185a700Sflorian {
5045185a700Sflorian 	dns_totext_ctx_t ctx;
5055185a700Sflorian 	isc_result_t result;
5065185a700Sflorian 	result = totext_ctx_init(style, &ctx);
5075185a700Sflorian 	if (result != ISC_R_SUCCESS) {
5085185a700Sflorian 		UNEXPECTED_ERROR(__FILE__, __LINE__,
5095185a700Sflorian 				 "could not set master file style");
5105185a700Sflorian 		return (ISC_R_UNEXPECTED);
5115185a700Sflorian 	}
5125185a700Sflorian 
5135185a700Sflorian 	return (rdataset_totext(rdataset, owner_name, &ctx,
514*1fb015a8Sflorian 				0, target));
5155185a700Sflorian }
5165185a700Sflorian 
5175185a700Sflorian isc_result_t
dns_master_questiontotext(dns_name_t * owner_name,dns_rdataset_t * rdataset,const dns_master_style_t * style,isc_buffer_t * target)5185185a700Sflorian dns_master_questiontotext(dns_name_t *owner_name,
5195185a700Sflorian 			  dns_rdataset_t *rdataset,
5205185a700Sflorian 			  const dns_master_style_t *style,
5215185a700Sflorian 			  isc_buffer_t *target)
5225185a700Sflorian {
5235185a700Sflorian 	dns_totext_ctx_t ctx;
5245185a700Sflorian 	isc_result_t result;
5255185a700Sflorian 	result = totext_ctx_init(style, &ctx);
5265185a700Sflorian 	if (result != ISC_R_SUCCESS) {
5275185a700Sflorian 		UNEXPECTED_ERROR(__FILE__, __LINE__,
5285185a700Sflorian 				 "could not set master file style");
5295185a700Sflorian 		return (ISC_R_UNEXPECTED);
5305185a700Sflorian 	}
5315185a700Sflorian 
5325185a700Sflorian 	return (question_totext(rdataset, owner_name, &ctx,
533*1fb015a8Sflorian 				0, target));
5345185a700Sflorian }
5355185a700Sflorian 
5365185a700Sflorian isc_result_t
dns_master_stylecreate2(dns_master_style_t ** stylep,unsigned int flags,unsigned int ttl_column,unsigned int class_column,unsigned int type_column,unsigned int rdata_column,unsigned int line_length,unsigned int tab_width,unsigned int split_width)5375185a700Sflorian dns_master_stylecreate2(dns_master_style_t **stylep, unsigned int flags,
5385185a700Sflorian 			unsigned int ttl_column, unsigned int class_column,
5395185a700Sflorian 			unsigned int type_column, unsigned int rdata_column,
5405185a700Sflorian 			unsigned int line_length, unsigned int tab_width,
5415185a700Sflorian 			unsigned int split_width)
5425185a700Sflorian {
5435185a700Sflorian 	dns_master_style_t *style;
5445185a700Sflorian 
5455185a700Sflorian 	REQUIRE(stylep != NULL && *stylep == NULL);
5465185a700Sflorian 	style = malloc(sizeof(*style));
5475185a700Sflorian 	if (style == NULL)
5485185a700Sflorian 		return (ISC_R_NOMEMORY);
5495185a700Sflorian 
5505185a700Sflorian 	style->flags = flags;
5515185a700Sflorian 	style->ttl_column = ttl_column;
5525185a700Sflorian 	style->class_column = class_column;
5535185a700Sflorian 	style->type_column = type_column;
5545185a700Sflorian 	style->rdata_column = rdata_column;
5555185a700Sflorian 	style->line_length = line_length;
5565185a700Sflorian 	style->tab_width = tab_width;
5575185a700Sflorian 	style->split_width = split_width;
5585185a700Sflorian 
5595185a700Sflorian 	*stylep = style;
5605185a700Sflorian 	return (ISC_R_SUCCESS);
5615185a700Sflorian }
5625185a700Sflorian 
5635185a700Sflorian void
dns_master_styledestroy(dns_master_style_t ** stylep)5645185a700Sflorian dns_master_styledestroy(dns_master_style_t **stylep) {
5655185a700Sflorian 	dns_master_style_t *style;
5665185a700Sflorian 
5675185a700Sflorian 	REQUIRE(stylep != NULL && *stylep != NULL);
5685185a700Sflorian 	style = *stylep;
5695185a700Sflorian 	*stylep = NULL;
5705185a700Sflorian 	free(style);
5715185a700Sflorian }
572