summary refs log tree commit diff
path: root/resolv/res_debug.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1996-08-14 21:45:21 +0000
committerUlrich Drepper <drepper@redhat.com>1996-08-14 21:45:21 +0000
commitdf21c8581af14b07680c17eefc7479eac510c60f (patch)
treedb37b915d549e10ae51bb81573367e180a12cf1b /resolv/res_debug.c
parent13d84ccd535e133f68005dca8d8a1a99e3861b6d (diff)
downloadglibc-df21c8581af14b07680c17eefc7479eac510c60f.tar.gz
glibc-df21c8581af14b07680c17eefc7479eac510c60f.tar.xz
glibc-df21c8581af14b07680c17eefc7479eac510c60f.zip
Update.
Wed Aug 14 21:36:16 1996  Ulrich Drepper  <drepper@cygnus.com>

	* stdlib/strtod.c (STRTOD): Correct assertion about size of
	wint_t and wchar_t.  Reported by David Mosberger-Tang.

Mon Aug 12 22:40:16 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* elf/dl-lookup.c (_dl_lookup_symbol): Remove fifth parameter
	RELOC_ADDR and make NOPLT a set of flags.  All callers
	changed.  Delete condition that checks for resolving to the
	location being filled in.  Add condition to skip the
	executable's symbols if requested.
	* elf/link.h: Change declaration of _dl_lookup_symbol
	accordingly.
	(DL_LOOKUP_NOEXEC, DL_LOOKUP_NOPLT): New definitions.
	* elf/dl-reloc.c (RESOLVE): Remove second parameter and rename
	NOPLT to FLAGS.
	* elf/dl-runtime.c (RESOLVE): Likewise.
	* elf/rtld.c (RESOLVE): Likewise.
	* sysdeps/m68k/dl-machine.h (elf_machine_rela): Pass
	DL_LOOKUP_NOEXEC as second argument to the RESOLVE macro if
	processing a copy reloc, DL_LOOKUP_NOPLT for a jump slot
	reloc, zero otherwise.
	* sysdeps/alpha/dl-machine.h (elf_machine_rela): Likewise.
	* sysdeps/i386/dl-machine.h (elf_machine_rel): Likewise.
	* sysdeps/mips/dl-machine.h (elf_machine_rel): Likewise.

Wed Aug 14 17:57:08 1996  Ulrich Drepper  <drepper@cygnus.com>

	* MakeTAGS: Clean up use of --omit-header and -n for xgettext.
	* po/header.pot: Add empty line at end.

Sun Aug 11 13:45:33 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* MakeTAGS (all-pot): Remove $P/errlist.pot, all error messages
 	are now in $P/stdio-common.pot.
	(XGETTEXTFLAGS-errlist.pot): Variable removed.

Mon Aug 12 19:25:03 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* Makerules (do-ar, o-iterator-doit): Compute path to autolock
 	script at run time, not configure time.
	* config.make.in, configure.in: Undo previous change.

Wed Aug 14 13:20:02 1996  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/unix/sysv/linux/i386/close.S: Push return value of thread
	on stack as argument for `_exit'.  Reported by Andreas Schwab.

Mon Aug 12 19:36:25 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/unix/sysv/linux/m68k/clone.S: New file.

Wed Aug 14 04:22:35 1996  Richard Henderson  <rth@tamu.edu>

	* elf/dl-load.c (_dl_map_object): Save name in malloced memory.
	(_dl_map_object_from_fd): Free name on error.

Wed Aug 14 13:00:09 1996  Ulrich Drepper  <drepper@cygnus.com>

	* string/strdup.c: Use result of memcpy to avoid reloading.

Tue Aug 13 00:55:03 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* shadow/sgetspent_r.c (__sgetspent_r): Copy string to buffer, not
	the other way round.

	* resolv/Makefile (libresolv-routines): Add base64, inet_net_ntop,
 	inet_net_pton, inet_net.
	* resolv/arpa/nameser.h (__BIND): Update version number.
Mon Aug 12 19:03:22 1996  Thomas Bushnell n/BSG  <thomas@psilocin.gnu.ai.mit.edu>

	* sysdeps/generic/gnu/types.h: Declare __fd_mask as `unsigned long'.

	* mach/Makefile (mach/mach_host.uh): Depend on
 	$(objpfx)/mach-syscalls.mk.
	($(objpfx)mach-shortcuts.h): Depend on $(objpfx)mach/mach_host.h.
	(This fixes a make loop; thanks to Marcus Daniels
 	<marcus@sysc.pdx.edu> for the patch.)
