/*
 * print.c - common print support functions for lsof
 */


/*
 * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
 * 47907.  All rights reserved.
 *
 * Written by Victor A. Abell
 *
 * This software is not subject to any license of the American Telephone
 * and Telegraph Company or the Regents of the University of California.
 *
 * Permission is granted to anyone to use this software for any purpose on
 * any computer system, and to alter it and redistribute it freely, subject
 * to the following restrictions:
 *
 * 1. Neither the authors nor Purdue University are responsible for any
 *    consequences of the use of this software.
 *
 * 2. The origin of this software must not be misrepresented, either by
 *    explicit claim or by omission.  Credit to the authors and Purdue
 *    University must appear in documentation and sources.
 *
 * 3. Altered versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 *
 * 4. This notice may not be removed or altered.
 */

#ifndef lint
static char copyright[] =
"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
static char *rcsid = "$Id: print.c,v 1.21 95/10/19 14:09:35 abe Exp $";
#endif


#include "lsof.h"

#if	defined(EMPTY)
#undef	EMPTY
#endif

#include <utmp.h>

struct utmp dutmp;			/* dummy entry to get login name size */

#define HCINC	64			/* host cache size increase chunk */
#define LNML sizeof(dutmp.ut_name)
#define PCINC	512			/* port cache size increase chunk */

struct hostcache {
	unsigned char addr[4];
	char *name;
};

struct porttab {
	int port;
	char *name;
};

struct uidcache {
	uid_t u;
	char nm[LNML+1];
};

static int Npt[2] = { 0, 0};		/* TCP and UDP port entry counts */
static int Nuc = 0;			/* number of entries in UID cache */
static struct porttab *Pt[2] =		/* TCP and UDP port tables */
	{ NULL, NULL };
static int Pts = 0;			/* port tables initialization status */
static struct uidcache *Uc = NULL;	/* UID cache */
static int Ucnp = 0;			/* number of processes that determined
					 * UID cache size */
static unsigned Ucmask;			/* UID cache address mask */


/*
 * endnm() - locate end of Namech
 */

char *
endnm()
{
	char *s;

	for (s = Namech; *s; s++)
		;
	return(s);
}


/*
 * gethostnm() - get host name
 */

char *
gethostnm(ia)
	struct in_addr *ia;		/* pointer to Internet address */
{
	char hbuf[32];
	static struct hostcache *hc = NULL;
	static int hcx = 0;
	char *hn, *np;
	int i;
	struct hostent *he = NULL;
	static int nhc = 0;
	unsigned char *u;

	u = (unsigned char *)ia;
/*
 * Search cache.
 */
	for (i = 0; i < hcx; i++) {
		if (u[3] != hc[i].addr[3] || u[2] != hc[i].addr[2]
		||  u[1] != hc[i].addr[1] || u[0] != hc[i].addr[0])
			continue;
		return(hc[i].name);
	}
/*
 * If -H has been specified, construct a dot-form address.  Otherwise,
 * look up host name by address.  If that fails, or if there is no name
 * in the returned hostent structure, construct a dot-form version of the
 * address.
 */
	if (Fhost)
		he = gethostbyaddr((char *)ia, sizeof(struct in_addr), AF_INET);
	if (he == NULL || he->h_name == NULL) {
		(void) sprintf(hbuf, "%u.%u.%u.%u", u[0], u[1], u[2], u[3]);
		hn = hbuf;
	} else
		hn = (char *)he->h_name;
/*
 * Allocate space for name and copy name to it.
 */
	if ((np = (char *)malloc((MALLOC_S)(strlen(hn) + 1))) == NULL) {
		(void) fprintf(stderr, "%s: no space for host name: %s\n",
			Pn, hn);
		exit(1);
	}
	(void) strcpy(np, hn);
/*
 * Add address/name entry to cache.  Allocate cache space in HCINC chunks.
 */
	if (hcx >= nhc) {
		nhc += HCINC;
		if (hc == NULL)
			hc = (struct hostcache *)malloc(
				(MALLOC_S)(sizeof(struct hostcache) * nhc));
		else
			hc = (struct hostcache *)realloc((MALLOC_P *)hc,
				(MALLOC_S)(sizeof(struct hostcache) * nhc));
		if (hc == NULL) {
			(void) fprintf(stderr, "%s: no space for host cache\n",
				Pn);
			exit(1);
		}
	}
	hc[hcx].addr[0] = u[0];
	hc[hcx].addr[1] = u[1];
	hc[hcx].addr[2] = u[2];
	hc[hcx].addr[3] = u[3];
	hc[hcx++].name = np;
	return(np);
}


