Home | History | Annotate | Line # | Download | only in nameser
ns_print.c revision 1.9
      1 /*	$NetBSD: ns_print.c,v 1.9 2009/04/12 17:07:17 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
      5  * Copyright (c) 1996-1999 by Internet Software Consortium.
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 #include <sys/cdefs.h>
     21 #ifndef lint
     22 #ifdef notdef
     23 static const char rcsid[] = "Id: ns_print.c,v 1.12 2009/03/03 05:29:58 each Exp";
     24 #else
     25 __RCSID("$NetBSD: ns_print.c,v 1.9 2009/04/12 17:07:17 christos Exp $");
     26 #endif
     27 #endif
     28 
     29 /* Import. */
     30 
     31 #include "port_before.h"
     32 
     33 #include <sys/types.h>
     34 #include <sys/socket.h>
     35 
     36 #include <netinet/in.h>
     37 #include <arpa/nameser.h>
     38 #include <arpa/inet.h>
     39 
     40 #include <isc/assertions.h>
     41 #include <isc/dst.h>
     42 #include <errno.h>
     43 #include <resolv.h>
     44 #include <string.h>
     45 #include <ctype.h>
     46 
     47 #include "port_after.h"
     48 
     49 #ifdef SPRINTF_CHAR
     50 # define SPRINTF(x) strlen(sprintf/**/x)
     51 #else
     52 # define SPRINTF(x) ((size_t)sprintf x)
     53 #endif
     54 
     55 /* Forward. */
     56 
     57 static size_t	prune_origin(const char *name, const char *origin);
     58 static int	charstr(const u_char *rdata, const u_char *edata,
     59 			char **buf, size_t *buflen);
     60 static int	addname(const u_char *msg, size_t msglen,
     61 			const u_char **p, const char *origin,
     62 			char **buf, size_t *buflen);
     63 static void	addlen(size_t len, char **buf, size_t *buflen);
     64 static int	addstr(const char *src, size_t len,
     65 		       char **buf, size_t *buflen);
     66 static int	addtab(size_t len, size_t target, int spaced,
     67 		       char **buf, size_t *buflen);
     68 
     69 /* Macros. */
     70 
     71 #define	T(x) \
     72 	do { \
     73 		if ((x) < 0) \
     74 			return (-1); \
     75 	} while (/*CONSTCOND*/0)
     76 
     77 static const char base32hex[] =
     78         "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
     79 
     80 /* Public. */
     81 
     82 /*%
     83  *	Convert an RR to presentation format.
     84  *
     85  * return:
     86  *\li	Number of characters written to buf, or -1 (check errno).
     87  */
     88 int
     89 ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
     90 	    const char *name_ctx, const char *origin,
     91 	    char *buf, size_t buflen)
     92 {
     93 	int n;
     94 
     95 	n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
     96 			 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
     97 			 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
     98 			 name_ctx, origin, buf, buflen);
     99 	return (n);
    100 }
    101 
    102 /*%
    103  *	Convert the fields of an RR into presentation format.
    104  *
    105  * return:
    106  *\li	Number of characters written to buf, or -1 (check errno).
    107  */
    108 int
    109 ns_sprintrrf(const u_char *msg, size_t msglen,
    110 	    const char *name, ns_class class, ns_type type,
    111 	    u_long ttl, const u_char *rdata, size_t rdlen,
    112 	    const char *name_ctx, const char *origin,
    113 	    char *buf, size_t buflen)
    114 {
    115 	const char *obuf = buf;
    116 	const u_char *edata = rdata + rdlen;
    117 	int spaced = 0;
    118 
    119 	const char *comment;
    120 	char tmp[100];
    121 	int len, x;
    122 
    123 	/*
    124 	 * Owner.
    125 	 */
    126 	if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
    127 		T(addstr("\t\t\t", (size_t)3, &buf, &buflen));
    128 	} else {
    129 		len = prune_origin(name, origin);
    130 		if (*name == '\0') {
    131 			goto root;
    132 		} else if (len == 0) {
    133 			T(addstr("@\t\t\t", (size_t)4, &buf, &buflen));
    134 		} else {
    135 			T(addstr(name, (size_t)len, &buf, &buflen));
    136 			/* Origin not used or not root, and no trailing dot? */
    137 			if (((origin == NULL || origin[0] == '\0') ||
    138 			    (origin[0] != '.' && origin[1] != '\0' &&
    139 			    name[len] == '\0')) && name[len - 1] != '.') {
    140  root:
    141 				T(addstr(".", (size_t)1, &buf, &buflen));
    142 				len++;
    143 			}
    144 			T(spaced = addtab((size_t)len, 24, spaced, &buf, &buflen));
    145 		}
    146 	}
    147 
    148 	/*
    149 	 * TTL, Class, Type.
    150 	 */
    151 	T(x = ns_format_ttl(ttl, buf, buflen));
    152 	addlen((size_t)x, &buf, &buflen);
    153 	len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
    154 	T(addstr(tmp, (size_t)len, &buf, &buflen));
    155 	T(spaced = addtab((size_t)(x + len), (size_t)16, spaced, &buf, &buflen));
    156 
    157 	/*
    158 	 * RData.
    159 	 */
    160 	switch (type) {
    161 	case ns_t_a:
    162 		if (rdlen != (size_t)NS_INADDRSZ)
    163 			goto formerr;
    164 		(void) inet_ntop(AF_INET, rdata, buf, buflen);
    165 		addlen(strlen(buf), &buf, &buflen);
    166 		break;
    167 
    168 	case ns_t_cname:
    169 	case ns_t_mb:
    170 	case ns_t_mg:
    171 	case ns_t_mr:
    172 	case ns_t_ns:
    173 	case ns_t_ptr:
    174 	case ns_t_dname:
    175 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    176 		break;
    177 
    178 	case ns_t_hinfo:
    179 	case ns_t_isdn:
    180 		/* First word. */
    181 		T(len = charstr(rdata, edata, &buf, &buflen));
    182 		if (len == 0)
    183 			goto formerr;
    184 		rdata += len;
    185 		T(addstr(" ", (size_t)1, &buf, &buflen));
    186 
    187 
    188 		/* Second word, optional in ISDN records. */
    189 		if (type == ns_t_isdn && rdata == edata)
    190 			break;
    191 
    192 		T(len = charstr(rdata, edata, &buf, &buflen));
    193 		if (len == 0)
    194 			goto formerr;
    195 		rdata += len;
    196 		break;
    197 
    198 	case ns_t_soa: {
    199 		u_long t;
    200 
    201 		/* Server name. */
    202 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    203 		T(addstr(" ", (size_t)1, &buf, &buflen));
    204 
    205 		/* Administrator name. */
    206 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    207 		T(addstr(" (\n", (size_t)3, &buf, &buflen));
    208 		spaced = 0;
    209 
    210 		if ((edata - rdata) != 5*NS_INT32SZ)
    211 			goto formerr;
    212 
    213 		/* Serial number. */
    214 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    215 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    216 		len = SPRINTF((tmp, "%lu", t));
    217 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    218 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    219 		T(addstr("; serial\n", (size_t)9, &buf, &buflen));
    220 		spaced = 0;
    221 
    222 		/* Refresh interval. */
    223 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    224 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    225 		T(len = ns_format_ttl(t, buf, buflen));
    226 		addlen((size_t)len, &buf, &buflen);
    227 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    228 		T(addstr("; refresh\n", (size_t)10, &buf, &buflen));
    229 		spaced = 0;
    230 
    231 		/* Retry interval. */
    232 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    233 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    234 		T(len = ns_format_ttl(t, buf, buflen));
    235 		addlen((size_t)len, &buf, &buflen);
    236 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    237 		T(addstr("; retry\n", (size_t)8, &buf, &buflen));
    238 		spaced = 0;
    239 
    240 		/* Expiry. */
    241 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    242 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    243 		T(len = ns_format_ttl(t, buf, buflen));
    244 		addlen((size_t)len, &buf, &buflen);
    245 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    246 		T(addstr("; expiry\n", (size_t)9, &buf, &buflen));
    247 		spaced = 0;
    248 
    249 		/* Minimum TTL. */
    250 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    251 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    252 		T(len = ns_format_ttl(t, buf, buflen));
    253 		addlen((size_t)len, &buf, &buflen);
    254 		T(addstr(" )", (size_t)2, &buf, &buflen));
    255 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    256 		T(addstr("; minimum\n", (size_t)10, &buf, &buflen));
    257 
    258 		break;
    259 	    }
    260 
    261 	case ns_t_mx:
    262 	case ns_t_afsdb:
    263 	case ns_t_rt:
    264 	case ns_t_kx: {
    265 		u_int t;
    266 
    267 		if (rdlen < (size_t)NS_INT16SZ)
    268 			goto formerr;
    269 
    270 		/* Priority. */
    271 		t = ns_get16(rdata);
    272 		rdata += NS_INT16SZ;
    273 		len = SPRINTF((tmp, "%u ", t));
    274 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    275 
    276 		/* Target. */
    277 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    278 
    279 		break;
    280 	    }
    281 
    282 	case ns_t_px: {
    283 		u_int t;
    284 
    285 		if (rdlen < (size_t)NS_INT16SZ)
    286 			goto formerr;
    287 
    288 		/* Priority. */
    289 		t = ns_get16(rdata);
    290 		rdata += NS_INT16SZ;
    291 		len = SPRINTF((tmp, "%u ", t));
    292 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    293 
    294 		/* Name1. */
    295 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    296 		T(addstr(" ", (size_t)1, &buf, &buflen));
    297 
    298 		/* Name2. */
    299 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    300 
    301 		break;
    302 	    }
    303 
    304 	case ns_t_x25:
    305 		T(len = charstr(rdata, edata, &buf, &buflen));
    306 		if (len == 0)
    307 			goto formerr;
    308 		rdata += len;
    309 		break;
    310 
    311 	case ns_t_txt:
    312 	case ns_t_spf:
    313 		while (rdata < edata) {
    314 			T(len = charstr(rdata, edata, &buf, &buflen));
    315 			if (len == 0)
    316 				goto formerr;
    317 			rdata += len;
    318 			if (rdata < edata)
    319 				T(addstr(" ", (size_t)1, &buf, &buflen));
    320 		}
    321 		break;
    322 
    323 	case ns_t_nsap: {
    324 		char t[2+255*3];
    325 
    326 		(void) inet_nsap_ntoa((int)rdlen, rdata, t);
    327 		T(addstr(t, strlen(t), &buf, &buflen));
    328 		break;
    329 	    }
    330 
    331 	case ns_t_aaaa:
    332 		if (rdlen != (size_t)NS_IN6ADDRSZ)
    333 			goto formerr;
    334 		(void) inet_ntop(AF_INET6, rdata, buf, buflen);
    335 		addlen(strlen(buf), &buf, &buflen);
    336 		break;
    337 
    338 	case ns_t_loc: {
    339 		char t[255];
    340 
    341 		/* XXX protocol format checking? */
    342 		(void) loc_ntoa(rdata, t);
    343 		T(addstr(t, strlen(t), &buf, &buflen));
    344 		break;
    345 	    }
    346 
    347 	case ns_t_naptr: {
    348 		u_int order, preference;
    349 		char t[50];
    350 
    351 		if (rdlen < 2U*NS_INT16SZ)
    352 			goto formerr;
    353 
    354 		/* Order, Precedence. */
    355 		order = ns_get16(rdata);	rdata += NS_INT16SZ;
    356 		preference = ns_get16(rdata);	rdata += NS_INT16SZ;
    357 		len = SPRINTF((t, "%u %u ", order, preference));
    358 		T(addstr(t, (size_t)len, &buf, &buflen));
    359 
    360 		/* Flags. */
    361 		T(len = charstr(rdata, edata, &buf, &buflen));
    362 		if (len == 0)
    363 			goto formerr;
    364 		rdata += len;
    365 		T(addstr(" ", (size_t)1, &buf, &buflen));
    366 
    367 		/* Service. */
    368 		T(len = charstr(rdata, edata, &buf, &buflen));
    369 		if (len == 0)
    370 			goto formerr;
    371 		rdata += len;
    372 		T(addstr(" ", (size_t)1, &buf, &buflen));
    373 
    374 		/* Regexp. */
    375 		T(len = charstr(rdata, edata, &buf, &buflen));
    376 		if (len < 0)
    377 			return (-1);
    378 		if (len == 0)
    379 			goto formerr;
    380 		rdata += len;
    381 		T(addstr(" ", (size_t)1, &buf, &buflen));
    382 
    383 		/* Server. */
    384 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    385 		break;
    386 	    }
    387 
    388 	case ns_t_srv: {
    389 		u_int priority, weight, port;
    390 		char t[50];
    391 
    392 		if (rdlen < 3U*NS_INT16SZ)
    393 			goto formerr;
    394 
    395 		/* Priority, Weight, Port. */
    396 		priority = ns_get16(rdata);  rdata += NS_INT16SZ;
    397 		weight   = ns_get16(rdata);  rdata += NS_INT16SZ;
    398 		port     = ns_get16(rdata);  rdata += NS_INT16SZ;
    399 		len = SPRINTF((t, "%u %u %u ", priority, weight, port));
    400 		T(addstr(t, (size_t)len, &buf, &buflen));
    401 
    402 		/* Server. */
    403 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    404 		break;
    405 	    }
    406 
    407 	case ns_t_minfo:
    408 	case ns_t_rp:
    409 		/* Name1. */
    410 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    411 		T(addstr(" ", (size_t)1, &buf, &buflen));
    412 
    413 		/* Name2. */
    414 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    415 
    416 		break;
    417 
    418 	case ns_t_wks: {
    419 		int n, lcnt;
    420 
    421 		if (rdlen < 1U + NS_INT32SZ)
    422 			goto formerr;
    423 
    424 		/* Address. */
    425 		(void) inet_ntop(AF_INET, rdata, buf, buflen);
    426 		addlen(strlen(buf), &buf, &buflen);
    427 		rdata += NS_INADDRSZ;
    428 
    429 		/* Protocol. */
    430 		len = SPRINTF((tmp, " %u ( ", *rdata));
    431 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    432 		rdata += NS_INT8SZ;
    433 
    434 		/* Bit map. */
    435 		n = 0;
    436 		lcnt = 0;
    437 		while (rdata < edata) {
    438 			u_int c = *rdata++;
    439 			do {
    440 				if (c & 0200) {
    441 					if (lcnt == 0) {
    442 						T(addstr("\n\t\t\t\t", (size_t)5,
    443 							 &buf, &buflen));
    444 						lcnt = 10;
    445 						spaced = 0;
    446 					}
    447 					len = SPRINTF((tmp, "%d ", n));
    448 					T(addstr(tmp, (size_t)len, &buf, &buflen));
    449 					lcnt--;
    450 				}
    451 				c <<= 1;
    452 			} while (++n & 07);
    453 		}
    454 		T(addstr(")", (size_t)1, &buf, &buflen));
    455 
    456 		break;
    457 	    }
    458 
    459 	case ns_t_key:
    460 	case ns_t_dnskey: {
    461 		char base64_key[NS_MD5RSA_MAX_BASE64];
    462 		u_int keyflags, protocol, algorithm, key_id;
    463 		const char *leader;
    464 		int n;
    465 
    466 		if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
    467 			goto formerr;
    468 
    469 		/* Key flags, Protocol, Algorithm. */
    470 #ifndef _LIBC
    471 		key_id = dst_s_dns_key_id(rdata, edata-rdata);
    472 #else
    473 		key_id = 0;
    474 #endif
    475 		keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
    476 		protocol = *rdata++;
    477 		algorithm = *rdata++;
    478 		len = SPRINTF((tmp, "0x%04x %u %u",
    479 			       keyflags, protocol, algorithm));
    480 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    481 
    482 		/* Public key data. */
    483 		len = b64_ntop(rdata, (size_t)(edata - rdata),
    484 			       base64_key, sizeof base64_key);
    485 		if (len < 0)
    486 			goto formerr;
    487 		if (len > 15) {
    488 			T(addstr(" (", (size_t)2, &buf, &buflen));
    489 			leader = "\n\t\t";
    490 			spaced = 0;
    491 		} else
    492 			leader = " ";
    493 		for (n = 0; n < len; n += 48) {
    494 			T(addstr(leader, strlen(leader), &buf, &buflen));
    495 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
    496 				 &buf, &buflen));
    497 		}
    498 		if (len > 15)
    499 			T(addstr(" )", (size_t)2, &buf, &buflen));
    500 		n = SPRINTF((tmp, " ; key_tag= %u", key_id));
    501 		T(addstr(tmp, (size_t)n, &buf, &buflen));
    502 
    503 		break;
    504 	    }
    505 
    506 	case ns_t_sig:
    507 	case ns_t_rrsig: {
    508 		char base64_key[NS_MD5RSA_MAX_BASE64];
    509 		u_int typ, algorithm, labels, footprint;
    510 		const char *leader;
    511 		u_long t;
    512 		int n;
    513 
    514 		if (rdlen < 22U)
    515 			goto formerr;
    516 
    517 		/* Type covered, Algorithm, Label count, Original TTL. */
    518 	        typ = ns_get16(rdata);  rdata += NS_INT16SZ;
    519 		algorithm = *rdata++;
    520 		labels = *rdata++;
    521 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    522 		len = SPRINTF((tmp, "%s %d %d %lu ",
    523 			       p_type((int)typ), algorithm, labels, t));
    524 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    525 		if (labels > (u_int)dn_count_labels(name))
    526 			goto formerr;
    527 
    528 		/* Signature expiry. */
    529 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    530 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    531 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    532 
    533 		/* Time signed. */
    534 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    535 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    536 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    537 
    538 		/* Signature Footprint. */
    539 		footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
    540 		len = SPRINTF((tmp, "%u ", footprint));
    541 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    542 
    543 		/* Signer's name. */
    544 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    545 
    546 		/* Signature. */
    547 		len = b64_ntop(rdata, (size_t)(edata - rdata),
    548 			       base64_key, sizeof base64_key);
    549 		if (len > 15) {
    550 			T(addstr(" (", (size_t)2, &buf, &buflen));
    551 			leader = "\n\t\t";
    552 			spaced = 0;
    553 		} else
    554 			leader = " ";
    555 		if (len < 0)
    556 			goto formerr;
    557 		for (n = 0; n < len; n += 48) {
    558 			T(addstr(leader, strlen(leader), &buf, &buflen));
    559 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
    560 				 &buf, &buflen));
    561 		}
    562 		if (len > 15)
    563 			T(addstr(" )", (size_t)2, &buf, &buflen));
    564 		break;
    565 	    }
    566 
    567 	case ns_t_nxt: {
    568 		int n, c;
    569 
    570 		/* Next domain name. */
    571 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    572 
    573 		/* Type bit map. */
    574 		n = edata - rdata;
    575 		for (c = 0; c < n*8; c++)
    576 			if (NS_NXT_BIT_ISSET(c, rdata)) {
    577 				len = SPRINTF((tmp, " %s", p_type(c)));
    578 				T(addstr(tmp, (size_t)len, &buf, &buflen));
    579 			}
    580 		break;
    581 	    }
    582 
    583 	case ns_t_cert: {
    584 		u_int c_type, key_tag, alg;
    585 		int n;
    586 		unsigned int siz;
    587 		char base64_cert[8192], tmp1[40];
    588 		const char *leader;
    589 
    590 		c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
    591 		key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
    592 		alg = (u_int) *rdata++;
    593 
    594 		len = SPRINTF((tmp1, "%d %d %d ", c_type, key_tag, alg));
    595 		T(addstr(tmp1, (size_t)len, &buf, &buflen));
    596 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
    597 		if (siz > sizeof(base64_cert) * 3/4) {
    598 			const char *str = "record too long to print";
    599 			T(addstr(str, strlen(str), &buf, &buflen));
    600 		}
    601 		else {
    602 			len = b64_ntop(rdata, (size_t)(edata-rdata),
    603 			    base64_cert, siz);
    604 
    605 			if (len < 0)
    606 				goto formerr;
    607 			else if (len > 15) {
    608 				T(addstr(" (", (size_t)2, &buf, &buflen));
    609 				leader = "\n\t\t";
    610 				spaced = 0;
    611 			}
    612 			else
    613 				leader = " ";
    614 
    615 			for (n = 0; n < len; n += 48) {
    616 				T(addstr(leader, strlen(leader),
    617 					 &buf, &buflen));
    618 				T(addstr(base64_cert + n, (size_t)MIN(len - n, 48),
    619 					 &buf, &buflen));
    620 			}
    621 			if (len > 15)
    622 				T(addstr(" )", (size_t)2, &buf, &buflen));
    623 		}
    624 		break;
    625 	    }
    626 
    627 	case ns_t_tkey: {
    628 		/* KJD - need to complete this */
    629 		u_long t;
    630 		int mode, err, keysize;
    631 
    632 		/* Algorithm name. */
    633 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    634 		T(addstr(" ", (size_t)1, &buf, &buflen));
    635 
    636 		/* Inception. */
    637 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    638 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    639 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    640 
    641 		/* Experation. */
    642 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    643 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    644 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    645 
    646 		/* Mode , Error, Key Size. */
    647 		/* Priority, Weight, Port. */
    648 		mode = ns_get16(rdata);  rdata += NS_INT16SZ;
    649 		err  = ns_get16(rdata);  rdata += NS_INT16SZ;
    650 		keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
    651 		len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
    652 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    653 
    654 		/* XXX need to dump key, print otherdata length & other data */
    655 		break;
    656 	    }
    657 
    658 	case ns_t_tsig: {
    659 		/* BEW - need to complete this */
    660 		int n;
    661 
    662 		T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
    663 		T(addstr(" ", (size_t)1, &buf, &buflen));
    664 		rdata += 8; /*%< time */
    665 		n = ns_get16(rdata); rdata += INT16SZ;
    666 		rdata += n; /*%< sig */
    667 		n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
    668 		sprintf(buf, "%d", ns_get16(rdata));
    669 		rdata += INT16SZ;
    670 		addlen(strlen(buf), &buf, &buflen);
    671 		break;
    672 	    }
    673 
    674 	case ns_t_a6: {
    675 		struct in6_addr a;
    676 		int pbyte, pbit;
    677 
    678 		/* prefix length */
    679 		if (rdlen == 0U) goto formerr;
    680 		len = SPRINTF((tmp, "%d ", *rdata));
    681 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    682 		pbit = *rdata;
    683 		if (pbit > 128) goto formerr;
    684 		pbyte = (pbit & ~7) / 8;
    685 		rdata++;
    686 
    687 		/* address suffix: provided only when prefix len != 128 */
    688 		if (pbit < 128) {
    689 			if (rdata + pbyte >= edata) goto formerr;
    690 			memset(&a, 0, sizeof(a));
    691 			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
    692 			(void) inet_ntop(AF_INET6, &a, buf, buflen);
    693 			addlen(strlen(buf), &buf, &buflen);
    694 			rdata += sizeof(a) - pbyte;
    695 		}
    696 
    697 		/* prefix name: provided only when prefix len > 0 */
    698 		if (pbit == 0)
    699 			break;
    700 		if (rdata >= edata) goto formerr;
    701 		T(addstr(" ", (size_t)1, &buf, &buflen));
    702 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    703 
    704 		break;
    705 	    }
    706 
    707 	case ns_t_opt: {
    708 		len = SPRINTF((tmp, "%u bytes", class));
    709 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    710 		break;
    711 	    }
    712 
    713 	case ns_t_ds:
    714 	case ns_t_dlv:
    715 	case ns_t_sshfp: {
    716 		u_int t;
    717 
    718 		if (type == ns_t_ds || type == ns_t_dlv) {
    719 			if (rdlen < 4U) goto formerr;
    720 			t = ns_get16(rdata);
    721 			rdata += NS_INT16SZ;
    722 			len = SPRINTF((tmp, "%u ", t));
    723 			T(addstr(tmp, len, &buf, &buflen));
    724 		} else
    725 			if (rdlen < 2U) goto formerr;
    726 
    727 		len = SPRINTF((tmp, "%u ", *rdata));
    728 		T(addstr(tmp, len, &buf, &buflen));
    729 		rdata++;
    730 
    731 		len = SPRINTF((tmp, "%u ", *rdata));
    732 		T(addstr(tmp, len, &buf, &buflen));
    733 		rdata++;
    734 
    735 		while (rdata < edata) {
    736 			len = SPRINTF((tmp, "%02X", *rdata));
    737 			T(addstr(tmp, len, &buf, &buflen));
    738 			rdata++;
    739 		}
    740 		break;
    741 	    }
    742 
    743 	case ns_t_nsec3:
    744 	case ns_t_nsec3param: {
    745 		u_int t, w, l, j, k, c;
    746 
    747 		len = SPRINTF((tmp, "%u ", *rdata));
    748 		T(addstr(tmp, len, &buf, &buflen));
    749 		rdata++;
    750 
    751 		len = SPRINTF((tmp, "%u ", *rdata));
    752 		T(addstr(tmp, len, &buf, &buflen));
    753 		rdata++;
    754 
    755 		t = ns_get16(rdata);
    756 		rdata += NS_INT16SZ;
    757 		len = SPRINTF((tmp, "%u ", t));
    758 		T(addstr(tmp, len, &buf, &buflen));
    759 
    760 		t = *rdata++;
    761 		if (t == 0) {
    762 			T(addstr("-", 1, &buf, &buflen));
    763 		} else {
    764 			while (t-- > 0) {
    765 				len = SPRINTF((tmp, "%02X", *rdata));
    766 				T(addstr(tmp, len, &buf, &buflen));
    767 				rdata++;
    768 			}
    769 		}
    770 		if (type == ns_t_nsec3param)
    771 			break;
    772 		T(addstr(" ", 1, &buf, &buflen));
    773 
    774 		t = *rdata++;
    775 		while (t > 0) {
    776 			switch (t) {
    777 			case 1:
    778 				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
    779 				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)];
    780 				tmp[2] = tmp[3] = tmp[4] = '=';
    781 				tmp[5] = tmp[6] = tmp[7] = '=';
    782 				break;
    783 			case 2:
    784 				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
    785 				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
    786 						   ((rdata[1]>>6)&0x03)];
    787 				tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
    788 				tmp[3] = base32hex[((rdata[1]<<4)&0x10)];
    789 				tmp[4] = tmp[5] = tmp[6] = tmp[7] = '=';
    790 				break;
    791 			case 3:
    792 				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
    793 				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
    794 						   ((rdata[1]>>6)&0x03)];
    795 				tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
    796 				tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
    797 						   ((rdata[2]>>4)&0x0f)];
    798 				tmp[4] = base32hex[((rdata[2]<<1)&0x1e)];
    799 				tmp[5] = tmp[6] = tmp[7] = '=';
    800 				break;
    801 			case 4:
    802 				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
    803 				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
    804 						   ((rdata[1]>>6)&0x03)];
    805 				tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
    806 				tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
    807 						   ((rdata[2]>>4)&0x0f)];
    808 				tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
    809 						   ((rdata[3]>>7)&0x01)];
    810 				tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
    811 				tmp[6] = base32hex[(rdata[3]<<3)&0x18];
    812 				tmp[7] = '=';
    813 				break;
    814 			default:
    815 				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
    816 				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
    817 						   ((rdata[1]>>6)&0x03)];
    818 				tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
    819 				tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
    820 						   ((rdata[2]>>4)&0x0f)];
    821 				tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
    822 						   ((rdata[3]>>7)&0x01)];
    823 				tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
    824 				tmp[6] = base32hex[((rdata[3]<<3)&0x18)|
    825 						   ((rdata[4]>>5)&0x07)];
    826 				tmp[7] = base32hex[(rdata[4]&0x1f)];
    827 				break;
    828 			}
    829 			T(addstr(tmp, 8, &buf, &buflen));
    830 			if (t >= 5) {
    831 				rdata += 5;
    832 				t -= 5;
    833 			} else {
    834 				rdata += t;
    835 				t -= t;
    836 			}
    837 		}
    838 
    839 		while (rdata < edata) {
    840 			w = *rdata++;
    841 			l = *rdata++;
    842 			for (j = 0; j < l; j++) {
    843 				if (rdata[j] == 0)
    844 					continue;
    845 				for (k = 0; k < 8; k++) {
    846 					if ((rdata[j] & (0x80 >> k)) == 0)
    847 						continue;
    848 					c = w * 256 + j * 8 + k;
    849 					len = SPRINTF((tmp, " %s", p_type(c)));
    850 					T(addstr(tmp, len, &buf, &buflen));
    851 				}
    852 			}
    853 			rdata += l;
    854 		}
    855 		break;
    856 	    }
    857 
    858 	case ns_t_nsec: {
    859 		u_int w, l, j, k, c;
    860 
    861 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    862 
    863 		while (rdata < edata) {
    864 			w = *rdata++;
    865 			l = *rdata++;
    866 			for (j = 0; j < l; j++) {
    867 				if (rdata[j] == 0)
    868 					continue;
    869 				for (k = 0; k < 8; k++) {
    870 					if ((rdata[j] & (0x80 >> k)) == 0)
    871 						continue;
    872 					c = w * 256 + j * 8 + k;
    873 					len = SPRINTF((tmp, " %s", p_type(c)));
    874 					T(addstr(tmp, len, &buf, &buflen));
    875 				}
    876 			}
    877 			rdata += l;
    878 		}
    879 		break;
    880 	    }
    881 
    882 	case ns_t_dhcid: {
    883 		int n;
    884 		unsigned int siz;
    885 		char base64_dhcid[8192];
    886 		const char *leader;
    887 
    888 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
    889 		if (siz > sizeof(base64_dhcid) * 3/4) {
    890 			const char *str = "record too long to print";
    891 			T(addstr(str, strlen(str), &buf, &buflen));
    892 		} else {
    893 			len = b64_ntop(rdata, edata-rdata, base64_dhcid, siz);
    894 
    895 			if (len < 0)
    896 				goto formerr;
    897 
    898 			else if (len > 15) {
    899 				T(addstr(" (", 2, &buf, &buflen));
    900 				leader = "\n\t\t";
    901 				spaced = 0;
    902 			}
    903 			else
    904 				leader = " ";
    905 
    906 			for (n = 0; n < len; n += 48) {
    907 				T(addstr(leader, strlen(leader),
    908 					 &buf, &buflen));
    909 				T(addstr(base64_dhcid + n, MIN(len - n, 48),
    910 					 &buf, &buflen));
    911 			}
    912 			if (len > 15)
    913 				T(addstr(" )", 2, &buf, &buflen));
    914 		}
    915 	}
    916 
    917 	case ns_t_ipseckey: {
    918 		int n;
    919 		unsigned int siz;
    920 		char base64_key[8192];
    921 		const char *leader;
    922 
    923 		if (rdlen < 2)
    924 			goto formerr;
    925 
    926 		switch (rdata[1]) {
    927 		case 0:
    928 		case 3:
    929 			if (rdlen < 3)
    930 				goto formerr;
    931 			break;
    932 		case 1:
    933 			if (rdlen < 7)
    934 				goto formerr;
    935 			break;
    936 		case 2:
    937 			if (rdlen < 19)
    938 				goto formerr;
    939 			break;
    940 		default:
    941 			comment = "unknown IPSECKEY gateway type";
    942 			goto hexify;
    943 		}
    944 
    945 		len = SPRINTF((tmp, "%u ", *rdata));
    946 		T(addstr(tmp, len, &buf, &buflen));
    947 		rdata++;
    948 
    949 		len = SPRINTF((tmp, "%u ", *rdata));
    950 		T(addstr(tmp, len, &buf, &buflen));
    951 		rdata++;
    952 
    953 		len = SPRINTF((tmp, "%u ", *rdata));
    954 		T(addstr(tmp, len, &buf, &buflen));
    955 		rdata++;
    956 
    957 		switch (rdata[-2]) {
    958 		case 0:
    959 			T(addstr(".", 1, &buf, &buflen));
    960 			break;
    961 		case 1:
    962 			(void) inet_ntop(AF_INET, rdata, buf, buflen);
    963 			addlen(strlen(buf), &buf, &buflen);
    964 			rdata += 4;
    965 			break;
    966 		case 2:
    967 			(void) inet_ntop(AF_INET6, rdata, buf, buflen);
    968 			addlen(strlen(buf), &buf, &buflen);
    969 			rdata += 16;
    970 			break;
    971 		case 3:
    972 			T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    973 			break;
    974 		}
    975 
    976 		if (rdata >= edata)
    977 			break;
    978 
    979 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
    980 		if (siz > sizeof(base64_key) * 3/4) {
    981 			const char *str = "record too long to print";
    982 			T(addstr(str, strlen(str), &buf, &buflen));
    983 		} else {
    984 			len = b64_ntop(rdata, edata-rdata, base64_key, siz);
    985 
    986 			if (len < 0)
    987 				goto formerr;
    988 
    989 			else if (len > 15) {
    990 				T(addstr(" (", 2, &buf, &buflen));
    991 				leader = "\n\t\t";
    992 				spaced = 0;
    993 			}
    994 			else
    995 				leader = " ";
    996 
    997 			for (n = 0; n < len; n += 48) {
    998 				T(addstr(leader, strlen(leader),
    999 					 &buf, &buflen));
   1000 				T(addstr(base64_key + n, MIN(len - n, 48),
   1001 					 &buf, &buflen));
   1002 			}
   1003 			if (len > 15)
   1004 				T(addstr(" )", 2, &buf, &buflen));
   1005 		}
   1006 	}
   1007 
   1008 	case ns_t_hip: {
   1009 		unsigned int i, hip_len, algorithm, key_len;
   1010 		char base64_key[NS_MD5RSA_MAX_BASE64];
   1011 		unsigned int siz;
   1012 		const char *leader = "\n\t\t\t\t\t";
   1013 
   1014 		hip_len = *rdata++;
   1015 		algorithm = *rdata++;
   1016 		key_len = ns_get16(rdata);
   1017 		rdata += NS_INT16SZ;
   1018 
   1019 		siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */
   1020 		if (siz > sizeof(base64_key) * 3/4) {
   1021 			const char *str = "record too long to print";
   1022 			T(addstr(str, strlen(str), &buf, &buflen));
   1023 		} else {
   1024 			len = sprintf(tmp, "( %u ", algorithm);
   1025 			T(addstr(tmp, len, &buf, &buflen));
   1026 
   1027 			for (i = 0; i < hip_len; i++) {
   1028 				len = sprintf(tmp, "%02X", *rdata);
   1029 				T(addstr(tmp, len, &buf, &buflen));
   1030 				rdata++;
   1031 			}
   1032 			T(addstr(leader, strlen(leader), &buf, &buflen));
   1033 
   1034 			len = b64_ntop(rdata, key_len, base64_key, siz);
   1035 			if (len < 0)
   1036 				goto formerr;
   1037 
   1038 			T(addstr(base64_key, len, &buf, &buflen));
   1039 
   1040 			rdata += key_len;
   1041 			while (rdata < edata) {
   1042 				T(addstr(leader, strlen(leader), &buf, &buflen));
   1043 				T(addname(msg, msglen, &rdata, origin,
   1044 					  &buf, &buflen));
   1045 			}
   1046 			T(addstr(" )", 2, &buf, &buflen));
   1047 		}
   1048 		break;
   1049 	}
   1050 
   1051 	default:
   1052 		comment = "unknown RR type";
   1053 		goto hexify;
   1054 	}
   1055 	return (buf - obuf);
   1056  formerr:
   1057 	comment = "RR format error";
   1058  hexify: {
   1059 	int n, m;
   1060 	char *p;
   1061 
   1062 	len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
   1063 		       rdlen != 0U ? " (" : "", comment));
   1064 	T(addstr(tmp, (size_t)len, &buf, &buflen));
   1065 	while (rdata < edata) {
   1066 		p = tmp;
   1067 		p += SPRINTF((p, "\n\t"));
   1068 		spaced = 0;
   1069 		n = MIN(16, edata - rdata);
   1070 		for (m = 0; m < n; m++)
   1071 			p += SPRINTF((p, "%02x ", rdata[m]));
   1072 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
   1073 		if (n < 16) {
   1074 			T(addstr(")", (size_t)1, &buf, &buflen));
   1075 			T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen));
   1076 		}
   1077 		p = tmp;
   1078 		p += SPRINTF((p, "; "));
   1079 		for (m = 0; m < n; m++)
   1080 			*p++ = (isascii(rdata[m]) && isprint(rdata[m]))
   1081 				? rdata[m]
   1082 				: '.';
   1083 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
   1084 		rdata += n;
   1085 	}
   1086 	return (buf - obuf);
   1087     }
   1088 }
   1089 
   1090 /* Private. */
   1091 
   1092 /*%
   1093  * size_t
   1094  * prune_origin(name, origin)
   1095  *	Find out if the name is at or under the current origin.
   1096  * return:
   1097  *	Number of characters in name before start of origin,
   1098  *	or length of name if origin does not match.
   1099  * notes:
   1100  *	This function should share code with samedomain().
   1101  */
   1102 static size_t
   1103 prune_origin(const char *name, const char *origin) {
   1104 	const char *oname = name;
   1105 
   1106 	while (*name != '\0') {
   1107 		if (origin != NULL && ns_samename(name, origin) == 1)
   1108 			return (name - oname - (name > oname));
   1109 		while (*name != '\0') {
   1110 			if (*name == '\\') {
   1111 				name++;
   1112 				/* XXX need to handle \nnn form. */
   1113 				if (*name == '\0')
   1114 					break;
   1115 			} else if (*name == '.') {
   1116 				name++;
   1117 				break;
   1118 			}
   1119 			name++;
   1120 		}
   1121 	}
   1122 	return (name - oname);
   1123 }
   1124 
   1125 /*%
   1126  * int
   1127  * charstr(rdata, edata, buf, buflen)
   1128  *	Format a <character-string> into the presentation buffer.
   1129  * return:
   1130  *	Number of rdata octets consumed
   1131  *	0 for protocol format error
   1132  *	-1 for output buffer error
   1133  * side effects:
   1134  *	buffer is advanced on success.
   1135  */
   1136 static int
   1137 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
   1138 	const u_char *odata = rdata;
   1139 	size_t save_buflen = *buflen;
   1140 	char *save_buf = *buf;
   1141 
   1142 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
   1143 		goto enospc;
   1144 	if (rdata < edata) {
   1145 		int n = *rdata;
   1146 
   1147 		if (rdata + 1 + n <= edata) {
   1148 			rdata++;
   1149 			while (n-- > 0) {
   1150 				if (strchr("\n\"\\", *rdata) != NULL)
   1151 					if (addstr("\\", (size_t)1, buf, buflen) < 0)
   1152 						goto enospc;
   1153 				if (addstr((const char *)rdata, (size_t)1,
   1154 					   buf, buflen) < 0)
   1155 					goto enospc;
   1156 				rdata++;
   1157 			}
   1158 		}
   1159 	}
   1160 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
   1161 		goto enospc;
   1162 	return (rdata - odata);
   1163  enospc:
   1164 	errno = ENOSPC;
   1165 	*buf = save_buf;
   1166 	*buflen = save_buflen;
   1167 	return (-1);
   1168 }
   1169 
   1170 static int
   1171 addname(const u_char *msg, size_t msglen,
   1172 	const u_char **pp, const char *origin,
   1173 	char **buf, size_t *buflen)
   1174 {
   1175 	size_t newlen, save_buflen = *buflen;
   1176 	char *save_buf = *buf;
   1177 	int n;
   1178 
   1179 	n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen);
   1180 	if (n < 0)
   1181 		goto enospc;	/*%< Guess. */
   1182 	newlen = prune_origin(*buf, origin);
   1183 	if (**buf == '\0') {
   1184 		goto root;
   1185 	} else if (newlen == 0U) {
   1186 		/* Use "@" instead of name. */
   1187 		if (newlen + 2 > *buflen)
   1188 			goto enospc;        /* No room for "@\0". */
   1189 		(*buf)[newlen++] = '@';
   1190 		(*buf)[newlen] = '\0';
   1191 	} else {
   1192 		if (((origin == NULL || origin[0] == '\0') ||
   1193 		    (origin[0] != '.' && origin[1] != '\0' &&
   1194 		    (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
   1195 			/* No trailing dot. */
   1196  root:
   1197 			if (newlen + 2 > *buflen)
   1198 				goto enospc;	/* No room for ".\0". */
   1199 			(*buf)[newlen++] = '.';
   1200 			(*buf)[newlen] = '\0';
   1201 		}
   1202 	}
   1203 	*pp += n;
   1204 	addlen(newlen, buf, buflen);
   1205 	**buf = '\0';
   1206 	return (newlen);
   1207  enospc:
   1208 	errno = ENOSPC;
   1209 	*buf = save_buf;
   1210 	*buflen = save_buflen;
   1211 	return (-1);
   1212 }
   1213 
   1214 static void
   1215 addlen(size_t len, char **buf, size_t *buflen) {
   1216 	INSIST(len <= *buflen);
   1217 	*buf += len;
   1218 	*buflen -= len;
   1219 }
   1220 
   1221 static int
   1222 addstr(const char *src, size_t len, char **buf, size_t *buflen) {
   1223 	if (len >= *buflen) {
   1224 		errno = ENOSPC;
   1225 		return (-1);
   1226 	}
   1227 	memcpy(*buf, src, len);
   1228 	addlen(len, buf, buflen);
   1229 	**buf = '\0';
   1230 	return (0);
   1231 }
   1232 
   1233 static int
   1234 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
   1235 	size_t save_buflen = *buflen;
   1236 	char *save_buf = *buf;
   1237 	int t;
   1238 
   1239 	if (spaced || len >= target - 1) {
   1240 		T(addstr("  ", (size_t)2, buf, buflen));
   1241 		spaced = 1;
   1242 	} else {
   1243 		for (t = (target - len - 1) / 8; t >= 0; t--)
   1244 			if (addstr("\t", (size_t)1, buf, buflen) < 0) {
   1245 				*buflen = save_buflen;
   1246 				*buf = save_buf;
   1247 				return (-1);
   1248 			}
   1249 		spaced = 0;
   1250 	}
   1251 	return (spaced);
   1252 }
   1253 
   1254 /*! \file */
   1255