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