/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*	Call:	ipad [-options] [name]...
*
* This program delivers up addresses for hosts, networks, interfaces, etc.
* It gives the value in hex or dotted-decimal notation.  The options are:
*
*	-d	Produce dotted-decimal notation (default).
*	-x	Produce hexadecimal notation.
*
*	-b	Produce the broadcast address.
*	-e	Produce Ethernet addresses; implies -i and -x.
*	-m	Produce the netmask.
*	-p	Produce the other address in a point-to-point link.
*
*	-h	Interpret names as hosts (default).
*	-i	Interpret names as interfaces.
*	-n	Interpret names as networks.
*
* With no args, this program will produce the IP address of the main network
* interface, in dotted-decimal notation.
*
* Using -d and -x together will get both notations; using either alone will
* get only one notation; using neither will get dotted-decimal notation.
* These are only effective for IP addresses; Ethernet addresses are always
* given in hex-colon notation.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Note: For some reason (if we may so dignify it), much network info (such
* as the netmask) is denied to ordinary users, so this program must run as
* super-user.  You should install it as:
*	install -c -s -o root -m 4755 ipad /bin
*
* Expect some portability problems...
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*			Modification History
*
*	1990/03 Written by John Chambers as "ipadr", an obsolete name which was
*		changed to "addr".  This came into conflict with /bin/addr on some
*		unices, so it got changed to "ipad", and that has stayed stable.
*
*	1990/08	Ethernet -e option added by John Chambers, after Keith Dilsworth
*		discovered how to extract an Ethernet address from Ultrix.  
*
*	1990/09 HP version of -e option implemented by John Chambers.
*
*	1990/10	Point-to-point -p option added by John Chambers, to give the other
*		address associated with such interfaces.  E.g., "ipad -i sl0 -p sl0"
*		will give both IP addresses of a SLIP link.
*
*	1990/12 code added by John Chambers to notice IP addresses and generate
*		the /etc/hosts entry by calling gethostbyaddr().
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
:1#include "V.h"

#include "ifdflt.h"
#include "sys_netdb.h"
#include "sys_ioctl.h"
#include "sys_socket.h"

#if defined(AIX3)
#include "sys_stream.h"
/*#include <sys/sioctl.h>*/
#include "sys_in.h"
#endif
#if defined(AIX)	/* AIX's route.h (actually radix.h) grabs these */
#undef Bcmp
#undef Bzero
#undef Free
#endif

#include "sys_route.h"
#include "sys_if.h"
#include "sys_in.h"
#if defined(ESIX4) || defined(SunOS)
#include <sys/sockio.h>
#endif

#define HOSTNAMLEN 31			/* Longest legal hostname */

static Flag  decfl = 0;		/* True if decimal output wanted */
static Flag  ethfl = 0;		/* True if Ethernet address wanted */
static Flag  hexfl = 0;		/* True if hexadecimal output wanted */
static int   outfl = 0;		/* True if we have produced output */

static Flag  bcfl  = 0;		/* Want broadcast address */
static Flag  iffl  = 0;		/* Names are interfaces */
static Flag  nafl  = 1;		/* Names are network attachments (hosts) */
static Flag  nefl  = 0;		/* Names are networks */
static Flag  nmfl  = 0;		/* Want netmask */
static Flag  ppfl  = 0;		/* True if Point-to-point address wanted */

static struct sockaddr_in skad = {0};
static int   sock = -1;		/* Socket */
static int   status = 0;	/* Exit status */

struct ifreq if_info = {0};	/* Kernel's interface-info structure */
static char *ifdflt = IFDFLT;		/* Default interface */

