]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/BsdSocketLib/ns_print.c
Fix send to properly wait while long transmits are in progress
[mirror_edk2.git] / StdLib / BsdSocketLib / ns_print.c
1 /*
2 * Copyright (c) 1996, 1998 by Internet Software Consortium.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15 * SOFTWARE.
16 */
17
18 /*
19 * Portions copyright (c) 1999, 2000
20 * Intel Corporation.
21 * All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 *
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 *
30 * 2. Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in the
32 * documentation and/or other materials provided with the distribution.
33 *
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 *
37 * This product includes software developed by Intel Corporation and
38 * its contributors.
39 *
40 * 4. Neither the name of Intel Corporation or its contributors may be
41 * used to endorse or promote products derived from this software
42 * without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS''
45 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE
48 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
54 * THE POSSIBILITY OF SUCH DAMAGE.
55 *
56 */
57
58 #ifndef lint
59 static char rcsid[] = "$Id: ns_print.c,v 1.1.1.1 2003/11/19 01:51:34 kyu3 Exp $";
60 #endif
61
62 /* Import. */
63
64 #include <sys/types.h>
65 #include <sys/socket.h>
66
67 #include <netinet/in.h>
68 #include <arpa/nameser.h>
69 #include <arpa/inet.h>
70
71 #include <assert.h>
72 #include <errno.h>
73 #include <resolv.h>
74 #include <string.h>
75 #include <ctype.h>
76
77 #define SPRINTF(x) (sprintf x)
78
79 /* Forward. */
80
81 static size_t prune_origin(const char *name, const char *origin);
82 static int charstr(const u_char *rdata, const u_char *edata,
83 char **buf, size_t *buflen);
84 static int addname(const u_char *msg, size_t msglen,
85 const u_char **p, const char *origin,
86 char **buf, size_t *buflen);
87 static void addlen(size_t len, char **buf, size_t *buflen);
88 static int addstr(const char *src, size_t len,
89 char **buf, size_t *buflen);
90 static int addtab(size_t len, size_t target, int spaced,
91 char **buf, size_t *buflen);
92
93 /* Macros. */
94
95 #define T(x) \
96 do { \
97 if ((ssize_t)(x) < 0) \
98 return (-1); \
99 } while (0)
100
101 /* Public. */
102
103 /*
104 * int
105 * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen)
106 * Convert an RR to presentation format.
107 * return:
108 * Number of characters written to buf, or -1 (check errno).
109 */
110 int
111 ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
112 const char *name_ctx, const char *origin,
113 char *buf, size_t buflen)
114 {
115 int n;
116
117 n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
118 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
119 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
120 name_ctx, origin, buf, buflen);
121 return (n);
122 }
123
124 /*
125 * int
126 * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen,
127 * name_ctx, origin, buf, buflen)
128 * Convert the fields of an RR into presentation format.
129 * return:
130 * Number of characters written to buf, or -1 (check errno).
131 */
132 int
133 ns_sprintrrf(const u_char *msg, size_t msglen,
134 const char *name, ns_class class, ns_type type,
135 u_long ttl, const u_char *rdata, size_t rdlen,
136 const char *name_ctx, const char *origin,
137 char *buf, size_t buflen)
138 {
139 const char *obuf = buf;
140 const u_char *edata = rdata + rdlen;
141 int spaced = 0;
142
143 const char *comment;
144 char tmp[100];
145 int x;
146 size_t len;
147
148 static char base64_key[NS_MD5RSA_MAX_BASE64];
149 static char t[255*3];
150
151 /*
152 * Owner.
153 */
154 if (name_ctx != NULL && strcasecmp(name_ctx, name) == 0) {
155 T(addstr("\t\t\t", 3, &buf, &buflen));
156 } else {
157 len = prune_origin(name, origin);
158 if (len == 0) {
159 T(addstr("@\t\t\t", 4, &buf, &buflen));
160 } else {
161 T(addstr(name, len, &buf, &buflen));
162 /* Origin not used and no trailing dot? */
163 if ((!origin || !origin[0] || name[len] == '\0') &&
164 name[len - 1] != '.') {
165 T(addstr(".", 1, &buf, &buflen));
166 len++;
167 }
168 T(spaced = addtab(len, 24, spaced, &buf, &buflen));
169 }
170 }
171
172 /*
173 * TTL, Class, Type.
174 */
175 T(x = ns_format_ttl(ttl, buf, buflen));
176 addlen(x, &buf, &buflen);
177 len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
178 T(addstr(tmp, len, &buf, &buflen));
179 T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
180
181 /*
182 * RData.
183 */
184 switch (type) {
185 case ns_t_a:
186 if (rdlen != NS_INADDRSZ)
187 goto formerr;
188 (void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen);
189 addlen(strlen(buf), &buf, &buflen);
190 break;
191
192 case ns_t_cname:
193 case ns_t_mb:
194 case ns_t_mg:
195 case ns_t_mr:
196 case ns_t_ns:
197 case ns_t_ptr:
198 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
199 break;
200
201 case ns_t_hinfo:
202 case ns_t_isdn:
203 /* First word. */
204 T(len = charstr(rdata, edata, &buf, &buflen));
205 if (len == 0)
206 goto formerr;
207 rdata += len;
208 T(addstr(" ", 1, &buf, &buflen));
209
210 /* Second word. */
211 T(len = charstr(rdata, edata, &buf, &buflen));
212 if (len == 0)
213 goto formerr;
214 rdata += len;
215 break;
216
217 case ns_t_soa: {
218 u_long t;
219
220 /* Server name. */
221 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
222 T(addstr(" ", 1, &buf, &buflen));
223
224 /* Administrator name. */
225 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
226 T(addstr(" (\n", 3, &buf, &buflen));
227 spaced = 0;
228
229 if ((edata - rdata) != 5*NS_INT32SZ)
230 goto formerr;
231
232 /* Serial number. */
233 t = ns_get32(rdata); rdata += NS_INT32SZ;
234 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
235 len = SPRINTF((tmp, "%lu", t));
236 T(addstr(tmp, len, &buf, &buflen));
237 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
238 T(addstr("; serial\n", 9, &buf, &buflen));
239 spaced = 0;
240
241 /* Refresh interval. */
242 t = ns_get32(rdata); rdata += NS_INT32SZ;
243 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
244 T(len = ns_format_ttl(t, buf, buflen));
245 addlen(len, &buf, &buflen);
246 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
247 T(addstr("; refresh\n", 10, &buf, &buflen));
248 spaced = 0;
249
250 /* Retry interval. */
251 t = ns_get32(rdata); rdata += NS_INT32SZ;
252 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
253 T(len = ns_format_ttl(t, buf, buflen));
254 addlen(len, &buf, &buflen);
255 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
256 T(addstr("; retry\n", 8, &buf, &buflen));
257 spaced = 0;
258
259 /* Expiry. */
260 t = ns_get32(rdata); rdata += NS_INT32SZ;
261 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
262 T(len = ns_format_ttl(t, buf, buflen));
263 addlen(len, &buf, &buflen);
264 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
265 T(addstr("; expiry\n", 9, &buf, &buflen));
266 spaced = 0;
267
268 /* Minimum TTL. */
269 t = ns_get32(rdata); rdata += NS_INT32SZ;
270 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
271 T(len = ns_format_ttl(t, buf, buflen));
272 addlen(len, &buf, &buflen);
273 T(addstr(" )", 2, &buf, &buflen));
274 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
275 T(addstr("; minimum\n", 10, &buf, &buflen));
276
277 break;
278 }
279
280 case ns_t_mx:
281 case ns_t_afsdb:
282 case ns_t_rt: {
283 u_int t;
284
285 if (rdlen < 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, len, &buf, &buflen));
293
294 /* Target. */
295 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
296
297 break;
298 }
299
300 case ns_t_px: {
301 u_int t;
302
303 if (rdlen < NS_INT16SZ)
304 goto formerr;
305
306 /* Priority. */
307 t = ns_get16(rdata);
308 rdata += NS_INT16SZ;
309 len = SPRINTF((tmp, "%u ", t));
310 T(addstr(tmp, len, &buf, &buflen));
311
312 /* Name1. */
313 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
314 T(addstr(" ", 1, &buf, &buflen));
315
316 /* Name2. */
317 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
318
319 break;
320 }
321
322 case ns_t_x25:
323 T(len = charstr(rdata, edata, &buf, &buflen));
324 if (len == 0)
325 goto formerr;
326 rdata += len;
327 break;
328
329 case ns_t_txt:
330 while (rdata < edata) {
331 T(len = charstr(rdata, edata, &buf, &buflen));
332 if (len == 0)
333 goto formerr;
334 rdata += len;
335 if (rdata < edata)
336 T(addstr(" ", 1, &buf, &buflen));
337 }
338 break;
339
340 case ns_t_nsap: {
341
342 (void) inet_nsap_ntoa((int)rdlen, rdata, t);
343 T(addstr(t, strlen(t), &buf, &buflen));
344 break;
345 }
346
347 case ns_t_aaaa:
348 if (rdlen != NS_IN6ADDRSZ)
349 goto formerr;
350 (void) inet_ntop(AF_INET6, rdata, buf, (socklen_t)buflen);
351 addlen(strlen(buf), &buf, &buflen);
352 break;
353
354 case ns_t_loc: {
355 /* XXX protocol format checking? */
356 (void) loc_ntoa(rdata, t);
357 T(addstr(t, strlen(t), &buf, &buflen));
358 break;
359 }
360
361 case ns_t_naptr: {
362 u_int order, preference;
363
364 if (rdlen < 2*NS_INT16SZ)
365 goto formerr;
366
367 /* Order, Precedence. */
368 order = ns_get16(rdata); rdata += NS_INT16SZ;
369 preference = ns_get16(rdata); rdata += NS_INT16SZ;
370 len = SPRINTF((t, "%u %u ", order, preference));
371 T(addstr(t, len, &buf, &buflen));
372
373 /* Flags. */
374 T(len = charstr(rdata, edata, &buf, &buflen));
375 if (len == 0)
376 goto formerr;
377 rdata += len;
378 T(addstr(" ", 1, &buf, &buflen));
379
380 /* Service. */
381 T(len = charstr(rdata, edata, &buf, &buflen));
382 if (len == 0)
383 goto formerr;
384 rdata += len;
385 T(addstr(" ", 1, &buf, &buflen));
386
387 /* Regexp. */
388 T(len = charstr(rdata, edata, &buf, &buflen));
389 if ((ssize_t)len < 0)
390 return (-1);
391 if (len == 0)
392 goto formerr;
393 rdata += len;
394 T(addstr(" ", 1, &buf, &buflen));
395
396 /* Server. */
397 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
398 break;
399 }
400
401 case ns_t_srv: {
402 u_int priority, weight, port;
403
404 if (rdlen < NS_INT16SZ*3)
405 goto formerr;
406
407 /* Priority, Weight, Port. */
408 priority = ns_get16(rdata); rdata += NS_INT16SZ;
409 weight = ns_get16(rdata); rdata += NS_INT16SZ;
410 port = ns_get16(rdata); rdata += NS_INT16SZ;
411 len = SPRINTF((t, "%u %u %u ", priority, weight, port));
412 T(addstr(t, len, &buf, &buflen));
413
414 /* Server. */
415 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
416 break;
417 }
418
419 case ns_t_minfo:
420 case ns_t_rp:
421 /* Name1. */
422 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
423 T(addstr(" ", 1, &buf, &buflen));
424
425 /* Name2. */
426 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
427
428 break;
429
430 case ns_t_wks: {
431 int n, lcnt;
432
433 if (rdlen < NS_INT32SZ + 1)
434 goto formerr;
435
436 /* Address. */
437 (void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen);
438 addlen(strlen(buf), &buf, &buflen);
439 rdata += NS_INADDRSZ;
440
441 /* Protocol. */
442 len = SPRINTF((tmp, " %u ( ", *rdata));
443 T(addstr(tmp, len, &buf, &buflen));
444 rdata += NS_INT8SZ;
445
446 /* Bit map. */
447 n = 0;
448 lcnt = 0;
449 while (rdata < edata) {
450 u_int c = *rdata++;
451 do {
452 if (c & 0200) {
453 if (lcnt == 0) {
454 T(addstr("\n\t\t\t\t", 5,
455 &buf, &buflen));
456 lcnt = 10;
457 spaced = 0;
458 }
459 len = SPRINTF((tmp, "%d ", n));
460 T(addstr(tmp, len, &buf, &buflen));
461 lcnt--;
462 }
463 c <<= 1;
464 } while (++n & 07);
465 }
466 T(addstr(")", 1, &buf, &buflen));
467
468 break;
469 }
470
471 case ns_t_key: {
472 u_int keyflags, protocol, algorithm;
473 const char *leader;
474 int n;
475
476 if (rdlen < NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
477 goto formerr;
478
479 /* Key flags, Protocol, Algorithm. */
480 keyflags = ns_get16(rdata); rdata += NS_INT16SZ;
481 protocol = *rdata++;
482 algorithm = *rdata++;
483 len = SPRINTF((tmp, "0x%04x %u %u",
484 keyflags, protocol, algorithm));
485 T(addstr(tmp, len, &buf, &buflen));
486
487 /* Public key data. */
488 len = b64_ntop(rdata, edata - rdata,
489 base64_key, sizeof base64_key);
490 if ((ssize_t)len < 0)
491 goto formerr;
492 if (len > 15) {
493 T(addstr(" (", 2, &buf, &buflen));
494 leader = "\n\t\t";
495 spaced = 0;
496 } else
497 leader = " ";
498 for (n = 0; n < (int)len; n += 48) {
499 T(addstr(leader, strlen(leader), &buf, &buflen));
500 T(addstr(base64_key + n, MIN(len - n, 48),
501 &buf, &buflen));
502 }
503 if (len > 15)
504 T(addstr(" )", 2, &buf, &buflen));
505
506 break;
507 }
508
509 case ns_t_sig: {
510 u_int type, algorithm, labels, footprint;
511 const char *leader;
512 u_long t;
513 int n;
514
515 if (rdlen < 22)
516 goto formerr;
517
518 /* Type covered, Algorithm, Label count, Original TTL. */
519 type = ns_get16(rdata); rdata += NS_INT16SZ;
520 algorithm = *rdata++;
521 labels = *rdata++;
522 t = ns_get32(rdata); rdata += NS_INT32SZ;
523 len = SPRINTF((tmp, " %s %d %lu ",
524 p_type((int)type), algorithm, t));
525 T(addstr(tmp, len, &buf, &buflen));
526 if (labels != (u_int)dn_count_labels(name))
527 goto formerr;
528
529 /* Signature expiry. */
530 t = ns_get32(rdata); rdata += NS_INT32SZ;
531 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
532 T(addstr(tmp, len, &buf, &buflen));
533
534 /* Time signed. */
535 t = ns_get32(rdata); rdata += NS_INT32SZ;
536 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
537 T(addstr(tmp, len, &buf, &buflen));
538
539 /* Signature Footprint. */
540 footprint = ns_get16(rdata); rdata += NS_INT16SZ;
541 len = SPRINTF((tmp, "%u ", footprint));
542 T(addstr(tmp, len, &buf, &buflen));
543
544 /* Signer's name. */
545 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
546
547 /* Signature. */
548 len = b64_ntop(rdata, edata - rdata,
549 base64_key, sizeof base64_key);
550 if (len > 15) {
551 T(addstr(" (", 2, &buf, &buflen));
552 leader = "\n\t\t";
553 spaced = 0;
554 } else
555 leader = " ";
556 if ((ssize_t)len < 0)
557 goto formerr;
558 for (n = 0; n < (int)len; n += 48) {
559 T(addstr(leader, strlen(leader), &buf, &buflen));
560 T(addstr(base64_key + n, MIN(len - n, 48),
561 &buf, &buflen));
562 }
563 if (len > 15)
564 T(addstr(" )", 2, &buf, &buflen));
565
566 break;
567 }
568
569 case ns_t_nxt: {
570 int n, c;
571
572 /* Next domain name. */
573 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
574
575 /* Type bit map. */
576 n = (int)(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(c)));
580 T(addstr(tmp, len, &buf, &buflen));
581 }
582 break;
583 }
584
585 default:
586 comment = "unknown RR type";
587 goto hexify;
588 }
589 return ((int)(buf - obuf));
590 formerr:
591 comment = "RR format error";
592 hexify: {
593 int n, m;
594 char *p;
595
596 len = SPRINTF((tmp, "\\#(\t\t; %s", comment));
597 T(addstr(tmp, len, &buf, &buflen));
598 while (rdata < edata) {
599 p = tmp;
600 p += SPRINTF((p, "\n\t"));
601 spaced = 0;
602 n = MIN(16, (int)(edata - rdata));
603 for (m = 0; m < n; m++)
604 p += SPRINTF((p, "%02x ", rdata[m]));
605 T(addstr(tmp, (u_int)(p - tmp), &buf, &buflen));
606 if (n < 16) {
607 T(addstr(")", 1, &buf, &buflen));
608 T(addtab((u_int)(p - tmp) + 1, 48, spaced, &buf, &buflen));
609 }
610 p = tmp;
611 p += SPRINTF((p, "; "));
612 for (m = 0; m < n; m++)
613 *p++ = (isascii(rdata[m]) && isprint(rdata[m]))
614 ? rdata[m]
615 : '.';
616 T(addstr(tmp, (u_int)(p - tmp), &buf, &buflen));
617 rdata += n;
618 }
619 return ((int)(buf - obuf));
620 }
621 }
622
623 /* Private. */
624
625 /*
626 * size_t
627 * prune_origin(name, origin)
628 * Find out if the name is at or under the current origin.
629 * return:
630 * Number of characters in name before start of origin,
631 * or length of name if origin does not match.
632 * notes:
633 * This function should share code with samedomain().
634 */
635 static size_t
636 prune_origin(const char *name, const char *origin) {
637 const char *oname = name;
638
639 while (*name != '\0') {
640 if (origin != NULL && strcasecmp(name, origin) == 0)
641 return ((size_t)(name - oname) - (name > oname));
642 while (*name != '\0') {
643 if (*name == '\\') {
644 name++;
645 /* XXX need to handle \nnn form. */
646 if (*name == '\0')
647 break;
648 } else if (*name == '.') {
649 name++;
650 break;
651 }
652 name++;
653 }
654 }
655 return ((size_t)(name - oname));
656 }
657
658 /*
659 * int
660 * charstr(rdata, edata, buf, buflen)
661 * Format a <character-string> into the presentation buffer.
662 * return:
663 * Number of rdata octets consumed
664 * 0 for protocol format error
665 * -1 for output buffer error
666 * side effects:
667 * buffer is advanced on success.
668 */
669 static int
670 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
671 const u_char *odata = rdata;
672 size_t save_buflen = *buflen;
673 char *save_buf = *buf;
674
675 if (addstr("\"", 1, buf, buflen) < 0)
676 goto enospc;
677 if (rdata < edata) {
678 int n = *rdata;
679
680 if (rdata + 1 + n <= edata) {
681 rdata++;
682 while (n-- > 0) {
683 if (strchr("\n\"\\", *rdata) != NULL)
684 if (addstr("\\", 1, buf, buflen) < 0)
685 goto enospc;
686 if (addstr((const char *)rdata, 1,
687 buf, buflen) < 0)
688 goto enospc;
689 rdata++;
690 }
691 }
692 }
693 if (addstr("\"", 1, buf, buflen) < 0)
694 goto enospc;
695 return ((int)(rdata - odata));
696 enospc:
697 errno = ENOSPC;
698 *buf = save_buf;
699 *buflen = save_buflen;
700 return (-1);
701 }
702
703 static int
704 addname(const u_char *msg, size_t msglen,
705 const u_char **pp, const char *origin,
706 char **buf, size_t *buflen)
707 {
708 size_t newlen, save_buflen = *buflen;
709 char *save_buf = *buf;
710 int n;
711
712 n = dn_expand(msg, msg + msglen, *pp, *buf, (int)(*buflen));
713 if (n < 0)
714 goto enospc; /* Guess. */
715 newlen = prune_origin(*buf, origin);
716 if ((origin == NULL || origin[0] == '\0' || (*buf)[newlen] == '\0') &&
717 (newlen == 0 || (*buf)[newlen - 1] != '.')) {
718 /* No trailing dot. */
719 if (newlen + 2 > *buflen)
720 goto enospc; /* No room for ".\0". */
721 (*buf)[newlen++] = '.';
722 (*buf)[newlen] = '\0';
723 }
724 if (newlen == 0) {
725 /* Use "@" instead of name. */
726 if (newlen + 2 > *buflen)
727 goto enospc; /* No room for "@\0". */
728 (*buf)[newlen++] = '@';
729 (*buf)[newlen] = '\0';
730 }
731 *pp += n;
732 addlen(newlen, buf, buflen);
733 **buf = '\0';
734 return ((int)newlen);
735 enospc:
736 errno = ENOSPC;
737 *buf = save_buf;
738 *buflen = save_buflen;
739 return (-1);
740 }
741
742 static void
743 addlen(size_t len, char **buf, size_t *buflen) {
744 assert(len <= *buflen);
745 *buf += len;
746 *buflen -= len;
747 }
748
749 static int
750 addstr(const char *src, size_t len, char **buf, size_t *buflen) {
751 if (len > *buflen) {
752 errno = ENOSPC;
753 return (-1);
754 }
755 memcpy(*buf, src, len);
756 addlen(len, buf, buflen);
757 **buf = '\0';
758 return (0);
759 }
760
761 static int
762 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
763 size_t save_buflen = *buflen;
764 char *save_buf = *buf;
765 int t;
766
767 if (spaced || len >= target - 1) {
768 T(addstr(" ", 2, buf, buflen));
769 spaced = 1;
770 } else {
771 for (t = (int)(target - len - 1) / 8; t >= 0; t--)
772 if (addstr("\t", 1, buf, buflen) < 0) {
773 *buflen = save_buflen;
774 *buf = save_buf;
775 return (-1);
776 }
777 spaced = 0;
778 }
779 return (spaced);
780 }