174462Salfred/*	$NetBSD: rpcinfo.c,v 1.15 2000/10/04 20:09:05 mjl Exp $	*/
21900Swollman
31900Swollman/*
41900Swollman * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
51900Swollman * unrestricted use provided that this legend is included on all tape
61900Swollman * media and as a part of the software program in whole or part.  Users
71900Swollman * may copy or modify Sun RPC without charge, but are not authorized
81900Swollman * to license or distribute it to anyone else except as part of a product or
91900Swollman * program developed by the user.
108874Srgrimes *
111900Swollman * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
121900Swollman * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
131900Swollman * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
148874Srgrimes *
151900Swollman * Sun RPC is provided with no support and without any obligation on the
161900Swollman * part of Sun Microsystems, Inc. to assist in its use, correction,
171900Swollman * modification or enhancement.
188874Srgrimes *
191900Swollman * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
201900Swollman * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
211900Swollman * OR ANY PART THEREOF.
228874Srgrimes *
231900Swollman * In no event will Sun Microsystems, Inc. be liable for any lost revenue
241900Swollman * or profits or other special, indirect and consequential damages, even if
251900Swollman * Sun has been advised of the possibility of such damages.
268874Srgrimes *
271900Swollman * Sun Microsystems, Inc.
281900Swollman * 2550 Garcia Avenue
291900Swollman * Mountain View, California  94043
301900Swollman */
311900Swollman
3274462Salfred/*
3374462Salfred * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
3474462Salfred */
3574462Salfred
3674462Salfred/* #ident	"@(#)rpcinfo.c	1.18	93/07/05 SMI" */
3774462Salfred
3874462Salfred#if 0
3974462Salfred#ifndef lint
4074462Salfredstatic char sccsid[] = "@(#)rpcinfo.c 1.16 89/04/05 Copyr 1986 Sun Micro";
4174462Salfred#endif
4274462Salfred#endif
4374462Salfred
44119849Scharnier#include <sys/cdefs.h>
45119849Scharnier__FBSDID("$FreeBSD: stable/10/usr.bin/rpcinfo/rpcinfo.c 319256 2017-05-30 21:58:53Z asomers $");
46119849Scharnier
4774462Salfred/*
4874462Salfred * rpcinfo: ping a particular rpc program
49218909Sbrucec * 	or dump the registered programs on the remote machine.
5074462Salfred */
5174462Salfred
5274462Salfred/*
53228992Suqs * We are for now defining PORTMAP here.  It doesn't even compile
5474462Salfred * unless it is defined.
5574462Salfred */
5674462Salfred#ifndef	PORTMAP
5774462Salfred#define	PORTMAP
5874462Salfred#endif
5974462Salfred
6074462Salfred/*
6174462Salfred * If PORTMAP is defined, rpcinfo will talk to both portmapper and
6274462Salfred * rpcbind programs; else it talks only to rpcbind. In the latter case
6374462Salfred * all the portmapper specific options such as -u, -t, -p become void.
6474462Salfred */
6574462Salfred#include <sys/types.h>
6674462Salfred#include <sys/param.h>
6774462Salfred#include <sys/socket.h>
6874462Salfred#include <sys/un.h>
6974462Salfred#include <rpc/rpc.h>
7074462Salfred#include <stdio.h>
7174462Salfred#include <rpc/rpcb_prot.h>
7274462Salfred#include <rpc/rpcent.h>
7374462Salfred#include <rpc/nettype.h>
7474462Salfred#include <rpc/rpc_com.h>
7574462Salfred#include <stdlib.h>
7674462Salfred#include <string.h>
7774462Salfred#include <unistd.h>
7827936Scharnier#include <err.h>
7927936Scharnier#include <ctype.h>
8074462Salfred
8174462Salfred#ifdef PORTMAP		/* Support for version 2 portmapper */
8274462Salfred#include <netinet/in.h>
831900Swollman#include <netdb.h>
8474462Salfred#include <arpa/inet.h>
851900Swollman#include <rpc/pmap_prot.h>
861900Swollman#include <rpc/pmap_clnt.h>
8774462Salfred#endif
881900Swollman
891900Swollman#define MAXHOSTLEN 256
901900Swollman#define	MIN_VERS	((u_long) 0)
911900Swollman#define	MAX_VERS	((u_long) 4294967295UL)
9274462Salfred#define	UNKNOWN		"unknown"
931900Swollman
941900Swollman/*
951900Swollman * Functions to be performed.
961900Swollman */
971900Swollman#define	NONE		0	/* no function */
981900Swollman#define	PMAPDUMP	1	/* dump portmapper registrations */
991900Swollman#define	TCPPING		2	/* ping TCP service */
1001900Swollman#define	UDPPING		3	/* ping UDP service */
10174462Salfred#define	BROADCAST	4	/* ping broadcast service */
10274462Salfred#define	DELETES		5	/* delete registration for the service */
10374462Salfred#define	ADDRPING	6	/* pings at the given address */
10474462Salfred#define	PROGPING	7	/* pings a program on a given host */
10574462Salfred#define	RPCBDUMP	8	/* dump rpcbind registrations */
10674462Salfred#define	RPCBDUMP_SHORT	9	/* dump rpcbind registrations - short version */
10774462Salfred#define	RPCBADDRLIST	10	/* dump addr list about one prog */
10874462Salfred#define	RPCBGETSTAT	11	/* Get statistics */
1091900Swollman
11074462Salfredstruct netidlist {
11174462Salfred	char *netid;
11274462Salfred	struct netidlist *next;
11374462Salfred};
11474462Salfred
11574462Salfredstruct verslist {
11674462Salfred	int vers;
11774462Salfred	struct verslist *next;
11874462Salfred};
11974462Salfred
12074462Salfredstruct rpcbdump_short {
12174462Salfred	u_long prog;
12274462Salfred	struct verslist *vlist;
12374462Salfred	struct netidlist *nlist;
12474462Salfred	struct rpcbdump_short *next;
12574462Salfred	char *owner;
12674462Salfred};
12774462Salfred
12874462Salfred
12974462Salfred
13074462Salfred#ifdef PORTMAP
131221860Sdelphijstatic void	ip_ping(u_short, const char *, int, char **);
13274462Salfredstatic CLIENT	*clnt_com_create(struct sockaddr_in *, u_long, u_long, int *,
133221860Sdelphij				 const char *);
13474462Salfredstatic void	pmapdump(int, char **);
13574462Salfredstatic void	get_inet_address(struct sockaddr_in *, char *);
13674462Salfred#endif
13774462Salfred
13874462Salfredstatic bool_t	reply_proc(void *, struct netbuf *, struct netconfig *);
13974462Salfredstatic void	brdcst(int, char **);
14074462Salfredstatic void	addrping(char *, char *, int, char **);
14174462Salfredstatic void	progping(char *, int, char **);
14274462Salfredstatic CLIENT	*clnt_addr_create(char *, struct netconfig *, u_long, u_long);
14374462Salfredstatic CLIENT   *clnt_rpcbind_create(char *, int, struct netbuf **);
14474462Salfredstatic CLIENT   *getclnthandle(char *, struct netconfig *, u_long,
14574462Salfred			       struct netbuf **);
14674462Salfredstatic CLIENT	*local_rpcb(u_long, u_long);
14774462Salfredstatic int	pstatus(CLIENT *, u_long, u_long);
14874462Salfredstatic void	rpcbdump(int, char *, int, char **);
14974462Salfredstatic void	rpcbgetstat(int, char **);
15074462Salfredstatic void	rpcbaddrlist(char *, int, char **);
15174462Salfredstatic void	deletereg(char *, int, char **);
15274462Salfredstatic void	print_rmtcallstat(int, rpcb_stat *);
15374462Salfredstatic void	print_getaddrstat(int, rpcb_stat *);
15474462Salfredstatic void	usage(void);
15574462Salfredstatic u_long	getprognum(char *);
15674462Salfredstatic u_long	getvers(char *);
15774462Salfredstatic char	*spaces(int);
15874462Salfredstatic bool_t	add_version(struct rpcbdump_short *, u_long);
15974462Salfredstatic bool_t	add_netid(struct rpcbdump_short *, char *);
16074462Salfred
1611900Swollmanint
16274462Salfredmain(int argc, char **argv)
1631900Swollman{
1641900Swollman	register int c;
1651900Swollman	int errflg;
1661900Swollman	int function;
16774462Salfred	char *netid = NULL;
16874462Salfred	char *address = NULL;
16974462Salfred#ifdef PORTMAP
17074462Salfred	char *strptr;
17174462Salfred	u_short portnum = 0;
17274462Salfred#endif
1731900Swollman
1741900Swollman	function = NONE;
1751900Swollman	errflg = 0;
17674462Salfred#ifdef PORTMAP
17774462Salfred	while ((c = getopt(argc, argv, "a:bdlmn:pstT:u")) != -1) {
17874462Salfred#else
17974462Salfred	while ((c = getopt(argc, argv, "a:bdlmn:sT:")) != -1) {
18074462Salfred#endif
1811900Swollman		switch (c) {
18274462Salfred#ifdef PORTMAP
1831900Swollman		case 'p':
1841900Swollman			if (function != NONE)
1851900Swollman				errflg = 1;
1861900Swollman			else
1871900Swollman				function = PMAPDUMP;
1881900Swollman			break;
1891900Swollman
1901900Swollman		case 't':
1911900Swollman			if (function != NONE)
1921900Swollman				errflg = 1;
1931900Swollman			else
1941900Swollman				function = TCPPING;
1951900Swollman			break;
1961900Swollman
1971900Swollman		case 'u':
1981900Swollman			if (function != NONE)
1991900Swollman				errflg = 1;
2001900Swollman			else
2011900Swollman				function = UDPPING;
2021900Swollman			break;
2031900Swollman
20474462Salfred		case 'n':
20574462Salfred			portnum = (u_short) strtol(optarg, &strptr, 10);
206119849Scharnier			if (strptr == optarg || *strptr != '\0')
207119849Scharnier				errx(1, "%s is illegal port number", optarg);
20874462Salfred			break;
20974462Salfred#endif
21074462Salfred		case 'a':
21174462Salfred			address = optarg;
21274462Salfred			if (function != NONE)
21374462Salfred				errflg = 1;
21474462Salfred			else
21574462Salfred				function = ADDRPING;
21674462Salfred			break;
2171900Swollman		case 'b':
2181900Swollman			if (function != NONE)
2191900Swollman				errflg = 1;
2201900Swollman			else
22174462Salfred				function = BROADCAST;
2221900Swollman			break;
2231900Swollman
2241900Swollman		case 'd':
2251900Swollman			if (function != NONE)
2261900Swollman				errflg = 1;
2271900Swollman			else
2281900Swollman				function = DELETES;
2291900Swollman			break;
2301900Swollman
23174462Salfred		case 'l':
23274462Salfred			if (function != NONE)
23374462Salfred				errflg = 1;
23474462Salfred			else
23574462Salfred				function = RPCBADDRLIST;
23674462Salfred			break;
23774462Salfred
23874462Salfred		case 'm':
23974462Salfred			if (function != NONE)
24074462Salfred				errflg = 1;
24174462Salfred			else
24274462Salfred				function = RPCBGETSTAT;
24374462Salfred			break;
24474462Salfred
24574462Salfred		case 's':
24674462Salfred			if (function != NONE)
24774462Salfred				errflg = 1;
24874462Salfred			else
24974462Salfred				function = RPCBDUMP_SHORT;
25074462Salfred			break;
25174462Salfred
25274462Salfred		case 'T':
25374462Salfred			netid = optarg;
25474462Salfred			break;
2551900Swollman		case '?':
2561900Swollman			errflg = 1;
25774462Salfred			break;
2581900Swollman		}
2591900Swollman	}
2601900Swollman
261119849Scharnier	if (errflg || ((function == ADDRPING) && !netid))
2621900Swollman		usage();
2631900Swollman
26474462Salfred	if (function == NONE) {
26574462Salfred		if (argc - optind > 1)
26674462Salfred			function = PROGPING;
26774462Salfred		else
26874462Salfred			function = RPCBDUMP;
26974462Salfred	}
27074462Salfred
2711900Swollman	switch (function) {
27274462Salfred#ifdef PORTMAP
2731900Swollman	case PMAPDUMP:
274119849Scharnier		if (portnum != 0)
2751900Swollman			usage();
2761900Swollman		pmapdump(argc - optind, argv + optind);
2771900Swollman		break;
2781900Swollman
2791900Swollman	case UDPPING:
28074462Salfred		ip_ping(portnum, "udp", argc - optind, argv + optind);
2811900Swollman		break;
2821900Swollman
2831900Swollman	case TCPPING:
28474462Salfred		ip_ping(portnum, "tcp", argc - optind, argv + optind);
2851900Swollman		break;
28674462Salfred#endif
28774462Salfred	case BROADCAST:
2881900Swollman		brdcst(argc - optind, argv + optind);
2891900Swollman		break;
2901900Swollman	case DELETES:
29174462Salfred		deletereg(netid, argc - optind, argv + optind);
2921900Swollman		break;
29374462Salfred	case ADDRPING:
29474462Salfred		addrping(address, netid, argc - optind, argv + optind);
29574462Salfred		break;
29674462Salfred	case PROGPING:
29774462Salfred		progping(netid, argc - optind, argv + optind);
29874462Salfred		break;
29974462Salfred	case RPCBDUMP:
30074462Salfred	case RPCBDUMP_SHORT:
30174462Salfred		rpcbdump(function, netid, argc - optind, argv + optind);
30274462Salfred		break;
30374462Salfred	case RPCBGETSTAT:
30474462Salfred		rpcbgetstat(argc - optind, argv + optind);
30574462Salfred		break;
30674462Salfred	case RPCBADDRLIST:
30774462Salfred		rpcbaddrlist(netid, argc - optind, argv + optind);
30874462Salfred		break;
3091900Swollman	}
3101900Swollman	return (0);
3111900Swollman}
3128874Srgrimes
31374462Salfredstatic CLIENT *
31474462Salfredlocal_rpcb(u_long prog, u_long vers)
3151900Swollman{
31690256Salfred	void *localhandle;
31790256Salfred	struct netconfig *nconf;
31890256Salfred	CLIENT *clnt;
3198874Srgrimes
32090256Salfred	localhandle = setnetconfig();
32190256Salfred	while ((nconf = getnetconfig(localhandle)) != NULL) {
32290256Salfred		if (nconf->nc_protofmly != NULL &&
32390256Salfred		    strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
32490256Salfred			break;
32590256Salfred	}
32690256Salfred	if (nconf == NULL) {
32790256Salfred		warnx("getnetconfig: %s", nc_sperror());
32890256Salfred		return (NULL);
32990256Salfred	}
33074462Salfred
33190256Salfred	clnt = clnt_tp_create(NULL, prog, vers, nconf);
33290256Salfred	endnetconfig(localhandle);
33390256Salfred	return clnt;
33474462Salfred}
33574462Salfred
33674462Salfred#ifdef PORTMAP
33774462Salfredstatic CLIENT *
33874462Salfredclnt_com_create(struct sockaddr_in *addr, u_long prog, u_long vers,
339221860Sdelphij    int *fdp, const char *trans)
34074462Salfred{
34174462Salfred	CLIENT *clnt;
34274462Salfred
34374462Salfred	if (strcmp(trans, "tcp") == 0) {
34474462Salfred		clnt = clnttcp_create(addr, prog, vers, fdp, 0, 0);
34574462Salfred	} else {
34674462Salfred		struct timeval to;
34774462Salfred
3481900Swollman		to.tv_sec = 5;
3491900Swollman		to.tv_usec = 0;
35074462Salfred		clnt = clntudp_create(addr, prog, vers, to, fdp);
3511900Swollman	}
35274462Salfred	if (clnt == (CLIENT *)NULL) {
35374462Salfred		clnt_pcreateerror("rpcinfo");
35474462Salfred		if (vers == MIN_VERS)
35574462Salfred			printf("program %lu is not available\n", prog);
35674462Salfred		else
3571900Swollman			printf("program %lu version %lu is not available\n",
35874462Salfred							prog, vers);
35974462Salfred		exit(1);
3601900Swollman	}
36174462Salfred	return (clnt);
3621900Swollman}
3631900Swollman
36474462Salfred/*
36574462Salfred * If portnum is 0, then go and get the address from portmapper, which happens
36674462Salfred * transparently through clnt*_create(); If version number is not given, it
36774462Salfred * tries to find out the version number by making a call to version 0 and if
36874462Salfred * that fails, it obtains the high order and the low order version number. If
36974462Salfred * version 0 calls succeeds, it tries for MAXVERS call and repeats the same.
37074462Salfred */
3711900Swollmanstatic void
372221860Sdelphijip_ping(u_short portnum, const char *trans, int argc, char **argv)
3731900Swollman{
37474462Salfred	CLIENT *client;
37574462Salfred	int fd = RPC_ANYFD;
3761900Swollman	struct timeval to;
3771900Swollman	struct sockaddr_in addr;
3781900Swollman	enum clnt_stat rpc_stat;
3791900Swollman	u_long prognum, vers, minvers, maxvers;
3801900Swollman	struct rpc_err rpcerr;
38174462Salfred	int failure = 0;
3821900Swollman
383119849Scharnier	if (argc < 2 || argc > 3)
3841900Swollman		usage();
38574462Salfred	to.tv_sec = 10;
38674462Salfred	to.tv_usec = 0;
3871900Swollman	prognum = getprognum(argv[1]);
3881900Swollman	get_inet_address(&addr, argv[0]);
38974462Salfred	if (argc == 2) {	/* Version number not known */
3901900Swollman		/*
3911900Swollman		 * A call to version 0 should fail with a program/version
3921900Swollman		 * mismatch, and give us the range of versions supported.
3931900Swollman		 */
39474462Salfred		vers = MIN_VERS;
39574462Salfred	} else {
39674462Salfred		vers = getvers(argv[2]);
39774462Salfred	}
39874462Salfred	addr.sin_port = htons(portnum);
39974462Salfred	client = clnt_com_create(&addr, prognum, vers, &fd, trans);
40074462Salfred	rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
40174462Salfred			(char *)NULL, (xdrproc_t) xdr_void, (char *)NULL,
40274462Salfred			to);
40374462Salfred	if (argc != 2) {
40474462Salfred		/* Version number was known */
40574462Salfred		if (pstatus(client, prognum, vers) < 0)
40674462Salfred			exit(1);
40774462Salfred		(void) CLNT_DESTROY(client);
40874462Salfred		return;
40974462Salfred	}
41074462Salfred	/* Version number not known */
41174462Salfred	(void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL);
41274462Salfred	if (rpc_stat == RPC_PROGVERSMISMATCH) {
41374462Salfred		clnt_geterr(client, &rpcerr);
41474462Salfred		minvers = rpcerr.re_vers.low;
41574462Salfred		maxvers = rpcerr.re_vers.high;
41674462Salfred	} else if (rpc_stat == RPC_SUCCESS) {
41774462Salfred		/*
41874462Salfred		 * Oh dear, it DOES support version 0.
41974462Salfred		 * Let's try version MAX_VERS.
42074462Salfred		 */
42174462Salfred		(void) CLNT_DESTROY(client);
4221900Swollman		addr.sin_port = htons(portnum);
42374462Salfred		client = clnt_com_create(&addr, prognum, MAX_VERS, &fd, trans);
42474462Salfred		rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
42574462Salfred				(char *)NULL, (xdrproc_t) xdr_void,
42674462Salfred				(char *)NULL, to);
4271900Swollman		if (rpc_stat == RPC_PROGVERSMISMATCH) {
4281900Swollman			clnt_geterr(client, &rpcerr);
4291900Swollman			minvers = rpcerr.re_vers.low;
4301900Swollman			maxvers = rpcerr.re_vers.high;
4311900Swollman		} else if (rpc_stat == RPC_SUCCESS) {
4321900Swollman			/*
43374462Salfred			 * It also supports version MAX_VERS.
43474462Salfred			 * Looks like we have a wise guy.
43574462Salfred			 * OK, we give them information on all
43674462Salfred			 * 4 billion versions they support...
4371900Swollman			 */
43874462Salfred			minvers = 0;
43974462Salfred			maxvers = MAX_VERS;
4401900Swollman		} else {
44174462Salfred			(void) pstatus(client, prognum, MAX_VERS);
4421900Swollman			exit(1);
4431900Swollman		}
44474462Salfred	} else {
44574462Salfred		(void) pstatus(client, prognum, (u_long)0);
44674462Salfred		exit(1);
4471900Swollman	}
44874462Salfred	(void) CLNT_DESTROY(client);
44974462Salfred	for (vers = minvers; vers <= maxvers; vers++) {
4501900Swollman		addr.sin_port = htons(portnum);
45174462Salfred		client = clnt_com_create(&addr, prognum, vers, &fd, trans);
45274462Salfred		rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
45374462Salfred				(char *)NULL, (xdrproc_t) xdr_void,
45474462Salfred				(char *)NULL, to);
4551900Swollman		if (pstatus(client, prognum, vers) < 0)
45674462Salfred				failure = 1;
45774462Salfred		(void) CLNT_DESTROY(client);
4581900Swollman	}
4591900Swollman	if (failure)
4601900Swollman		exit(1);
46174462Salfred	(void) close(fd);
46274462Salfred	return;
4631900Swollman}
4641900Swollman
4651900Swollman/*
46674462Salfred * Dump all the portmapper registerations
4671900Swollman */
4681900Swollmanstatic void
46974462Salfredpmapdump(int argc, char **argv)
4701900Swollman{
4711900Swollman	struct sockaddr_in server_addr;
4721900Swollman	struct pmaplist *head = NULL;
4731900Swollman	int socket = RPC_ANYSOCK;
4741900Swollman	struct timeval minutetimeout;
4751900Swollman	register CLIENT *client;
4761900Swollman	struct rpcent *rpc;
47774462Salfred	enum clnt_stat clnt_st;
47874462Salfred	struct rpc_err err;
479239373Skevlo	char *host = NULL;
4808874Srgrimes
481119849Scharnier	if (argc > 1)
4821900Swollman		usage();
48374462Salfred	if (argc == 1) {
48474462Salfred		host = argv[0];
48574462Salfred		get_inet_address(&server_addr, host);
48674462Salfred		server_addr.sin_port = htons(PMAPPORT);
48774462Salfred		client = clnttcp_create(&server_addr, PMAPPROG, PMAPVERS,
48874462Salfred		    &socket, 50, 500);
48974462Salfred	} else
49074462Salfred		client = local_rpcb(PMAPPROG, PMAPVERS);
49174462Salfred
49274462Salfred	if (client == NULL) {
49374462Salfred		if (rpc_createerr.cf_stat == RPC_TLIERROR) {
49474462Salfred			/*
49574462Salfred			 * "Misc. TLI error" is not too helpful. Most likely
49674462Salfred			 * the connection to the remote server timed out, so
49774462Salfred			 * this error is at least less perplexing.
49874462Salfred			 */
49974462Salfred			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
50074462Salfred			rpc_createerr.cf_error.re_status = RPC_FAILED;
50174462Salfred		}
50274462Salfred		clnt_pcreateerror("rpcinfo: can't contact portmapper");
50374462Salfred		exit(1);
5041900Swollman	}
50574462Salfred
5061900Swollman	minutetimeout.tv_sec = 60;
5071900Swollman	minutetimeout.tv_usec = 0;
50874462Salfred
50974462Salfred	clnt_st = CLNT_CALL(client, PMAPPROC_DUMP, (xdrproc_t) xdr_void,
51074462Salfred		NULL, (xdrproc_t) xdr_pmaplist_ptr, (char *)&head,
51174462Salfred		minutetimeout);
51274462Salfred	if (clnt_st != RPC_SUCCESS) {
51374462Salfred		if ((clnt_st == RPC_PROGVERSMISMATCH) ||
51474462Salfred		    (clnt_st == RPC_PROGUNAVAIL)) {
51574462Salfred			CLNT_GETERR(client, &err);
516239373Skevlo			if (err.re_vers.low > PMAPVERS) {
517239373Skevlo				if (host)
518239373Skevlo					warnx("%s does not support portmapper."
519239373Skevlo					    "Try rpcinfo %s instead", host,
520239373Skevlo					    host);
521239373Skevlo				else
522239373Skevlo					warnx("local host does not support "
523239373Skevlo					    "portmapper.  Try 'rpcinfo' "
524239373Skevlo					    "instead");
525239373Skevlo			}
52674462Salfred			exit(1);
52774462Salfred		}
52874462Salfred		clnt_perror(client, "rpcinfo: can't contact portmapper");
5291900Swollman		exit(1);
5301900Swollman	}
5311900Swollman	if (head == NULL) {
5321900Swollman		printf("No remote programs registered.\n");
5331900Swollman	} else {
53474462Salfred		printf("   program vers proto   port  service\n");
5351900Swollman		for (; head != NULL; head = head->pml_next) {
5361900Swollman			printf("%10ld%5ld",
53774462Salfred				head->pml_map.pm_prog,
53874462Salfred				head->pml_map.pm_vers);
5391900Swollman			if (head->pml_map.pm_prot == IPPROTO_UDP)
54074462Salfred				printf("%6s", "udp");
5411900Swollman			else if (head->pml_map.pm_prot == IPPROTO_TCP)
5421900Swollman				printf("%6s", "tcp");
54374462Salfred			else if (head->pml_map.pm_prot == IPPROTO_ST)
544107952Smbr				printf("%6s", "local");
5451900Swollman			else
54674462Salfred				printf("%6ld", head->pml_map.pm_prot);
54774462Salfred			printf("%7ld", head->pml_map.pm_port);
5481900Swollman			rpc = getrpcbynumber(head->pml_map.pm_prog);
5491900Swollman			if (rpc)
5501900Swollman				printf("  %s\n", rpc->r_name);
5511900Swollman			else
5521900Swollman				printf("\n");
5531900Swollman		}
5541900Swollman	}
5551900Swollman}
5561900Swollman
55774462Salfredstatic void
55874462Salfredget_inet_address(struct sockaddr_in *addr, char *host)
55974462Salfred{
56074462Salfred	struct netconfig *nconf;
56174462Salfred	struct addrinfo hints, *res;
56274462Salfred	int error;
56374462Salfred
56474462Salfred	(void) memset((char *)addr, 0, sizeof (*addr));
56574462Salfred	addr->sin_addr.s_addr = inet_addr(host);
56674462Salfred	if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
56774462Salfred		if ((nconf = __rpc_getconfip("udp")) == NULL &&
568119849Scharnier		    (nconf = __rpc_getconfip("tcp")) == NULL)
569119849Scharnier			errx(1, "couldn't find a suitable transport");
570119849Scharnier		else {
57174462Salfred			memset(&hints, 0, sizeof hints);
57274462Salfred			hints.ai_family = AF_INET;
57374462Salfred			if ((error = getaddrinfo(host, "rpcbind", &hints, &res))
574119849Scharnier			    != 0)
575119849Scharnier				errx(1, "%s: %s", host, gai_strerror(error));
576119849Scharnier			else {
57774462Salfred				memcpy(addr, res->ai_addr, res->ai_addrlen);
57874462Salfred				freeaddrinfo(res);
57974462Salfred			}
58074462Salfred			(void) freenetconfigent(nconf);
58174462Salfred		}
58274462Salfred	} else {
58374462Salfred		addr->sin_family = AF_INET;
58474462Salfred	}
58574462Salfred}
58674462Salfred#endif /* PORTMAP */
58774462Salfred
5888874Srgrimes/*
5898874Srgrimes * reply_proc collects replies from the broadcast.
5901900Swollman * to get a unique list of responses the output of rpcinfo should
5911900Swollman * be piped through sort(1) and then uniq(1).
5921900Swollman */
5931900Swollman
5941900Swollman/*ARGSUSED*/
5951900Swollmanstatic bool_t
59674462Salfredreply_proc(void *res, struct netbuf *who, struct netconfig *nconf)
59774462Salfred	/* void *res;			Nothing comes back */
59874462Salfred	/* struct netbuf *who;		Who sent us the reply */
59974462Salfred	/* struct netconfig *nconf; 	On which transport the reply came */
6001900Swollman{
60174462Salfred	char *uaddr;
60274462Salfred	char hostbuf[NI_MAXHOST];
603221860Sdelphij	const char *hostname;
60474462Salfred	struct sockaddr *sa = (struct sockaddr *)who->buf;
6051900Swollman
60674462Salfred	if (getnameinfo(sa, sa->sa_len, hostbuf, NI_MAXHOST, NULL, 0, 0)) {
60774462Salfred		hostname = UNKNOWN;
60874462Salfred	} else {
60974462Salfred		hostname = hostbuf;
61074462Salfred	}
61174462Salfred	if (!(uaddr = taddr2uaddr(nconf, who))) {
61274462Salfred		uaddr = UNKNOWN;
61374462Salfred	}
61474462Salfred	printf("%s\t%s\n", uaddr, hostname);
61574462Salfred	if (strcmp(uaddr, UNKNOWN))
61674462Salfred		free((char *)uaddr);
61774462Salfred	return (FALSE);
6181900Swollman}
6191900Swollman
6201900Swollmanstatic void
62174462Salfredbrdcst(int argc, char **argv)
6221900Swollman{
6231900Swollman	enum clnt_stat rpc_stat;
6241900Swollman	u_long prognum, vers;
6251900Swollman
626119849Scharnier	if (argc != 2)
6271900Swollman		usage();
6281900Swollman	prognum = getprognum(argv[0]);
6291900Swollman	vers = getvers(argv[1]);
63074462Salfred	rpc_stat = rpc_broadcast(prognum, vers, NULLPROC,
63174462Salfred		(xdrproc_t) xdr_void, (char *)NULL, (xdrproc_t) xdr_void,
63274462Salfred		(char *)NULL, (resultproc_t) reply_proc, NULL);
633119849Scharnier	if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT))
634119849Scharnier		errx(1, "broadcast failed: %s", clnt_sperrno(rpc_stat));
6351900Swollman	exit(0);
6361900Swollman}
6371900Swollman
63874462Salfredstatic bool_t
63974462Salfredadd_version(struct rpcbdump_short *rs, u_long vers)
64074462Salfred{
64174462Salfred	struct verslist *vl;
64274462Salfred
64374462Salfred	for (vl = rs->vlist; vl; vl = vl->next)
64474462Salfred		if (vl->vers == vers)
64574462Salfred			break;
64674462Salfred	if (vl)
64774462Salfred		return (TRUE);
64874462Salfred	vl = (struct verslist *)malloc(sizeof (struct verslist));
64974462Salfred	if (vl == NULL)
65074462Salfred		return (FALSE);
65174462Salfred	vl->vers = vers;
65274462Salfred	vl->next = rs->vlist;
65374462Salfred	rs->vlist = vl;
65474462Salfred	return (TRUE);
65574462Salfred}
65674462Salfred
65774462Salfredstatic bool_t
65874462Salfredadd_netid(struct rpcbdump_short *rs, char *netid)
65974462Salfred{
66074462Salfred	struct netidlist *nl;
66174462Salfred
66274462Salfred	for (nl = rs->nlist; nl; nl = nl->next)
66374462Salfred		if (strcmp(nl->netid, netid) == 0)
66474462Salfred			break;
66574462Salfred	if (nl)
66674462Salfred		return (TRUE);
66774462Salfred	nl = (struct netidlist *)malloc(sizeof (struct netidlist));
66874462Salfred	if (nl == NULL)
66974462Salfred		return (FALSE);
67074462Salfred	nl->netid = netid;
67174462Salfred	nl->next = rs->nlist;
67274462Salfred	rs->nlist = nl;
67374462Salfred	return (TRUE);
67474462Salfred}
67574462Salfred
6761900Swollmanstatic void
67774462Salfredrpcbdump(int dumptype, char *netid, int argc, char **argv)
67874462Salfred{
67974462Salfred	rpcblist_ptr head = NULL;
68074462Salfred	struct timeval minutetimeout;
68174462Salfred	register CLIENT *client;
68274462Salfred	struct rpcent *rpc;
68374462Salfred	char *host;
68474462Salfred	struct netidlist *nl;
68574462Salfred	struct verslist *vl;
68674462Salfred	struct rpcbdump_short *rs, *rs_tail;
68774462Salfred	char buf[256];
68874462Salfred	enum clnt_stat clnt_st;
68974462Salfred	struct rpc_err err;
69074462Salfred	struct rpcbdump_short *rs_head = NULL;
6911900Swollman
692119849Scharnier	if (argc > 1)
69374462Salfred		usage();
69474462Salfred	if (argc == 1) {
69574462Salfred		host = argv[0];
69674462Salfred		if (netid == NULL) {
69774462Salfred			client = clnt_rpcbind_create(host, RPCBVERS, NULL);
69874462Salfred		} else {
69974462Salfred			struct netconfig *nconf;
70074462Salfred
70174462Salfred			nconf = getnetconfigent(netid);
70274462Salfred			if (nconf == NULL) {
70374462Salfred				nc_perror("rpcinfo: invalid transport");
70474462Salfred				exit(1);
70574462Salfred			}
70674462Salfred			client = getclnthandle(host, nconf, RPCBVERS, NULL);
70774462Salfred			if (nconf)
70874462Salfred				(void) freenetconfigent(nconf);
70974462Salfred		}
71074462Salfred	} else
71174462Salfred		client = local_rpcb(PMAPPROG, RPCBVERS);
71274462Salfred
71374462Salfred	if (client == (CLIENT *)NULL) {
71474462Salfred		clnt_pcreateerror("rpcinfo: can't contact rpcbind");
71574462Salfred		exit(1);
71674462Salfred	}
71774462Salfred
71874462Salfred	minutetimeout.tv_sec = 60;
71974462Salfred	minutetimeout.tv_usec = 0;
72074462Salfred	clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t) xdr_void,
72174462Salfred		NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
72274462Salfred		minutetimeout);
72374462Salfred	if (clnt_st != RPC_SUCCESS) {
72474462Salfred	    if ((clnt_st == RPC_PROGVERSMISMATCH) ||
72574462Salfred		(clnt_st == RPC_PROGUNAVAIL)) {
72674462Salfred		int vers;
72774462Salfred
72874462Salfred		CLNT_GETERR(client, &err);
72974462Salfred		if (err.re_vers.low == RPCBVERS4) {
73074462Salfred		    vers = RPCBVERS4;
73174462Salfred		    clnt_control(client, CLSET_VERS, (char *)&vers);
73274462Salfred		    clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
73374462Salfred			(xdrproc_t) xdr_void, NULL,
73474462Salfred			(xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
73574462Salfred			minutetimeout);
73674462Salfred		    if (clnt_st != RPC_SUCCESS)
73774462Salfred			goto failed;
73874462Salfred		} else {
73974462Salfred		    if (err.re_vers.high == PMAPVERS) {
74074462Salfred			int high, low;
74174462Salfred			struct pmaplist *pmaphead = NULL;
74274462Salfred			rpcblist_ptr list, prev;
74374462Salfred
74474462Salfred			vers = PMAPVERS;
74574462Salfred			clnt_control(client, CLSET_VERS, (char *)&vers);
74674462Salfred			clnt_st = CLNT_CALL(client, PMAPPROC_DUMP,
74774462Salfred				(xdrproc_t) xdr_void, NULL,
74874462Salfred				(xdrproc_t) xdr_pmaplist_ptr,
74974462Salfred				(char *)&pmaphead, minutetimeout);
75074462Salfred			if (clnt_st != RPC_SUCCESS)
75174462Salfred				goto failed;
75274462Salfred			/*
75374462Salfred			 * convert to rpcblist_ptr format
75474462Salfred			 */
75574462Salfred			for (head = NULL; pmaphead != NULL;
75674462Salfred				pmaphead = pmaphead->pml_next) {
75774462Salfred			    list = (rpcblist *)malloc(sizeof (rpcblist));
75874462Salfred			    if (list == NULL)
75974462Salfred				goto error;
76074462Salfred			    if (head == NULL)
76174462Salfred				head = list;
76274462Salfred			    else
76374462Salfred				prev->rpcb_next = (rpcblist_ptr) list;
76474462Salfred
76574462Salfred			    list->rpcb_next = NULL;
76674462Salfred			    list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog;
76774462Salfred			    list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers;
76874462Salfred			    if (pmaphead->pml_map.pm_prot == IPPROTO_UDP)
76974462Salfred				list->rpcb_map.r_netid = "udp";
77074462Salfred			    else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP)
77174462Salfred				list->rpcb_map.r_netid = "tcp";
77274462Salfred			    else {
77374462Salfred#define	MAXLONG_AS_STRING	"2147483648"
77474462Salfred				list->rpcb_map.r_netid =
77574462Salfred					malloc(strlen(MAXLONG_AS_STRING) + 1);
77674462Salfred				if (list->rpcb_map.r_netid == NULL)
77774462Salfred					goto error;
77874462Salfred				sprintf(list->rpcb_map.r_netid, "%6ld",
77974462Salfred					pmaphead->pml_map.pm_prot);
78074462Salfred			    }
78174462Salfred			    list->rpcb_map.r_owner = UNKNOWN;
78274462Salfred			    low = pmaphead->pml_map.pm_port & 0xff;
78374462Salfred			    high = (pmaphead->pml_map.pm_port >> 8) & 0xff;
78474462Salfred			    list->rpcb_map.r_addr = strdup("0.0.0.0.XXX.XXX");
78574462Salfred			    sprintf(&list->rpcb_map.r_addr[8], "%d.%d",
78674462Salfred				high, low);
78774462Salfred			    prev = list;
78874462Salfred			}
78974462Salfred		    }
79074462Salfred		}
79174462Salfred	    } else {	/* any other error */
79274462Salfredfailed:
79374462Salfred		    clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
79474462Salfred		    exit(1);
79574462Salfred	    }
79674462Salfred	}
79774462Salfred	if (head == NULL) {
79874462Salfred		printf("No remote programs registered.\n");
79974462Salfred	} else if (dumptype == RPCBDUMP) {
80074462Salfred		printf(
80174462Salfred"   program version netid     address                service    owner\n");
80274462Salfred		for (; head != NULL; head = head->rpcb_next) {
80374462Salfred			printf("%10u%5u    ",
80474462Salfred				head->rpcb_map.r_prog, head->rpcb_map.r_vers);
80574462Salfred			printf("%-9s ", head->rpcb_map.r_netid);
80674462Salfred			printf("%-22s", head->rpcb_map.r_addr);
80774462Salfred			rpc = getrpcbynumber(head->rpcb_map.r_prog);
80874462Salfred			if (rpc)
80974462Salfred				printf(" %-10s", rpc->r_name);
81074462Salfred			else
81174462Salfred				printf(" %-10s", "-");
81274462Salfred			printf(" %s\n", head->rpcb_map.r_owner);
81374462Salfred		}
81474462Salfred	} else if (dumptype == RPCBDUMP_SHORT) {
81574462Salfred		for (; head != NULL; head = head->rpcb_next) {
81674462Salfred			for (rs = rs_head; rs; rs = rs->next)
81774462Salfred				if (head->rpcb_map.r_prog == rs->prog)
81874462Salfred					break;
81974462Salfred			if (rs == NULL) {
82074462Salfred				rs = (struct rpcbdump_short *)
82174462Salfred					malloc(sizeof (struct rpcbdump_short));
82274462Salfred				if (rs == NULL)
82374462Salfred					goto error;
82474462Salfred				rs->next = NULL;
82574462Salfred				if (rs_head == NULL) {
82674462Salfred					rs_head = rs;
82774462Salfred					rs_tail = rs;
82874462Salfred				} else {
82974462Salfred					rs_tail->next = rs;
83074462Salfred					rs_tail = rs;
83174462Salfred				}
83274462Salfred				rs->prog = head->rpcb_map.r_prog;
83374462Salfred				rs->owner = head->rpcb_map.r_owner;
83474462Salfred				rs->nlist = NULL;
83574462Salfred				rs->vlist = NULL;
83674462Salfred			}
83774462Salfred			if (add_version(rs, head->rpcb_map.r_vers) == FALSE)
83874462Salfred				goto error;
83974462Salfred			if (add_netid(rs, head->rpcb_map.r_netid) == FALSE)
84074462Salfred				goto error;
84174462Salfred		}
84274462Salfred		printf(
84374462Salfred"   program version(s) netid(s)                         service     owner\n");
84474462Salfred		for (rs = rs_head; rs; rs = rs->next) {
84574462Salfred			char *p = buf;
84674462Salfred
84774462Salfred			printf("%10ld  ", rs->prog);
84874462Salfred			for (vl = rs->vlist; vl; vl = vl->next) {
84974462Salfred				sprintf(p, "%d", vl->vers);
85074462Salfred				p = p + strlen(p);
85174462Salfred				if (vl->next)
85274462Salfred					sprintf(p++, ",");
85374462Salfred			}
85474462Salfred			printf("%-10s", buf);
855126840Sbde			buf[0] = '\0';
85674462Salfred			for (nl = rs->nlist; nl; nl = nl->next) {
857319256Sasomers				strlcat(buf, nl->netid, sizeof(buf));
85874462Salfred				if (nl->next)
859319256Sasomers					strlcat(buf, ",", sizeof(buf));
86074462Salfred			}
86174462Salfred			printf("%-32s", buf);
86274462Salfred			rpc = getrpcbynumber(rs->prog);
86374462Salfred			if (rpc)
86474462Salfred				printf(" %-11s", rpc->r_name);
86574462Salfred			else
86674462Salfred				printf(" %-11s", "-");
86774462Salfred			printf(" %s\n", rs->owner);
86874462Salfred		}
86974462Salfred	}
87074462Salfred	clnt_destroy(client);
87174462Salfred	return;
872119849Scharniererror:	warnx("no memory");
87374462Salfred	return;
87474462Salfred}
87574462Salfred
87674462Salfredstatic char nullstring[] = "\000";
87774462Salfred
87874462Salfredstatic void
87974462Salfredrpcbaddrlist(char *netid, int argc, char **argv)
88074462Salfred{
88174462Salfred	rpcb_entry_list_ptr head = NULL;
88274462Salfred	struct timeval minutetimeout;
88374462Salfred	register CLIENT *client;
88474462Salfred	struct rpcent *rpc;
88574462Salfred	char *host;
88674462Salfred	RPCB parms;
88774462Salfred	struct netbuf *targaddr;
88874462Salfred
889119849Scharnier	if (argc != 3)
89074462Salfred		usage();
89174462Salfred	host = argv[0];
89274462Salfred	if (netid == NULL) {
89374462Salfred		client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr);
89474462Salfred	} else {
89574462Salfred		struct netconfig *nconf;
89674462Salfred
89774462Salfred		nconf = getnetconfigent(netid);
89874462Salfred		if (nconf == NULL) {
89974462Salfred			nc_perror("rpcinfo: invalid transport");
90074462Salfred			exit(1);
90174462Salfred		}
90274462Salfred		client = getclnthandle(host, nconf, RPCBVERS4, &targaddr);
90374462Salfred		if (nconf)
90474462Salfred			(void) freenetconfigent(nconf);
90574462Salfred	}
90674462Salfred	if (client == (CLIENT *)NULL) {
90774462Salfred		clnt_pcreateerror("rpcinfo: can't contact rpcbind");
90874462Salfred		exit(1);
90974462Salfred	}
91074462Salfred	minutetimeout.tv_sec = 60;
91174462Salfred	minutetimeout.tv_usec = 0;
91274462Salfred
91374462Salfred	parms.r_prog = 	getprognum(argv[1]);
91474462Salfred	parms.r_vers = 	getvers(argv[2]);
91574462Salfred	parms.r_netid = client->cl_netid;
91674462Salfred	if (targaddr == NULL) {
91774462Salfred		parms.r_addr = nullstring;	/* for XDRing */
91874462Salfred	} else {
91974462Salfred		/*
92074462Salfred		 * We also send the remote system the address we
92174462Salfred		 * used to contact it in case it can help it
92274462Salfred		 * connect back with us
92374462Salfred		 */
92474462Salfred		struct netconfig *nconf;
92574462Salfred
92674462Salfred		nconf = getnetconfigent(client->cl_netid);
92774462Salfred		if (nconf != NULL) {
92874462Salfred			parms.r_addr = taddr2uaddr(nconf, targaddr);
92974462Salfred			if (parms.r_addr == NULL)
93074462Salfred				parms.r_addr = nullstring;
93174462Salfred			freenetconfigent(nconf);
93274462Salfred		} else {
93374462Salfred			parms.r_addr = nullstring;	/* for XDRing */
93474462Salfred		}
93574462Salfred		free(targaddr->buf);
93674462Salfred		free(targaddr);
93774462Salfred	}
93874462Salfred	parms.r_owner = nullstring;
93974462Salfred
94074462Salfred	if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb,
94174462Salfred		(char *) &parms, (xdrproc_t) xdr_rpcb_entry_list_ptr,
94274462Salfred		(char *) &head, minutetimeout) != RPC_SUCCESS) {
94374462Salfred		clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
94474462Salfred		exit(1);
94574462Salfred	}
94674462Salfred	if (head == NULL) {
94774462Salfred		printf("No remote programs registered.\n");
94874462Salfred	} else {
94974462Salfred		printf(
95074462Salfred	"   program vers  tp_family/name/class    address\t\t  service\n");
95174462Salfred		for (; head != NULL; head = head->rpcb_entry_next) {
95274462Salfred			rpcb_entry *re;
95374462Salfred			char buf[128];
95474462Salfred
95574462Salfred			re = &head->rpcb_entry_map;
95674462Salfred			printf("%10u%3u    ",
95774462Salfred				parms.r_prog, parms.r_vers);
95874462Salfred			sprintf(buf, "%s/%s/%s ",
95974462Salfred				re->r_nc_protofmly, re->r_nc_proto,
96074462Salfred				re->r_nc_semantics == NC_TPI_CLTS ? "clts" :
96174462Salfred				re->r_nc_semantics == NC_TPI_COTS ? "cots" :
96274462Salfred						"cots_ord");
96374462Salfred			printf("%-24s", buf);
96474462Salfred			printf("%-24s", re->r_maddr);
96574462Salfred			rpc = getrpcbynumber(parms.r_prog);
96674462Salfred			if (rpc)
96774462Salfred				printf(" %-13s", rpc->r_name);
96874462Salfred			else
96974462Salfred				printf(" %-13s", "-");
97074462Salfred			printf("\n");
97174462Salfred		}
97274462Salfred	}
97374462Salfred	clnt_destroy(client);
97474462Salfred	return;
97574462Salfred}
97674462Salfred
97774462Salfred/*
97874462Salfred * monitor rpcbind
97974462Salfred */
98074462Salfredstatic void
98174462Salfredrpcbgetstat(int argc, char **argv)
98274462Salfred{
98374462Salfred	rpcb_stat_byvers inf;
98474462Salfred	struct timeval minutetimeout;
98574462Salfred	register CLIENT *client;
98674462Salfred	char *host;
98774462Salfred	int i, j;
98874462Salfred	rpcbs_addrlist *pa;
98974462Salfred	rpcbs_rmtcalllist *pr;
99074462Salfred	int cnt, flen;
99174462Salfred#define	MAXFIELD	64
99274462Salfred	char fieldbuf[MAXFIELD];
99374462Salfred#define	MAXLINE		256
99474462Salfred	char linebuf[MAXLINE];
99574462Salfred	char *cp, *lp;
996221860Sdelphij	const char *pmaphdr[] = {
99774462Salfred		"NULL", "SET", "UNSET", "GETPORT",
99874462Salfred		"DUMP", "CALLIT"
99974462Salfred	};
1000221860Sdelphij	const char *rpcb3hdr[] = {
100174462Salfred		"NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
100274462Salfred		"U2T", "T2U"
100374462Salfred	};
1004221860Sdelphij	const char *rpcb4hdr[] = {
100574462Salfred		"NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
100674462Salfred		"U2T",  "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT"
100774462Salfred	};
100874462Salfred
100974462Salfred#define	TABSTOP	8
101074462Salfred
101174462Salfred	if (argc >= 1) {
101274462Salfred		host = argv[0];
101374462Salfred		client = clnt_rpcbind_create(host, RPCBVERS4, NULL);
101474462Salfred	} else
101574462Salfred		client = local_rpcb(PMAPPROG, RPCBVERS4);
101674462Salfred	if (client == (CLIENT *)NULL) {
101774462Salfred		clnt_pcreateerror("rpcinfo: can't contact rpcbind");
101874462Salfred		exit(1);
101974462Salfred	}
102074462Salfred	minutetimeout.tv_sec = 60;
102174462Salfred	minutetimeout.tv_usec = 0;
102274462Salfred	memset((char *)&inf, 0, sizeof (rpcb_stat_byvers));
102374462Salfred	if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t) xdr_void, NULL,
102474462Salfred		(xdrproc_t) xdr_rpcb_stat_byvers, (char *)&inf, minutetimeout)
102574462Salfred			!= RPC_SUCCESS) {
102674462Salfred		clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
102774462Salfred		exit(1);
102874462Salfred	}
102974462Salfred	printf("PORTMAP (version 2) statistics\n");
103074462Salfred	lp = linebuf;
103174462Salfred	for (i = 0; i <= rpcb_highproc_2; i++) {
103274462Salfred		fieldbuf[0] = '\0';
103374462Salfred		switch (i) {
103474462Salfred		case PMAPPROC_SET:
103574462Salfred			sprintf(fieldbuf, "%d/", inf[RPCBVERS_2_STAT].setinfo);
103674462Salfred			break;
103774462Salfred		case PMAPPROC_UNSET:
103874462Salfred			sprintf(fieldbuf, "%d/",
103974462Salfred				inf[RPCBVERS_2_STAT].unsetinfo);
104074462Salfred			break;
104174462Salfred		case PMAPPROC_GETPORT:
104274462Salfred			cnt = 0;
104374462Salfred			for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa;
104474462Salfred				pa = pa->next)
104574462Salfred				cnt += pa->success;
104674462Salfred			sprintf(fieldbuf, "%d/", cnt);
104774462Salfred			break;
104874462Salfred		case PMAPPROC_CALLIT:
104974462Salfred			cnt = 0;
105074462Salfred			for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr;
105174462Salfred				pr = pr->next)
105274462Salfred				cnt += pr->success;
105374462Salfred			sprintf(fieldbuf, "%d/", cnt);
105474462Salfred			break;
105574462Salfred		default: break;  /* For the remaining ones */
105674462Salfred		}
105774462Salfred		cp = &fieldbuf[0] + strlen(fieldbuf);
105874462Salfred		sprintf(cp, "%d", inf[RPCBVERS_2_STAT].info[i]);
105974462Salfred		flen = strlen(fieldbuf);
106074462Salfred		printf("%s%s", pmaphdr[i],
106174462Salfred			spaces((TABSTOP * (1 + flen / TABSTOP))
106274462Salfred			- strlen(pmaphdr[i])));
106374462Salfred		sprintf(lp, "%s%s", fieldbuf,
106474462Salfred			spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
106574462Salfred			- flen)));
106674462Salfred		lp += (flen + cnt);
106774462Salfred	}
106874462Salfred	printf("\n%s\n\n", linebuf);
106974462Salfred
107074462Salfred	if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) {
107174462Salfred		printf("PMAP_RMTCALL call statistics\n");
107274462Salfred		print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
107374462Salfred		printf("\n");
107474462Salfred	}
107574462Salfred
107674462Salfred	if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) {
107774462Salfred		printf("PMAP_GETPORT call statistics\n");
107874462Salfred		print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
107974462Salfred		printf("\n");
108074462Salfred	}
108174462Salfred
108274462Salfred	printf("RPCBIND (version 3) statistics\n");
108374462Salfred	lp = linebuf;
108474462Salfred	for (i = 0; i <= rpcb_highproc_3; i++) {
108574462Salfred		fieldbuf[0] = '\0';
108674462Salfred		switch (i) {
108774462Salfred		case RPCBPROC_SET:
108874462Salfred			sprintf(fieldbuf, "%d/", inf[RPCBVERS_3_STAT].setinfo);
108974462Salfred			break;
109074462Salfred		case RPCBPROC_UNSET:
109174462Salfred			sprintf(fieldbuf, "%d/",
109274462Salfred				inf[RPCBVERS_3_STAT].unsetinfo);
109374462Salfred			break;
109474462Salfred		case RPCBPROC_GETADDR:
109574462Salfred			cnt = 0;
109674462Salfred			for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa;
109774462Salfred				pa = pa->next)
109874462Salfred				cnt += pa->success;
109974462Salfred			sprintf(fieldbuf, "%d/", cnt);
110074462Salfred			break;
110174462Salfred		case RPCBPROC_CALLIT:
110274462Salfred			cnt = 0;
110374462Salfred			for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr;
110474462Salfred				pr = pr->next)
110574462Salfred				cnt += pr->success;
110674462Salfred			sprintf(fieldbuf, "%d/", cnt);
110774462Salfred			break;
110874462Salfred		default: break;  /* For the remaining ones */
110974462Salfred		}
111074462Salfred		cp = &fieldbuf[0] + strlen(fieldbuf);
111174462Salfred		sprintf(cp, "%d", inf[RPCBVERS_3_STAT].info[i]);
111274462Salfred		flen = strlen(fieldbuf);
111374462Salfred		printf("%s%s", rpcb3hdr[i],
111474462Salfred			spaces((TABSTOP * (1 + flen / TABSTOP))
111574462Salfred			- strlen(rpcb3hdr[i])));
111674462Salfred		sprintf(lp, "%s%s", fieldbuf,
111774462Salfred			spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
111874462Salfred			- flen)));
111974462Salfred		lp += (flen + cnt);
112074462Salfred	}
112174462Salfred	printf("\n%s\n\n", linebuf);
112274462Salfred
112374462Salfred	if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) {
112474462Salfred		printf("RPCB_RMTCALL (version 3) call statistics\n");
112574462Salfred		print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
112674462Salfred		printf("\n");
112774462Salfred	}
112874462Salfred
112974462Salfred	if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) {
113074462Salfred		printf("RPCB_GETADDR (version 3) call statistics\n");
113174462Salfred		print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
113274462Salfred		printf("\n");
113374462Salfred	}
113474462Salfred
113574462Salfred	printf("RPCBIND (version 4) statistics\n");
113674462Salfred
113774462Salfred	for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */
113874462Salfred		lp = linebuf;
113974462Salfred		for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) {
114074462Salfred			fieldbuf[0] = '\0';
114174462Salfred			switch (i) {
114274462Salfred			case RPCBPROC_SET:
114374462Salfred				sprintf(fieldbuf, "%d/",
114474462Salfred					inf[RPCBVERS_4_STAT].setinfo);
114574462Salfred				break;
114674462Salfred			case RPCBPROC_UNSET:
114774462Salfred				sprintf(fieldbuf, "%d/",
114874462Salfred					inf[RPCBVERS_4_STAT].unsetinfo);
114974462Salfred				break;
115074462Salfred			case RPCBPROC_GETADDR:
115174462Salfred				cnt = 0;
115274462Salfred				for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa;
115374462Salfred					pa = pa->next)
115474462Salfred					cnt += pa->success;
115574462Salfred				sprintf(fieldbuf, "%d/", cnt);
115674462Salfred				break;
115774462Salfred			case RPCBPROC_CALLIT:
115874462Salfred				cnt = 0;
115974462Salfred				for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr;
116074462Salfred					pr = pr->next)
116174462Salfred					cnt += pr->success;
116274462Salfred				sprintf(fieldbuf, "%d/", cnt);
116374462Salfred				break;
116474462Salfred			default: break;  /* For the remaining ones */
116574462Salfred			}
116674462Salfred			cp = &fieldbuf[0] + strlen(fieldbuf);
116774462Salfred			/*
116874462Salfred			 * XXX: We also add RPCBPROC_GETADDRLIST queries to
116974462Salfred			 * RPCB_GETADDR because rpcbind includes the
117074462Salfred			 * RPCB_GETADDRLIST successes in RPCB_GETADDR.
117174462Salfred			 */
117274462Salfred			if (i != RPCBPROC_GETADDR)
117374462Salfred			    sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i]);
117474462Salfred			else
117574462Salfred			    sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i] +
117674462Salfred			    inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]);
117774462Salfred			flen = strlen(fieldbuf);
117874462Salfred			printf("%s%s", rpcb4hdr[i],
117974462Salfred				spaces((TABSTOP * (1 + flen / TABSTOP))
118074462Salfred				- strlen(rpcb4hdr[i])));
118174462Salfred			sprintf(lp, "%s%s", fieldbuf,
118274462Salfred				spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
118374462Salfred				- flen)));
118474462Salfred			lp += (flen + cnt);
118574462Salfred		}
118674462Salfred		printf("\n%s\n", linebuf);
118774462Salfred	}
118874462Salfred
118974462Salfred	if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] ||
119074462Salfred			    inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) {
119174462Salfred		printf("\n");
119274462Salfred		printf("RPCB_RMTCALL (version 4) call statistics\n");
119374462Salfred		print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
119474462Salfred	}
119574462Salfred
119674462Salfred	if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) {
119774462Salfred		printf("\n");
119874462Salfred		printf("RPCB_GETADDR (version 4) call statistics\n");
119974462Salfred		print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
120074462Salfred	}
120174462Salfred	clnt_destroy(client);
120274462Salfred}
120374462Salfred
120474462Salfred/*
120574462Salfred * Delete registeration for this (prog, vers, netid)
120674462Salfred */
120774462Salfredstatic void
120874462Salfreddeletereg(char *netid, int argc, char **argv)
120974462Salfred{
121074462Salfred	struct netconfig *nconf = NULL;
121174462Salfred
1212119849Scharnier	if (argc != 2)
121374462Salfred		usage();
121474462Salfred	if (netid) {
121574462Salfred		nconf = getnetconfigent(netid);
1216119849Scharnier		if (nconf == NULL)
1217119849Scharnier			errx(1, "netid %s not supported", netid);
121874462Salfred	}
1219119849Scharnier	if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0)
1220119849Scharnier		errx(1,
1221119849Scharnier	"could not delete registration for prog %s version %s",
122274462Salfred			argv[0], argv[1]);
12231900Swollman}
12241900Swollman
122574462Salfred/*
122674462Salfred * Create and return a handle for the given nconf.
122774462Salfred * Exit if cannot create handle.
122874462Salfred */
122974462Salfredstatic CLIENT *
123074462Salfredclnt_addr_create(char *address, struct netconfig *nconf,
123174462Salfred    u_long prog, u_long vers)
123274462Salfred{
123374462Salfred	CLIENT *client;
123474462Salfred	static struct netbuf *nbuf;
123574462Salfred	static int fd = RPC_ANYFD;
123674462Salfred
123774462Salfred	if (fd == RPC_ANYFD) {
123874462Salfred		if ((fd = __rpc_nconf2fd(nconf)) == -1) {
123974462Salfred			rpc_createerr.cf_stat = RPC_TLIERROR;
124074462Salfred			clnt_pcreateerror("rpcinfo");
124174462Salfred			exit(1);
124274462Salfred		}
124374462Salfred		/* Convert the uaddr to taddr */
124474462Salfred		nbuf = uaddr2taddr(nconf, address);
1245119849Scharnier		if (nbuf == NULL)
1246119849Scharnier			errx(1, "no address for client handle");
124774462Salfred	}
124874462Salfred	client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0);
124974462Salfred	if (client == (CLIENT *)NULL) {
125074462Salfred		clnt_pcreateerror("rpcinfo");
125174462Salfred		exit(1);
125274462Salfred	}
125374462Salfred	return (client);
125474462Salfred}
125574462Salfred
125674462Salfred/*
125774462Salfred * If the version number is given, ping that (prog, vers); else try to find
125874462Salfred * the version numbers supported for that prog and ping all the versions.
125974462Salfred * Remote rpcbind is not contacted for this service. The requests are
126074462Salfred * sent directly to the services themselves.
126174462Salfred */
12621900Swollmanstatic void
126374462Salfredaddrping(char *address, char *netid, int argc, char **argv)
126474462Salfred{
126574462Salfred	CLIENT *client;
126674462Salfred	struct timeval to;
126774462Salfred	enum clnt_stat rpc_stat;
126874462Salfred	u_long prognum, versnum, minvers, maxvers;
126974462Salfred	struct rpc_err rpcerr;
127074462Salfred	int failure = 0;
127174462Salfred	struct netconfig *nconf;
127274462Salfred	int fd;
127374462Salfred
1274119849Scharnier	if (argc < 1 || argc > 2 || (netid == NULL))
127574462Salfred		usage();
127674462Salfred	nconf = getnetconfigent(netid);
1277119849Scharnier	if (nconf == (struct netconfig *)NULL)
1278119849Scharnier		errx(1, "could not find %s", netid);
127974462Salfred	to.tv_sec = 10;
128074462Salfred	to.tv_usec = 0;
128174462Salfred	prognum = getprognum(argv[0]);
128274462Salfred	if (argc == 1) {	/* Version number not known */
128374462Salfred		/*
128474462Salfred		 * A call to version 0 should fail with a program/version
128574462Salfred		 * mismatch, and give us the range of versions supported.
128674462Salfred		 */
128774462Salfred		versnum = MIN_VERS;
128874462Salfred	} else {
128974462Salfred		versnum = getvers(argv[1]);
129074462Salfred	}
129174462Salfred	client = clnt_addr_create(address, nconf, prognum, versnum);
129274462Salfred	rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
129374462Salfred			(char *)NULL, (xdrproc_t) xdr_void,
129474462Salfred			(char *)NULL, to);
129574462Salfred	if (argc == 2) {
129674462Salfred		/* Version number was known */
129774462Salfred		if (pstatus(client, prognum, versnum) < 0)
129874462Salfred			failure = 1;
129974462Salfred		(void) CLNT_DESTROY(client);
130074462Salfred		if (failure)
130174462Salfred			exit(1);
130274462Salfred		return;
130374462Salfred	}
130474462Salfred	/* Version number not known */
130574462Salfred	(void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL);
130674462Salfred	(void) CLNT_CONTROL(client, CLGET_FD, (char *)&fd);
130774462Salfred	if (rpc_stat == RPC_PROGVERSMISMATCH) {
130874462Salfred		clnt_geterr(client, &rpcerr);
130974462Salfred		minvers = rpcerr.re_vers.low;
131074462Salfred		maxvers = rpcerr.re_vers.high;
131174462Salfred	} else if (rpc_stat == RPC_SUCCESS) {
131274462Salfred		/*
131374462Salfred		 * Oh dear, it DOES support version 0.
131474462Salfred		 * Let's try version MAX_VERS.
131574462Salfred		 */
131674462Salfred		(void) CLNT_DESTROY(client);
131774462Salfred		client = clnt_addr_create(address, nconf, prognum, MAX_VERS);
131874462Salfred		rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
131974462Salfred				(char *)NULL, (xdrproc_t) xdr_void,
132074462Salfred				(char *)NULL, to);
132174462Salfred		if (rpc_stat == RPC_PROGVERSMISMATCH) {
132274462Salfred			clnt_geterr(client, &rpcerr);
132374462Salfred			minvers = rpcerr.re_vers.low;
132474462Salfred			maxvers = rpcerr.re_vers.high;
132574462Salfred		} else if (rpc_stat == RPC_SUCCESS) {
132674462Salfred			/*
132774462Salfred			 * It also supports version MAX_VERS.
132874462Salfred			 * Looks like we have a wise guy.
132974462Salfred			 * OK, we give them information on all
133074462Salfred			 * 4 billion versions they support...
133174462Salfred			 */
133274462Salfred			minvers = 0;
133374462Salfred			maxvers = MAX_VERS;
133474462Salfred		} else {
133574462Salfred			(void) pstatus(client, prognum, MAX_VERS);
133674462Salfred			exit(1);
133774462Salfred		}
133874462Salfred	} else {
133974462Salfred		(void) pstatus(client, prognum, (u_long)0);
134074462Salfred		exit(1);
134174462Salfred	}
134274462Salfred	(void) CLNT_DESTROY(client);
134374462Salfred	for (versnum = minvers; versnum <= maxvers; versnum++) {
134474462Salfred		client = clnt_addr_create(address, nconf, prognum, versnum);
134574462Salfred		rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
134674462Salfred				(char *)NULL, (xdrproc_t) xdr_void,
134774462Salfred				(char *)NULL, to);
134874462Salfred		if (pstatus(client, prognum, versnum) < 0)
134974462Salfred				failure = 1;
135074462Salfred		(void) CLNT_DESTROY(client);
135174462Salfred	}
135274462Salfred	(void) close(fd);
135374462Salfred	if (failure)
135474462Salfred		exit(1);
135574462Salfred	return;
135674462Salfred}
135774462Salfred
135874462Salfred/*
135974462Salfred * If the version number is given, ping that (prog, vers); else try to find
136074462Salfred * the version numbers supported for that prog and ping all the versions.
136174462Salfred * Remote rpcbind is *contacted* for this service. The requests are
136274462Salfred * then sent directly to the services themselves.
136374462Salfred */
136474462Salfredstatic void
136574462Salfredprogping(char *netid, int argc, char **argv)
136674462Salfred{
136774462Salfred	CLIENT *client;
136874462Salfred	struct timeval to;
136974462Salfred	enum clnt_stat rpc_stat;
137074462Salfred	u_long prognum, versnum, minvers, maxvers;
137174462Salfred	struct rpc_err rpcerr;
137274462Salfred	int failure = 0;
137374462Salfred	struct netconfig *nconf;
137474462Salfred
1375119849Scharnier	if (argc < 2 || argc > 3 || (netid == NULL))
137674462Salfred		usage();
137774462Salfred	prognum = getprognum(argv[1]);
137874462Salfred	if (argc == 2) { /* Version number not known */
137974462Salfred		/*
138074462Salfred		 * A call to version 0 should fail with a program/version
138174462Salfred		 * mismatch, and give us the range of versions supported.
138274462Salfred		 */
138374462Salfred		versnum = MIN_VERS;
138474462Salfred	} else {
138574462Salfred		versnum = getvers(argv[2]);
138674462Salfred	}
138774462Salfred	if (netid) {
138874462Salfred		nconf = getnetconfigent(netid);
1389119849Scharnier		if (nconf == (struct netconfig *)NULL)
1390119849Scharnier			errx(1, "could not find %s", netid);
139174462Salfred		client = clnt_tp_create(argv[0], prognum, versnum, nconf);
139274462Salfred	} else {
139374462Salfred		client = clnt_create(argv[0], prognum, versnum, "NETPATH");
139474462Salfred	}
139574462Salfred	if (client == (CLIENT *)NULL) {
139674462Salfred		clnt_pcreateerror("rpcinfo");
139774462Salfred		exit(1);
139874462Salfred	}
139974462Salfred	to.tv_sec = 10;
140074462Salfred	to.tv_usec = 0;
140174462Salfred	rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
140274462Salfred			(char *)NULL, (xdrproc_t) xdr_void,
140374462Salfred			(char *)NULL, to);
140474462Salfred	if (argc == 3) {
140574462Salfred		/* Version number was known */
140674462Salfred		if (pstatus(client, prognum, versnum) < 0)
140774462Salfred			failure = 1;
140874462Salfred		(void) CLNT_DESTROY(client);
140974462Salfred		if (failure)
141074462Salfred			exit(1);
141174462Salfred		return;
141274462Salfred	}
141374462Salfred	/* Version number not known */
141474462Salfred	if (rpc_stat == RPC_PROGVERSMISMATCH) {
141574462Salfred		clnt_geterr(client, &rpcerr);
141674462Salfred		minvers = rpcerr.re_vers.low;
141774462Salfred		maxvers = rpcerr.re_vers.high;
141874462Salfred	} else if (rpc_stat == RPC_SUCCESS) {
141974462Salfred		/*
142074462Salfred		 * Oh dear, it DOES support version 0.
142174462Salfred		 * Let's try version MAX_VERS.
142274462Salfred		 */
142374462Salfred		versnum = MAX_VERS;
142474462Salfred		(void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
142574462Salfred		rpc_stat = CLNT_CALL(client, NULLPROC,
142674462Salfred				(xdrproc_t) xdr_void, (char *)NULL,
142774462Salfred				(xdrproc_t)  xdr_void, (char *)NULL, to);
142874462Salfred		if (rpc_stat == RPC_PROGVERSMISMATCH) {
142974462Salfred			clnt_geterr(client, &rpcerr);
143074462Salfred			minvers = rpcerr.re_vers.low;
143174462Salfred			maxvers = rpcerr.re_vers.high;
143274462Salfred		} else if (rpc_stat == RPC_SUCCESS) {
143374462Salfred			/*
143474462Salfred			 * It also supports version MAX_VERS.
143574462Salfred			 * Looks like we have a wise guy.
143674462Salfred			 * OK, we give them information on all
143774462Salfred			 * 4 billion versions they support...
143874462Salfred			 */
143974462Salfred			minvers = 0;
144074462Salfred			maxvers = MAX_VERS;
144174462Salfred		} else {
144274462Salfred			(void) pstatus(client, prognum, MAX_VERS);
144374462Salfred			exit(1);
144474462Salfred		}
144574462Salfred	} else {
144674462Salfred		(void) pstatus(client, prognum, (u_long)0);
144774462Salfred		exit(1);
144874462Salfred	}
144974462Salfred	for (versnum = minvers; versnum <= maxvers; versnum++) {
145074462Salfred		(void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
145174462Salfred		rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
145274462Salfred					(char *)NULL, (xdrproc_t) xdr_void,
145374462Salfred					(char *)NULL, to);
145474462Salfred		if (pstatus(client, prognum, versnum) < 0)
145574462Salfred				failure = 1;
145674462Salfred	}
145774462Salfred	(void) CLNT_DESTROY(client);
145874462Salfred	if (failure)
145974462Salfred		exit(1);
146074462Salfred	return;
146174462Salfred}
146274462Salfred
146374462Salfredstatic void
1464221860Sdelphijusage(void)
14651900Swollman{
146695258Sdes	fprintf(stderr, "usage: rpcinfo [-m | -s] [host]\n");
146774462Salfred#ifdef PORTMAP
146874462Salfred	fprintf(stderr, "       rpcinfo -p [host]\n");
146974462Salfred#endif
147074462Salfred	fprintf(stderr, "       rpcinfo -T netid host prognum [versnum]\n");
147174462Salfred	fprintf(stderr, "       rpcinfo -l host prognum versnum\n");
147274462Salfred#ifdef PORTMAP
147374462Salfred	fprintf(stderr,
147474462Salfred"       rpcinfo [-n portnum] -u | -t host prognum [versnum]\n");
147574462Salfred#endif
147674462Salfred	fprintf(stderr,
147774462Salfred"       rpcinfo -a serv_address -T netid prognum [version]\n");
147874462Salfred	fprintf(stderr, "       rpcinfo -b prognum versnum\n");
147974462Salfred	fprintf(stderr, "       rpcinfo -d [-T netid] prognum versnum\n");
1480119849Scharnier	exit(1);
14811900Swollman}
14821900Swollman
14831900Swollmanstatic u_long
148474462Salfredgetprognum (char *arg)
14851900Swollman{
148674462Salfred	char *strptr;
14871900Swollman	register struct rpcent *rpc;
14881900Swollman	register u_long prognum;
148974462Salfred	char *tptr = arg;
14901900Swollman
149174462Salfred	while (*tptr && isdigit(*tptr++));
149274462Salfred	if (*tptr || isalpha(*(tptr - 1))) {
14931900Swollman		rpc = getrpcbyname(arg);
1494119849Scharnier		if (rpc == NULL)
1495119849Scharnier			errx(1, "%s is unknown service", arg);
14961900Swollman		prognum = rpc->r_number;
14971900Swollman	} else {
149874462Salfred		prognum = strtol(arg, &strptr, 10);
1499119849Scharnier		if (strptr == arg || *strptr != '\0')
1500119849Scharnier			errx(1, "%s is illegal program number", arg);
15011900Swollman	}
15021900Swollman	return (prognum);
15031900Swollman}
15041900Swollman
15051900Swollmanstatic u_long
150674462Salfredgetvers(char *arg)
15071900Swollman{
150874462Salfred	char *strptr;
15091900Swollman	register u_long vers;
15101900Swollman
151174462Salfred	vers = (int) strtol(arg, &strptr, 10);
1512119849Scharnier	if (strptr == arg || *strptr != '\0')
1513119849Scharnier		errx(1, "%s is illegal version number", arg);
15141900Swollman	return (vers);
15151900Swollman}
15161900Swollman
151774462Salfred/*
151874462Salfred * This routine should take a pointer to an "rpc_err" structure, rather than
151974462Salfred * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
152074462Salfred * a CLIENT structure rather than a pointer to an "rpc_err" structure.
152174462Salfred * As such, we have to keep the CLIENT structure around in order to print
152274462Salfred * a good error message.
152374462Salfred */
152474462Salfredstatic int
152574462Salfredpstatus(register CLIENT *client, u_long prog, u_long vers)
152674462Salfred{
152774462Salfred	struct rpc_err rpcerr;
152874462Salfred
152974462Salfred	clnt_geterr(client, &rpcerr);
153074462Salfred	if (rpcerr.re_status != RPC_SUCCESS) {
153174462Salfred		clnt_perror(client, "rpcinfo");
153274462Salfred		printf("program %lu version %lu is not available\n",
153374462Salfred			prog, vers);
153474462Salfred		return (-1);
153574462Salfred	} else {
153674462Salfred		printf("program %lu version %lu ready and waiting\n",
153774462Salfred			prog, vers);
153874462Salfred		return (0);
153974462Salfred	}
154074462Salfred}
154174462Salfred
154274462Salfredstatic CLIENT *
154374462Salfredclnt_rpcbind_create(char *host, int rpcbversnum, struct netbuf **targaddr)
154474462Salfred{
1545221860Sdelphij	static const char *tlist[3] = {
154674462Salfred		"circuit_n", "circuit_v", "datagram_v"
154774462Salfred	};
154874462Salfred	int i;
154974462Salfred	struct netconfig *nconf;
155074462Salfred	CLIENT *clnt = NULL;
155174462Salfred	void *handle;
155274462Salfred
155374462Salfred	rpc_createerr.cf_stat = RPC_SUCCESS;
155474462Salfred	for (i = 0; i < 3; i++) {
155574462Salfred		if ((handle = __rpc_setconf(tlist[i])) == NULL)
155674462Salfred			continue;
155774462Salfred		while (clnt == (CLIENT *)NULL) {
155874462Salfred			if ((nconf = __rpc_getconf(handle)) == NULL) {
155974462Salfred				if (rpc_createerr.cf_stat == RPC_SUCCESS)
156074462Salfred				    rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
156174462Salfred				break;
156274462Salfred			}
156374462Salfred			clnt = getclnthandle(host, nconf, rpcbversnum,
156474462Salfred					targaddr);
156574462Salfred		}
156674462Salfred		if (clnt)
156774462Salfred			break;
156874462Salfred		__rpc_endconf(handle);
156974462Salfred	}
157074462Salfred	return (clnt);
157174462Salfred}
157274462Salfred
157374462Salfredstatic CLIENT*
157474462Salfredgetclnthandle(char *host, struct netconfig *nconf,
157574462Salfred    u_long rpcbversnum, struct netbuf **targaddr)
157674462Salfred{
157774462Salfred	struct netbuf addr;
157874462Salfred	struct addrinfo hints, *res;
157974462Salfred	CLIENT *client = NULL;
158074462Salfred
158174462Salfred	/* Get the address of the rpcbind */
158274462Salfred	memset(&hints, 0, sizeof hints);
158374462Salfred	if (getaddrinfo(host, "rpcbind", &hints, &res) != 0) {
158474462Salfred		rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
158574462Salfred		return (NULL);
158674462Salfred	}
158774462Salfred	addr.len = addr.maxlen = res->ai_addrlen;
158874462Salfred	addr.buf = res->ai_addr;
158974462Salfred	client = clnt_tli_create(RPC_ANYFD, nconf, &addr, RPCBPROG,
159074462Salfred			rpcbversnum, 0, 0);
159174462Salfred	if (client) {
159274462Salfred		if (targaddr != NULL) {
159374462Salfred			*targaddr =
159474462Salfred			    (struct netbuf *)malloc(sizeof (struct netbuf));
159574462Salfred			if (*targaddr != NULL) {
159674462Salfred				(*targaddr)->maxlen = addr.maxlen;
159774462Salfred				(*targaddr)->len = addr.len;
159874462Salfred				(*targaddr)->buf = (char *)malloc(addr.len);
159974462Salfred				if ((*targaddr)->buf != NULL) {
160074462Salfred					memcpy((*targaddr)->buf, addr.buf,
160174462Salfred						addr.len);
160274462Salfred				}
160374462Salfred			}
160474462Salfred		}
160574462Salfred	} else {
160674462Salfred		if (rpc_createerr.cf_stat == RPC_TLIERROR) {
160774462Salfred			/*
160874462Salfred			 * Assume that the other system is dead; this is a
160974462Salfred			 * better error to display to the user.
161074462Salfred			 */
161174462Salfred			rpc_createerr.cf_stat = RPC_RPCBFAILURE;
161274462Salfred			rpc_createerr.cf_error.re_status = RPC_FAILED;
161374462Salfred		}
161474462Salfred	}
161574462Salfred	freeaddrinfo(res);
161674462Salfred	return (client);
161774462Salfred}
161874462Salfred
16191900Swollmanstatic void
162074462Salfredprint_rmtcallstat(int rtype, rpcb_stat *infp)
16211900Swollman{
162274462Salfred	register rpcbs_rmtcalllist_ptr pr;
162374462Salfred	struct rpcent *rpc;
16241900Swollman
162574462Salfred	if (rtype == RPCBVERS_4_STAT)
162674462Salfred		printf(
162774462Salfred		"prog\t\tvers\tproc\tnetid\tindirect success failure\n");
162874462Salfred	else
162974462Salfred		printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n");
163074462Salfred	for (pr = infp->rmtinfo; pr; pr = pr->next) {
163174462Salfred		rpc = getrpcbynumber(pr->prog);
163274462Salfred		if (rpc)
163374462Salfred			printf("%-16s", rpc->r_name);
163474462Salfred		else
163574462Salfred			printf("%-16d", pr->prog);
163674462Salfred		printf("%d\t%d\t%s\t",
163774462Salfred			pr->vers, pr->proc, pr->netid);
163874462Salfred		if (rtype == RPCBVERS_4_STAT)
163974462Salfred			printf("%d\t ", pr->indirect);
164074462Salfred		printf("%d\t%d\n", pr->success, pr->failure);
16411900Swollman	}
16421900Swollman}
164374462Salfred
164474462Salfredstatic void
164574462Salfredprint_getaddrstat(int rtype, rpcb_stat *infp)
164674462Salfred{
164774462Salfred	rpcbs_addrlist_ptr al;
164874462Salfred	register struct rpcent *rpc;
164974462Salfred
165074462Salfred	printf("prog\t\tvers\tnetid\t  success\tfailure\n");
165174462Salfred	for (al = infp->addrinfo; al; al = al->next) {
165274462Salfred		rpc = getrpcbynumber(al->prog);
165374462Salfred		if (rpc)
165474462Salfred			printf("%-16s", rpc->r_name);
165574462Salfred		else
165674462Salfred			printf("%-16d", al->prog);
165774462Salfred		printf("%d\t%s\t  %-12d\t%d\n",
165874462Salfred			al->vers, al->netid,
165974462Salfred			al->success, al->failure);
166074462Salfred	}
166174462Salfred}
166274462Salfred
166374462Salfredstatic char *
166474462Salfredspaces(int howmany)
166574462Salfred{
166674462Salfred	static char space_array[] =		/* 64 spaces */
166774462Salfred	"                                                                ";
166874462Salfred
166974462Salfred	if (howmany <= 0 || howmany > sizeof (space_array)) {
167074462Salfred		return ("");
167174462Salfred	}
167274462Salfred	return (&space_array[sizeof (space_array) - howmany - 1]);
167374462Salfred}
1674