static char  thishost[HOSTNAMLEN+1];
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
int main(ac,av)
	char**av;
{	int   a;
	char *p;

//	printf("%s: Started.\n",av[0]);
:1	ac = Vinit(ac,av);
//	printf("%s: Vinit done.\n",av[0]);

:1	V2 "Initialized V=%d ac=%d.\n",Vlvl,ac D;
	for (a=1; a<ac; a++) {
		Switch(av[a][0]) {
		case '-':
		case '+':
			switch(av[a][1]) {
			case 'B':
			case 'b':
				bcfl = 1;
:2				V2 "Broadcast address wanted." D;
				iffl = 1;
:2				V2 "Interpreting names as interfaces." D;
				nafl = nefl = nmfl = ppfl = 0;
				break;
			case 'D':
			case 'd':
				decfl = 1;
:2				V2 "Decimal output wanted." D;
				break;
			case 'E':
			case 'e':
				ethfl = 1;
:2				V2 "Ethernet address wanted." D;
				break;
			case 'H':
			case 'h':
				nafl = 1;
:2				V2 "Interpreting names as hosts." D;
				bcfl = iffl = nefl = nmfl = 0;
				break;
			case 'I':
			case 'i':
				iffl = 1;
:2				V2 "Interpreting names as interfaces." D;
				bcfl = nafl = nefl = nmfl = ppfl = 0;
				break;
			case 'M':
			case 'm':
				nmfl = 1;
:2				V2 "Netmask wanted." D;
				iffl = 1;
:2				V2 "Interpreting names as interfaces." D;
				bcfl = nafl = nefl = ppfl = 0;
				break;
			case 'N':
			case 'n':
				nefl = 1;
:2				V2 "Interpreting names as networks." D;
				bcfl = iffl = nafl = nmfl = 0;
				break;
			case 'P':
			case 'p':
				ppfl = 1;
:2				V2 "Point-to-point address." D;
				iffl = 1;
:2				V2 "Interpreting names as interfaces." D;
				nafl = nefl = nmfl= 0;
				break;
			case 'X':
			case 'x':
				hexfl = 1;
:2				V2 "Hex output wanted." D;
				break;
			default:
:1				P1 "Option `%s' unknown, ignored.",pname,av[a] D;
			case  0 :		/* "-" by itself */
			case '?':
				help();
				break;
			}
			break;
		default:
			if (av[a] && av[a][0])
				addr(av[a]);
			break;
		}
	}
	if (! outfl) {
:5		V5 "No output yet; use defaults." D;
		addr(0);
	}
	Done;
fail:
	++status;
done:
	exit(status);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Open a socket so we can do system calls that require a socket.  Note that
* if we fail, we return -errno, which is a bit redundant, but so what?  Note
* also that we leave the socket file number in the global "sock" variable.
*/
opensock()
{	int on = 1;

:f	Fenter("opensock");
	sock = Socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0)
:1		P1 "%s ### Can't get socket [Err %d=%s]",progname,Erreason D;
:4	V4 "File %d is socket.",sock D;
:2	if (Vlvl > 1) {
:2		if (Setsockopt(sock,SOL_SOCKET,SO_REUSEADDR|SO_DEBUG,&on,sizeof(on))<0)
:2			P1 "%s ### Can't set socket options [Err %d=%s]",progname,Erreason D;
:4		V4 "Socket debugging on." D;
:2	}
	if (Bind(sock, &skad, sizeof(skad)) < 0) {
:1		P1 "%s ### Can't bind socket [Err %d=%s]",progname,Erreason D;
		Close(sock);
		Fexit;
	return -errno;
	}
:f	Fexit;
	return sock;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Ethernet address.  The name must be an interface name.
*/
ethadr(name)
	char *name;
{	int   i;
#ifdef SIOCRPHYSADDR
	struct ifdevea devea;
#endif
#if	defined(HP)
#	include <netio.h>
#	include "sys_fcntl.h"
	struct fis fis;
	char   device[100];	/* This should be plenty */
	int    dev;			/* File handle */
#endif

:f	Fenter("ethadr");
:3	V3 "Want Ethernet address of interface `%s'",name D;
	if (name == 0) name = ifdflt;
	if (sock <  0) opensock();
/*
*	Here's how you get an Ethernet address on Ultrix:
*/
#ifdef SIOCRPHYSADDR
	strcpy(devea.ifr_name,name?name:ifdflt);
:3	V3 "Interface: `%s'",devea.ifr_name D;
	i = ioctl(sock,SIOCRPHYSADDR,&devea);
	if (i < 0) {
:1		P1 "%s ### Can't get Ethernet address for `%s' [Err %d=%s]",
:1			progname,name,Erreason D;
		Fail;
	}
	printf("%02X:%02X:%02X:%02X:%02X:%02X\n"
	,	devea.current_pa[0]
	,	devea.current_pa[1]
	,	devea.current_pa[2]
	,	devea.current_pa[3]
	,	devea.current_pa[4]
	,	devea.current_pa[5]
	);
#define ETHADDR
#endif
/*
*	The following code works on HP 9000 series:
*/
#if defined(NETSTAT) && defined(LOCAL_ADDRESS)
	sprintf(device,"/dev/%s\0",name);
:3	V3 "Interface: `%s'",device D;
	if ((dev = Open(device,O_RDWR|O_NDELAY,0)) < 0) {
:1		P1 "%s ### Can't access `%s' [Err %d=%s]",Vtime(),device,Erreason D;
		Fail;
	}
	fis.reqtype = LOCAL_ADDRESS;
	i = ioctl(dev,NETSTAT,&fis);
	if (i < 0) {
:1		P1 "%s ### Can't get Ethernet address for `%s' [Err %d=%s]",
:1			progname,device,Erreason D;
		Fail;
	}
	printf("%02X:%02X:%02X:%02X:%02X:%02X\n"
	,	fis.value.s[0]
	,	fis.value.s[1]
	,	fis.value.s[2]
	,	fis.value.s[3]
	,	fis.value.s[4]
	,	fis.value.s[5]
	);
	Close(dev);
#define ETHADDR
#endif
#ifndef ETHADDR
:1	V1 "Don't know how to get Ethernet address on this system." D;
#endif
	Done;
fail:
	++status;
done:
:f	Fexit;
	return 0;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* IP address.  It makes sense to use any sort of name here, and the appropriate
* Internet address will be output.
*/
ifaddr(name)
	char *name;
{	int   i;
	struct sockaddr_in *sp;
	unsigned char *ap;

:f	Fenter("ifaddr");
:3	V3 "Want address of interface `%s'",name D;
	if (name == 0)
		name = ifdflt;
	if (sock < 0)
		opensock();
	strcpy(if_info.ifr_name,name?name:ifdflt);
:3	V3 "Interface: `%s'",if_info.ifr_name D;
:7	H7(&if_info,sizeof(if_info),"Before");
	errno = 0;
	i = ioctl(sock,SIOCGIFADDR,&if_info);
:7	H7(&if_info,sizeof(if_info),"After");
	if (i < 0) {
:1		P1 "%s ### Can't get address for `%s' [Err %d=%s]",progname,name,Erreason D;
		Fail;
	}
	sp = (struct sockaddr_in *)&if_info.ifr_ifru.ifru_addr;
	ap = (unsigned char *)&(sp->sin_addr.s_addr);
	if (hexfl)
		printf("%02lX%02lX%02lX%02lX\n", ap[0], ap[1], ap[2], ap[3]);
	if (decfl || !hexfl)
		printf("%u.%u.%u.%u\n", ap[0], ap[1], ap[2], ap[3]);
	Done;
fail:
	++status;
done:
:f	Fexit;
	return 0;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Figure out whether an IP or Ethernet address is wanted, and call the
* appropriate routine.
*/
addr(name)
	char *name;
{
:f	Fenter("addr");
	++outfl;		/* Count the number of addresses generated */
	if (ethfl) {
:3		V3 "Want Ethernet address for `%s'.",name D;
		ethadr(name);
	} else {
:3		V3 "Want Internet address for `%s'.",name D;
		ipaddr(name);
	}
:f	Fexit;
	return 0;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*	The default address is the IP address.  Note that we may be asked to give
*	the IP address for an interface or a network; by default we give the IP
*	address of the main interface for this machine.  For gateways and other
*	multi-homed hosts, this isn't too well-defined; you take what you get.
*/
ipaddr(name)
	char *name;
{
:f	Fenter("ipaddr");
:3	V3 "Want IP address for `%s'",name D;
	if (nafl) {		/* Network attachment (/etc/hosts) */
		naaddr(name);
	} else
	if (nefl) {		/* Network info (/etc/networks) */
		neaddr(name);
	} else
	if (ppfl) {		/* Network info (/etc/networks) */
		ppaddr(name);
	} else
	if (iffl) {		/* Interface info */
		if (nmfl) nemask(name); else
		if (bcfl) bcaddr(name); else
				  ifaddr(name);
:2	} else {
:2		V2 "Screwup: nefl = iffl = nafl = 0" D;
	}
:f	Fexit;
	return 0;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* IP address.  It makes sense to use any sort of name here, and the appropriate
* Internet address will be output.  If the first byte of the name is a digit,
* we check to see if we have an IP address; if so, we print out the name(s)
* that correspond to the address.
*/
naaddr(name)
	char *name;
{	int   i;
	int  c1,c2,c3,c4;
	int  i1,i2,i3,i4;
	int  s1,s2,s3,s4;
	HOST *hp;

:f	Fenter("naaddr");
:3	V3 "Want network-attachment address for `%s'",NulC(name) D;
	if (!name || !*name) {
		gethostname(thishost,HOSTNAMLEN);
:3		V3 "Our hostname is `%s'",thishost D;
		name = thishost;
	}
	if (isdigit(name[0])) {
:5		V5 "First char of name is digit: %c",name[0] D;
		if (sscanf(name,"%d%c%d%c%d%c%d",&i1,&c1,&i2,&c2,&i3,&c3,&i4) == 7) {
:5			V5 "Matched four numbers: %d%c%d%c%d%c%d",i1,c1,i2,c2,i3,c3,i4 D;
			naname(name,i1,i2,i3,i4);
			Done;
		}
		if (sscanf(name,"%d%c%d.%d",&i1,&c1,&i2,&c2,&i3) == 5) {
:5			V5 "Matched three numbers: %d%c%d%c%d",i1,c1,i2,c2,i3 D;
			naname(name,i1,i2,i3,0);
			Done;
		}
		if (sscanf(name,"%d%c%d",&i1,&c1,&i2) == 3) {
:5			V5 "Matched two numbers: %d%c%d",i1,c1,i2 D;
			naname(name,i1,i2,0,0);
			Done;
		}
:5	} else {
:5		V5 "First char of \"%s\" is not digit: %02X='%c'",Dspp(name),B8(name[0]),Dsp(name[0]) D;
	}
	errno = 0;
	if ((hp = (HOST*)Gethostbyn(name)) == 0) {
:1		P1 "%s: Unknown host `%s'",progname,name D;
		Fail;
	}
	if (hexfl) {
		for (i=0; i<hp->h_length; i++) {
			printf("%02X",B8(hp->h_addr[i]));
		}
		putchar('\n');
	}
	if (decfl || ! hexfl) {
		for (i=0; i<hp->h_length; i++) {
			if (i > 0) putchar('.');
			printf("%d",B8(hp->h_addr[i]));
		}
		putchar('\n');
	}
done:
:f	Fexit;
	return 0;
fail:
	++status;
:f	Fexit;
	return 1;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Network name, called from naaddr() to decode an IP address.  We produce an
* approximation of the /etc/hosts entry, with the address, the hostname, and
* all the aliases.  Note the tab after the address and before the hostname.
*/
naname(name,i1,i2,i3,i4)
	char*name;
	int  i1,i2,i3,i4;
{	U32  addr;
	struct hostent *hp;
	struct netent  *np;
	int  i;
:f	Fenter("naname");
	addr = ntohl((i1<<24) | (i2<<16) | (i3<<8) | i4);
:3	V3 "Want hostname and aliases for `%s'",name D;
:4	V4 "Getting host entry for %08X=%s.",addr,name D;
	if (hp = Gethostbyaddr(&addr,sizeof(addr),AF_INET)) {
:6		H6(hp,sizeof(struct hostent),"hostent");
:5		V5 "Host `%s' alias[0]=`%s'",hp->h_name,NulC(hp->h_aliases[0]) D;
		printf("%s	%s",name,hp->h_name);
		if (hp->h_aliases)
			for (i=0; hp->h_aliases[i]; i++)
				printf(" %s",hp->h_aliases[i]);
		putchar('\n');
	} else
	if (np = getnetbyaddr(addr,AF_INET)) {
:6		H6(np,sizeof(struct netent),"hostent");
:5		V5 "Net `%s' alias[0]=`%s'",np->n_name,NulC(np->n_aliases[0]) D;
		printf("%s	%s",name,np->n_name);
		if (np->n_aliases)
			for (i=0; np->n_aliases[i]; i++)
				printf(" %s",np->n_aliases[i]);
		putchar('\n');
	} else {
		printf("%d.%d.%d.%d	UNKNOWN\n",i1,i2,i3,i4);
	}
:f	Fexit;
	return 0;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Network name, called from naaddr() to decode an IP address.  We  produce  an
* approximation of the /etc/networks entry, with the address, the netname, and
* all the aliases. Note the tab after the address and before the netname. Note
* also  that getnetbyaddr() and gethostbyaddr() have a very strange difference
* in the type of their first parameters.
*/
nename(name,i1,i2,i3,i4)
	char*name;
	int  i1,i2,i3,i4;
{	U32  addr;
	struct netent*np;
	int  i;

:f	Fenter("nename");
	addr = ntohl((i1<<24) | (i2<<16) | (i3<<8) | i4);
:3	V3 "Want netname and aliases for `%s'",name D;
:4	V4 "Getting net entry for %08X=%s.",addr,name D;
	if (np = getnetbyaddr(addr,AF_INET)) {
:6		H6(np,sizeof(HOST),"netent");
:5		V5 "Host `%s' alias[0]=`%s'",np->n_name,NulC(np->n_aliases[0]) D;
		printf("%s	%s",np->n_name,name);
		if (np->n_aliases)
			for (i=0; np->n_aliases[i]; i++)
				printf(" %s",np->n_aliases[i]);
		putchar('\n');
	} else
		printf("%s	UNKNOWN\n",name);
:f	Fexit;
	return 0;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Network address.  The name will be looked up in /etc/networks, and the
* internet address will be output.  The getnetbyname produces a truly
* bizarre result:  The network address is a 32-bit value, packed into
* the first 3 bytes in reverse order.  (This is true with VAX/Ultrix;
* it is likely different on other systems.)
*/
neaddr(name)
	char *name;
{	int   i, i1, i2, i3, i4;
	struct netent *np;
	unsigned char *p;

:f	Fenter("neaddr");
:3	V3 "Want network address for `%s'",name D;
	if (name == 0) {
:1		V1 "No default network name." D;
		Fail;
	} else
	if (isdigit(name[0])) {
		switch (sscanf(name,"%d.%d.%d.%d",&i1,&i2,&i3,&i4)) {
		  case 0: i1 = 0;
		  case 1: i2 = 0;
		  case 2: i3 = 0;
		  case 3: i4 = 0;
		}
		nename(name,i1,i2,i3,i4);
		Done;
	}
	errno = 0;
	if ((np = getnetbyname(name)) == 0) {
:1		P1 "%s Unknown network: `%s'",progname,name D;
		Fail;
	}
	p = (unsigned char*)&np->n_net;
	if (hexfl) {
		for (i=2; i>=0; i--) {	/* Note strange byte order! */
			printf("%02X",B8(p[i]));
		}
		putchar('\n');
	}
	if (decfl || ! hexfl) {
		for (i=2; i>=0; i--) {	/* Note strange byte order! */
			if (i != 2) putchar('.');
			printf("%d",B8(p[i]));
		}
		putchar('\n');
	}
	Done;
fail:
	++status;
done:
:f	Fexit;
	return 0;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Netmask.  This is only possible for interface names.
*/
nemask(name)
	char *name;
{	int   i;
	struct sockaddr_in *sp;
	unsigned char *ap;

:f	Fenter("nemask");
:3	V3 "Want netmask for `%s'",name D;
	if (name==0 || *name==0)
		name = ifdflt;
	if (name==0 || *name==0) {
:1		P1 "%s ### Can't get netmask without interface name.",progname D;
		Fail;
	}
	if (sock < 0)
		opensock();
	strcpy(if_info.ifr_name,name?name:ifdflt);
:3	V3 "Interface: `%s'",if_info.ifr_name D;
:7	H7(&if_info,sizeof(if_info),"Before");
	errno = 0;
	i = ioctl(sock,SIOCGIFNETMASK,&if_info);
:7	H7(&if_info,sizeof(if_info),"After");
	if (i < 0) {
:1		P1 "%s ### Can't get netmask for `%s' [Err %d=%s]",
:1			progname,name,Erreason D;
		Fail;
	}
	sp = (struct sockaddr_in *)&if_info.ifr_ifru.ifru_addr;
	ap = (unsigned char *)&(sp->sin_addr.s_addr);
	if (hexfl)
		printf("%02lX%02lX%02lX%02lX\n", ap[0], ap[1], ap[2], ap[3]);
	if (decfl || !hexfl)
		printf("%u.%u.%u.%u\n", ap[0], ap[1], ap[2], ap[3]);
	Done;
fail:
	++status;
done:
:f	Fexit;
	return 0;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Broadcast address.  This is only possible for interface names.
*/
bcaddr(name)
	char *name;
{	int   i;
	struct sockaddr_in *sp;
	unsigned char *ap;

:f	Fenter("bcaddr");
	if (name==0 || *name==0)
		name = ifdflt;
:3	V3 "Want broadcast address for `%s'",name D;
	if (sock < 0)
		opensock();
	strcpy(if_info.ifr_name,name?name:ifdflt);
:3	V3 "Interface: `%s'",if_info.ifr_name D;
:7	H7(&if_info,sizeof(if_info),"Before");
	errno = 0;
	i = ioctl(sock,SIOCGIFBRDADDR,&if_info);
:7	H7(&if_info,sizeof(if_info),"After");
	if (i < 0) {
:1		P1 "%s ### Can't get broadcast address for `%s' [Err %d=%s]",progname,
:1			if_info.ifr_name,Erreason D;
		Fail;
	}
	sp = (struct sockaddr_in *)&if_info.ifr_ifru.ifru_addr;
	ap = (unsigned char *)&(sp->sin_addr.s_addr);
	if (hexfl)
		printf("%02lX%02lX%02lX%02lX\n", ap[0], ap[1], ap[2], ap[3]);
	if (decfl || !hexfl)
		printf("%u.%u.%u.%u\n", ap[0], ap[1], ap[2], ap[3]);
	Done;
fail:
	++status;
done:
:f	Fexit;
	return 0;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Point-to-point address.  This is only possible for interface names.
*/
ppaddr(name)
	char *name;
{	int   i;
	struct sockaddr_in *sp;
	unsigned char *ap;

:f	Fenter("ppaddr");
	if (name==0 || *name==0)
		name = ifdflt;
:3	V3 "Want point-to-point address for `%s'",name D;
	if (sock < 0)
		opensock();
	strcpy(if_info.ifr_name,name?name:ifdflt);
:3	V3 "Interface: `%s'",if_info.ifr_name D;
:7	H7(&if_info,sizeof(if_info),"Before");
	errno = 0;
	i = ioctl(sock,SIOCGIFDSTADDR,&if_info);
:7	H7(&if_info,sizeof(if_info),"After");
	if (i < 0) {
:1		P1 "%s ### Can't get point-to-point address for `%s' [Err %d=%s]",
:1			progname,if_info.ifr_name,Erreason D;
		Fail;
	}
	sp = (struct sockaddr_in *)&if_info.ifr_ifru.ifru_addr;
	ap = (unsigned char *)&(sp->sin_addr.s_addr);
	if (hexfl)
		printf("%02lX%02lX%02lX%02lX\n", ap[0], ap[1], ap[2], ap[3]);
	if (decfl || !hexfl)
		printf("%u.%u.%u.%u\n", ap[0], ap[1], ap[2], ap[3]);
	Done;
fail:
	++status;
done:
:f	Fexit;
	return 0;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
*/
help()
{
	if (!stdiofl && fileno(Vout)<3) return 0;
	fprintf(stderr,"Usage: %s [-options] names...\n",pname);
	fprintf(stderr,"	-  produces this explanation.\n");
	fprintf(stderr,"Format options:\n");
	fprintf(stderr,"	-d produces dotted-decimal notation (default).\n");
	fprintf(stderr,"	-x produces hexadecimal notation.\n");
	fprintf(stderr,"Address options:\n");
	fprintf(stderr,"	-e gets the Ethernet address.\n");
	fprintf(stderr,"	-b gets the broadcast address.\n");
	fprintf(stderr,"	-m gets the the netmask.\n");
	fprintf(stderr,"	-p gets the other end of a point-to-point link.\n");
	fprintf(stderr,"Name interpretation:\n");
	fprintf(stderr,"	-h means names are hosts (default).\n");
	fprintf(stderr,"	-i means names are interfaces.\n");
	fprintf(stderr,"	-n means names are networks.\n");
	fprintf(stderr,"Note: -d and -x may be used together;\n");
	fprintf(stderr,"	  -e -b -m -p imply the -i option.\n");
}