/*
 * iporttab() - initialize port table
 */

void
iporttab()
{
	int i[2];
	char *np;
	short p, ty;
	struct servent *se;

	if (Pts || !Fport)
		return;
	i[0] = i[1] = 0;
/*
 * Look up port name.
 */
	(void) setservent(1);
	while ((se = getservent()) != NULL) {
	    if (se->s_name == NULL)
		continue;
	    p = ntohs(se->s_port);
	/*
	 * Determine protocol type -- TCP or UDP.  Ignore others.
	 */
	    if (strcasecmp(se->s_proto, "TCP") == 0)
		ty = 0;
	    else if (strcasecmp(se->s_proto, "UDP") == 0)
		ty = 1;
	    else
		continue;
	/*
	 * Make a copy of the service name.
	 */
	    if ((np = (char *)malloc(strlen(se->s_name) + 1)) == NULL) {
		(void) fprintf(stderr,
		    "%s: no space for %s port %d cache name: %s\n", Pn,
		    ty ? "UDP" : "TCP", p, se->s_name);
		(void) endservent();
		exit(1);
	    }
	    (void) strcpy(np, se->s_name);
	/*
	 * Allocate the port table in PCINC chunks.
	 */
	    if (i[ty] >= Npt[ty]) {
		Npt[ty] += PCINC;
		if (Pt[ty] == NULL)
		    Pt[ty] = (struct porttab *)malloc(
				(MALLOC_S)(sizeof(struct porttab) * Npt[ty]));
		else
		    Pt[ty] = (struct porttab *)realloc((MALLOC_P *)Pt[ty],
				(MALLOC_S)(sizeof(struct porttab) * Npt[ty]));
		if (Pt[ty] == NULL) {
		    (void) fprintf(stderr,
			"%s: no space for %s port table\n", Pn,
			ty ? "UDP" : "TCP");
		    (void) endservent();
		    exit(1);
		}
	    }
	/*
	 * Add the service name to the port table.
	 */
	    Pt[ty][i[ty]].port = p;
	    Pt[ty][i[ty]].name = np;
	    i[ty]++;
	}
/*
 * Reduce the port table sizes to the sizes of their contents.
 */
	(void) endservent();
	for (ty = 0; ty < 2; ty++) {
	    if (Pt[ty] == NULL)
		continue;
	    if ((Pt[ty] = (struct porttab *)realloc((MALLOC_P *)Pt[ty],
			  (MALLOC_S)(sizeof(struct porttab) * i[ty])))
	    == NULL) {
		(void) fprintf(stderr,
		    "%s: can't reduce %s port table size\n",
		    ty ? "UDP" : "TCP", Pn);
		exit(1);
	    }
	    Npt[ty] = i[ty];
	}
	Pts = 1;
}


/*
 * iuidcache() - initialize UID cache
 */

void
iuidcache(np)
	int np;				/* number of processes */
{
	int i;
	MALLOC_S len;
	unsigned shft;

	if (!Futol)
		return;
/*
 * Set the first estimate of the cache size to 512, then adjust the size so
 * that it's a power of 2 and larger than the number of processes.
 */
	for (i = Nuc, Nuc = 512, shft = 9; Nuc < np; shft++) {
		Nuc += Nuc;
	}
	Ucmask = (1 << shft) - 1;
	if (i >= Nuc)
		return;
	len = (MALLOC_S)(Nuc * sizeof(struct uidcache));
/*
 * Allocate or reallocate space for the cache and set its new entries empty.
 */
	if (Uc)
		Uc = (struct uidcache *)realloc(Uc, len);
	else
		Uc = (struct uidcache *)malloc(len);
	if (Uc == NULL) {
		(void) fprintf(stderr, "%s: no space for UID cache\n", Pn);
		exit(1);
	}
	while (i < Nuc) {
		Uc[i++].nm[0] = '\0';
	}
}


/*
 * printinaddr() - print Internet address
 */

