Home | History | Annotate | Line # | Download | only in rpcinfo
rpcinfo.c revision 1.29
      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