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