Incorporated from BIND-4.9.3-BETA9.
[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",
83         "4",
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                         cp = p_rr(cp, msg, file);
214                         if ((cp - msg) > PACKETSZ)
215                                 return (NULL);
216                 }
217                 if ((!_res.pfcode) ||
218                     ((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
219                         putc('\n', file);
220         }
221         return (cp);
222 }
223
224 void
225 __p_query(msg)
226         const u_char *msg;
227 {
228         __fp_query(msg, stdout);
229 }
230
231 #ifdef ultrix
232 /* ultrix 4.0's packaging has some icky packaging.  alias for it here.
233  * there is more junk of this kind over in res_comp.c.
234  */
235 void
236 p_query(msg)
237         const u_char *msg;
238 {
239         __p_query(msg);
240 }
241 #endif
242
243 /*
244  * Print the current options.
245  * This is intended to be primarily a debugging routine.
246  */
247 void
248 __fp_resstat(statp, file)
249         struct __res_state *statp;
250         FILE *file;
251 {
252         register u_long mask;
253
254         fprintf(file, ";; res options:");
255         if (!statp)
256                 statp = &_res;
257         for (mask = 1;  mask != 0;  mask <<= 1)
258                 if (statp->options & mask)
259                         fprintf(file, " %s", p_option(mask));
260         putc('\n', file);
261 }
262
263 /*
264  * Print the contents of a query.
265  * This is intended to be primarily a debugging routine.
266  */
267 void
268 __fp_nquery(msg, len, file)
269         const u_char *msg;
270         int len;
271         FILE *file;
272 {
273         register const u_char *cp, *endMark;
274         register const HEADER *hp;
275         register int n;
276
277 #define TruncTest(x) if (x >= endMark) goto trunc
278 #define ErrorTest(x) if (x == NULL) goto error
279
280         /*
281          * Print header fields.
282          */
283         hp = (HEADER *)msg;
284         cp = msg + HFIXEDSZ;
285         endMark = cp + len;
286         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || hp->rcode) {
287                 fprintf(file, ";; ->>HEADER<<- opcode: %s, status: %s, id: %d",
288                         _res_opcodes[hp->opcode],
289                         _res_resultcodes[hp->rcode],
290                         ntohs(hp->id));
291                 putc('\n', file);
292         }
293         putc(';', file);
294         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) {
295                 fprintf(file,"; flags:");
296                 if (hp->qr)
297                         fprintf(file, " qr");
298                 if (hp->aa)
299                         fprintf(file, " aa");
300                 if (hp->tc)
301                         fprintf(file, " tc");
302                 if (hp->rd)
303                         fprintf(file, " rd");
304                 if (hp->ra)
305                         fprintf(file, " ra");
306                 if (hp->pr)
307                         fprintf(file, " pr");
308         }
309         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) {
310                 fprintf(file, "; Ques: %d", ntohs(hp->qdcount));
311                 fprintf(file, ", Ans: %d", ntohs(hp->ancount));
312                 fprintf(file, ", Auth: %d", ntohs(hp->nscount));
313                 fprintf(file, ", Addit: %d", ntohs(hp->arcount));
314         }
315         if ((!_res.pfcode) || (_res.pfcode & 
316                 (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
317                 putc('\n',file);
318         }
319         /*
320          * Print question records.
321          */
322         if (n = ntohs(hp->qdcount)) {
323                 if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
324                         fprintf(file,";; QUESTIONS:\n");
325                 while (--n >= 0) {
326                         fprintf(file,";;\t");
327                         TruncTest(cp);
328                         cp = p_cdname(cp, msg, file);
329                         ErrorTest(cp);
330                         TruncTest(cp);
331                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
332                                 fprintf(file, ", type = %s",
333                                         __p_type(_getshort((u_char*)cp)));
334                         cp += INT16SZ;
335                         TruncTest(cp);
336                         if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
337                                 fprintf(file, ", class = %s\n",
338                                         __p_class(_getshort((u_char*)cp)));
339                         cp += INT16SZ;
340                         putc('\n', file);
341                 }
342         }
343         /*
344          * Print authoritative answer records
345          */
346         TruncTest(cp);
347         cp = do_rrset(msg, cp, hp->ancount, RES_PRF_ANS, file,
348                       ";; ANSWERS:\n");
349         ErrorTest(cp);
350
351         /*
352          * print name server records
353          */
354         TruncTest(cp);
355         cp = do_rrset(msg, cp, hp->nscount, RES_PRF_AUTH, file,
356                       ";; AUTHORITY RECORDS:\n");
357         ErrorTest(cp);
358
359         TruncTest(cp);
360         /*
361          * print additional records
362          */
363         cp = do_rrset(msg, cp, hp->arcount, RES_PRF_ADD, file,
364                       ";; ADDITIONAL RECORDS:\n");
365         ErrorTest(cp);
366         return;
367  trunc:
368         fprintf(file, "\n;; ...truncated\n");
369         return;
370  error:
371         fprintf(file, "\n;; ...malformed\n");
372 }
373
374 void
375 __fp_query(msg, file)
376         const u_char *msg;
377         FILE *file;
378 {
379         fp_nquery(msg, PACKETSZ, file);
380 }
381
382 const u_char *
383 __p_cdnname(cp, msg, len, file)
384         const u_char *cp, *msg;
385         int len;
386         FILE *file;
387 {
388         char name[MAXDNAME];
389         int n;
390
391         if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
392                 return (NULL);
393         if (name[0] == '\0')
394                 putc('.', file);
395         else
396                 fputs(name, file);
397         return (cp + n);
398 }
399
400 const u_char *
401 __p_cdname(cp, msg, file)
402         const u_char *cp, *msg;
403         FILE *file;
404 {
405         return (p_cdnname(cp, msg, PACKETSZ, file));
406 }
407
408 /* XXX: the rest of these functions need to become length-limited, too. (vix)
409  */
410
411 const u_char *
412 __p_fqname(cp, msg, file)
413         const u_char *cp, *msg;
414         FILE *file;
415 {
416         char name[MAXDNAME];
417         int n, len;
418
419         if ((n = dn_expand(msg, cp + MAXCDNAME, cp, name, sizeof name)) < 0)
420                 return (NULL);
421         if (name[0] == '\0') {
422                 putc('.', file);
423         } else {
424                 fputs(name, file);
425                 if (name[strlen(name) - 1] != '.')
426                         putc('.', file);
427         }
428         return (cp + n);
429 }
430
431 /*
432  * Print resource record fields in human readable form.
433  */
434 const u_char *
435 __p_rr(cp, msg, file)
436         const u_char *cp, *msg;
437         FILE *file;
438 {
439         int type, class, dlen, n, c;
440         struct in_addr inaddr;
441         const u_char *cp1, *cp2;
442         u_int32_t tmpttl, t;
443         int lcnt;
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", 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                 cp = p_fqname(cp, msg, file);
500                 break;
501
502         case T_HINFO:
503         case T_ISDN:
504                 if (n = *cp++) {
505                         fprintf(file,"\t%.*s", n, cp);
506                         cp += n;
507                 }
508                 if (n = *cp++) {
509                         fprintf(file,"\t%.*s", n, cp);
510                         cp += n;
511                 }
512                 break;
513
514         case T_SOA:
515                 putc('\t', file);
516                 cp = p_fqname(cp, msg, file);   /* origin */
517                 putc(' ', file);
518                 cp = p_fqname(cp, msg, file);   /* mail addr */
519                 fputs(" (\n", file);
520                 t = _getlong((u_char*)cp);  cp += INT32SZ;
521                 fprintf(file,"\t\t\t%lu\t; serial\n", t);
522                 t = _getlong((u_char*)cp);  cp += INT32SZ;
523                 fprintf(file,"\t\t\t%lu\t; refresh (%s)\n", t, __p_time(t));
524                 t = _getlong((u_char*)cp);  cp += INT32SZ;
525                 fprintf(file,"\t\t\t%lu\t; retry (%s)\n", t, __p_time(t));
526                 t = _getlong((u_char*)cp);  cp += INT32SZ;
527                 fprintf(file,"\t\t\t%lu\t; expire (%s)\n", t, __p_time(t));
528                 t = _getlong((u_char*)cp);  cp += INT32SZ;
529                 fprintf(file,"\t\t\t%lu )\t; minimum (%s)", t, __p_time(t));
530                 break;
531
532         case T_MX:
533         case T_AFSDB:
534         case T_RT:
535                 fprintf(file,"\t%d ", _getshort((u_char*)cp));
536                 cp += INT16SZ;
537                 cp = p_fqname(cp, msg, file);
538                 break;
539
540         case T_TXT:
541         case T_X25:
542                 (void) fputs("\t\"", file);
543                 cp2 = cp1 + dlen;
544                 while (cp < cp2) {
545                         if (n = (unsigned char) *cp++) {
546                                 for (c = n; c > 0 && cp < cp2; c--)
547                                         if (*cp == '\n') {
548                                             (void) putc('\\', file);
549                                             (void) putc(*cp++, file);
550                                         } else
551                                             (void) putc(*cp++, file);
552                         }
553                 }
554                 putc('"', file);
555                 break;
556
557         case T_NSAP:
558                 (void) fprintf(file, "\t%s", inet_nsap_ntoa(dlen, cp, NULL));
559                 cp += dlen;
560                 break;
561
562         case T_MINFO:
563         case T_RP:
564                 putc('\t', file);
565                 cp = p_fqname(cp, msg, file);
566                 putc(' ', file);
567                 cp = p_fqname(cp, msg, file);
568                 break;
569
570         case T_UINFO:
571                 putc('\t', file);
572                 fputs((char *)cp, file);
573                 cp += dlen;
574                 break;
575
576         case T_UID:
577         case T_GID:
578                 if (dlen == 4) {
579                         fprintf(file,"\t%u", _getlong((u_char*)cp));
580                         cp += INT32SZ;
581                 }
582                 break;
583
584         case T_WKS:
585                 if (dlen < INT32SZ + 1)
586                         break;
587                 bcopy(cp, (char *)&inaddr, INADDRSZ);
588                 cp += INT32SZ;
589                 fprintf(file, "\t%s %s ( ",
590                         inet_ntoa(inaddr),
591                         deproto((int) *cp));
592                 cp += sizeof(u_char);
593                 n = 0;
594                 lcnt = 0;
595                 while (cp < cp1 + dlen) {
596                         c = *cp++;
597                         do {
598                                 if (c & 0200) {
599                                         if (lcnt == 0) {
600                                                 fputs("\n\t\t\t", file);
601                                                 lcnt = 5;
602                                         }
603                                         fputs(dewks(n), file);
604                                         putc(' ', file);
605                                         lcnt--;
606                                 }
607                                 c <<= 1;
608                         } while (++n & 07);
609                 }
610                 putc(')', file);
611                 break;
612
613 #ifdef ALLOW_T_UNSPEC
614         case T_UNSPEC:
615                 {
616                         int NumBytes = 8;
617                         u_char *DataPtr;
618                         int i;
619
620                         if (dlen < NumBytes) NumBytes = dlen;
621                         fprintf(file, "\tFirst %d bytes of hex data:",
622                                 NumBytes);
623                         for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
624                                 fprintf(file, " %x", *DataPtr);
625                         cp += dlen;
626                 }
627                 break;
628 #endif /* ALLOW_T_UNSPEC */
629
630         default:
631                 fprintf(file,"\t?%d?", type);
632                 cp += dlen;
633         }
634 #if 0
635         fprintf(file, "\t; dlen=%d, ttl %s\n", dlen, __p_time(tmpttl));
636 #else
637         putc('\n', file);
638 #endif
639         if (cp - cp1 != dlen) {
640                 fprintf(file,";; packet size error (found %d, dlen was %d)\n",
641                         cp - cp1, dlen);
642                 cp = NULL;
643         }
644         return (cp);
645 }
646
647 static  char nbuf[40];
648
649 /*
650  * Return a string for the type
651  */
652 const char *
653 __p_type(type)
654         int type;
655 {
656         switch (type) {
657         case T_A:       return "A";
658         case T_NS:      return "NS";
659         case T_CNAME:   return "CNAME";
660         case T_SOA:     return "SOA";
661         case T_MB:      return "MB";
662         case T_MG:      return "MG";
663         case T_MR:      return "MR";
664         case T_NULL:    return "NULL";
665         case T_WKS:     return "WKS";
666         case T_PTR:     return "PTR";
667         case T_HINFO:   return "HINFO";
668         case T_MINFO:   return "MINFO";
669         case T_MX:      return "MX";
670         case T_TXT:     return "TXT";
671         case T_NSAP:    return "NSAP";
672         case T_RP:      return "RP";
673         case T_AFSDB:   return "AFSDB";
674         case T_X25:     return "X25";
675         case T_ISDN:    return "ISDN";
676         case T_RT:      return "RT";
677         case T_AXFR:    return "AXFR";
678         case T_MAILB:   return "MAILB";
679         case T_MAILA:   return "MAILA";
680         case T_ANY:     return "ANY";
681         case T_UINFO:   return "UINFO";
682         case T_UID:     return "UID";
683         case T_GID:     return "GID";
684 #ifdef ALLOW_T_UNSPEC
685         case T_UNSPEC:  return "UNSPEC";
686 #endif /* ALLOW_T_UNSPEC */
687         default:        (void)sprintf(nbuf, "%d", type); return (nbuf);
688         }
689 }
690
691 /*
692  * Return a mnemonic for class
693  */
694 const char *
695 __p_class(class)
696         int class;
697 {
698         switch (class) {
699         case C_IN:      return("IN");
700         case C_HS:      return("HS");
701         case C_ANY:     return("ANY");
702         default:        (void)sprintf(nbuf, "%d", class); return (nbuf);
703         }
704 }
705
706 /*
707  * Return a mnemonic for an option
708  */
709 const char *
710 __p_option(option)
711         u_long option;
712 {
713         switch (option) {
714         case RES_INIT:          return "init";
715         case RES_DEBUG:         return "debug";
716         case RES_AAONLY:        return "aaonly";
717         case RES_USEVC:         return "usevc";
718         case RES_PRIMARY:       return "primry";
719         case RES_IGNTC:         return "igntc";
720         case RES_RECURSE:       return "recurs";
721         case RES_DEFNAMES:      return "defnam";
722         case RES_STAYOPEN:      return "styopn";
723         case RES_DNSRCH:        return "dnsrch";
724         case RES_INSECURE1:     return "insecure1";
725         case RES_INSECURE2:     return "insecure2";
726         default:                sprintf(nbuf, "?0x%x?", option); return nbuf;
727         }
728 }
729
730 /*
731  * Return a mnemonic for a time to live
732  */
733 char *
734 __p_time(value)
735         u_int32_t value;
736 {
737         int secs, mins, hours, days;
738         register char *p;
739
740         if (value == 0) {
741                 strcpy(nbuf, "0 secs");
742                 return (nbuf);
743         }
744
745         secs = value % 60;
746         value /= 60;
747         mins = value % 60;
748         value /= 60;
749         hours = value % 24;
750         value /= 24;
751         days = value;
752         value = 0;
753
754 #define PLURALIZE(x)    x, (x == 1) ? "" : "s"
755         p = nbuf;
756         if (days) {
757                 (void)sprintf(p, "%d day%s", PLURALIZE(days));
758                 while (*++p);
759         }
760         if (hours) {
761                 if (days)
762                         *p++ = ' ';
763                 (void)sprintf(p, "%d hour%s", PLURALIZE(hours));
764                 while (*++p);
765         }
766         if (mins) {
767                 if (days || hours)
768                         *p++ = ' ';
769                 (void)sprintf(p, "%d min%s", PLURALIZE(mins));
770                 while (*++p);
771         }
772         if (secs || ! (days || hours || mins)) {
773                 if (days || hours || mins)
774                         *p++ = ' ';
775                 (void)sprintf(p, "%d sec%s", PLURALIZE(secs));
776         }
777         return (nbuf);
778 }