void
printinaddr(ia, p)
	struct in_addr *ia;		/* Internet address */
	int p;				/* port */
{
	char pbuf[16];
	int i, len, nl, ty;
	char *host = NULL;
	char *port = NULL;
	char *np;
	unsigned char *u;

	if ((Selflags & SELNA) && Nwad && is_nw_addr(ia, p))
		Lf->sf |= SELNA;
	if (ia->s_addr == INADDR_ANY)
		host = "*";
	else
		host = gethostnm(ia);
	if (p > 0) {
		if (Fport) {
			if (strcasecmp(Lf->iproto, "TCP") == 0)
				ty = 0;
			else if (strcasecmp(Lf->iproto, "UDP") == 0)
				ty = 1;
			else
				ty = 2;
			if (ty < 2) {
				if (! Pts)
					iporttab();
				for (i = 0; i < Npt[ty]; i++) {
					if (p == Pt[ty][i].port) {
						port = Pt[ty][i].name;
						break;
					}
				}
			}
		}
		if (port == NULL) {
			(void) sprintf(pbuf, "%d", p);
			port = pbuf;
		}
	} else if (p == 0)
		port = "0";
	np = endnm();
	nl = MAXPATHLEN - 1 - (np - Namech);
	if ((len = strlen(host)) > nl)
		len = nl;
	if (len) {
		(void) strncpy(np, host, len);
		np += len;
		*np = '\0';
		nl -= len;
	}
	if (port) {
		if (nl >= 1) {
			*np = ':';
			np++;
			*np = '\0';
			nl--;
		}
		if ((len = strlen(port)) > nl)
			len = nl;
		if (len) {
			(void) strncpy(np, port, len);
			np += len;
			*np = '\0';
		}
	}
}


/*
 * printiproto() - print Internet protocol name
 */

void
printiproto(p)
	int p;				/* protocol number */
{
	int i;
	static int m = -1;
	char *s;

	switch(p) {

#if	defined(IPPROTO_TCP)
	case IPPROTO_TCP:
		s = "TCP";
		break;
#endif

#if	defined(IPPROTO_UDP)
	case IPPROTO_UDP:
		s = "UDP";
		break;
#endif

#if	defined(IPPROTO_IP)
	case IPPROTO_IP:
		s = "IP";
		break;
#endif

#if	defined(IPPROTO_ICMP)
	case IPPROTO_ICMP:
		s = "ICMP";
		break;
#endif

#if	defined(IPPROTO_IGMP)
	case IPPROTO_IGMP:
		s = "IGMP";
		break;
#endif

#if	defined(IPPROTO_GGP)
	case IPPROTO_GGP:
		s = "GGP";
		break;
#endif

#if	defined(IPPROTO_EGP)
	case IPPROTO_EGP:
		s = "EGP";
		break;
#endif

#if	defined(IPPROTO_PUP)
	case IPPROTO_PUP:
		s = "PUP";
		break;
#endif

#if	defined(IPPROTO_IDP)
	case IPPROTO_IDP:
		s = "IDP";
		break;
#endif

#if	defined(IPPROTO_ND)
	case IPPROTO_ND:
		s = "ND";
		break;
#endif

#if	defined(IPPROTO_RAW)
	case IPPROTO_RAW:
		s = "RAW";
		break;
#endif

#if	defined(IPPROTO_HELLO)
	case IPPROTO_HELLO:
		s = "HELLO";
		break;
#endif

#if	defined(IPPROTO_PXP)
	case IPPROTO_PXP:
		s = "PXP";
		break;
#endif

#if	defined(IPPROTO_RAWIP)
	case IPPROTO_RAWIP:
		s = "RAWIP";
		break;
#endif

#if	defined(IPPROTO_RAWIF)
	case IPPROTO_RAWIF:
		s = "RAWIF";
		break;
#endif

	default:
		s = NULL;
	}
	if (s)
		(void) sprintf(Lf->iproto, "%.*s", IPROTOL-1, s);
	else {	
		if (m < 0) {
			for (i = 0, m = 1; i < IPROTOL-2; i++)
				m *= 10;
		}
		if (m > p)
			(void) sprintf(Lf->iproto, "%d?", p);
		else
			(void) sprintf(Lf->iproto, "*%d?", p % (m/10));
	}
}


/*
 * printname() - print output name field
 */