Diffstat (limited to 'resolv/res_debug.c')
-rw-r--r--resolv/res_debug.c419
1 files changed, 348 insertions, 71 deletions
diff --git a/resolv/res_debug.c b/resolv/res_debug.c
index 62cd81cd0f..dfb3b4706f 100644
--- a/resolv/res_debug.c
+++ b/resolv/res_debug.c
@@ -50,6 +50,28 @@
  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  * SOFTWARE.
  * -
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
  * --Copyright--
  */
 
@@ -65,11 +87,14 @@ static char rcsid[] = "$Id$";
 #include <arpa/inet.h>
 #include <arpa/nameser.h>
 
-#include <stdio.h>
 #include <ctype.h>
 #include <netdb.h>
 #include <resolv.h>
+#include <stdio.h>
+#include <time.h>
+
 #if defined(BSD) && (BSD >= 199103) && defined(AF_INET6)
+# include <stdlib.h>
 # include <string.h>
 #else
 # include "../conf/portability.h"
@@ -291,6 +316,12 @@ __fp_nquery(msg, len, file)
 			fprintf(file, " rd");
 		if (hp->ra)
 			fprintf(file, " ra");
+		if (hp->unused)
+			fprintf(file, " UNUSED-BIT-ON");
+		if (hp->ad)
+			fprintf(file, " ad");
+		if (hp->cd)
+			fprintf(file, " cd");
 	}
 	if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) {
 		fprintf(file, "; Ques: %d", ntohs(hp->qdcount));
@@ -404,6 +435,30 @@ __p_cdname(cp, msg, file)
 	return (p_cdnname(cp, msg, PACKETSZ, file));
 }
 
+
+/* Return a fully-qualified domain name from a compressed name (with
+   length supplied).  */
+
+const u_char *
+__p_fqnname(cp, msg, msglen, name, namelen)
+	const u_char *cp, *msg;
+	int msglen;
+	char *name;
+	int namelen;
+{
+	int n, newlen;
+
+	if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0)
+		return (NULL);
+	newlen = strlen (name);
+	if (newlen == 0 || name[newlen - 1] != '.')
+		if (newlen+1 >= namelen)        /* Lack space for final dot */
+			return (NULL);
+		else
+			strcpy(name + newlen, ".");
+	return (cp + n);
+}
+
 /* XXX:	the rest of these functions need to become length-limited, too. (vix)
  */
 
@@ -413,18 +468,13 @@ __p_fqname(cp, msg, file)
 	FILE *file;
 {
 	char name[MAXDNAME];
-	int n;
+	const u_char *n;
 
-	if ((n = dn_expand(msg, cp + MAXCDNAME, cp, name, sizeof name)) < 0)
+	n = __p_fqnname(cp, msg, MAXCDNAME, name, sizeof name);
+	if (n == NULL)
 		return (NULL);
-	if (name[0] == '\0') {
-		putc('.', file);
-	} else {
-		fputs(name, file);
-		if (name[strlen(name) - 1] != '.')
-			putc('.', file);
-	}
-	return (cp + n);
+	fputs(name, file);
+	return (n);
 }
 
 /*
@@ -440,13 +490,19 @@ __p_rr(cp, msg, file)
 	const u_char *cp1, *cp2;
 	u_int32_t tmpttl, t;
 	int lcnt;
+	u_int16_t keyflags;
+	char rrname[MAXDNAME];          /* The fqdn of this RR */
+	char base64_key[MAX_KEY_BASE64];
 
 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
 		h_errno = NETDB_INTERNAL;
 		return (NULL);
 	}
-	if ((cp = p_fqname(cp, msg, file)) == NULL)
+	cp = __p_fqnname(cp, msg, MAXCDNAME, rrname, sizeof rrname);
+	if (!cp)
 		return (NULL);			/* compression error */
+	fputs(rrname, file);
+
 	type = _getshort((u_char*)cp);
 	cp += INT16SZ;
 	class = _getshort((u_char*)cp);
@@ -481,7 +537,7 @@ __p_rr(cp, msg, file)
 				address = inet_ntoa(inaddr);
 				cp += INADDRSZ;
 				protocol = *(u_char*)cp;
