Updated from BIND-4.9.3-BETA27.
[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         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX))
313         putc(';', file);
314         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) {
315                 fprintf(file, "; flags:");
316                 if (hp->qr)
317                         fprintf(file, " qr");
318                 if (hp->aa)
319                         fprintf(file, " aa");
320                 if (hp->tc)
321                         fprintf(file, " tc");
322                 if (hp->rd)
323                         fprintf(file, " rd");
324                 if (hp->ra)
325                         fprintf(file, " ra");
326         }
327         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) {
328                 fprintf(file, "; Ques: %d", ntohs(hp->qdcount));
329                 fprintf(file, ", Ans: %d", ntohs(hp->ancount));
330                 fprintf(file, ", Auth: %d", ntohs(hp->nscount));
331                 fprintf(file, ", Addit: %d", ntohs(hp->arcount));
332         }
333         if ((!_res.pfcode) || (_res.pfcode & 
334                 (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
335                 putc('\n',file);
336         }
337         /*
338          * Print question records.
339          */
340         if (n = ntohs(hp->qdcount)) {
341                 if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
342                         fprintf(file, ";; QUESTIONS:\n");
343                 while (--n >= 0) {
344                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
345                         fprintf(file, ";;\t");
346                         TruncTest(cp);
347                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
348                         cp = p_cdnname(cp, msg, len, file);
349                         else {
350                                 int n;
351                                 char name[MAXDNAME];
352
353                                 if ((n = dn_expand(msg, msg+len, cp, name,
354                                                 sizeof name)) < 0)
355                                         cp = NULL;
356                                 else
357                                         cp += n;
358                         }
359                         ErrorTest(cp);
360                         TruncTest(cp);
361                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
362                                 fprintf(file, ", type = %s",
363                                         __p_type(_getshort((u_char*)cp)));
364                         cp += INT16SZ;
365                         TruncTest(cp);
366                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
367                                 fprintf(file, ", class = %s\n",
368                                         __p_class(_getshort((u_char*)cp)));
369                         cp += INT16SZ;
370                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
371                         putc('\n', file);
372                 }
373         }
374         /*
375          * Print authoritative answer records
376          */
377         TruncTest(cp);
378         cp = do_rrset(msg, len, cp, hp->ancount, RES_PRF_ANS, file,
379                       ";; ANSWERS:\n");
380         ErrorTest(cp);
381
382         /*
383          * print name server records
384          */
385         TruncTest(cp);
386         cp = do_rrset(msg, len, cp, hp->nscount, RES_PRF_AUTH, file,
387                       ";; AUTHORITY RECORDS:\n");
388         ErrorTest(cp);
389
390         TruncTest(cp);
391         /*
392          * print additional records
393          */
394         cp = do_rrset(msg, len, cp, hp->arcount, RES_PRF_ADD, file,
395                       ";; ADDITIONAL RECORDS:\n");
396         ErrorTest(cp);
397         return;
398  trunc:
399         fprintf(file, "\n;; ...truncated\n");
400         return;
401  error:
402         fprintf(file, "\n;; ...malformed\n");
403 }
404
405 void
406 __fp_query(msg, file)
407         const u_char *msg;
408         FILE *file;
409 {
410         fp_nquery(msg, PACKETSZ, file);
411 }
412
413 const u_char *
414 __p_cdnname(cp, msg, len, file)
415         const u_char *cp, *msg;
416         int len;
417         FILE *file;
418 {
419         char name[MAXDNAME];
420         int n;
421
422         if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
423                 return (NULL);
424         if (name[0] == '\0')
425                 putc('.', file);
426         else
427                 fputs(name, file);
428         return (cp + n);
429 }
430
431 const u_char *
432 __p_cdname(cp, msg, file)
433         const u_char *cp, *msg;
434         FILE *file;
435 {
436         return (p_cdnname(cp, msg, PACKETSZ, file));
437 }
438
439 /* XXX: the rest of these functions need to become length-limited, too. (vix)
440  */
441
442 const u_char *
443 __p_fqname(cp, msg, file)
444         const u_char *cp, *msg;
445         FILE *file;
446 {
447         char name[MAXDNAME];
448         int n;
449
450         if ((n = dn_expand(msg, cp + MAXCDNAME, cp, name, sizeof name)) < 0)
451                 return (NULL);
452         if (name[0] == '\0') {
453                 putc('.', file);
454         } else {
455                 fputs(name, file);
456                 if (name[strlen(name) - 1] != '.')
457                         putc('.', file);
458         }
459         return (cp + n);
460 }
461
462 /*
463  * Print resource record fields in human readable form.
464  */
465 const u_char *
466 __p_rr(cp, msg, file)
467         const u_char *cp, *msg;
468         FILE *file;
469 {
470         int type, class, dlen, n, c;
471         struct in_addr inaddr;
472         const u_char *cp1, *cp2;
473         u_int32_t tmpttl, t;
474         int lcnt;
475
476         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
477                 h_errno = NETDB_INTERNAL;
478                 return (NULL);
479         }
480         if ((cp = p_fqname(cp, msg, file)) == NULL)
481                 return (NULL);                  /* compression error */
482         type = _getshort((u_char*)cp);
483         cp += INT16SZ;
484         class = _getshort((u_char*)cp);
485         cp += INT16SZ;
486         tmpttl = _getlong((u_char*)cp);
487         cp += INT32SZ;
488         dlen = _getshort((u_char*)cp);
489         cp += INT16SZ;
490         cp1 = cp;
491         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_TTLID))
492                 fprintf(file, "\t%lu", (u_long)tmpttl);
493         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_CLASS))
494                 fprintf(file, "\t%s", __p_class(class));
495         fprintf(file, "\t%s", __p_type(type));
496         /*
497          * Print type specific data, if appropriate
498          */
499         switch (type) {
500         case T_A:
501                 switch (class) {
502                 case C_IN:
503                 case C_HS:
504                         bcopy(cp, (char *)&inaddr, INADDRSZ);
505                         if (dlen == 4) {
506                                 fprintf(file, "\t%s", inet_ntoa(inaddr));
507                                 cp += dlen;
508                         } else if (dlen == 7) {
509                                 char *address;
510                                 u_char protocol;
511                                 u_short port;
512
513                                 address = inet_ntoa(inaddr);
514                                 cp += INADDRSZ;
515                                 protocol = *(u_char*)cp;
516                                 cp += sizeof(u_char);
517                                 port = _getshort((u_char*)cp);
518                                 cp += INT16SZ;
519                                 fprintf(file, "\t%s\t; proto %d, port %d",
520                                         address, protocol, port);
521                         }
522                         break;
523                 default:
524                         cp += dlen;
525                 }
526                 break;
527         case T_CNAME:
528         case T_MB:
529         case T_MG:
530         case T_MR:
531         case T_NS:
532         case T_PTR:
533                 putc('\t', file);
534                 if ((cp = p_fqname(cp, msg, file)) == NULL)
535                         return (NULL);
536                 break;
537
538         case T_HINFO:
539         case T_ISDN:
540                 cp2 = cp + dlen;
541                 if (n = *cp++) {
542                         fprintf(file, "\t%.*s", n, cp);
543                         cp += n;
544                 }
545                 if ((cp < cp2) && (n = *cp++)) {
546                         fprintf(file, "\t%.*s", n, cp);
547                         cp += n;
548                 } else if (type == T_HINFO)
549                         fprintf(file, "\n;; *** Warning *** OS-type missing");
550                 break;
551
552         case T_SOA:
553                 putc('\t', file);
554                 if ((cp = p_fqname(cp, msg, file)) == NULL)
555                         return (NULL);
556                 putc(' ', file);
557                 if ((cp = p_fqname(cp, msg, file)) == NULL)
558                         return (NULL);
559                 fputs(" (\n", file);
560                 t = _getlong((u_char*)cp);  cp += INT32SZ;
561                 fprintf(file, "\t\t\t%lu\t; serial\n", (u_long)t);
562                 t = _getlong((u_char*)cp);  cp += INT32SZ;
563                 fprintf(file, "\t\t\t%lu\t; refresh (%s)\n",
564                         (u_long)t, __p_time(t));
565                 t = _getlong((u_char*)cp);  cp += INT32SZ;
566                 fprintf(file, "\t\t\t%lu\t; retry (%s)\n",
567                         (u_long)t, __p_time(t));
568                 t = _getlong((u_char*)cp);  cp += INT32SZ;
569                 fprintf(file, "\t\t\t%lu\t; expire (%s)\n",
570                         (u_long)t, __p_time(t));
571                 t = _getlong((u_char*)cp);  cp += INT32SZ;
572                 fprintf(file, "\t\t\t%lu )\t; minimum (%s)",
573                         (u_long)t, __p_time(t));
574                 break;
575
576         case T_MX:
577         case T_AFSDB:
578         case T_RT:
579                 fprintf(file, "\t%d ", _getshort((u_char*)cp));
580                 cp += INT16SZ;
581                 if ((cp = p_fqname(cp, msg, file)) == NULL)
582                         return (NULL);
583                 break;
584
585         case T_PX:
586                 fprintf(file, "\t%d ", _getshort((u_char*)cp));
587                 cp += INT16SZ;
588                 if ((cp = p_fqname(cp, msg, file)) == NULL)
589                         return (NULL);
590                 putc(' ', file);
591                 if ((cp = p_fqname(cp, msg, file)) == NULL)
592                         return (NULL);
593                 break;
594
595         case T_TXT:
596         case T_X25:
597                 (void) fputs("\t\"", file);
598                 cp2 = cp1 + dlen;
599                 while (cp < cp2) {
600                         if (n = (unsigned char) *cp++) {
601                                 for (c = n; c > 0 && cp < cp2; c--)
602                                         if ((*cp == '\n') || (*cp == '"')) {
603                                             (void) putc('\\', file);
604                                             (void) putc(*cp++, file);
605                                         } else
606                                             (void) putc(*cp++, file);
607                         }
608                 }
609                 putc('"', file);
610                 break;
611
612         case T_NSAP:
613                 (void) fprintf(file, "\t%s", inet_nsap_ntoa(dlen, cp, NULL));
614                 cp += dlen;
615                 break;
616
617         case T_MINFO:
618         case T_RP:
619                 putc('\t', file);
620                 if ((cp = p_fqname(cp, msg, file)) == NULL)
621                         return (NULL);
622                 putc(' ', file);
623                 if ((cp = p_fqname(cp, msg, file)) == NULL)
624                         return (NULL);
625                 break;
626
627         case T_UINFO:
628                 putc('\t', file);
629                 fputs((char *)cp, file);
630                 cp += dlen;
631                 break;
632
633         case T_UID:
634         case T_GID:
635                 if (dlen == 4) {
636                         fprintf(file, "\t%u", _getlong((u_char*)cp));
637                         cp += INT32SZ;
638                 }
639                 break;
640
641         case T_WKS:
642                 if (dlen < INT32SZ + 1)
643                         break;
644                 bcopy(cp, (char *)&inaddr, INADDRSZ);
645                 cp += INT32SZ;
646                 fprintf(file, "\t%s %s ( ",
647                         inet_ntoa(inaddr),
648                         deproto((int) *cp));
649                 cp += sizeof(u_char);
650                 n = 0;
651                 lcnt = 0;
652                 while (cp < cp1 + dlen) {
653                         c = *cp++;
654                         do {
655                                 if (c & 0200) {
656                                         if (lcnt == 0) {
657                                                 fputs("\n\t\t\t", file);
658                                                 lcnt = 5;
659                                         }
660                                         fputs(dewks(n), file);
661                                         putc(' ', file);
662                                         lcnt--;
663                                 }
664                                 c <<= 1;
665                         } while (++n & 07);
666                 }
667                 putc(')', file);
668                 break;
669
670 #ifdef ALLOW_T_UNSPEC
671         case T_UNSPEC:
672                 {
673                         int NumBytes = 8;
674                         u_char *DataPtr;
675                         int i;
676
677                         if (dlen < NumBytes) NumBytes = dlen;
678                         fprintf(file, "\tFirst %d bytes of hex data:",
679                                 NumBytes);
680                         for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
681                                 fprintf(file, " %x", *DataPtr);
682                         cp += dlen;
683                 }
684                 break;
685 #endif /* ALLOW_T_UNSPEC */
686
687         default:
688                 fprintf(file, "\t?%d?", type);
689                 cp += dlen;
690         }
691 #if 0
692         fprintf(file, "\t; dlen=%d, ttl %s\n", dlen, __p_time(tmpttl));
693 #else
694         putc('\n', file);
695 #endif
696         if (cp - cp1 != dlen) {
697                 fprintf(file, ";; packet size error (found %d, dlen was %d)\n",
698                         cp - cp1, dlen);
699                 cp = NULL;
700         }
701         return (cp);
702 }
703
704 /*
705  * Return a string for the type
706  */
707 const char *
708 __p_type(type)
709         int type;
710 {
711         static char nbuf[20];
712
713         switch (type) {
714         case T_A:       return "A";
715         case T_NS:      return "NS";
716         case T_CNAME:   return "CNAME";
717         case T_SOA:     return "SOA";
718         case T_MB:      return "MB";
719         case T_MG:      return "MG";
720         case T_MR:      return "MR";
721         case T_NULL:    return "NULL";
722         case T_WKS:     return "WKS";
723         case T_PTR:     return "PTR";
724         case T_HINFO:   return "HINFO";
725         case T_MINFO:   return "MINFO";
726         case T_MX:      return "MX";
727         case T_TXT:     return "TXT";
728         case T_RP:      return "RP";
729         case T_AFSDB:   return "AFSDB";
730         case T_X25:     return "X25";
731         case T_ISDN:    return "ISDN";
732         case T_RT:      return "RT";
733         case T_NSAP:    return "NSAP";
734         case T_NSAP_PTR: return "NSAP_PTR";
735         case T_SIG:     return "SIG";
736         case T_KEY:     return "KEY";
737         case T_PX:      return "PX";
738         case T_GPOS:    return "GPOS";
739         case T_AAAA:    return "AAAA";
740         case T_LOC:     return "LOC";
741         case T_AXFR:    return "AXFR";
742         case T_MAILB:   return "MAILB";
743         case T_MAILA:   return "MAILA";
744         case T_ANY:     return "ANY";
745         case T_UINFO:   return "UINFO";
746         case T_UID:     return "UID";
747         case T_GID:     return "GID";
748 #ifdef ALLOW_T_UNSPEC
749         case T_UNSPEC:  return "UNSPEC";
750 #endif /* ALLOW_T_UNSPEC */
751         default:        (void)sprintf(nbuf, "%d", type); return (nbuf);
752         }
753 }
754
755 /*
756  * Return a mnemonic for class
757  */
758 const char *
759 __p_class(class)
760         int class;
761 {
762         static char nbuf[20];
763
764         switch (class) {
765         case C_IN:      return "IN";
766         case C_HS:      return "HS";
767         case C_ANY:     return "ANY";
768         default:        (void)sprintf(nbuf, "%d", class); return (nbuf);
769         }
770 }
771
772 /*
773  * Return a mnemonic for an option
774  */
775 const char *
776 __p_option(option)
777         u_long option;
778 {
779         static char nbuf[40];
780
781         switch (option) {
782         case RES_INIT:          return "init";
783         case RES_DEBUG:         return "debug";
784         case RES_AAONLY:        return "aaonly(unimpl)";
785         case RES_USEVC:         return "usevc";
786         case RES_PRIMARY:       return "primry(unimpl)";
787         case RES_IGNTC:         return "igntc";
788         case RES_RECURSE:       return "recurs";
789         case RES_DEFNAMES:      return "defnam";
790         case RES_STAYOPEN:      return "styopn";
791         case RES_DNSRCH:        return "dnsrch";
792         case RES_INSECURE1:     return "insecure1";
793         case RES_INSECURE2:     return "insecure2";
794         default:                sprintf(nbuf, "?0x%lx?", (u_long)option);
795                                 return (nbuf);
796         }
797 }
798
799 /*
800  * Return a mnemonic for a time to live
801  */
802 char *
803 __p_time(value)
804         u_int32_t value;
805 {
806         static char nbuf[40];
807         int secs, mins, hours, days;
808         register char *p;
809
810         if (value == 0) {
811                 strcpy(nbuf, "0 secs");
812                 return (nbuf);
813         }
814
815         secs = value % 60;
816         value /= 60;
817         mins = value % 60;
818         value /= 60;
819         hours = value % 24;
820         value /= 24;
821         days = value;
822         value = 0;
823
824 #define PLURALIZE(x)    x, (x == 1) ? "" : "s"
825         p = nbuf;
826         if (days) {
827                 (void)sprintf(p, "%d day%s", PLURALIZE(days));
828                 while (*++p);
829         }
830         if (hours) {
831                 if (days)
832                         *p++ = ' ';
833                 (void)sprintf(p, "%d hour%s", PLURALIZE(hours));
834                 while (*++p);
835         }
836         if (mins) {
837                 if (days || hours)
838                         *p++ = ' ';
839                 (void)sprintf(p, "%d min%s", PLURALIZE(mins));
840                 while (*++p);
841         }
842         if (secs || ! (days || hours || mins)) {
843                 if (days || hours || mins)
844                         *p++ = ' ';
845                 (void)sprintf(p, "%d sec%s", PLURALIZE(secs));
846         }
847         return (nbuf);
848 }