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