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