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