void
printname(nl)
	int nl;				/* NL status */
{

#if	defined(HASNCACHE)
	char buf[MAXPATHLEN];
	char *cp, *cp1;
	int fp;
#endif	/* defined(HASNCACHE) */

	int ps = 0;

	if (Lf->nm && Lf->nm[0]) {

	/*
	 * Print the name characters, if there are some.
	 */
		if (nl && !Lf->nma) {
			(void) puts(Lf->nm);
			return;
		}
		(void) fputs(Lf->nm, stdout);
		ps++;
		goto print_nma;
	}
/*
 * If this is a character device and it has a name, print it.
 */
	if (Lf->is_chr_dev && printchdevname(&Lf->dev, Lf->nma ? 0 : nl)) {
		if (!Lf->nma)
			return;
		ps++;
		goto print_nma;
	}
	if (Lf->is_com) {

	/*
	 * If this is a common node, print that fact.
	 */
		if (nl && !Lf->nma) {
			(void) puts("COMMON: ");
			return;
		}
		(void) fputs("COMMON: ", stdout);
		ps++;
		goto print_nma;
	}
	if (Lf->fsdir || Lf->fsdev) {

	/*
	 * Print the file system directory name, device name, and
	 * possible path name components.
	 */
		if (Lf->fsdir) {
			(void) fputs(Lf->fsdir, stdout);
			ps++;
		}

#if	defined(HASNCACHE)
		if (Lf->na
		&&  (cp = ncache_lookup(buf, sizeof(buf), &fp))) {
			if (*cp == '\0')
			    goto print_nma;
			if (fp) {
				if (*cp != '/') {
					cp1 = strrchr(Lf->fsdir, '/');
					if (cp1 == (char *)NULL
					||  *(cp1 + 1) != '\0')
						putchar('/');
				}
			} else
				(void) fputs(" -- ", stdout);
			if (nl && !Lf->nma) {
				(void) puts(cp);
				return;
			}
			(void) fputs(cp, stdout);
			ps++;
			goto print_nma;
		}
#endif	/* defined(HASNCACHE) */

		if (Lf->fsdev) {
			if (Lf->fsdir)
				(void) fputs(" (", stdout);
			else
				(void) putchar('(');
			(void) fputs(Lf->fsdev, stdout);
			if (nl && !Lf->nma) {
				(void) puts(")");
				return;
			}
			(void) putchar(')');
			ps++;
		}
	}
/*
 * Print the NAME column addition, if there is one.  If there isn't
 * make sure a NL is printed, as requested.
 */

print_nma:

	if (Lf->nma) {
		if (ps)
			putchar(' ');
		if (nl)
			(void) puts(Lf->nma);
		else
			(void) fputs(Lf->nma, stdout);
	} else if (nl)
		putchar('\n');
}


/*
 * printrawaddr() - print raw socket address
 */

void
printrawaddr(sa)
	struct sockaddr *sa;		/* socket address */
{
	(void) sprintf(endnm(), "%u/%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
		sa->sa_family,
		(unsigned char)sa->sa_data[0],
		(unsigned char)sa->sa_data[1],
		(unsigned char)sa->sa_data[2],
		(unsigned char)sa->sa_data[3],
		(unsigned char)sa->sa_data[4],
		(unsigned char)sa->sa_data[5],
		(unsigned char)sa->sa_data[6],
		(unsigned char)sa->sa_data[7],
		(unsigned char)sa->sa_data[8],
		(unsigned char)sa->sa_data[9],
		(unsigned char)sa->sa_data[10],
		(unsigned char)sa->sa_data[11],
		(unsigned char)sa->sa_data[12],
		(unsigned char)sa->sa_data[13]);
}


/*
 * printuid() - print User ID or login name
 */

