Incorporated from BIND 4.9.3-BETA24 release.
[kopensolaris-gnu/glibc.git] / resolv / res_debug.c
1 /*
2  * ++Copyright++ 1985, 1990, 1993
3  * -
4  * Copyright (c) 1985, 1990, 1993
5  *    The Regents of the University of California.  All rights reserved.
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by the University of
18  *      California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  * 
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  * -
35  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36  * 
37  * Permission to use, copy, modify, and distribute this software for any
38  * purpose with or without fee is hereby granted, provided that the above
39  * copyright notice and this permission notice appear in all copies, and that
40  * the name of Digital Equipment Corporation not be used in advertising or
41  * publicity pertaining to distribution of the document or software without
42  * specific, written prior permission.
43  * 
44  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
47  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51  * SOFTWARE.
52  * -
53  * --Copyright--
54  */
55
56 #if defined(LIBC_SCCS) && !defined(lint)
57 static char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
58 static char rcsid[] = "$Id$";
59 #endif /* LIBC_SCCS and not lint */
60
61 #include <sys/param.h>
62 #include <netinet/in.h>
63 #include <arpa/inet.h>
64 #include <arpa/nameser.h>
65
66 #include <stdio.h>
67 #include <netdb.h>
68 #include <resolv.h>
69 #if defined(BSD) && (BSD >= 199103)
70 # include <string.h>
71 #else
72 # include "../conf/portability.h"
73 #endif
74
75 #if defined(USE_OPTIONS_H)
76 # include "../conf/options.h"
77 #endif
78
79 const char *_res_opcodes[] = {
80         "QUERY",
81         "IQUERY",
82         "CQUERYM",
83         "CQUERYU",      /* experimental */
84         "NOTIFY",       /* experimental */
85         "5",
86         "6",
87         "7",
88         "8",
89         "UPDATEA",
90         "UPDATED",
91         "UPDATEDA",
92         "UPDATEM",
93         "UPDATEMA",
94         "ZONEINIT",
95         "ZONEREF",
96 };
97
98 const char *_res_resultcodes[] = {
99         "NOERROR",
100         "FORMERR",
101         "SERVFAIL",
102         "NXDOMAIN",
103         "NOTIMP",
104         "REFUSED",
105         "6",
106         "7",
107         "8",
108         "9",
109         "10",
110         "11",
111         "12",
112         "13",
113         "14",
114         "NOCHANGE",
115 };
116
117 /* XXX: we should use getservbyport() instead. */
118 static const char *
119 dewks(wks)
120         int wks;
121 {
122         static char nbuf[20];
123
124         switch (wks) {
125         case 5: return "rje";
126         case 7: return "echo";
127         case 9: return "discard";
128         case 11: return "systat";
129         case 13: return "daytime";
130         case 15: return "netstat";
131         case 17: return "qotd";
132         case 19: return "chargen";
133         case 20: return "ftp-data";
134         case 21: return "ftp";
135         case 23: return "telnet";
136         case 25: return "smtp";
137         case 37: return "time";
138         case 39: return "rlp";
139         case 42: return "name";
140         case 43: return "whois";
141         case 53: return "domain";
142         case 57: return "apts";
143         case 59: return "apfs";
144         case 67: return "bootps";
145         case 68: return "bootpc";
146         case 69: return "tftp";
147         case 77: return "rje";
148         case 79: return "finger";
149         case 87: return "link";
150         case 95: return "supdup";
151         case 100: return "newacct";
152         case 101: return "hostnames";
153         case 102: return "iso-tsap";
154         case 103: return "x400";
155         case 104: return "x400-snd";
156         case 105: return "csnet-ns";
157         case 109: return "pop-2";
158         case 111: return "sunrpc";
159         case 113: return "auth";
160         case 115: return "sftp";
161         case 117: return "uucp-path";
162         case 119: return "nntp";
163         case 121: return "erpc";
164         case 123: return "ntp";
165         case 133: return "statsrv";
166         case 136: return "profile";
167         case 144: return "NeWS";
168         case 161: return "snmp";
169         case 162: return "snmp-trap";
170         case 170: return "print-srv";
171         default: (void) sprintf(nbuf, "%d", wks); return (nbuf);
172         }
173 }
174
175 /* XXX: we should use getprotobynumber() instead. */
176 static const char *
177 deproto(protonum)
178         int protonum;
179 {
180         static char nbuf[20];
181
182         switch (protonum) {
183         case 1: return "icmp";
184         case 2: return "igmp";
185         case 3: return "ggp";
186         case 5: return "st";
187         case 6: return "tcp";
188         case 7: return "ucl";
189         case 8: return "egp";
190         case 9: return "igp";
191         case 11: return "nvp-II";
192         case 12: return "pup";
193         case 16: return "chaos";
194         case 17: return "udp";
195         default: (void) sprintf(nbuf, "%d", protonum); return (nbuf);
196         }
197 }
198
199 static const u_char *
200 do_rrset(msg, len, cp, cnt, pflag, file, hs)
201         int cnt, pflag, len;
202         const u_char *cp, *msg;
203         const char *hs;
204         FILE *file;
205 {
206         int n;
207         int sflag;
208
209         /*
210          * Print answer records.
211          */
212         sflag = (_res.pfcode & pflag);
213         if (n = ntohs(cnt)) {
214                 if ((!_res.pfcode) ||
215                     ((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
216                         fprintf(file, hs);
217                 while (--n >= 0) {
218                         if ((!_res.pfcode) || sflag) {
219                                 cp = p_rr(cp, msg, file);
220                         } else {
221                                 unsigned int dlen;
222                                 cp += __dn_skipname(cp, cp + MAXCDNAME);
223                                 cp += INT16SZ;
224                                 cp += INT16SZ;
225                                 cp += INT32SZ;
226                                 dlen = _getshort((u_char*)cp);
227                                 cp += INT16SZ;
228                                 cp += dlen;
229                         }
230                         if ((cp - msg) > len)
231                                 return (NULL);
232                 }
233                 if ((!_res.pfcode) ||
234                     ((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
235                         putc('\n', file);
236         }
237         return (cp);
238 }
239
240 void
241 __p_query(msg)
242         const u_char *msg;
243 {
244         __fp_query(msg, stdout);
245 }
246
247 #ifdef ultrix
248 /* ultrix 4.0's packaging has some icky packaging.  alias for it here.
249  * there is more junk of this kind over in res_comp.c.
250  */
251 void
252 p_query(msg)
253         const u_char *msg;
254 {
255         __p_query(msg);
256 }
257 #endif
258
259 /*
260  * Print the current options.
261  * This is intended to be primarily a debugging routine.
262  */
263 void
264 __fp_resstat(statp, file)
265         struct __res_state *statp;
266         FILE *file;
267 {
268         register u_long mask;
269
270         fprintf(file, ";; res options:");
271         if (!statp)
272                 statp = &_res;
273         for (mask = 1;  mask != 0;  mask <<= 1)
274                 if (statp->options & mask)
275                         fprintf(file, " %s", p_option(mask));
276         putc('\n', file);
277 }
278
279 /*
280  * Print the contents of a query.
281  * This is intended to be primarily a debugging routine.
282  */
283 void
284 __fp_nquery(msg, len, file)
285         const u_char *msg;
286         int len;
287         FILE *file;
288 {
289         register const u_char *cp, *endMark;
290         register const HEADER *hp;
291         register int n;
292
293         if ((_res.options & RES_INIT) == 0 && res_init() == -1)
294                 return;
295
296 #define TruncTest(x) if (x >= endMark) goto trunc
297 #define ErrorTest(x) if (x == NULL) goto error
298
299         /*
300          * Print header fields.
301          */
302         hp = (HEADER *)msg;
303         cp = msg + HFIXEDSZ;
304         endMark = cp + len;
305         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || hp->rcode) {
306                 fprintf(file, ";; ->>HEADER<<- opcode: %s, status: %s, id: %d",
307                         _res_opcodes[hp->opcode],
308                         _res_resultcodes[hp->rcode],
309                         ntohs(hp->id));
310                 putc('\n', file);
311         }
312         putc(';', file);
313         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) {
314                 fprintf(file, "; flags:");
315                 if (hp->qr)
316                         fprintf(file, " qr");
317                 if (hp->aa)
318                         fprintf(file, " aa");
319                 if (hp->tc)
320                         fprintf(file, " tc");
321                 if (hp->rd)
322                         fprintf(file, " rd");
323                 if (hp->ra)
324                         fprintf(file, " ra");
325         }
326         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) {
327                 fprintf(file, "; Ques: %d", ntohs(hp->qdcount));
328                 fprintf(file, ", Ans: %d", ntohs(hp->ancount));
329                 fprintf(file, ", Auth: %d", ntohs(hp->nscount));
330                 fprintf(file, ", Addit: %d", ntohs(hp->arcount));
331         }
332         if ((!_res.pfcode) || (_res.pfcode & 
333                 (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
334                 putc('\n',file);
335         }
336         /*
337          * Print question records.
338          */
339         if (n = ntohs(hp->qdcount)) {
340                 if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
341                         fprintf(file, ";; QUESTIONS:\n");
342                 while (--n >= 0) {
343                         fprintf(file, ";;\t");
344                         TruncTest(cp);
345                         cp = p_cdnname(cp, msg, len, file);
346                         ErrorTest(cp);
347                         TruncTest(cp);
348                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
349                                 fprintf(file, ", type = %s",
350                                         __p_type(_getshort((u_char*)cp)));
351                         cp += INT16SZ;
352                         TruncTest(cp);
353                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
354                                 fprintf(file, ", class = %s\n",
355                                         __p_class(_getshort((u_char*)cp)));
356                         cp += INT16SZ;
357                         putc('\n', file);
358                 }
359         }
360         /*
361          * Print authoritative answer records
362          */
363         TruncTest(cp);
364         cp = do_rrset(msg, len, cp, hp->ancount, RES_PRF_ANS, file,
365                       ";; ANSWERS:\n");
366         ErrorTest(cp);
367
368         /*
369          * print name server records
370          */
371         TruncTest(cp);
372         cp = do_rrset(msg, len, cp, hp->nscount, RES_PRF_AUTH, file,
373                       ";; AUTHORITY RECORDS:\n");
374         ErrorTest(cp);
375
376         TruncTest(cp);
377         /*
378          * print additional records
379          */
380         cp = do_rrset(msg, len, cp, hp->arcount, RES_PRF_ADD, file,
381                       ";; ADDITIONAL RECORDS:\n");
382         ErrorTest(cp);
383         return;
384  trunc:
385         fprintf(file, "\n;; ...truncated\n");
386         return;
387  error:
388         fprintf(file, "\n;; ...malformed\n");
389 }
390
391 void
392 __fp_query(msg, file)
393         const u_char *msg;
394         FILE *file;
395 {
396         fp_nquery(msg, PACKETSZ, file);
397 }
398
399 const u_char *
400 __p_cdnname(cp, msg, len, file)
401         const u_char *cp, *msg;
402         int len;
403         FILE *file;
404 {
405         char name[MAXDNAME];
406         int n;
407
408         if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
409                 return (NULL);
410         if (name[0] == '\0')
411                 putc('.', file);
412         else
413                 fputs(name, file);
414         return (cp + n);
415 }
416
417 const u_char *
418 __p_cdname(cp, msg, file)
419         const u_char *cp, *msg;
420         FILE *file;
421 {
422         return (p_cdnname(cp, msg, PACKETSZ, file));
423 }
424
425 /* XXX: the rest of these functions need to become length-limited, too. (vix)
426  */
427
428 const u_char *
429 __p_fqname(cp, msg, file)
430         const u_char *cp, *msg;
431         FILE *file;
432 {
433         char name[MAXDNAME];
434         int n;
435
436         if ((n = dn_expand(msg, cp + MAXCDNAME, cp, name, sizeof name)) < 0)
437                 return (NULL);
438         if (name[0] == '\0') {
439                 putc('.', file);
440         } else {
441                 fputs(name, file);
442                 if (name[strlen(name) - 1] != '.')
443                         putc('.', file);
444         }
445         return (cp + n);
446 }
447
448 /*
449  * Print resource record fields in human readable form.
450  */
451 const u_char *
452 __p_rr(cp, msg, file)
453         const u_char *cp, *msg;
454         FILE *file;
455 {
456         int type, class, dlen, n, c;
457         struct in_addr inaddr;
458         const u_char *cp1, *cp2;
459         u_int32_t tmpttl, t;
460         int lcnt;
461
462         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
463                 h_errno = NETDB_INTERNAL;
464                 return (NULL);
465         }
466         if ((cp = p_fqname(cp, msg, file)) == NULL)
467                 return (NULL);                  /* compression error */
468         type = _getshort((u_char*)cp);
469         cp += INT16SZ;
470         class = _getshort((u_char*)cp);
471         cp += INT16SZ;
472         tmpttl = _getlong((u_char*)cp);
473         cp += INT32SZ;
474         dlen = _getshort((u_char*)cp);
475         cp += INT16SZ;
476         cp1 = cp;
477         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_TTLID))
478                 fprintf(file, "\t%lu", (u_long)tmpttl);
479         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_CLASS))
480                 fprintf(file, "\t%s", __p_class(class));
481         fprintf(file, "\t%s", __p_type(type));
482         /*
483          * Print type specific data, if appropriate
484          */
485         switch (type) {
486         case T_A:
487                 switch (class) {
488                 case C_IN:
489                 case C_HS:
490                         bcopy(cp, (char *)&inaddr, INADDRSZ);
491                         if (dlen == 4) {
492                                 fprintf(file, "\t%s", inet_ntoa(inaddr));
493                                 cp += dlen;
494                         } else if (dlen == 7) {
495                                 char *address;
496                                 u_char protocol;
497                                 u_short port;
498
499                                 address = inet_ntoa(inaddr);
500                                 cp += INADDRSZ;
501                                 protocol = *(u_char*)cp;
502                                 cp += sizeof(u_char);
503                                 port = _getshort((u_char*)cp);
504                                 cp += INT16SZ;
505                                 fprintf(file, "\t%s\t; proto %d, port %d",
506                                         address, protocol, port);
507                         }
508                         break;
509                 default:
510                         cp += dlen;
511                 }
512                 break;
513         case T_CNAME:
514         case T_MB:
515         case T_MG:
516         case T_MR:
517         case T_NS:
518         case T_PTR:
519                 putc('\t', file);
520                 if ((cp = p_fqname(cp, msg, file)) == NULL)
521                         return (NULL);
522                 break;
523
524         case T_HINFO:
525         case T_ISDN:
526                 cp2 = cp + dlen;
527                 if (n = *cp++) {
528                         fprintf(file, "\t%.*s", n, cp);
529                         cp += n;
530                 }
531                 if ((cp < cp2) && (n = *cp++)) {
532                         fprintf(file, "\t%.*s", n, cp);
533                         cp += n;
534                 } else if (type == T_HINFO)
535                         fprintf(file, "\n;; *** Warning *** OS-type missing");
536                 break;
537
538         case T_SOA:
539                 putc('\t', file);
540                 if ((cp = p_fqname(cp, msg, file)) == NULL)
541                         return (NULL);
542                 putc(' ', file);
543                 if ((cp = p_fqname(cp, msg, file)) == NULL)
544                         return (NULL);
545                 fputs(" (\n", file);
546                 t = _getlong((u_char*)cp);  cp += INT32SZ;
547                 fprintf(file, "\t\t\t%lu\t; serial\n", (u_long)t);
548                 t = _getlong((u_char*)cp);  cp += INT32SZ;
549                 fprintf(file, "\t\t\t%lu\t; refresh (%s)\n",
550                         (u_long)t, __p_time(t));
551                 t = _getlong((u_char*)cp);  cp += INT32SZ;
552                 fprintf(file, "\t\t\t%lu\t; retry (%s)\n",
553                         (u_long)t, __p_time(t));
554                 t = _getlong((u_char*)cp);  cp += INT32SZ;
555                 fprintf(file, "\t\t\t%lu\t; expire (%s)\n",
556                         (u_long)t, __p_time(t));
557                 t = _getlong((u_char*)cp);  cp += INT32SZ;
558                 fprintf(file, "\t\t\t%lu )\t; minimum (%s)",
559                         (u_long)t, __p_time(t));
560                 break;
561
562         case T_MX:
563         case T_AFSDB:
564         case T_RT:
565                 fprintf(file, "\t%d ", _getshort((u_char*)cp));
566                 cp += INT16SZ;
567                 if ((cp = p_fqname(cp, msg, file)) == NULL)
568                         return (NULL);
569                 break;
570
571         case T_PX:
572                 fprintf(file, "\t%d ", _getshort((u_char*)cp));
573                 cp += INT16SZ;
574                 if ((cp = p_fqname(cp, msg, file)) == NULL)
575                         return (NULL);
576                 putc(' ', file);
577                 if ((cp = p_fqname(cp, msg, file)) == NULL)
578                         return (NULL);
579                 break;
580
581         case T_TXT:
582         case T_X25:
583                 (void) fputs("\t\"", file);
584                 cp2 = cp1 + dlen;
585                 while (cp < cp2) {
586                         if (n = (unsigned char) *cp++) {
587                                 for (c = n; c > 0 && cp < cp2; c--)
588                                         if ((*cp == '\n') || (*cp == '"')) {
589                                             (void) putc('\\', file);
590                                             (void) putc(*cp++, file);
591                                         } else
592                                             (void) putc(*cp++, file);
593                         }
594                 }
595                 putc('"', file);
596                 break;
597
598         case T_NSAP:
599                 (void) fprintf(file, "\t%s", inet_nsap_ntoa(dlen, cp, NULL));
600                 cp += dlen;
601                 break;
602
603         case T_MINFO:
604         case T_RP:
605                 putc('\t', file);
606                 if ((cp = p_fqname(cp, msg, file)) == NULL)
607                         return (NULL);
608                 putc(' ', file);
609                 if ((cp = p_fqname(cp, msg, file)) == NULL)
610                         return (NULL);
611                 break;
612
613         case T_UINFO:
614                 putc('\t', file);
615                 fputs((char *)cp, file);
616                 cp += dlen;
617                 break;
618
619         case T_UID:
620         case T_GID:
621                 if (dlen == 4) {
622                         fprintf(file, "\t%u", _getlong((u_char*)cp));
623                         cp += INT32SZ;
624                 }
625                 break;
626
627         case T_WKS:
628                 if (dlen < INT32SZ + 1)
629                         break;
630                 bcopy(cp, (char *)&inaddr, INADDRSZ);
631                 cp += INT32SZ;
632                 fprintf(file, "\t%s %s ( ",
633                         inet_ntoa(inaddr),
634                         deproto((int) *cp));
635                 cp += sizeof(u_char);
636                 n = 0;
637                 lcnt = 0;
638                 while (cp < cp1 + dlen) {
639                         c = *cp++;
640                         do {
641                                 if (c & 0200) {
642                                         if (lcnt == 0) {
643                                                 fputs("\n\t\t\t", file);
644                                                 lcnt = 5;
645                                         }
646                                         fputs(dewks(n), file);
647                                         putc(' ', file);
648                                         lcnt--;
649                                 }
650                                 c <<= 1;
651                         } while (++n & 07);
652                 }
653                 putc(')', file);
654                 break;
655
656 #ifdef ALLOW_T_UNSPEC
657         case T_UNSPEC:
658                 {
659                         int NumBytes = 8;
660                         u_char *DataPtr;
661                         int i;
662
663                         if (dlen < NumBytes) NumBytes = dlen;
664                         fprintf(file, "\tFirst %d bytes of hex data:",
665                                 NumBytes);
666                         for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
667                                 fprintf(file, " %x", *DataPtr);
668                         cp += dlen;
669                 }
670                 break;
671 #endif /* ALLOW_T_UNSPEC */
672
673         default:
674                 fprintf(file, "\t?%d?", type);
675                 cp += dlen;
676         }
677 #if 0
678         fprintf(file, "\t; dlen=%d, ttl %s\n", dlen, __p_time(tmpttl));
679 #else
680         putc('\n', file);
681 #endif
682         if (cp - cp1 != dlen) {
683                 fprintf(file, ";; packet size error (found %d, dlen was %d)\n",
684                         cp - cp1, dlen);
685                 cp = NULL;
686         }
687         return (cp);
688 }
689
690 /*
691  * Return a string for the type
692  */
693 const char *
694 __p_type(type)
695         int type;
696 {
697         static char nbuf[20];
698
699         switch (type) {
700         case T_A:       return "A";
701         case T_NS:      return "NS";
702         case T_CNAME:   return "CNAME";
703         case T_SOA:     return "SOA";
704         case T_MB:      return "MB";
705         case T_MG:      return "MG";
706         case T_MR:      return "MR";
707         case T_NULL:    return "NULL";
708         case T_WKS:     return "WKS";
709         case T_PTR:     return "PTR";
710         case T_HINFO:   return "HINFO";
711         case T_MINFO:   return "MINFO";
712         case T_MX:      return "MX";
713         case T_TXT:     return "TXT";
714         case T_RP:      return "RP";
715         case T_AFSDB:   return "AFSDB";
716         case T_X25:     return "X25";
717         case T_ISDN:    return "ISDN";
718         case T_RT:      return "RT";
719         case T_NSAP:    return "NSAP";
720         case T_NSAP_PTR: return "NSAP_PTR";
721         case T_SIG:     return "SIG";
722         case T_KEY:     return "KEY";
723         case T_PX:      return "PX";
724         case T_GPOS:    return "GPOS";
725         case T_AAAA:    return "AAAA";
726         case T_LOC:     return "LOC";
727         case T_AXFR:    return "AXFR";
728         case T_MAILB:   return "MAILB";
729         case T_MAILA:   return "MAILA";
730         case T_ANY:     return "ANY";
731         case T_UINFO:   return "UINFO";
732         case T_UID:     return "UID";
733         case T_GID:     return "GID";
734 #ifdef ALLOW_T_UNSPEC
735         case T_UNSPEC:  return "UNSPEC";
736 #endif /* ALLOW_T_UNSPEC */
737         default:        (void)sprintf(nbuf, "%d", type); return (nbuf);
738         }
739 }
740
741 /*
742  * Return a mnemonic for class
743  */
744 const char *
745 __p_class(class)
746         int class;
747 {
748         static char nbuf[20];
749
750         switch (class) {
751         case C_IN:      return "IN";
752         case C_HS:      return "HS";
753         case C_ANY:     return "ANY";
754         default:        (void)sprintf(nbuf, "%d", class); return (nbuf);
755         }
756 }
757
758 /*
759  * Return a mnemonic for an option
760  */
761 const char *
762 __p_option(option)
763         u_long option;
764 {
765         static char nbuf[40];
766
767         switch (option) {
768         case RES_INIT:          return "init";
769         case RES_DEBUG:         return "debug";
770         case RES_AAONLY:        return "aaonly(unimpl)";
771         case RES_USEVC:         return "usevc";
772         case RES_PRIMARY:       return "primry(unimpl)";
773         case RES_IGNTC:         return "igntc";
774         case RES_RECURSE:       return "recurs";
775         case RES_DEFNAMES:      return "defnam";
776         case RES_STAYOPEN:      return "styopn";
777         case RES_DNSRCH:        return "dnsrch";
778         case RES_INSECURE1:     return "insecure1";
779         case RES_INSECURE2:     return "insecure2";
780         default:                sprintf(nbuf, "?0x%lx?", (u_long)option);
781                                 return (nbuf);
782         }
783 }
784
785 /*
786  * Return a mnemonic for a time to live
787  */
788 char *
789 __p_time(value)
790         u_int32_t value;
791 {
792         static char nbuf[40];
793         int secs, mins, hours, days;
794         register char *p;
795
796         if (value == 0) {
797                 strcpy(nbuf, "0 secs");
798                 return (nbuf);
799         }
800
801         secs = value % 60;
802         value /= 60;
803         mins = value % 60;
804         value /= 60;
805         hours = value % 24;
806         value /= 24;
807         days = value;
808         value = 0;
809
810 #define PLURALIZE(x)    x, (x == 1) ? "" : "s"
811         p = nbuf;
812         if (days) {
813                 (void)sprintf(p, "%d day%s", PLURALIZE(days));
814                 while (*++p);
815         }
816         if (hours) {
817                 if (days)
818                         *p++ = ' ';
819                 (void)sprintf(p, "%d hour%s", PLURALIZE(hours));
820                 while (*++p);
821         }
822         if (mins) {
823                 if (days || hours)
824                         *p++ = ' ';
825                 (void)sprintf(p, "%d min%s", PLURALIZE(mins));
826                 while (*++p);
827         }
828         if (secs || ! (days || hours || mins)) {
829                 if (days || hours || mins)
830                         *p++ = ' ';
831                 (void)sprintf(p, "%d sec%s", PLURALIZE(secs));
832         }
833         return (nbuf);
834 }