1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 *
21 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
22 * Use is subject to license terms.
23 */
24/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
25/* All Rights Reserved */
26/*
27 * University Copyright- Copyright (c) 1982, 1986, 1988
28 * The Regents of the University of California
29 * All Rights Reserved
30 *
31 * University Acknowledgment- Portions of this document are derived from
32 * software developed by the University of California, Berkeley, and its
33 * contributors.
34 */
35
36/*
37 * rpcinfo: ping a particular rpc program
38 * 	or dump the the registered programs on the remote machine.
39 */
40
41/*
42 * We are for now defining PORTMAP here.  It doesnt even compile
43 * unless it is defined.
44 */
45#ifndef	PORTMAP
46#define	PORTMAP
47#endif
48
49/*
50 * If PORTMAP is defined, rpcinfo will talk to both portmapper and
51 * rpcbind programs; else it talks only to rpcbind. In the latter case
52 * all the portmapper specific options such as -u, -t, -p become void.
53 */
54#include <rpc/rpc.h>
55#include <stdio.h>
56#include <rpc/rpcb_prot.h>
57#include <rpc/nettype.h>
58#include <netdir.h>
59#include <rpc/rpcent.h>
60#include <sys/utsname.h>
61#include <stdlib.h>
62#include <string.h>
63#include <ctype.h>
64
65#ifdef PORTMAP		/* Support for version 2 portmapper */
66#include <netinet/in.h>
67#include <sys/socket.h>
68#include <netdb.h>
69#include <arpa/inet.h>
70#include <rpc/pmap_prot.h>
71#include <rpc/pmap_clnt.h>
72#endif
73
74#define	MAXHOSTLEN	256
75#define	MIN_VERS	((ulong_t)0)
76#define	MAX_VERS	(4294967295UL)
77#define	UNKNOWN		"unknown"
78
79#define	MAX(a, b) (((a) > (b)) ? (a) : (b))
80
81extern int	t_errno;
82extern long	strtol();
83static char *spaces();
84
85#ifdef PORTMAP
86static void	ip_ping(/*ushort_t portflag, char *trans,
87				int argc, char **argv*/);
88static CLIENT	*clnt_com_create(/* struct sockaddr_in *addr, long prog,
89			long vers, int *fd, char *trans*/);
90static void	pmapdump(/*int argc, char **argv*/);
91static void	get_inet_address(/*struct sockaddr_in *addr, char *host*/);
92#endif
93
94static bool_t	reply_proc(/*void *res, struct netbuf *who*,
95			struct netconfig *nconf*/);
96static void	brdcst(/*int argc, char **argv*/);
97static void	addrping(/*char *address, char *netid,
98				int argc, char **argv*/);
99static void	progping(/* char *netid, int argc, char **argv*/);
100static CLIENT	*clnt_addr_create(/* char *addr, struct netconfig *nconf,
101				long prog, long vers*/);
102static CLIENT   *clnt_rpcbind_create(/* char *host, int vers */);
103static CLIENT   *getclnthandle(/* host, nconf, rpcbversnum */);
104static int	pstatus(/*CLIENT *client, ulong_t prognum, ulong_t vers*/);
105static void	rpcbdump(/*char *netid, int argc, char **argv*/);
106static void	rpcbgetstat(/* int argc, char **argv*/);
107static void	rpcbaddrlist(/*char *netid, int argc, char **argv*/);
108static void	deletereg(/*char *netid, int argc, char **argv */);
109static void	print_rmtcallstat(/* rtype, infp */);
110static void	print_getaddrstat(/* rtype, infp */);
111static void	usage(/*void*/);
112static ulong_t	getprognum(/*char *arg*/);
113static ulong_t	getvers(/*char *arg*/);
114
115/*
116 * Functions to be performed.
117 */
118#define	NONE		0	/* no function */
119#define	PMAPDUMP	1	/* dump portmapper registrations */
120#define	TCPPING		2	/* ping TCP service */
121#define	UDPPING		3	/* ping UDP service */
122#define	BROADCAST	4	/* ping broadcast service */
123#define	DELETES		5	/* delete registration for the service */
124#define	ADDRPING	6	/* pings at the given address */
125#define	PROGPING	7	/* pings a program on a given host */
126#define	RPCBDUMP	8	/* dump rpcbind registrations */
127#define	RPCBDUMP_SHORT	9	/* dump rpcbind registrations - short version */
128#define	RPCBADDRLIST	10	/* dump addr list about one prog */
129#define	RPCBGETSTAT	11	/* Get statistics */
130
131struct netidlist {
132	char *netid;
133	struct netidlist *next;
134};
135
136struct verslist {
137	int vers;
138	struct verslist *next;
139};
140
141struct rpcbdump_short {
142	ulong_t prog;
143	struct verslist *vlist;
144	struct netidlist *nlist;
145	struct rpcbdump_short *next;
146	char *owner;
147};
148
149
150char *loopback_netid = NULL;
151struct netconfig *loopback_nconf;
152
153int
154main(argc, argv)
155	int argc;
156	char **argv;
157{
158	register int c;
159	extern char *optarg;
160	extern int optind;
161	int errflg;
162	int function;
163	char *netid = NULL;
164	char *address = NULL;
165	void *handle;
166#ifdef PORTMAP
167	char *strptr;
168	ushort_t portnum = 0;
169#endif
170
171	function = NONE;
172	errflg = 0;
173#ifdef PORTMAP
174	while ((c = getopt(argc, argv, "a:bdlmn:pstT:u")) != EOF) {
175#else
176	while ((c = getopt(argc, argv, "a:bdlmn:sT:")) != EOF) {
177#endif
178		switch (c) {
179#ifdef PORTMAP
180		case 'p':
181			if (function != NONE)
182				errflg = 1;
183			else
184				function = PMAPDUMP;
185			break;
186
187		case 't':
188			if (function != NONE)
189				errflg = 1;
190			else
191				function = TCPPING;
192			break;
193
194		case 'u':
195			if (function != NONE)
196				errflg = 1;
197			else
198				function = UDPPING;
199			break;
200
201		case 'n':
202			portnum = (ushort_t)strtol(optarg, &strptr, 10);
203			if (strptr == optarg || *strptr != '\0') {
204				(void) fprintf(stderr,
205			"rpcinfo: %s is illegal port number\n",
206					optarg);
207				exit(1);
208			}
209			break;
210#endif
211		case 'a':
212			address = optarg;
213			if (function != NONE)
214				errflg = 1;
215			else
216				function = ADDRPING;
217			break;
218		case 'b':
219			if (function != NONE)
220				errflg = 1;
221			else
222				function = BROADCAST;
223			break;
224
225		case 'd':
226			if (function != NONE)
227				errflg = 1;
228			else
229				function = DELETES;
230			break;
231
232		case 'l':
233			if (function != NONE)
234				errflg = 1;
235			else
236				function = RPCBADDRLIST;
237			break;
238
239		case 'm':
240			if (function != NONE)
241				errflg = 1;
242			else
243				function = RPCBGETSTAT;
244			break;
245
246		case 's':
247			if (function != NONE)
248				errflg = 1;
249			else
250				function = RPCBDUMP_SHORT;
251			break;
252
253		case 'T':
254			netid = optarg;
255			break;
256		case '?':
257			errflg = 1;
258			break;
259		}
260	}
261
262	if (errflg || ((function == ADDRPING) && !netid)) {
263		usage();
264		return (1);
265	}
266	if (netid == NULL) {	/* user has not selected transport to use */
267		/*
268		 * See if a COTS loopback transport is available, in case we
269		 * will be talking to the local system.
270		 */
271		handle = setnetconfig();
272		while ((loopback_nconf = getnetconfig(handle)) != NULL) {
273			if (strcmp(loopback_nconf->nc_protofmly,
274				NC_LOOPBACK) == 0 &&
275			    (loopback_nconf->nc_semantics == NC_TPI_COTS ||
276			    loopback_nconf->nc_semantics == NC_TPI_COTS_ORD)) {
277				loopback_netid = loopback_nconf->nc_netid;
278				break;
279			}
280		}
281		if (loopback_netid == NULL) {
282			(void) endnetconfig(handle);
283		}
284	}
285	if (function == NONE) {
286		if (argc - optind > 1)
287			function = PROGPING;
288		else
289			function = RPCBDUMP;
290	}
291
292	switch (function) {
293#ifdef PORTMAP
294	case PMAPDUMP:
295		if (portnum != 0) {
296			usage();
297			return (1);
298		}
299		pmapdump(argc - optind, argv + optind);
300		break;
301
302	case UDPPING:
303		ip_ping(portnum, "udp", argc - optind, argv + optind);
304		break;
305
306	case TCPPING:
307		ip_ping(portnum, "tcp", argc - optind, argv + optind);
308		break;
309#endif
310	case BROADCAST:
311		brdcst(argc - optind, argv + optind);
312		break;
313	case DELETES:
314		deletereg(netid, argc - optind, argv + optind);
315		break;
316	case ADDRPING:
317		addrping(address, netid, argc - optind, argv + optind);
318		break;
319	case PROGPING:
320		progping(netid, argc - optind, argv + optind);
321		break;
322	case RPCBDUMP:
323	case RPCBDUMP_SHORT:
324		rpcbdump(function, netid, argc - optind, argv + optind);
325		break;
326	case RPCBGETSTAT:
327		rpcbgetstat(argc - optind, argv + optind);
328		break;
329	case RPCBADDRLIST:
330		rpcbaddrlist(netid, argc - optind, argv + optind);
331		break;
332	}
333	return (0);
334}
335
336#ifdef PORTMAP
337static CLIENT *
338clnt_com_create(addr, prog, vers, fdp, trans)
339	struct sockaddr_in *addr;
340	ulong_t prog;
341	ulong_t vers;
342	int *fdp;
343	char *trans;
344{
345	CLIENT *clnt;
346
347	if (strcmp(trans, "tcp") == 0) {
348		clnt = clnttcp_create(addr, prog, vers, fdp, 0, 0);
349	} else {
350		struct timeval to;
351
352		to.tv_sec = 5;
353		to.tv_usec = 0;
354		clnt = clntudp_create(addr, prog, vers, to, fdp);
355	}
356	if (clnt == (CLIENT *)NULL) {
357		clnt_pcreateerror("rpcinfo");
358		if (vers == MIN_VERS)
359			(void) printf("program %lu is not available\n", prog);
360		else
361			(void) printf(
362				"program %lu version %lu is not available\n",
363							prog, vers);
364		exit(1);
365	}
366	return (clnt);
367}
368
369/*
370 * If portnum is 0, then go and get the address from portmapper, which happens
371 * transparently through clnt*_create(); If version number is not given, it
372 * tries to find out the version number by making a call to version 0 and if
373 * that fails, it obtains the high order and the low order version number. If
374 * version 0 calls succeeds, it tries for MAXVERS call and repeats the same.
375 */
376static void
377ip_ping(portnum, trans, argc, argv)
378	ushort_t portnum;
379	char *trans;
380	int argc;
381	char **argv;
382{
383	CLIENT *client;
384	int fd = RPC_ANYFD;
385	struct timeval to;
386	struct sockaddr_in addr;
387	enum clnt_stat rpc_stat;
388	ulong_t prognum, vers, minvers, maxvers;
389	struct rpc_err rpcerr;
390	int failure = 0;
391
392	if (argc < 2 || argc > 3) {
393		usage();
394		exit(1);
395	}
396	to.tv_sec = 10;
397	to.tv_usec = 0;
398	prognum = getprognum(argv[1]);
399	get_inet_address(&addr, argv[0]);
400	if (argc == 2) {	/* Version number not known */
401		/*
402		 * A call to version 0 should fail with a program/version
403		 * mismatch, and give us the range of versions supported.
404		 */
405		vers = MIN_VERS;
406	} else {
407		vers = getvers(argv[2]);
408	}
409	addr.sin_port = htons(portnum);
410	client = clnt_com_create(&addr, prognum, vers, &fd, trans);
411	rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
412			(char *)NULL, (xdrproc_t)xdr_void, (char *)NULL,
413			to);
414	if (argc != 2) {
415		/* Version number was known */
416		if (pstatus(client, prognum, vers) < 0)
417			exit(1);
418		(void) CLNT_DESTROY(client);
419		return;
420	}
421	/* Version number not known */
422	(void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL);
423	if (rpc_stat == RPC_PROGVERSMISMATCH) {
424		clnt_geterr(client, &rpcerr);
425		minvers = rpcerr.re_vers.low;
426		maxvers = rpcerr.re_vers.high;
427	} else if (rpc_stat == RPC_SUCCESS) {
428		/*
429		 * Oh dear, it DOES support version 0.
430		 * Let's try version MAX_VERS.
431		 */
432		(void) CLNT_DESTROY(client);
433		addr.sin_port = htons(portnum);
434		client = clnt_com_create(&addr, prognum, MAX_VERS, &fd, trans);
435		rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
436				(char *)NULL, (xdrproc_t)xdr_void,
437				(char *)NULL, to);
438		if (rpc_stat == RPC_PROGVERSMISMATCH) {
439			clnt_geterr(client, &rpcerr);
440			minvers = rpcerr.re_vers.low;
441			maxvers = rpcerr.re_vers.high;
442		} else if (rpc_stat == RPC_SUCCESS) {
443			/*
444			 * It also supports version MAX_VERS.
445			 * Looks like we have a wise guy.
446			 * OK, we give them information on all
447			 * 4 billion versions they support...
448			 */
449			minvers = 0;
450			maxvers = MAX_VERS;
451		} else {
452			(void) pstatus(client, prognum, MAX_VERS);
453			exit(1);
454		}
455	} else {
456		(void) pstatus(client, prognum, (ulong_t)0);
457		exit(1);
458	}
459	(void) CLNT_DESTROY(client);
460	for (vers = minvers; vers <= maxvers; vers++) {
461		addr.sin_port = htons(portnum);
462		client = clnt_com_create(&addr, prognum, vers, &fd, trans);
463		rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
464				(char *)NULL, (xdrproc_t)xdr_void,
465				(char *)NULL, to);
466		if (pstatus(client, prognum, vers) < 0)
467				failure = 1;
468		(void) CLNT_DESTROY(client);
469	}
470	if (failure)
471		exit(1);
472	(void) t_close(fd);
473}
474
475/*
476 * Dump all the portmapper registerations
477 */
478static void
479pmapdump(argc, argv)
480	int argc;
481	char **argv;
482{
483	struct sockaddr_in server_addr;
484	pmaplist_ptr head = NULL;
485	int socket = RPC_ANYSOCK;
486	struct timeval minutetimeout;
487	register CLIENT *client;
488	struct rpcent *rpc;
489	enum clnt_stat clnt_st;
490	struct rpc_err err;
491	struct utsname utsname;
492	char *host;
493
494	if (argc > 1) {
495		usage();
496		exit(1);
497	}
498	if (argc == 1) {
499		host = argv[0];
500		get_inet_address(&server_addr, host);
501	} else {
502		(void) uname(&utsname);
503		host = utsname.nodename;
504		get_inet_address(&server_addr, host);
505	}
506	minutetimeout.tv_sec = 60;
507	minutetimeout.tv_usec = 0;
508	server_addr.sin_port = htons(PMAPPORT);
509	if ((client = clnttcp_create(&server_addr, PMAPPROG,
510		PMAPVERS, &socket, 50, 500)) == NULL) {
511		if (rpc_createerr.cf_stat == RPC_TLIERROR) {
512			/*
513			 * "Misc. TLI error" is not too helpful. Most likely
514			 * the connection to the remote server timed out, so
515			 * this error is at least less perplexing.
516			 */
517			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
518			rpc_createerr.cf_error.re_status = RPC_FAILED;
519		}
520		clnt_pcreateerror("rpcinfo: can't contact portmapper");
521		exit(1);
522	}
523	clnt_st = CLNT_CALL(client, PMAPPROC_DUMP, (xdrproc_t)xdr_void,
524		NULL, (xdrproc_t)xdr_pmaplist_ptr, (char *)&head,
525		minutetimeout);
526	if (clnt_st != RPC_SUCCESS) {
527		if ((clnt_st == RPC_PROGVERSMISMATCH) ||
528		    (clnt_st == RPC_PROGUNAVAIL)) {
529			CLNT_GETERR(client, &err);
530			if (err.re_vers.low > PMAPVERS)
531				(void) fprintf(stderr,
532		"%s does not support portmapper.  Try rpcinfo %s instead\n",
533					host, host);
534			exit(1);
535		}
536		clnt_perror(client, "rpcinfo: can't contact portmapper");
537		exit(1);
538	}
539	if (head == NULL) {
540		(void) printf("No remote programs registered.\n");
541	} else {
542		(void) printf("   program vers proto   port  service\n");
543		for (; head != NULL; head = head->pml_next) {
544			(void) printf("%10ld%5ld",
545				head->pml_map.pm_prog,
546				head->pml_map.pm_vers);
547			if (head->pml_map.pm_prot == IPPROTO_UDP)
548				(void) printf("%6s", "udp");
549			else if (head->pml_map.pm_prot == IPPROTO_TCP)
550				(void) printf("%6s", "tcp");
551			else
552				(void) printf("%6ld", head->pml_map.pm_prot);
553			(void) printf("%7ld", head->pml_map.pm_port);
554			rpc = getrpcbynumber(head->pml_map.pm_prog);
555			if (rpc)
556				(void) printf("  %s\n", rpc->r_name);
557			else
558				(void) printf("\n");
559		}
560	}
561}
562
563static void
564get_inet_address(addr, host)
565	struct sockaddr_in *addr;
566	char *host;
567{
568	struct netconfig *nconf;
569	struct nd_hostserv service;
570	struct nd_addrlist *naddrs;
571
572	(void) memset((char *)addr, 0, sizeof (*addr));
573	addr->sin_addr.s_addr = inet_addr(host);
574	if (addr->sin_addr.s_addr == (uint32_t)-1 ||
575	    addr->sin_addr.s_addr == 0) {
576		if ((nconf = __rpc_getconfip("udp")) == NULL &&
577		    (nconf = __rpc_getconfip("tcp")) == NULL) {
578			(void) fprintf(stderr,
579			"rpcinfo: couldn't find a suitable transport\n");
580			exit(1);
581		} else {
582			service.h_host = host;
583			service.h_serv = "rpcbind";
584			if (netdir_getbyname(nconf, &service, &naddrs)) {
585				(void) fprintf(stderr, "rpcinfo: %s: %s\n",
586						host, netdir_sperror());
587				exit(1);
588			} else {
589				(void) memcpy((caddr_t)addr,
590				    naddrs->n_addrs->buf, naddrs->n_addrs->len);
591				(void) netdir_free((char *)naddrs, ND_ADDRLIST);
592			}
593			(void) freenetconfigent(nconf);
594		}
595	} else {
596		addr->sin_family = AF_INET;
597	}
598}
599#endif /* PORTMAP */
600
601/*
602 * reply_proc collects replies from the broadcast.
603 * to get a unique list of responses the output of rpcinfo should
604 * be piped through sort(1) and then uniq(1).
605 */
606
607/*ARGSUSED*/
608static bool_t
609reply_proc(res, who, nconf)
610	void *res;		/* Nothing comes back */
611	struct netbuf *who;	/* Who sent us the reply */
612	struct netconfig *nconf; /* On which transport the reply came */
613{
614	struct nd_hostservlist *serv;
615	char *uaddr;
616	char *hostname;
617
618	if (netdir_getbyaddr(nconf, &serv, who)) {
619		hostname = UNKNOWN;
620	} else {
621		hostname = serv->h_hostservs->h_host;
622	}
623	if (!(uaddr = taddr2uaddr(nconf, who))) {
624		uaddr = UNKNOWN;
625	}
626	(void) printf("%s\t%s\n", uaddr, hostname);
627	if (strcmp(hostname, UNKNOWN))
628		netdir_free((char *)serv, ND_HOSTSERVLIST);
629	if (strcmp(uaddr, UNKNOWN))
630		free((char *)uaddr);
631	return (FALSE);
632}
633
634static void
635brdcst(argc, argv)
636	int argc;
637	char **argv;
638{
639	enum clnt_stat rpc_stat;
640	ulong_t prognum, vers;
641
642	if (argc != 2) {
643		usage();
644		exit(1);
645	}
646	prognum = getprognum(argv[0]);
647	vers = getvers(argv[1]);
648	rpc_stat = rpc_broadcast(prognum, vers, NULLPROC,
649		(xdrproc_t)xdr_void, (char *)NULL, (xdrproc_t)xdr_void,
650		(char *)NULL, (resultproc_t)reply_proc, NULL);
651	if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
652		(void) fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
653			clnt_sperrno(rpc_stat));
654		exit(1);
655	}
656	exit(0);
657}
658
659static bool_t
660add_version(rs, vers)
661	struct rpcbdump_short *rs;
662	ulong_t vers;
663{
664	struct verslist *vl;
665
666	for (vl = rs->vlist; vl; vl = vl->next)
667		if (vl->vers == vers)
668			break;
669	if (vl)
670		return (TRUE);
671	vl = (struct verslist *)malloc(sizeof (struct verslist));
672	if (vl == NULL)
673		return (FALSE);
674	vl->vers = vers;
675	vl->next = rs->vlist;
676	rs->vlist = vl;
677	return (TRUE);
678}
679
680static bool_t
681add_netid(rs, netid)
682	struct rpcbdump_short *rs;
683	char *netid;
684{
685	struct netidlist *nl;
686
687	for (nl = rs->nlist; nl; nl = nl->next)
688		if (strcmp(nl->netid, netid) == 0)
689			break;
690	if (nl)
691		return (TRUE);
692	nl = (struct netidlist *)malloc(sizeof (struct netidlist));
693	if (nl == NULL)
694		return (FALSE);
695	nl->netid = netid;
696	nl->next = rs->nlist;
697	rs->nlist = nl;
698	return (TRUE);
699}
700
701static void
702rpcbdump(dumptype, netid, argc, argv)
703	int dumptype;
704	char *netid;
705	int argc;
706	char **argv;
707{
708	rpcblist_ptr head = NULL;
709	struct timeval minutetimeout;
710	register CLIENT *client;
711	struct rpcent *rpc;
712	char *host;
713	struct netidlist *nl;
714	struct verslist *vl;
715	struct rpcbdump_short *rs, *rs_tail;
716	enum clnt_stat clnt_st;
717	struct rpc_err err;
718	struct utsname utsname;
719	struct rpcbdump_short *rs_head = NULL;
720
721	if (argc > 1) {
722		usage();
723		exit(1);
724	}
725	if (argc == 1) {
726		host = argv[0];
727	} else {
728		(void) uname(&utsname);
729		host = utsname.nodename;
730	}
731	if (netid == NULL) {
732	    if (loopback_netid == NULL) {
733		client = clnt_rpcbind_create(host, RPCBVERS, NULL);
734	    } else {
735		client = getclnthandle(host, loopback_nconf, RPCBVERS, NULL);
736		if (client == NULL && rpc_createerr.cf_stat ==
737				RPC_N2AXLATEFAILURE) {
738			client = clnt_rpcbind_create(host, RPCBVERS, NULL);
739		}
740	    }
741	} else {
742		struct netconfig *nconf;
743
744		nconf = getnetconfigent(netid);
745		if (nconf == NULL) {
746			nc_perror("rpcinfo: invalid transport");
747			exit(1);
748		}
749		client = getclnthandle(host, nconf, RPCBVERS, NULL);
750		if (nconf)
751			(void) freenetconfigent(nconf);
752	}
753	if (client == (CLIENT *)NULL) {
754		clnt_pcreateerror("rpcinfo: can't contact rpcbind");
755		exit(1);
756	}
757	minutetimeout.tv_sec = 60;
758	minutetimeout.tv_usec = 0;
759	clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t)xdr_void,
760		NULL, (xdrproc_t)xdr_rpcblist_ptr, (char *)&head,
761		minutetimeout);
762	if (clnt_st != RPC_SUCCESS) {
763	    if ((clnt_st == RPC_PROGVERSMISMATCH) ||
764		(clnt_st == RPC_PROGUNAVAIL)) {
765		int vers;
766
767		CLNT_GETERR(client, &err);
768		if (err.re_vers.low == RPCBVERS4) {
769		    vers = RPCBVERS4;
770		    clnt_control(client, CLSET_VERS, (char *)&vers);
771		    clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
772			(xdrproc_t)xdr_void, NULL,
773			(xdrproc_t)xdr_rpcblist_ptr, (char *)&head,
774			minutetimeout);
775		    if (clnt_st != RPC_SUCCESS)
776			goto failed;
777		} else {
778		    if (err.re_vers.high == PMAPVERS) {
779			int high, low;
780			pmaplist_ptr pmaphead = NULL;
781			rpcblist_ptr list, prev = NULL;
782
783			vers = PMAPVERS;
784			clnt_control(client, CLSET_VERS, (char *)&vers);
785			clnt_st = CLNT_CALL(client, PMAPPROC_DUMP,
786				(xdrproc_t)xdr_void, NULL,
787				(xdrproc_t)xdr_pmaplist_ptr,
788				(char *)&pmaphead, minutetimeout);
789			if (clnt_st != RPC_SUCCESS)
790				goto failed;
791			/*
792			 * convert to rpcblist_ptr format
793			 */
794			for (head = NULL; pmaphead != NULL;
795				pmaphead = pmaphead->pml_next) {
796			    list = (rpcblist *)malloc(sizeof (rpcblist));
797			    if (list == NULL)
798				goto error;
799			    if (head == NULL)
800				head = list;
801			    else
802				prev->rpcb_next = (rpcblist_ptr) list;
803
804			    list->rpcb_next = NULL;
805			    list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog;
806			    list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers;
807			    if (pmaphead->pml_map.pm_prot == IPPROTO_UDP)
808				list->rpcb_map.r_netid = "udp";
809			    else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP)
810				list->rpcb_map.r_netid = "tcp";
811			    else {
812#define	MAXLONG_AS_STRING	"2147483648"
813				list->rpcb_map.r_netid =
814					malloc(strlen(MAXLONG_AS_STRING) + 1);
815				if (list->rpcb_map.r_netid == NULL)
816					goto error;
817				(void) sprintf(list->rpcb_map.r_netid, "%6ld",
818					pmaphead->pml_map.pm_prot);
819			    }
820			    list->rpcb_map.r_owner = UNKNOWN;
821			    low = pmaphead->pml_map.pm_port & 0xff;
822			    high = (pmaphead->pml_map.pm_port >> 8) & 0xff;
823			    list->rpcb_map.r_addr = strdup("0.0.0.0.XXX.XXX");
824			    (void) sprintf(&list->rpcb_map.r_addr[8], "%d.%d",
825				high, low);
826			    prev = list;
827			}
828		    }
829		}
830	    } else {	/* any other error */
831failed:
832		    clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
833		    exit(1);
834	    }
835	}
836	if (head == NULL) {
837		(void) printf("No remote programs registered.\n");
838	} else if (dumptype == RPCBDUMP) {
839		(void) printf(
840"   program version netid     address             service    owner\n");
841		for (; head != NULL; head = head->rpcb_next) {
842			(void) printf("%10ld%5ld    ",
843				head->rpcb_map.r_prog, head->rpcb_map.r_vers);
844			(void) printf("%-9s ", head->rpcb_map.r_netid);
845			(void) printf("%-19s", head->rpcb_map.r_addr);
846			rpc = getrpcbynumber(head->rpcb_map.r_prog);
847			if (rpc)
848				(void) printf(" %-10s", rpc->r_name);
849			else
850				(void) printf(" %-10s", "-");
851			(void) printf(" %s\n", head->rpcb_map.r_owner);
852		}
853	} else if (dumptype == RPCBDUMP_SHORT) {
854		for (; head != NULL; head = head->rpcb_next) {
855			for (rs = rs_head; rs; rs = rs->next)
856				if (head->rpcb_map.r_prog == rs->prog)
857					break;
858			if (rs == NULL) {
859				rs = (struct rpcbdump_short *)
860					malloc(sizeof (struct rpcbdump_short));
861				if (rs == NULL)
862					goto error;
863				rs->next = NULL;
864				if (rs_head == NULL) {
865					rs_head = rs;
866					rs_tail = rs;
867				} else {
868					rs_tail->next = rs;
869					rs_tail = rs;
870				}
871				rs->prog = head->rpcb_map.r_prog;
872				rs->owner = head->rpcb_map.r_owner;
873				rs->nlist = NULL;
874				rs->vlist = NULL;
875			}
876			if (add_version(rs, head->rpcb_map.r_vers) == FALSE)
877				goto error;
878			if (add_netid(rs, head->rpcb_map.r_netid) == FALSE)
879				goto error;
880		}
881		(void) printf(
882"   program version(s) netid(s)                         service     owner\n");
883		for (rs = rs_head; rs; rs = rs->next) {
884			int bytes_trans = 0;
885			int len;
886
887			(void) printf("%10ld  ", rs->prog);
888			for (vl = rs->vlist; vl; vl = vl->next) {
889				bytes_trans += (len = printf("%d", vl->vers))
890				    < 0 ? 0 : len;
891				if (vl->next)
892					bytes_trans += (len = printf(",")) < 0
893					    ? 0 : len;
894			}
895			/*
896			 * If number of bytes transferred is less than 10,
897			 * align 10 bytes for version(s) column. If bytes
898			 * transferred is more than 10, add a trailing white
899			 * space.
900			 */
901			if (bytes_trans < 10)
902				(void) printf("%*s", (bytes_trans - 10), " ");
903			else
904				(void) printf(" ");
905
906			bytes_trans = 0;
907			for (nl = rs->nlist; nl; nl = nl->next) {
908				bytes_trans += (len = printf("%s", nl->netid))
909				    < 0 ? 0 : len;
910				if (nl->next)
911					bytes_trans += (len = printf(",")) < 0
912					    ? 0 : len;
913			}
914			/*
915			 * Align netid(s) column output for 32 bytes.
916			 */
917			if (bytes_trans < 32)
918				(void) printf("%*s", (bytes_trans - 32), " ");
919
920			rpc = getrpcbynumber(rs->prog);
921			if (rpc)
922				(void) printf(" %-11s", rpc->r_name);
923			else
924				(void) printf(" %-11s", "-");
925			(void) printf(" %s\n", rs->owner);
926		}
927	}
928	clnt_destroy(client);
929	return;
930
931error:	(void) fprintf(stderr, "rpcinfo: no memory\n");
932}
933
934static char nullstring[] = "\000";
935
936static void
937rpcbaddrlist(netid, argc, argv)
938	char *netid;
939	int argc;
940	char **argv;
941{
942	rpcb_entry_list_ptr head = NULL;
943	struct timeval minutetimeout;
944	register CLIENT *client;
945	struct rpcent *rpc;
946	char *host;
947	RPCB parms;
948	struct netbuf *targaddr;
949
950	if (argc != 3) {
951		usage();
952		exit(1);
953	}
954	host = argv[0];
955	if (netid == NULL) {
956	    if (loopback_netid == NULL) {
957		client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr);
958	    } else {
959		client = getclnthandle(host, loopback_nconf, RPCBVERS4,
960			&targaddr);
961		if (client == NULL && rpc_createerr.cf_stat ==
962				RPC_N2AXLATEFAILURE) {
963		    client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr);
964		}
965	    }
966	} else {
967		struct netconfig *nconf;
968
969		nconf = getnetconfigent(netid);
970		if (nconf == NULL) {
971			nc_perror("rpcinfo: invalid transport");
972			exit(1);
973		}
974		client = getclnthandle(host, nconf, RPCBVERS4, &targaddr);
975		if (nconf)
976			(void) freenetconfigent(nconf);
977	}
978	if (client == (CLIENT *)NULL) {
979		clnt_pcreateerror("rpcinfo: can't contact rpcbind");
980		exit(1);
981	}
982	minutetimeout.tv_sec = 60;
983	minutetimeout.tv_usec = 0;
984
985	parms.r_prog = 	getprognum(argv[1]);
986	parms.r_vers = 	getvers(argv[2]);
987	parms.r_netid = client->cl_netid;
988	if (targaddr == NULL) {
989		parms.r_addr = nullstring;	/* for XDRing */
990	} else {
991		/*
992		 * We also send the remote system the address we
993		 * used to contact it in case it can help it
994		 * connect back with us
995		 */
996		struct netconfig *nconf;
997
998		nconf = getnetconfigent(client->cl_netid);
999		if (nconf != NULL) {
1000			parms.r_addr = taddr2uaddr(nconf, targaddr);
1001			if (parms.r_addr == NULL)
1002				parms.r_addr = nullstring;
1003			freenetconfigent(nconf);
1004		} else {
1005			parms.r_addr = nullstring;	/* for XDRing */
1006		}
1007		free(targaddr->buf);
1008		free(targaddr);
1009	}
1010	parms.r_owner = nullstring;
1011
1012	if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t)xdr_rpcb,
1013		(char *)&parms, (xdrproc_t)xdr_rpcb_entry_list_ptr,
1014		(char *)&head, minutetimeout) != RPC_SUCCESS) {
1015		clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
1016		exit(1);
1017	}
1018	if (head == NULL) {
1019		(void) printf("No remote programs registered.\n");
1020	} else {
1021		(void) printf(
1022	"   program vers  tp_family/name/class    address\t\t  service\n");
1023		for (; head != NULL; head = head->rpcb_entry_next) {
1024			rpcb_entry *re;
1025			char buf[128];
1026
1027			re = &head->rpcb_entry_map;
1028			(void) printf("%10ld%3ld    ",
1029				parms.r_prog, parms.r_vers);
1030			(void) snprintf(buf, sizeof (buf), "%s/%s/%s ",
1031				re->r_nc_protofmly, re->r_nc_proto,
1032				re->r_nc_semantics == NC_TPI_CLTS ? "clts" :
1033				re->r_nc_semantics == NC_TPI_COTS ? "cots" :
1034						"cots_ord");
1035			(void) printf("%-24s", buf);
1036			(void) printf("%-24s", re->r_maddr);
1037			rpc = getrpcbynumber(parms.r_prog);
1038			if (rpc)
1039				(void) printf(" %-13s", rpc->r_name);
1040			else
1041				(void) printf(" %-13s", "-");
1042			(void) printf("\n");
1043		}
1044	}
1045	clnt_destroy(client);
1046}
1047
1048/*
1049 * monitor rpcbind
1050 */
1051static void
1052rpcbgetstat(argc, argv)
1053	int argc;
1054	char **argv;
1055{
1056	rpcb_stat_byvers inf;
1057	struct timeval minutetimeout;
1058	register CLIENT *client;
1059	char *host;
1060	int i, j;
1061	rpcbs_addrlist *pa;
1062	rpcbs_rmtcalllist *pr;
1063	int cnt, flen;
1064	struct utsname utsname;
1065#define	MAXFIELD	64
1066	char fieldbuf[MAXFIELD];
1067#define	MAXLINE		256
1068	char linebuf[MAXLINE];
1069	char *cp, *lp;
1070	char *pmaphdr[] = {
1071		"NULL", "SET", "UNSET", "GETPORT",
1072		"DUMP", "CALLIT"
1073	};
1074	char *rpcb3hdr[] = {
1075		"NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1076		"U2T", "T2U"
1077	};
1078	char *rpcb4hdr[] = {
1079		"NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1080		"U2T",  "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT"
1081	};
1082
1083#define	TABSTOP	8
1084
1085	if (argc >= 1) {
1086		host = argv[0];
1087	} else {
1088		(void) uname(&utsname);
1089		host = utsname.nodename;
1090	}
1091	if (loopback_netid != NULL) {
1092		client = getclnthandle(host, loopback_nconf, RPCBVERS4, NULL);
1093		if (client == NULL && rpc_createerr.cf_stat ==
1094				RPC_N2AXLATEFAILURE) {
1095			client = clnt_rpcbind_create(host, RPCBVERS4, NULL);
1096		}
1097	} else {
1098		client = clnt_rpcbind_create(host, RPCBVERS4, NULL);
1099	}
1100	if (client == (CLIENT *)NULL) {
1101		clnt_pcreateerror("rpcinfo: can't contact rpcbind");
1102		exit(1);
1103	}
1104	minutetimeout.tv_sec = 60;
1105	minutetimeout.tv_usec = 0;
1106	(void) memset((char *)&inf, 0, sizeof (rpcb_stat_byvers));
1107	if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t)xdr_void, NULL,
1108		(xdrproc_t)xdr_rpcb_stat_byvers, (char *)&inf, minutetimeout)
1109			!= RPC_SUCCESS) {
1110		clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
1111		exit(1);
1112	}
1113	(void) printf("PORTMAP (version 2) statistics\n");
1114	lp = linebuf;
1115	for (i = 0; i <= rpcb_highproc_2; i++) {
1116		fieldbuf[0] = '\0';
1117		switch (i) {
1118		case PMAPPROC_SET:
1119			(void) sprintf(fieldbuf, "%d/",
1120				inf[RPCBVERS_2_STAT].setinfo);
1121			break;
1122		case PMAPPROC_UNSET:
1123			(void) sprintf(fieldbuf, "%d/",
1124				inf[RPCBVERS_2_STAT].unsetinfo);
1125			break;
1126		case PMAPPROC_GETPORT:
1127			cnt = 0;
1128			for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa;
1129				pa = pa->next)
1130				cnt += pa->success;
1131			(void) sprintf(fieldbuf, "%d/", cnt);
1132			break;
1133		case PMAPPROC_CALLIT:
1134			cnt = 0;
1135			for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr;
1136				pr = pr->next)
1137				cnt += pr->success;
1138			(void) sprintf(fieldbuf, "%d/", cnt);
1139			break;
1140		default: break;  /* For the remaining ones */
1141		}
1142		cp = &fieldbuf[0] + strlen(fieldbuf);
1143		(void) sprintf(cp, "%d", inf[RPCBVERS_2_STAT].info[i]);
1144		flen = strlen(fieldbuf);
1145		(void) printf("%s%s", pmaphdr[i],
1146			spaces((int)((TABSTOP * (1 + flen / TABSTOP))
1147			- strlen(pmaphdr[i]))));
1148		(void) snprintf(lp, (MAXLINE - (lp - linebuf)), "%s%s",
1149			fieldbuf, spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1150			- flen)));
1151		lp += (flen + cnt);
1152	}
1153	(void) printf("\n%s\n\n", linebuf);
1154
1155	if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) {
1156		(void) printf("PMAP_RMTCALL call statistics\n");
1157		print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1158		(void) printf("\n");
1159	}
1160
1161	if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) {
1162		(void) printf("PMAP_GETPORT call statistics\n");
1163		print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1164		(void) printf("\n");
1165	}
1166
1167	(void) printf("RPCBIND (version 3) statistics\n");
1168	lp = linebuf;
1169	for (i = 0; i <= rpcb_highproc_3; i++) {
1170		fieldbuf[0] = '\0';
1171		switch (i) {
1172		case RPCBPROC_SET:
1173			(void) sprintf(fieldbuf, "%d/",
1174				inf[RPCBVERS_3_STAT].setinfo);
1175			break;
1176		case RPCBPROC_UNSET:
1177			(void) sprintf(fieldbuf, "%d/",
1178				inf[RPCBVERS_3_STAT].unsetinfo);
1179			break;
1180		case RPCBPROC_GETADDR:
1181			cnt = 0;
1182			for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa;
1183				pa = pa->next)
1184				cnt += pa->success;
1185			(void) sprintf(fieldbuf, "%d/", cnt);
1186			break;
1187		case RPCBPROC_CALLIT:
1188			cnt = 0;
1189			for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr;
1190				pr = pr->next)
1191				cnt += pr->success;
1192			(void) sprintf(fieldbuf, "%d/", cnt);
1193			break;
1194		default: break;  /* For the remaining ones */
1195		}
1196		cp = &fieldbuf[0] + strlen(fieldbuf);
1197		(void) sprintf(cp, "%d", inf[RPCBVERS_3_STAT].info[i]);
1198		flen = strlen(fieldbuf);
1199		(void) printf("%s%s", rpcb3hdr[i],
1200			spaces((int)((TABSTOP * (1 + flen / TABSTOP))
1201			- strlen(rpcb3hdr[i]))));
1202		(void) snprintf(lp, (MAXLINE - (lp - linebuf)), "%s%s",
1203			fieldbuf, spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1204			- flen)));
1205		lp += (flen + cnt);
1206	}
1207	(void) printf("\n%s\n\n", linebuf);
1208
1209	if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) {
1210		(void) printf("RPCB_RMTCALL (version 3) call statistics\n");
1211		print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1212		(void) printf("\n");
1213	}
1214
1215	if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) {
1216		(void) printf("RPCB_GETADDR (version 3) call statistics\n");
1217		print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1218		(void) printf("\n");
1219	}
1220
1221	(void) printf("RPCBIND (version 4) statistics\n");
1222
1223	for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */
1224		lp = linebuf;
1225		for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) {
1226			fieldbuf[0] = '\0';
1227			switch (i) {
1228			case RPCBPROC_SET:
1229				(void) sprintf(fieldbuf, "%d/",
1230					inf[RPCBVERS_4_STAT].setinfo);
1231				break;
1232			case RPCBPROC_UNSET:
1233				(void) sprintf(fieldbuf, "%d/",
1234					inf[RPCBVERS_4_STAT].unsetinfo);
1235				break;
1236			case RPCBPROC_GETADDR:
1237				cnt = 0;
1238				for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa;
1239					pa = pa->next)
1240					cnt += pa->success;
1241				(void) sprintf(fieldbuf, "%d/", cnt);
1242				break;
1243			case RPCBPROC_CALLIT:
1244				cnt = 0;
1245				for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr;
1246					pr = pr->next)
1247					cnt += pr->success;
1248				(void) sprintf(fieldbuf, "%d/", cnt);
1249				break;
1250			default: break;  /* For the remaining ones */
1251			}
1252			cp = &fieldbuf[0] + strlen(fieldbuf);
1253			/*
1254			 * XXX: We also add RPCBPROC_GETADDRLIST queries to
1255			 * RPCB_GETADDR because rpcbind includes the
1256			 * RPCB_GETADDRLIST successes in RPCB_GETADDR.
1257			 */
1258			if (i != RPCBPROC_GETADDR)
1259			    (void) sprintf(cp, "%d",
1260				inf[RPCBVERS_4_STAT].info[i]);
1261			else
1262			    (void) sprintf(cp, "%d",
1263			    inf[RPCBVERS_4_STAT].info[i] +
1264			    inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]);
1265			flen = strlen(fieldbuf);
1266			(void) printf("%s%s", rpcb4hdr[i],
1267				spaces((int)((TABSTOP * (1 + flen / TABSTOP))
1268				- strlen(rpcb4hdr[i]))));
1269			(void) snprintf(lp, MAXLINE - (lp - linebuf), "%s%s",
1270				fieldbuf, spaces(cnt =
1271				((TABSTOP * (1 + flen / TABSTOP)) - flen)));
1272			lp += (flen + cnt);
1273		}
1274		(void) printf("\n%s\n", linebuf);
1275	}
1276
1277	if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] ||
1278			    inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) {
1279		(void) printf("\n");
1280		(void) printf("RPCB_RMTCALL (version 4) call statistics\n");
1281		print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1282	}
1283
1284	if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) {
1285		(void) printf("\n");
1286		(void) printf("RPCB_GETADDR (version 4) call statistics\n");
1287		print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1288	}
1289	clnt_destroy(client);
1290}
1291
1292/*
1293 * Delete registeration for this (prog, vers, netid)
1294 */
1295static void
1296deletereg(netid, argc, argv)
1297	char *netid;
1298	int argc;
1299	char **argv;
1300{
1301	struct netconfig *nconf = NULL;
1302
1303	if (argc != 2) {
1304		usage();
1305		exit(1);
1306	}
1307	if (netid) {
1308		nconf = getnetconfigent(netid);
1309		if (nconf == NULL) {
1310			(void) fprintf(stderr,
1311				"rpcinfo: netid %s not supported\n", netid);
1312			exit(1);
1313		}
1314	}
1315	if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0) {
1316		(void) fprintf(stderr,
1317	"rpcinfo: Could not delete registration for prog %s version %s\n",
1318			argv[0], argv[1]);
1319		exit(1);
1320	}
1321}
1322
1323/*
1324 * Create and return a handle for the given nconf.
1325 * Exit if cannot create handle.
1326 */
1327static CLIENT *
1328clnt_addr_create(address, nconf, prog, vers)
1329	char *address;
1330	struct netconfig *nconf;
1331	ulong_t prog;
1332	ulong_t vers;
1333{
1334	CLIENT *client;
1335	static struct netbuf *nbuf;
1336	static int fd = RPC_ANYFD;
1337	struct t_info tinfo;
1338
1339	if (fd == RPC_ANYFD) {
1340		if ((fd = t_open(nconf->nc_device, O_RDWR, &tinfo)) == -1) {
1341			rpc_createerr.cf_stat = RPC_TLIERROR;
1342			rpc_createerr.cf_error.re_terrno = t_errno;
1343			clnt_pcreateerror("rpcinfo");
1344			exit(1);
1345		}
1346		/* Convert the uaddr to taddr */
1347		nbuf = uaddr2taddr(nconf, address);
1348		if (nbuf == NULL) {
1349			netdir_perror("rpcinfo");
1350			exit(1);
1351		}
1352	}
1353	client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0);
1354	if (client == (CLIENT *)NULL) {
1355		clnt_pcreateerror("rpcinfo");
1356		exit(1);
1357	}
1358	return (client);
1359}
1360
1361/*
1362 * If the version number is given, ping that (prog, vers); else try to find
1363 * the version numbers supported for that prog and ping all the versions.
1364 * Remote rpcbind is not contacted for this service. The requests are
1365 * sent directly to the services themselves.
1366 */
1367static void
1368addrping(address, netid, argc, argv)
1369	char *address;
1370	char *netid;
1371	int argc;
1372	char **argv;
1373{
1374	CLIENT *client;
1375	struct timeval to;
1376	enum clnt_stat rpc_stat;
1377	ulong_t prognum, versnum, minvers, maxvers;
1378	struct rpc_err rpcerr;
1379	int failure = 0;
1380	struct netconfig *nconf;
1381	int fd;
1382
1383	if (argc < 1 || argc > 2 || (netid == NULL)) {
1384		usage();
1385		exit(1);
1386	}
1387	nconf = getnetconfigent(netid);
1388	if (nconf == (struct netconfig *)NULL) {
1389		(void) fprintf(stderr, "rpcinfo: Could not find %s\n", netid);
1390		exit(1);
1391	}
1392	to.tv_sec = 10;
1393	to.tv_usec = 0;
1394	prognum = getprognum(argv[0]);
1395	if (argc == 1) {	/* Version number not known */
1396		/*
1397		 * A call to version 0 should fail with a program/version
1398		 * mismatch, and give us the range of versions supported.
1399		 */
1400		versnum = MIN_VERS;
1401	} else {
1402		versnum = getvers(argv[1]);
1403	}
1404	client = clnt_addr_create(address, nconf, prognum, versnum);
1405	rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1406			(char *)NULL, (xdrproc_t)xdr_void,
1407			(char *)NULL, to);
1408	if (argc == 2) {
1409		/* Version number was known */
1410		if (pstatus(client, prognum, versnum) < 0)
1411			failure = 1;
1412		(void) CLNT_DESTROY(client);
1413		if (failure)
1414			exit(1);
1415		return;
1416	}
1417	/* Version number not known */
1418	(void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL);
1419	(void) CLNT_CONTROL(client, CLGET_FD, (char *)&fd);
1420	if (rpc_stat == RPC_PROGVERSMISMATCH) {
1421		clnt_geterr(client, &rpcerr);
1422		minvers = rpcerr.re_vers.low;
1423		maxvers = rpcerr.re_vers.high;
1424	} else if (rpc_stat == RPC_SUCCESS) {
1425		/*
1426		 * Oh dear, it DOES support version 0.
1427		 * Let's try version MAX_VERS.
1428		 */
1429		(void) CLNT_DESTROY(client);
1430		client = clnt_addr_create(address, nconf, prognum, MAX_VERS);
1431		rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1432				(char *)NULL, (xdrproc_t)xdr_void,
1433				(char *)NULL, to);
1434		if (rpc_stat == RPC_PROGVERSMISMATCH) {
1435			clnt_geterr(client, &rpcerr);
1436			minvers = rpcerr.re_vers.low;
1437			maxvers = rpcerr.re_vers.high;
1438		} else if (rpc_stat == RPC_SUCCESS) {
1439			/*
1440			 * It also supports version MAX_VERS.
1441			 * Looks like we have a wise guy.
1442			 * OK, we give them information on all
1443			 * 4 billion versions they support...
1444			 */
1445			minvers = 0;
1446			maxvers = MAX_VERS;
1447		} else {
1448			(void) pstatus(client, prognum, MAX_VERS);
1449			exit(1);
1450		}
1451	} else {
1452		(void) pstatus(client, prognum, (ulong_t)0);
1453		exit(1);
1454	}
1455	(void) CLNT_DESTROY(client);
1456	for (versnum = minvers; versnum <= maxvers; versnum++) {
1457		client = clnt_addr_create(address, nconf, prognum, versnum);
1458		rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1459				(char *)NULL, (xdrproc_t)xdr_void,
1460				(char *)NULL, to);
1461		if (pstatus(client, prognum, versnum) < 0)
1462				failure = 1;
1463		(void) CLNT_DESTROY(client);
1464	}
1465	(void) t_close(fd);
1466	if (failure)
1467		exit(1);
1468}
1469
1470/*
1471 * If the version number is given, ping that (prog, vers); else try to find
1472 * the version numbers supported for that prog and ping all the versions.
1473 * Remote rpcbind is *contacted* for this service. The requests are
1474 * then sent directly to the services themselves.
1475 */
1476static void
1477progping(netid, argc, argv)
1478	char *netid;
1479	int argc;
1480	char **argv;
1481{
1482	CLIENT *client;
1483	struct timeval to;
1484	enum clnt_stat rpc_stat;
1485	ulong_t prognum, versnum, minvers, maxvers;
1486	struct rpc_err rpcerr;
1487	int failure = 0;
1488	struct netconfig *nconf;
1489
1490	if (argc < 2 || argc > 3 || (netid == NULL)) {
1491		usage();
1492		exit(1);
1493	}
1494	prognum = getprognum(argv[1]);
1495	if (argc == 2) { /* Version number not known */
1496		/*
1497		 * A call to version 0 should fail with a program/version
1498		 * mismatch, and give us the range of versions supported.
1499		 */
1500		versnum = MIN_VERS;
1501	} else {
1502		versnum = getvers(argv[2]);
1503	}
1504	if (netid) {
1505		nconf = getnetconfigent(netid);
1506		if (nconf == (struct netconfig *)NULL) {
1507			(void) fprintf(stderr,
1508				"rpcinfo: Could not find %s\n", netid);
1509			exit(1);
1510		}
1511		client = clnt_tp_create(argv[0], prognum, versnum, nconf);
1512	} else {
1513		client = clnt_create(argv[0], prognum, versnum, "NETPATH");
1514	}
1515	if (client == (CLIENT *)NULL) {
1516		clnt_pcreateerror("rpcinfo");
1517		exit(1);
1518	}
1519	to.tv_sec = 10;
1520	to.tv_usec = 0;
1521	rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1522			(char *)NULL, (xdrproc_t)xdr_void,
1523			(char *)NULL, to);
1524	if (argc == 3) {
1525		/* Version number was known */
1526		if (pstatus(client, prognum, versnum) < 0)
1527			failure = 1;
1528		(void) CLNT_DESTROY(client);
1529		if (failure)
1530			exit(1);
1531		return;
1532	}
1533	/* Version number not known */
1534	if (rpc_stat == RPC_PROGVERSMISMATCH) {
1535		clnt_geterr(client, &rpcerr);
1536		minvers = rpcerr.re_vers.low;
1537		maxvers = rpcerr.re_vers.high;
1538	} else if (rpc_stat == RPC_SUCCESS) {
1539		/*
1540		 * Oh dear, it DOES support version 0.
1541		 * Let's try version MAX_VERS.
1542		 */
1543		versnum = MAX_VERS;
1544		(void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1545		rpc_stat = CLNT_CALL(client, NULLPROC,
1546				(xdrproc_t)xdr_void, (char *)NULL,
1547				(xdrproc_t)xdr_void, (char *)NULL, to);
1548		if (rpc_stat == RPC_PROGVERSMISMATCH) {
1549			clnt_geterr(client, &rpcerr);
1550			minvers = rpcerr.re_vers.low;
1551			maxvers = rpcerr.re_vers.high;
1552		} else if (rpc_stat == RPC_SUCCESS) {
1553			/*
1554			 * It also supports version MAX_VERS.
1555			 * Looks like we have a wise guy.
1556			 * OK, we give them information on all
1557			 * 4 billion versions they support...
1558			 */
1559			minvers = 0;
1560			maxvers = MAX_VERS;
1561		} else {
1562			(void) pstatus(client, prognum, MAX_VERS);
1563			exit(1);
1564		}
1565	} else {
1566		(void) pstatus(client, prognum, (ulong_t)0);
1567		exit(1);
1568	}
1569	for (versnum = minvers; versnum <= maxvers; versnum++) {
1570		(void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1571		rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1572					(char *)NULL, (xdrproc_t)xdr_void,
1573					(char *)NULL, to);
1574		if (pstatus(client, prognum, versnum) < 0)
1575				failure = 1;
1576	}
1577	(void) CLNT_DESTROY(client);
1578	if (failure)
1579		exit(1);
1580}
1581
1582static void
1583usage()
1584{
1585	(void) fprintf(stderr, "Usage: rpcinfo [-m | -s] [host]\n");
1586#ifdef PORTMAP
1587	(void) fprintf(stderr, "       rpcinfo -p [host]\n");
1588#endif
1589	(void) fprintf(stderr,
1590	    "       rpcinfo -T netid host prognum [versnum]\n");
1591	(void) fprintf(stderr, "       rpcinfo -l host prognum versnum\n");
1592#ifdef PORTMAP
1593	(void) fprintf(stderr,
1594"       rpcinfo [-n portnum] -u | -t host prognum [versnum]\n");
1595#endif
1596	(void) fprintf(stderr,
1597"       rpcinfo -a serv_address -T netid prognum [version]\n");
1598	(void) fprintf(stderr, "       rpcinfo -b prognum versnum\n");
1599	(void) fprintf(stderr,
1600	    "       rpcinfo -d [-T netid] prognum versnum\n");
1601}
1602
1603static ulong_t
1604getprognum  (arg)
1605	char *arg;
1606{
1607	char *strptr;
1608	register struct rpcent *rpc;
1609	register ulong_t prognum;
1610	char *tptr = arg;
1611
1612	while (*tptr && isdigit(*tptr++));
1613	if (*tptr || isalpha(*(tptr - 1))) {
1614		rpc = getrpcbyname(arg);
1615		if (rpc == NULL) {
1616			(void) fprintf(stderr,
1617				"rpcinfo: %s is unknown service\n", arg);
1618			exit(1);
1619		}
1620		prognum = rpc->r_number;
1621	} else {
1622		prognum = strtol(arg, &strptr, 10);
1623		if (strptr == arg || *strptr != '\0') {
1624			(void) fprintf(stderr,
1625		"rpcinfo: %s is illegal program number\n", arg);
1626			exit(1);
1627		}
1628	}
1629	return (prognum);
1630}
1631
1632static ulong_t
1633getvers(arg)
1634	char *arg;
1635{
1636	char *strptr;
1637	register ulong_t vers;
1638
1639	vers = (int)strtol(arg, &strptr, 10);
1640	if (strptr == arg || *strptr != '\0') {
1641		(void) fprintf(stderr,
1642			"rpcinfo: %s is illegal version number\n", arg);
1643		exit(1);
1644	}
1645	return (vers);
1646}
1647
1648/*
1649 * This routine should take a pointer to an "rpc_err" structure, rather than
1650 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
1651 * a CLIENT structure rather than a pointer to an "rpc_err" structure.
1652 * As such, we have to keep the CLIENT structure around in order to print
1653 * a good error message.
1654 */
1655static int
1656pstatus(client, prog, vers)
1657	register CLIENT *client;
1658	ulong_t prog;
1659	ulong_t vers;
1660{
1661	struct rpc_err rpcerr;
1662
1663	clnt_geterr(client, &rpcerr);
1664	if (rpcerr.re_status != RPC_SUCCESS) {
1665		clnt_perror(client, "rpcinfo");
1666		(void) printf("program %lu version %lu is not available\n",
1667			prog, vers);
1668		return (-1);
1669	} else {
1670		(void) printf("program %lu version %lu ready and waiting\n",
1671			prog, vers);
1672		return (0);
1673	}
1674}
1675
1676static CLIENT *
1677clnt_rpcbind_create(host, rpcbversnum, targaddr)
1678	char *host;
1679	ulong_t rpcbversnum;
1680	struct netbuf **targaddr;
1681{
1682	static char *tlist[3] = {
1683		"circuit_n", "circuit_v", "datagram_v"
1684	};
1685	int i;
1686	struct netconfig *nconf;
1687	CLIENT *clnt = NULL;
1688	void *handle;
1689
1690	rpc_createerr.cf_stat = RPC_SUCCESS;
1691	for (i = 0; i < 3; i++) {
1692		if ((handle = __rpc_setconf(tlist[i])) == NULL)
1693			continue;
1694		while (clnt == (CLIENT *)NULL) {
1695			if ((nconf = __rpc_getconf(handle)) == NULL) {
1696				if (rpc_createerr.cf_stat == RPC_SUCCESS)
1697				    rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1698				break;
1699			}
1700			clnt = getclnthandle(host, nconf, rpcbversnum,
1701					targaddr);
1702		}
1703		if (clnt)
1704			break;
1705		__rpc_endconf(handle);
1706	}
1707	return (clnt);
1708}
1709
1710static CLIENT*
1711getclnthandle(host, nconf, rpcbversnum, targaddr)
1712	char *host;
1713	struct netconfig *nconf;
1714	ulong_t rpcbversnum;
1715	struct netbuf **targaddr;
1716{
1717	struct netbuf *addr;
1718	struct nd_addrlist *nas;
1719	struct nd_hostserv rpcbind_hs;
1720	CLIENT *client = NULL;
1721
1722	/* Get the address of the rpcbind */
1723	rpcbind_hs.h_host = host;
1724	rpcbind_hs.h_serv = "rpcbind";
1725	if (netdir_getbyname(nconf, &rpcbind_hs, &nas)) {
1726		rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
1727		return (NULL);
1728	}
1729	addr = nas->n_addrs;
1730	client = clnt_tli_create(RPC_ANYFD, nconf, addr, RPCBPROG,
1731			rpcbversnum, 0, 0);
1732	if (client) {
1733		if (targaddr != NULL) {
1734			*targaddr =
1735			    (struct netbuf *)malloc(sizeof (struct netbuf));
1736			if (*targaddr != NULL) {
1737				(*targaddr)->maxlen = addr->maxlen;
1738				(*targaddr)->len = addr->len;
1739				(*targaddr)->buf = (char *)malloc(addr->len);
1740				if ((*targaddr)->buf != NULL) {
1741					(void) memcpy((*targaddr)->buf,
1742						addr->buf, addr->len);
1743				}
1744			}
1745		}
1746	} else {
1747		if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1748			/*
1749			 * Assume that the other system is dead; this is a
1750			 * better error to display to the user.
1751			 */
1752			rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1753			rpc_createerr.cf_error.re_status = RPC_FAILED;
1754		}
1755	}
1756	netdir_free((char *)nas, ND_ADDRLIST);
1757	return (client);
1758}
1759
1760static void
1761print_rmtcallstat(rtype, infp)
1762	int rtype;
1763	rpcb_stat *infp;
1764{
1765	register rpcbs_rmtcalllist_ptr pr;
1766	struct rpcent *rpc;
1767
1768	if (rtype == RPCBVERS_4_STAT)
1769		(void) printf(
1770		"prog\t\tvers\tproc\tnetid\tindirect success failure\n");
1771	else
1772		(void) printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n");
1773	for (pr = infp->rmtinfo; pr; pr = pr->next) {
1774		rpc = getrpcbynumber(pr->prog);
1775		if (rpc)
1776			(void) printf("%-16s", rpc->r_name);
1777		else
1778#if defined(_LP64) || defined(_I32LPx)
1779			(void) printf("%-16u", pr->prog);
1780		(void) printf("%u\t%u\t%-7s ",
1781#else
1782			(void) printf("%-16lu", pr->prog);
1783		(void) printf("%lu\t%lu\t%-7s ",
1784#endif
1785			pr->vers, pr->proc, pr->netid);
1786		if (rtype == RPCBVERS_4_STAT)
1787			(void) printf("%d\t ", pr->indirect);
1788		(void) printf("%d\t%d\n", pr->success, pr->failure);
1789	}
1790}
1791
1792static void
1793/* LINTED E_FUNC_ARG_UNUSED for 1st arg rtype */
1794print_getaddrstat(rtype, infp)
1795	int rtype;
1796	rpcb_stat *infp;
1797{
1798	rpcbs_addrlist_ptr al;
1799	register struct rpcent *rpc;
1800
1801	(void) printf("prog\t\tvers\tnetid\t  success\tfailure\n");
1802	for (al = infp->addrinfo; al; al = al->next) {
1803		rpc = getrpcbynumber(al->prog);
1804		if (rpc)
1805			(void) printf("%-16s", rpc->r_name);
1806		else
1807#if defined(_LP64) || defined(_I32LPx)
1808			(void) printf("%-16u", al->prog);
1809		(void) printf("%u\t%-9s %-12d\t%d\n",
1810#else
1811			(void) printf("%-16lu", al->prog);
1812		(void) printf("%lu\t%-9s %-12d\t%d\n",
1813#endif
1814			al->vers, al->netid,
1815			al->success, al->failure);
1816	}
1817}
1818
1819static char *
1820spaces(howmany)
1821int howmany;
1822{
1823	static char space_array[] =		/* 64 spaces */
1824	"                                                                ";
1825
1826	if (howmany <= 0 || howmany > sizeof (space_array)) {
1827		return ("");
1828	}
1829	return (&space_array[sizeof (space_array) - howmany - 1]);
1830}
1831