char *
printuid(u, ty)
	UID_ARG u;			/* User IDentification number */
	int *ty;			/* returned UID type pointer (NULL
					 * (if none wanted).  If non-NULL
					 * then: *ty = 0 = login name
					 *	     = 1 = UID number */
{
	long i;
	int j = 0;
	int k;
	struct passwd *pw;
	static char user[USERPRTL+1];

	if (Futol && Uc) {

	/*
	 * If UID to login name conversion is in effect, and if there is
	 * a UID cache, search the cache.
	 */
		for (i = (long)u; j < Nuc; j++) {
			k = (int)(((i * 31415L) >> 7) & Ucmask);
			if (Uc[k].nm[0] == '\0') {

			/*
			 * Create a new cache entry.
			 */

#if	defined(HASPWSTAYOPEN)
				pw_stay_open();
#endif

				if ((pw = getpwuid(u)) == NULL) {
				    if (!Fwarn) {
					(void) fprintf(stderr,
					    "%s: no pwd entry for UID %d\n",
					    Pn, u);
				    }
				    break;
				}
				(void) strncpy(Uc[k].nm, pw->pw_name, LNML);
				Uc[k].nm[LNML] = '\0';
				Uc[k].u = (uid_t)u;
			}
			if (Uc[k].u == (uid_t)u) {

			/*
			 * Use an existing cache entry.
			 */
				if (ty)
					*ty = 0;
				return(Uc[k].nm);
			}
		/*
		 * Reprobe after a cache collision.
		 */
			i = ((i + 1) >= Nuc) ? 0 : i + 1;
		}
	}
/*
 * Issue a warning if at the reprobe limit.
 */
	if (Nuc && j >= Nuc && !Fwarn) {
		(void) fprintf(stderr, "%s: at reprobe limit for UID %d\n",
			Pn, u);
	}
/*
 * Produce a numeric conversion of the UID.
 */
	(void) sprintf(user, "%*u", USERPRTL, u);
	if (ty)
		*ty = 1;
	return(user);
}


/*
 * printunkaf() - print unknown address family
 */

