aboutsummaryrefslogtreecommitdiff
path: root/resolv/res_debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'resolv/res_debug.c')
-rw-r--r--resolv/res_debug.c814
1 files changed, 814 insertions, 0 deletions
diff --git a/resolv/res_debug.c b/resolv/res_debug.c
new file mode 100644
index 0000000..254e1ef
--- /dev/null
+++ b/resolv/res_debug.c
@@ -0,0 +1,814 @@
+/*
+ * ++Copyright++ 1985, 1990, 1993
+ * -
+ * Copyright (c) 1985, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
+static char rcsid[] = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <stdio.h>
+#include <resolv.h>
+#if defined(BSD) && (BSD >= 199103)
+# include <string.h>
+#else
+# include "../conf/portability.h"
+#endif
+
+#if defined(USE_OPTIONS_H)
+# include "../conf/options.h"
+#endif
+
+const char *_res_opcodes[] = {
+ "QUERY",
+ "IQUERY",
+ "CQUERYM",
+ "CQUERYU", /* experimental */
+ "NOTIFY", /* experimental */
+ "5",
+ "6",
+ "7",
+ "8",
+ "UPDATEA",
+ "UPDATED",
+ "UPDATEDA",
+ "UPDATEM",
+ "UPDATEMA",
+ "ZONEINIT",
+ "ZONEREF",
+};
+
+const char *_res_resultcodes[] = {
+ "NOERROR",
+ "FORMERR",
+ "SERVFAIL",
+ "NXDOMAIN",
+ "NOTIMP",
+ "REFUSED",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "NOCHANGE",
+};
+
+static char retbuf[16];
+
+static const char *
+dewks(wks)
+ int wks;
+{
+ switch (wks) {
+ case 5: return "rje";
+ case 7: return "echo";
+ case 9: return "discard";
+ case 11: return "systat";
+ case 13: return "daytime";
+ case 15: return "netstat";
+ case 17: return "qotd";
+ case 19: return "chargen";
+ case 20: return "ftp-data";
+ case 21: return "ftp";
+ case 23: return "telnet";
+ case 25: return "smtp";
+ case 37: return "time";
+ case 39: return "rlp";
+ case 42: return "name";
+ case 43: return "whois";
+ case 53: return "domain";
+ case 57: return "apts";
+ case 59: return "apfs";
+ case 67: return "bootps";
+ case 68: return "bootpc";
+ case 69: return "tftp";
+ case 77: return "rje";
+ case 79: return "finger";
+ case 87: return "link";
+ case 95: return "supdup";
+ case 100: return "newacct";
+ case 101: return "hostnames";
+ case 102: return "iso-tsap";
+ case 103: return "x400";
+ case 104: return "x400-snd";
+ case 105: return "csnet-ns";
+ case 109: return "pop-2";
+ case 111: return "sunrpc";
+ case 113: return "auth";
+ case 115: return "sftp";
+ case 117: return "uucp-path";
+ case 119: return "nntp";
+ case 121: return "erpc";
+ case 123: return "ntp";
+ case 133: return "statsrv";
+ case 136: return "profile";
+ case 144: return "NeWS";
+ case 161: return "snmp";
+ case 162: return "snmp-trap";
+ case 170: return "print-srv";
+ default: (void) sprintf(retbuf, "%d", wks); return (retbuf);
+ }
+}
+
+static const char *
+deproto(protonum)
+ int protonum;
+{
+ switch (protonum) {
+ case 1: return "icmp";
+ case 2: return "igmp";
+ case 3: return "ggp";
+ case 5: return "st";
+ case 6: return "tcp";
+ case 7: return "ucl";
+ case 8: return "egp";
+ case 9: return "igp";
+ case 11: return "nvp-II";
+ case 12: return "pup";
+ case 16: return "chaos";
+ case 17: return "udp";
+ default: (void) sprintf(retbuf, "%d", protonum); return (retbuf);
+ }
+}
+
+static const u_char *
+do_rrset(msg, cp, cnt, pflag, file, hs)
+ int cnt, pflag;
+ const u_char *cp, *msg;
+ const char *hs;
+ FILE *file;
+{
+ int n;
+ int sflag;
+
+ /*
+ * Print answer records.
+ */
+ sflag = (_res.pfcode & pflag);
+ if (n = ntohs(cnt)) {
+ if ((!_res.pfcode) ||
+ ((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
+ fprintf(file, hs);
+ while (--n >= 0) {
+ if ((!_res.pfcode) || sflag) {
+ cp = p_rr(cp, msg, file);
+ } else {
+ unsigned int dlen;
+ cp += __dn_skipname(cp, cp + MAXCDNAME);
+ cp += INT16SZ;
+ cp += INT16SZ;
+ cp += INT32SZ;
+ dlen = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ cp += dlen;
+ }
+ if ((cp - msg) > PACKETSZ)
+ return (NULL);
+ }
+ if ((!_res.pfcode) ||
+ ((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
+ putc('\n', file);
+ }
+ return (cp);
+}
+
+void
+__p_query(msg)
+ const u_char *msg;
+{
+ __fp_query(msg, stdout);
+}
+
+#ifdef ultrix
+/* ultrix 4.0's packaging has some icky packaging. alias for it here.
+ * there is more junk of this kind over in res_comp.c.
+ */
+void
+p_query(msg)
+ const u_char *msg;
+{
+ __p_query(msg);
+}
+#endif
+
+/*
+ * Print the current options.
+ * This is intended to be primarily a debugging routine.
+ */
+void
+__fp_resstat(statp, file)
+ struct __res_state *statp;
+ FILE *file;
+{
+ register u_long mask;
+
+ fprintf(file, ";; res options:");
+ if (!statp)
+ statp = &_res;
+ for (mask = 1; mask != 0; mask <<= 1)
+ if (statp->options & mask)
+ fprintf(file, " %s", p_option(mask));
+ putc('\n', file);
+}
+
+/*
+ * Print the contents of a query.
+ * This is intended to be primarily a debugging routine.
+ */
+void
+__fp_nquery(msg, len, file)
+ const u_char *msg;
+ int len;
+ FILE *file;
+{
+ register const u_char *cp, *endMark;
+ register const HEADER *hp;
+ register int n;
+
+#define TruncTest(x) if (x >= endMark) goto trunc
+#define ErrorTest(x) if (x == NULL) goto error
+
+ /*
+ * Print header fields.
+ */
+ hp = (HEADER *)msg;
+ cp = msg + HFIXEDSZ;
+ endMark = cp + len;
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || hp->rcode) {
+ fprintf(file, ";; ->>HEADER<<- opcode: %s, status: %s, id: %d",
+ _res_opcodes[hp->opcode],
+ _res_resultcodes[hp->rcode],
+ ntohs(hp->id));
+ putc('\n', file);
+ }
+ putc(';', file);
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) {
+ fprintf(file, "; flags:");
+ if (hp->qr)
+ fprintf(file, " qr");
+ if (hp->aa)
+ fprintf(file, " aa");
+ if (hp->tc)
+ fprintf(file, " tc");
+ if (hp->rd)
+ fprintf(file, " rd");
+ if (hp->ra)
+ fprintf(file, " ra");
+ if (hp->pr)
+ fprintf(file, " pr");
+ }
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) {
+ fprintf(file, "; Ques: %d", ntohs(hp->qdcount));
+ fprintf(file, ", Ans: %d", ntohs(hp->ancount));
+ fprintf(file, ", Auth: %d", ntohs(hp->nscount));
+ fprintf(file, ", Addit: %d", ntohs(hp->arcount));
+ }
+ if ((!_res.pfcode) || (_res.pfcode &
+ (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
+ putc('\n',file);
+ }
+ /*
+ * Print question records.
+ */
+ if (n = ntohs(hp->qdcount)) {
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
+ fprintf(file, ";; QUESTIONS:\n");
+ while (--n >= 0) {
+ fprintf(file, ";;\t");
+ TruncTest(cp);
+ cp = p_cdname(cp, msg, file);
+ ErrorTest(cp);
+ TruncTest(cp);
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
+ fprintf(file, ", type = %s",
+ __p_type(_getshort((u_char*)cp)));
+ cp += INT16SZ;
+ TruncTest(cp);
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
+ fprintf(file, ", class = %s\n",
+ __p_class(_getshort((u_char*)cp)));
+ cp += INT16SZ;
+ putc('\n', file);
+ }
+ }
+ /*
+ * Print authoritative answer records
+ */
+ TruncTest(cp);
+ cp = do_rrset(msg, cp, hp->ancount, RES_PRF_ANS, file,
+ ";; ANSWERS:\n");
+ ErrorTest(cp);
+
+ /*
+ * print name server records
+ */
+ TruncTest(cp);
+ cp = do_rrset(msg, cp, hp->nscount, RES_PRF_AUTH, file,
+ ";; AUTHORITY RECORDS:\n");
+ ErrorTest(cp);
+
+ TruncTest(cp);
+ /*
+ * print additional records
+ */
+ cp = do_rrset(msg, cp, hp->arcount, RES_PRF_ADD, file,
+ ";; ADDITIONAL RECORDS:\n");
+ ErrorTest(cp);
+ return;
+ trunc:
+ fprintf(file, "\n;; ...truncated\n");
+ return;
+ error:
+ fprintf(file, "\n;; ...malformed\n");
+}
+
+void
+__fp_query(msg, file)
+ const u_char *msg;
+ FILE *file;
+{
+ fp_nquery(msg, PACKETSZ, file);
+}
+
+const u_char *
+__p_cdnname(cp, msg, len, file)
+ const u_char *cp, *msg;
+ int len;
+ FILE *file;
+{
+ char name[MAXDNAME];
+ int n;
+
+ if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
+ return (NULL);
+ if (name[0] == '\0')
+ putc('.', file);
+ else
+ fputs(name, file);
+ return (cp + n);
+}
+
+const u_char *
+__p_cdname(cp, msg, file)
+ const u_char *cp, *msg;
+ FILE *file;
+{
+ return (p_cdnname(cp, msg, PACKETSZ, file));
+}
+
+/* XXX: the rest of these functions need to become length-limited, too. (vix)
+ */
+
+const u_char *
+__p_fqname(cp, msg, file)
+ const u_char *cp, *msg;
+ FILE *file;
+{
+ char name[MAXDNAME];
+ int n, len;
+
+ if ((n = dn_expand(msg, cp + MAXCDNAME, cp, name, sizeof name)) < 0)
+ return (NULL);
+ if (name[0] == '\0') {
+ putc('.', file);
+ } else {
+ fputs(name, file);
+ if (name[strlen(name) - 1] != '.')
+ putc('.', file);
+ }
+ return (cp + n);
+}
+
+/*
+ * Print resource record fields in human readable form.
+ */
+const u_char *
+__p_rr(cp, msg, file)
+ const u_char *cp, *msg;
+ FILE *file;
+{
+ int type, class, dlen, n, c;
+ struct in_addr inaddr;
+ const u_char *cp1, *cp2;
+ u_int32_t tmpttl, t;
+ int lcnt;
+
+ if ((cp = p_fqname(cp, msg, file)) == NULL)
+ return (NULL); /* compression error */
+ type = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ class = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ tmpttl = _getlong((u_char*)cp);
+ cp += INT32SZ;
+ dlen = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ cp1 = cp;
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_TTLID))
+ fprintf(file, "\t%lu", tmpttl);
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_CLASS))
+ fprintf(file, "\t%s", __p_class(class));
+ fprintf(file, "\t%s", __p_type(type));
+ /*
+ * Print type specific data, if appropriate
+ */
+ switch (type) {
+ case T_A:
+ switch (class) {
+ case C_IN:
+ case C_HS:
+ bcopy(cp, (char *)&inaddr, INADDRSZ);
+ if (dlen == 4) {
+ fprintf(file, "\t%s", inet_ntoa(inaddr));
+ cp += dlen;
+ } else if (dlen == 7) {
+ char *address;
+ u_char protocol;
+ u_short port;
+
+ address = inet_ntoa(inaddr);
+ cp += INADDRSZ;
+ protocol = *(u_char*)cp;
+ cp += sizeof(u_char);
+ port = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ fprintf(file, "\t%s\t; proto %d, port %d",
+ address, protocol, port);
+ }
+ break;
+ default:
+ cp += dlen;
+ }
+ break;
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_NS:
+ case T_PTR:
+ putc('\t', file);
+ if ((cp = p_fqname(cp, msg, file)) == NULL)
+ return (NULL);
+ break;
+
+ case T_HINFO:
+ case T_ISDN:
+ cp2 = cp + dlen;
+ if (n = *cp++) {
+ fprintf(file, "\t%.*s", n, cp);
+ cp += n;
+ }
+ if ((cp < cp2) && (n = *cp++)) {
+ fprintf(file, "\t%.*s", n, cp);
+ cp += n;
+ } else if (type == T_HINFO)
+ fprintf(file, "\n;; *** Warning *** OS-type missing");
+ break;
+
+ case T_SOA:
+ putc('\t', file);
+ if ((cp = p_fqname(cp, msg, file)) == NULL)
+ return (NULL);
+ putc(' ', file);
+ if ((cp = p_fqname(cp, msg, file)) == NULL)
+ return (NULL);
+ fputs(" (\n", file);
+ t = _getlong((u_char*)cp); cp += INT32SZ;
+ fprintf(file, "\t\t\t%lu\t; serial\n", t);
+ t = _getlong((u_char*)cp); cp += INT32SZ;
+ fprintf(file, "\t\t\t%lu\t; refresh (%s)\n", t, __p_time(t));
+ t = _getlong((u_char*)cp); cp += INT32SZ;
+ fprintf(file, "\t\t\t%lu\t; retry (%s)\n", t, __p_time(t));
+ t = _getlong((u_char*)cp); cp += INT32SZ;
+ fprintf(file, "\t\t\t%lu\t; expire (%s)\n", t, __p_time(t));
+ t = _getlong((u_char*)cp); cp += INT32SZ;
+ fprintf(file, "\t\t\t%lu )\t; minimum (%s)", t, __p_time(t));
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ fprintf(file, "\t%d ", _getshort((u_char*)cp));
+ cp += INT16SZ;
+ if ((cp = p_fqname(cp, msg, file)) == NULL)
+ return (NULL);
+ break;
+
+ case T_PX:
+ fprintf(file, "\t%d ", _getshort((u_char*)cp));
+ cp += INT16SZ;
+ if ((cp = p_fqname(cp, msg, file)) == NULL)
+ return (NULL);
+ putc(' ', file);
+ if ((cp = p_fqname(cp, msg, file)) == NULL)
+ return (NULL);
+ break;
+
+ case T_TXT:
+ case T_X25:
+ (void) fputs("\t\"", file);
+ cp2 = cp1 + dlen;
+ while (cp < cp2) {
+ if (n = (unsigned char) *cp++) {
+ for (c = n; c > 0 && cp < cp2; c--)
+ if ((*cp == '\n') || (*cp == '"')) {
+ (void) putc('\\', file);
+ (void) putc(*cp++, file);
+ } else
+ (void) putc(*cp++, file);
+ }
+ }
+ putc('"', file);
+ break;
+
+ case T_NSAP:
+ (void) fprintf(file, "\t%s", inet_nsap_ntoa(dlen, cp, NULL));
+ cp += dlen;
+ break;
+
+ case T_MINFO:
+ case T_RP:
+ putc('\t', file);
+ if ((cp = p_fqname(cp, msg, file)) == NULL)
+ return (NULL);
+ putc(' ', file);
+ if ((cp = p_fqname(cp, msg, file)) == NULL)
+ return (NULL);
+ break;
+
+ case T_UINFO:
+ putc('\t', file);
+ fputs((char *)cp, file);
+ cp += dlen;
+ break;
+
+ case T_UID:
+ case T_GID:
+ if (dlen == 4) {
+ fprintf(file, "\t%u", _getlong((u_char*)cp));
+ cp += INT32SZ;
+ }
+ break;
+
+ case T_WKS:
+ if (dlen < INT32SZ + 1)
+ break;
+ bcopy(cp, (char *)&inaddr, INADDRSZ);
+ cp += INT32SZ;
+ fprintf(file, "\t%s %s ( ",
+ inet_ntoa(inaddr),
+ deproto((int) *cp));
+ cp += sizeof(u_char);
+ n = 0;
+ lcnt = 0;
+ while (cp < cp1 + dlen) {
+ c = *cp++;
+ do {
+ if (c & 0200) {
+ if (lcnt == 0) {
+ fputs("\n\t\t\t", file);
+ lcnt = 5;
+ }
+ fputs(dewks(n), file);
+ putc(' ', file);
+ lcnt--;
+ }
+ c <<= 1;
+ } while (++n & 07);
+ }
+ putc(')', file);
+ break;
+
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+ {
+ int NumBytes = 8;
+ u_char *DataPtr;
+ int i;
+
+ if (dlen < NumBytes) NumBytes = dlen;
+ fprintf(file, "\tFirst %d bytes of hex data:",
+ NumBytes);
+ for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
+ fprintf(file, " %x", *DataPtr);
+ cp += dlen;
+ }
+ break;
+#endif /* ALLOW_T_UNSPEC */
+
+ default:
+ fprintf(file, "\t?%d?", type);
+ cp += dlen;
+ }
+#if 0
+ fprintf(file, "\t; dlen=%d, ttl %s\n", dlen, __p_time(tmpttl));
+#else
+ putc('\n', file);
+#endif
+ if (cp - cp1 != dlen) {
+ fprintf(file, ";; packet size error (found %d, dlen was %d)\n",
+ cp - cp1, dlen);
+ cp = NULL;
+ }
+ return (cp);
+}
+
+static char nbuf[40];
+
+/*
+ * Return a string for the type
+ */
+const char *
+__p_type(type)
+ int type;
+{
+ switch (type) {
+ case T_A: return "A";
+ case T_NS: return "NS";
+ case T_CNAME: return "CNAME";
+ case T_SOA: return "SOA";
+ case T_MB: return "MB";
+ case T_MG: return "MG";
+ case T_MR: return "MR";
+ case T_NULL: return "NULL";
+ case T_WKS: return "WKS";
+ case T_PTR: return "PTR";
+ case T_HINFO: return "HINFO";
+ case T_MINFO: return "MINFO";
+ case T_MX: return "MX";
+ case T_TXT: return "TXT";
+ case T_RP: return "RP";
+ case T_AFSDB: return "AFSDB";
+ case T_X25: return "X25";
+ case T_ISDN: return "ISDN";
+ case T_RT: return "RT";
+ case T_NSAP: return "NSAP";
+ case T_NSAP_PTR: return "NSAP_PTR";
+ case T_SIG: return "SIG";
+ case T_KEY: return "KEY";
+ case T_PX: return "PX";
+ case T_GPOS: return "GPOS";
+ case T_AAAA: return "AAAA";
+ case T_LOC: return "LOC";
+ case T_AXFR: return "AXFR";
+ case T_MAILB: return "MAILB";
+ case T_MAILA: return "MAILA";
+ case T_ANY: return "ANY";
+ case T_UINFO: return "UINFO";
+ case T_UID: return "UID";
+ case T_GID: return "GID";
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC: return "UNSPEC";
+#endif /* ALLOW_T_UNSPEC */
+ default: (void)sprintf(nbuf, "%d", type); return (nbuf);
+ }
+}
+
+/*
+ * Return a mnemonic for class
+ */
+const char *
+__p_class(class)
+ int class;
+{
+ switch (class) {
+ case C_IN: return "IN";
+ case C_HS: return "HS";
+ case C_ANY: return "ANY";
+ default: (void)sprintf(nbuf, "%d", class); return (nbuf);
+ }
+}
+
+/*
+ * Return a mnemonic for an option
+ */
+const char *
+__p_option(option)
+ u_long option;
+{
+ switch (option) {
+ case RES_INIT: return "init";
+ case RES_DEBUG: return "debug";
+ case RES_AAONLY: return "aaonly";
+ case RES_USEVC: return "usevc";
+ case RES_PRIMARY: return "primry";
+ case RES_IGNTC: return "igntc";
+ case RES_RECURSE: return "recurs";
+ case RES_DEFNAMES: return "defnam";
+ case RES_STAYOPEN: return "styopn";
+ case RES_DNSRCH: return "dnsrch";
+ case RES_INSECURE1: return "insecure1";
+ case RES_INSECURE2: return "insecure2";
+ default: sprintf(nbuf, "?0x%x?", option); return (nbuf);
+ }
+}
+
+/*
+ * Return a mnemonic for a time to live
+ */
+char *
+__p_time(value)
+ u_int32_t value;
+{
+ int secs, mins, hours, days;
+ register char *p;
+
+ if (value == 0) {
+ strcpy(nbuf, "0 secs");
+ return (nbuf);
+ }
+
+ secs = value % 60;
+ value /= 60;
+ mins = value % 60;
+ value /= 60;
+ hours = value % 24;
+ value /= 24;
+ days = value;
+ value = 0;
+
+#define PLURALIZE(x) x, (x == 1) ? "" : "s"
+ p = nbuf;
+ if (days) {
+ (void)sprintf(p, "%d day%s", PLURALIZE(days));
+ while (*++p);
+ }
+ if (hours) {
+ if (days)
+ *p++ = ' ';
+ (void)sprintf(p, "%d hour%s", PLURALIZE(hours));
+ while (*++p);
+ }
+ if (mins) {
+ if (days || hours)
+ *p++ = ' ';
+ (void)sprintf(p, "%d min%s", PLURALIZE(mins));
+ while (*++p);
+ }
+ if (secs || ! (days || hours || mins)) {
+ if (days || hours || mins)
+ *p++ = ' ';
+ (void)sprintf(p, "%d sec%s", PLURALIZE(secs));
+ }
+ return (nbuf);
+}