-				cp += sizeof(u_char);
+				cp += sizeof (u_char);
 				port = _getshort((u_char*)cp);
 				cp += INT16SZ;
 				fprintf(file, "\t%s\t; proto %d, port %d",
@@ -505,16 +561,16 @@ __p_rr(cp, msg, file)
 
 	case T_HINFO:
 	case T_ISDN:
-		(void) fputs("\t\"", file);
 		cp2 = cp + dlen;
+		(void) fputs("\t\"", file);
 		if ((n = (unsigned char) *cp++) != 0) {
 			for (c = n; c > 0 && cp < cp2; c--) {
 				if (strchr("\n\"\\", *cp))
 					(void) putc('\\', file);
 				(void) putc(*cp++, file);
 			}
-			putc('"', file);
 		}
+		putc('"', file);
 		if (cp < cp2 && (n = (unsigned char) *cp++) != 0) {
 			(void) fputs ("\t\"", file);
 			for (c = n; c > 0 && cp < cp2; c--) {
@@ -572,11 +628,24 @@ __p_rr(cp, msg, file)
 			return (NULL);
 		break;
 
-	case T_TXT:
 	case T_X25:
+		cp2 = cp + dlen;
 		(void) fputs("\t\"", file);
+		if ((n = (unsigned char) *cp++) != 0) {
+			for (c = n; c > 0 && cp < cp2; c--) {
+				if (strchr("\n\"\\", *cp))
+					(void) putc('\\', file);
+				(void) putc(*cp++, file);
+			}
+		}
+		putc('"', file);
+		break;
+
+	case T_TXT:
+		(void) putc('\t', file);
 		cp2 = cp1 + dlen;
 		while (cp < cp2) {
+			putc('"', file);
 			if (n = (unsigned char) *cp++) {
 				for (c = n; c > 0 && cp < cp2; c--) {
 					if (strchr("\n\"\\", *cp))
@@ -584,8 +653,10 @@ __p_rr(cp, msg, file)
 					(void) putc(*cp++, file);
 				}
 			}
+			putc('"', file);
+			if (cp < cp2)
+				putc(' ', file);
 		}
-		putc('"', file);
 		break;
 
 	case T_NSAP:
@@ -641,7 +712,7 @@ __p_rr(cp, msg, file)
 		fprintf(file, "\t%s %s ( ",
 			inet_ntoa(inaddr),
 			deproto((int) *cp));
-		cp += sizeof(u_char);
+		cp += sizeof (u_char);
 		n = 0;
 		lcnt = 0;
 		while (cp < cp1 + dlen) {
@@ -662,6 +733,72 @@ __p_rr(cp, msg, file)
 		putc(')', file);
 		break;
 
+	case T_KEY:
+		putc('\t', file);
+		keyflags = _getshort(cp);
+		cp += 2;
+		fprintf(file,"0x%04x", keyflags );      /* flags */
+		fprintf(file," %u", *cp++);     /* protocol */
+		fprintf(file," %u (", *cp++);   /* algorithm */
+
+		n = b64_ntop(cp, (cp1 + dlen) - cp,
+			     base64_key, sizeof base64_key);
+		for (c = 0; c < n; ++c) {
+			if (0 == (c & 0x3F))
+				fprintf(file, "\n\t");
+			putc(base64_key[c], file);  /* public key data */
+		}
+
+		fprintf(file, " )");
+		if (n < 0)
+			fprintf(file, "\t; BAD BASE64");
+		fflush(file);
+		cp = cp1 + dlen;
+		break;
+
+	case T_SIG:
+		type = _getshort((u_char*)cp);
+		cp += INT16SZ;
+		fprintf(file, " %s", p_type(type));
+		fprintf(file, "\t%d", *cp++);   /* algorithm */
+		/* Check label value and print error if wrong. */
+		n = *cp++;
+		c = dn_count_labels (rrname);
+		if (n != c)
+			fprintf(file, "\t; LABELS WRONG (%d should be %d)\n\t",
+				n, c);
+		/* orig ttl */
+		n = _getlong((u_char*)cp);
+		if (n != tmpttl)
+			fprintf(file, " %u", n);
+		cp += INT32SZ;
+		/* sig expire */
+		fprintf(file, " (\n\t%s",
+			__p_secstodate(_getlong((u_char*)cp)));
+		cp += INT32SZ;
+		/* time signed */
+		fprintf(file, " %s", __p_secstodate(_getlong((u_char*)cp)));
+		cp += INT32SZ;
+		/* sig footprint */
+		fprintf(file," %u ", _getshort((u_char*)cp));
+		cp += INT16SZ;
+		/* signer's name */
+		cp = p_fqname(cp, msg, file);
+		n = b64_ntop(cp, (cp1 + dlen) - cp,
+			     base64_key, sizeof base64_key);
+		for (c = 0; c < n; c++) {
+			if (0 == (c & 0x3F))
+		  		fprintf (file, "\n\t");
+			putc(base64_key[c], file);              /* signature */
+		}
+		/* Clean up... */
+		fprintf(file, " )");
+		if (n < 0)
+			fprintf(file, "\t; BAD BASE64");
+		fflush(file);
+		cp = cp1+dlen;
+		break;
+
 #ifdef ALLOW_T_UNSPEC
 	case T_UNSPEC:
 		{
@@ -698,54 +835,151 @@ __p_rr(cp, msg, file)
 }
 
 /*
+ * Names of RR classes and qclasses.  Classes and qclasses are the same, except
+ * that C_ANY is a qclass but not a class.  (You can ask for records of class
+ * C_ANY, but you can't have any records of that class in the database.)
+ */
+const struct res_sym __p_class_syms[] = {
+	{C_IN,		"IN"},
+	{C_CHAOS,	"CHAOS"},
+	{C_HS,		"HS"},
+	{C_HS,		"HESIOD"},
+	{C_ANY,		"ANY"},
+	{C_IN,		(char *)0}
+};
+
+/*
+ * Names of RR types and qtypes.  Types and qtypes are the same, except
+ * that T_ANY is a qtype but not a type.  (You can ask for records of type
+ * T_ANY, but you can't have any records of that type in the database.)
+ */
+const struct res_sym __p_type_syms[] = {
+	{T_A,		"A",		"address"},
+	{T_NS,		"NS",		"name server"},
+	{T_CNAME,	"CNAME",	"canonical name"},
+	{T_SOA,		"SOA",		"start of authority"},
+	{T_MB,		"MB",		"mailbox"},
+	{T_MG,		"MG",		"mail group member"},
+	{T_MR,		"MR",		"mail rename"},
+	{T_NULL,	"NULL",		"null"},
+	{T_WKS,		"WKS",		"well-known service"},
+	{T_PTR,		"PTR",		"domain name pointer"},
+	{T_HINFO,	"HINFO",	"host information"},
+	{T_MINFO,	"MINFO",	"mailbox information"},
+	{T_MX,		"MX",		"mail exchanger"},
+	{T_TXT,		"TXT",		"text"},
+	{T_RP,		"RP",		"responsible person"},
+	{T_AFSDB,	"AFSDB",	"DCE or AFS server"},
+	{T_X25,		"X25",		"X25 address"},
+	{T_ISDN,	"ISDN",		"ISDN address"},
+	{T_RT,		"RT",		"router"},
+	{T_NSAP,	"NSAP",		"nsap address"},
+	{T_NSAP_PTR,	"NSAP_PTR",	"domain name pointer"},
+	{T_SIG,		"SIG",		"signature"},
+	{T_KEY,		"KEY",		"key"},
+	{T_NXT,		"NXT",		"next valid name"},
+	{T_PX,		"PX",		"mapping information"},
+	{T_GPOS,	"GPOS",		"geographical position"},
+	{T_AAAA,	"AAAA",		"IPv6 address"},
+	{T_LOC,		"LOC",		"location"},
+	{T_AXFR,	"AXFR",		"zone transfer"},
+	{T_MAILB,	"MAILB",	"mailbox-related data"},
+	{T_MAILA,	"MAILA",	"mail agent"},
+	{T_UINFO,	"UINFO",	"user information"},
+	{T_UID,		"UID",		"user ID"},
+	{T_GID,		"GID",		"group ID"},
+#ifdef ALLOW_T_UNSPEC
+	{T_UNSPEC,	"UNSPEC",	"unspecified data"},
+#endif /* ALLOW_T_UNSPEC */
+	{T_ANY,		"ANY",		"\"any\""},
+	{0,		(char *)0,	(char *)0}
+};
+
+int
+__sym_ston(syms, name, success)
+	const struct res_sym *syms;
+	char *name;
+	int *success;
+{
+#ifdef _LIBC
+	/* Changed to prevent warning. --drepper@gnu  */
+	for (; syms->name != 0; syms++) {
+#else
+	for (NULL; syms->name != 0; syms++) {
+#endif
+		if (strcasecmp (name, syms->name) == 0) {
+			if (success)
+				*success = 1;
+			return (syms->number);
+		}
+	}
+	if (success)
+		*success = 0;
+	return (syms->number);          /* The default value. */
+}
+
+const char *
+__sym_ntos(syms, number, success)
+	const struct res_sym *syms;
+	int number;
+	int *success;
+{
+	static char unname[20];
+
+#ifdef _LIBC
+	/* Changed to prevent warning. --drepper@gnu  */
+	for (; syms->name != 0; syms++) {
+#else
+	for (NULL; syms->name != 0; syms++) {
+#endif
+		if (number == syms->number) {
+			if (success)
+				*success = 1;
+			return (syms->name);
+		}
+	}
+
+	sprintf (unname, "%d", number);
+	if (success)
+		*success = 0;
+	return (unname);
+}
+
+
+const char *
+__sym_ntop(syms, number, success)
+	const struct res_sym *syms;
+	int number;
+	int *success;
+{
+	static char unname[20];
+
+#ifdef _LIBC
+	/* Changed to prevent warning. --drepper@gnu  */
+	for (; syms->name != 0; syms++) {
+#else
+	for (NULL; syms->name != 0; syms++) {
+#endif
+		if (number == syms->number) {
+			if (success)
+				*success = 1;
+			return (syms->humanname);
+		}
+	}
+	sprintf(unname, "%d", number);
+	if (success)
+		*success = 0;
+	return (unname);
+}
+
+/*
  * Return a string for the type
  */
 const char *
 __p_type(type)
 	int type;
 {
-	static char nbuf[20];
-
-	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 (__sym_ntos (__p_type_syms, type, (int *)0));
 }
 
 /*
@@ -755,14 +989,7 @@ const char *
 __p_class(class)
 	int class;
 {
-	static char nbuf[20];
-
-	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 (__sym_ntos (__p_class_syms, class, (int *)0));
 }
 
 /*
@@ -857,7 +1084,7 @@ static const char *
 precsize_ntoa(prec)
 	u_int8_t prec;
 {
-	static char retbuf[sizeof("90000000.00")];
+	static char retbuf[sizeof "90000000.00"];
 	unsigned long val;
 	int mantissa, exponent;
 
@@ -1044,11 +1271,11 @@ loc_aton(ascii, binary)
 			longit = lltemp1;
 			latit = lltemp2;
 		} else {	/* some kind of brokenness */
-			return 0;
+			return (0);
 		}
 		break;
 	default:		/* we didn't get one of each */
-		return 0;
+		return (0);
 	}
 
 	/* altitude */
@@ -1224,3 +1451,53 @@ loc_ntoa(binary, ascii)
 
 	return (ascii);
 }
+
+
+/* Return the number of DNS hierarchy levels in the name. */
+int
+__dn_count_labels(name)
+	char *name;
+{
+	int i, len, count;
+
+	len = strlen(name);
+
+	for(i = 0, count = 0; i < len; i++) {
+		if (name[i] == '.')
+			count++;
+	}
+
+	/* don't count initial wildcard */
+	if (name[0] == '*')
+		if (count)
+			count--;
+
+	/* don't count the null label for root. */
+	/* if terminating '.' not found, must adjust */
+	/* count to include last label */
+	if (len > 0 && name[len-1] != '.')
+		count++;
+	return (count);
+}
+
+
+/*
+ * Make dates expressed in seconds-since-Jan-1-1970 easy to read.
+ * SIG records are required to be printed like this, by the Secure DNS RFC.
+ */
+char *
+__p_secstodate (secs)
+	unsigned long secs;
+{
+	static char output[15];         /* YYYYMMDDHHMMSS and null */
+	time_t clock = secs;
+	struct tm *time;
+
+	time = gmtime(&clock);
+	time->tm_year += 1900;
+	time->tm_mon += 1;
+	sprintf(output, "%04d%02d%02d%02d%02d%02d",
+		time->tm_year, time->tm_mon, time->tm_mday,
+		time->tm_hour, time->tm_min, time->tm_sec);
+	return (output);
+}