void
printunkaf(fam)
	int fam;			/* unknown address family */
{
	char *p, *s;

	p = "";
	switch (fam) {

#if	defined(AF_UNSPEC)
	case AF_UNSPEC:
		s = "UNSPEC";
		break;
#endif	/* defined(AF_UNSPEC) */

#if	defined(AF_UNIX)
	case AF_UNIX:
		s = "UNIX";
		break;
#endif	/* defined(AF_UNIX) */

#if	defined(AF_INET)
	case AF_INET:
		s = "INET";
		break;
#endif	/* defined(AF_INET) */

#if	defined(AF_IMPLINK)
	case AF_IMPLINK:
		s = "IMPLINK";
		break;
#endif	/* defined(AF_IMPLINK) */

#if	defined(AF_PUP)
	case AF_PUP:
		s = "PUP";
		break;
#endif	/* defined(AF_PUP) */

#if	defined(AF_CHAOS)
	case AF_CHAOS:
		s = "CHAOS";
		break;
#endif	/* defined(AF_CHAOS) */

#if	defined(AF_NS)
	case AF_NS:
		s = "NS";
		break;
#endif	/* defined(AF_NS) */

#if	defined(AF_ISO)
	case AF_ISO:
		s = "ISO";
		break;
#endif	/* defined(AF_ISO) */

#if	defined(AF_NBS)
# if	!defined(AF_ISO) || AF_NBS!=AF_ISO
	case AF_NBS:
		s = "NBS";
		break;
# endif	/* !defined(AF_ISO) || AF_NBS!=AF_ISO */
#endif	/* defined(AF_NBS) */

#if	defined(AF_ECMA)
	case AF_ECMA:
		s = "ECMA";
		break;
#endif	/* defined(AF_ECMA) */

#if	defined(AF_DATAKIT)
	case AF_DATAKIT:
		s = "DATAKIT";
		break;
#endif	/* defined(AF_DATAKIT) */

#if	defined(AF_CCITT)
	case AF_CCITT:
		s = "CCITT";
		break;
#endif	/* defined(AF_CCITT) */

#if	defined(AF_SNA)
	case AF_SNA:
		s = "SNA";
		break;
#endif	/* defined(AF_SNA) */

#if	defined(AF_DECnet)
	case AF_DECnet:
		s = "DECnet";
		break;
#endif	/* defined(AF_DECnet) */

#if	defined(AF_DLI)
	case AF_DLI:
		s = "DLI";
		break;
#endif	/* defined(AF_DLI) */

#if	defined(AF_LAT)
	case AF_LAT:
		s = "LAT";
		break;
#endif	/* defined(AF_LAT) */

#if	defined(AF_HYLINK)
	case AF_HYLINK:
		s = "HYLINK";
		break;
#endif	/* defined(AF_HYLINK) */

#if	defined(AF_APPLETALK)
	case AF_APPLETALK:
		s = "APPLETALK";
		break;
#endif	/* defined(AF_APPLETALK) */

#if	defined(AF_BSC)
	case AF_BSC:
		s = "BSC";
		break;
#endif	/* defined(AF_BSC) */

#if	defined(AF_DSS)
	case AF_DSS:
		s = "DSS";
		break;
#endif	/* defined(AF_DSS) */

#if	defined(AF_ROUTE)
	case AF_ROUTE:
		s = "ROUTE";
		break;
#endif	/* defined(AF_ROUTE) */

#if	defined(AF_RAW)
	case AF_RAW:
		s = "RAW";
		break;
#endif	/* defined(AF_RAW) */

#if	defined(AF_LINK)
	case AF_LINK:
		s = "LINK";
		break;
#endif	/* defined(AF_LINK) */

#if	defined(pseudo_AF_XTP)
	case pseudo_AF_XTP:
		p = "pseudo_";
		s = "XTP";
		break;
#endif	/* defined(pseudo_AF_XTP) */

#if	defined(AF_RMP)
	case AF_RMP:
		s = "RMP";
		break;
#endif	/* defined(AF_RMP) */

#if	defined(AF_COIP)
	case AF_COIP:
		s = "COIP";
		break;
#endif	/* defined(AF_COIP) */

#if	defined(AF_CNT)
	case AF_CNT:
		s = "CNT";
		break;
#endif	/* defined(AF_CNT) */

#if	defined(pseudo_AF_RTIP)
	case pseudo_AF_RTIP:
		p = "pseudo_";
		s = "RTIP";
		break;
#endif	/* defined(pseudo_AF_RTIP) */

#if	defined(AF_NETMAN)
	case AF_NETMAN:
		s = "NETMAN";
		break;
#endif	/* defined(AF_NETMAN) */

#if	defined(AF_INTF)
	case AF_INTF:
		s = "INTF";
		break;
#endif	/* defined(AF_INTF) */

#if	defined(AF_NETWARE)
	case AF_NETWARE:
		s = "NETWARE";
		break;
#endif	/* defined(AF_NETWARE) */

#if	defined(AF_NDD)
	case AF_NDD:
		s = "NDD";
		break;
#endif	/* defined(AF_NDD) */

#if	defined(AF_NIT)
# if	!defined(AF_ROUTE) || AF_ROUTE!=AF_NIT
	case AF_NIT:
		s = "NIT";
		break;
# endif	/* !defined(AF_ROUTE) || AF_ROUTE!=AF_NIT */
#endif	/* defined(AF_NIT) */

#if	defined(AF_802)
# if	!defined(AF_RAW) || AF_RAW!=AF_802
	case AF_802:
		s = "802";
		break;
# endif	/* !defined(AF_RAW) || AF_RAW!=AF_802 */
#endif	/* defined(AF_802) */

#if	defined(AF_X25)
	case AF_X25:
		s = "X25";
		break;
#endif	/* defined(AF_X25) */

#if	defined(AF_CTF)
	case AF_CTF:
		s = "CTF";
		break;
#endif	/* defined(AF_CTF) */

#if	defined(AF_WAN)
	case AF_WAN:
		s = "WAN";
		break;
#endif	/* defined(AF_WAN) */

#if	defined(AF_OSINET)
# if	defined(AF_INET) && AF_INET!=AF_OSINET
	case AF_OSINET:
		s = "OSINET";
		break;
# endif	/* defined(AF_INET) && AF_INET!=AF_OSINET */
#endif	/* defined(AF_OSINET) */

#if	defined(AF_GOSIP)
	case AF_GOSIP:
		s = "GOSIP";
		break;
#endif	/* defined(AF_GOSIP) */

#if	defined(AF_SDL)
	case AF_SDL:
		s = "SDL";
		break;
#endif	/* defined(AF_SDL) */

#if	defined(AF_IPX)
	case AF_IPX:
		s = "IPX";
		break;
#endif	/* defined(AF_IPX) */

#if	defined(AF_SIP)
	case AF_SIP:
		s = "SIP";
		break;
#endif	/* defined(AF_SIP) */

#if	defined(psuedo_AF_PIP)
	case psuedo_AF_PIP:
		p = "pseudo_";
		s = "PIP";
		break;
#endif	/* defined(psuedo_AF_PIP) */

#if	defined(AF_OTS)
	case AF_OTS:
		s = "OTS";
		break;
#endif	/* defined(AF_OTS) */

#if	defined(AF_USER)
	case AF_USER:
		s = "USER";
		break;
#endif	/* defined(AF_USER) */

	default:
		(void) sprintf(Namech, "no further information on family %#x",
			fam);
		return;
	}
	(void) sprintf(Namech, "no further information on %sAF_%s", p, s);
	return;
}
