Home | History | Annotate | Line # | Download | only in rpcinfo
rpcinfo.c revision 1.3
      1 #ifndef lint
      2 /*static char sccsid[] = "from: @(#)rpcinfo.c 1.22 87/08/12 SMI";*/
      3 /*static char sccsid[] = "from: @(#)rpcinfo.c	2.2 88/08/11 4.0 RPCSRC";*/
      4 static char rcsid[] = "$Id: rpcinfo.c,v 1.3 1993/08/01 18:09:11 mycroft Exp $";
      5 #endif
      6 
      7 /*
      8  * Copyright (C) 1986, Sun Microsystems, Inc.
      9  */
     10 
     11 /*
     12  * rpcinfo: ping a particular rpc program
     13  *     or dump the portmapper
     14  */
     15 
     16 /*
     17  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
     18  * unrestricted use provided that this legend is included on all tape
     19  * media and as a part of the software program in whole or part.  Users
     20  * may copy or modify Sun RPC without charge, but are not authorized
     21  * to license or distribute it to anyone else except as part of a product or
     22  * program developed by the user.
     23  *
     24  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
     25  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
     26  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
     27  *
     28  * Sun RPC is provided with no support and without any obligation on the
     29  * part of Sun Microsystems, Inc. to assist in its use, correction,
     30  * modification or enhancement.
     31  *
     32  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
     33  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
     34  * OR ANY PART THEREOF.
     35  *
     36  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
     37  * or profits or other special, indirect and consequential damages, even if
     38  * Sun has been advised of the possibility of such damages.
     39  *
     40  * Sun Microsystems, Inc.
     41  * 2550 Garcia Avenue
     42  * Mountain View, California  94043
     43  */
     44 
     45 #include <rpc/rpc.h>
     46 #include <stdio.h>
     47 #include <sys/socket.h>
     48 #include <netdb.h>
     49 #include <rpc/pmap_prot.h>
     50 #include <rpc/pmap_clnt.h>
     51 #include <signal.h>
     52 #include <ctype.h>
     53 
     54 #define MAXHOSTLEN 256
     55 
     56 #define	MIN_VERS	((u_long) 0)
     57 #define	MAX_VERS	((u_long) 4294967295UL)
     58 
     59 static void	udpping(/*u_short portflag, int argc, char **argv*/);
     60 static void	tcpping(/*u_short portflag, int argc, char **argv*/);
     61 static int	pstatus(/*CLIENT *client, u_long prognum, u_long vers*/);
     62 static void	pmapdump(/*int argc, char **argv*/);
     63 static bool_t	reply_proc(/*void *res, struct sockaddr_in *who*/);
     64 static void	brdcst(/*int argc, char **argv*/);
     65 static void	deletereg(/* int argc, char **argv */) ;
     66 static void	usage(/*void*/);
     67 static u_long	getprognum(/*char *arg*/);
     68 static u_long	getvers(/*char *arg*/);
     69 static void	get_inet_address(/*struct sockaddr_in *addr, char *host*/);
     70 extern u_long inet_addr();  /* in 4.2BSD, arpa/inet.h called that a in_addr */
     71 extern char *inet_ntoa();
     72 
     73 /*
     74  * Functions to be performed.
     75  */
     76 #define	NONE		0	/* no function */
     77 #define	PMAPDUMP	1	/* dump portmapper registrations */
     78 #define	TCPPING		2	/* ping TCP service */
     79 #define	UDPPING		3	/* ping UDP service */
     80 #define	BRDCST		4	/* ping broadcast UDP service */
     81 #define DELETES		5	/* delete registration for the service */
     82 
     83 int
     84 main(argc, argv)
     85 	int argc;
     86 	char **argv;
     87 {
     88 	register int c;
     89 	extern char *optarg;
     90 	extern int optind;
     91 	int errflg;
     92 	int function;
     93 	u_short portnum;
     94 
     95 	function = NONE;
     96 	portnum = 0;
     97 	errflg = 0;
     98 	while ((c = getopt(argc, argv, "ptubdn:")) != EOF) {
     99 		switch (c) {
    100 
    101 		case 'p':
    102 			if (function != NONE)
    103 				errflg = 1;
    104 			else
    105 				function = PMAPDUMP;
    106 			break;
    107 
    108 		case 't':
    109 			if (function != NONE)
    110 				errflg = 1;
    111 			else
    112 				function = TCPPING;
    113 			break;
    114 
    115 		case 'u':
    116 			if (function != NONE)
    117 				errflg = 1;
    118 			else
    119 				function = UDPPING;
    120 			break;
    121 
    122 		case 'b':
    123 			if (function != NONE)
    124 				errflg = 1;
    125 			else
    126 				function = BRDCST;
    127 			break;
    128 
    129 		case 'n':
    130 			portnum = (u_short) atoi(optarg);   /* hope we don't get bogus # */
    131 			break;
    132 
    133 		case 'd':
    134 			if (function != NONE)
    135 				errflg = 1;
    136 			else
    137 				function = DELETES;
    138 			break;
    139 
    140 		case '?':
    141 			errflg = 1;
    142 		}
    143 	}
    144 
    145 	if (errflg || function == NONE) {
    146 		usage();
    147 		return (1);
    148 	}
    149 
    150 	switch (function) {
    151 
    152 	case PMAPDUMP:
    153 		if (portnum != 0) {
    154 			usage();
    155 			return (1);
    156 		}
    157 		pmapdump(argc - optind, argv + optind);
    158 		break;
    159 
    160 	case UDPPING:
    161 		udpping(portnum, argc - optind, argv + optind);
    162 		break;
    163 
    164 	case TCPPING:
    165 		tcpping(portnum, argc - optind, argv + optind);
    166 		break;
    167 
    168 	case BRDCST:
    169 		if (portnum != 0) {
    170 			usage();
    171 			return (1);
    172 		}
    173 		brdcst(argc - optind, argv + optind);
    174 		break;
    175 
    176 	case DELETES:
    177 		deletereg(argc - optind, argv + optind);
    178 		break;
    179 	}
    180 
    181 	return (0);
    182 }
    183 
    184 static void
    185 udpping(portnum, argc, argv)
    186 	u_short portnum;
    187 	int argc;
    188 	char **argv;
    189 {
    190 	struct timeval to;
    191 	struct sockaddr_in addr;
    192 	enum clnt_stat rpc_stat;
    193 	CLIENT *client;
    194 	u_long prognum, vers, minvers, maxvers;
    195 	int sock = RPC_ANYSOCK;
    196 	struct rpc_err rpcerr;
    197 	int failure;
    198 
    199 	if (argc < 2 || argc > 3) {
    200 		usage();
    201 		exit(1);
    202 	}
    203 	prognum = getprognum(argv[1]);
    204 	get_inet_address(&addr, argv[0]);
    205 	/* Open the socket here so it will survive calls to clnt_destroy */
    206 	sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    207 	if (sock < 0) {
    208 		perror("rpcinfo: socket");
    209 		exit(1);
    210 	}
    211 	failure = 0;
    212 	if (argc == 2) {
    213 		/*
    214 		 * A call to version 0 should fail with a program/version
    215 		 * mismatch, and give us the range of versions supported.
    216 		 */
    217 		addr.sin_port = htons(portnum);
    218 		to.tv_sec = 5;
    219 		to.tv_usec = 0;
    220 		if ((client = clntudp_create(&addr, prognum, (u_long)0,
    221 		    to, &sock)) == NULL) {
    222 			clnt_pcreateerror("rpcinfo");
    223 			printf("program %lu is not available\n",
    224 			    prognum);
    225 			exit(1);
    226 		}
    227 		to.tv_sec = 10;
    228 		to.tv_usec = 0;
    229 		rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
    230 		    xdr_void, (char *)NULL, to);
    231 		if (rpc_stat == RPC_PROGVERSMISMATCH) {
    232 			clnt_geterr(client, &rpcerr);
    233 			minvers = rpcerr.re_vers.low;
    234 			maxvers = rpcerr.re_vers.high;
    235 		} else if (rpc_stat == RPC_SUCCESS) {
    236 			/*
    237 			 * Oh dear, it DOES support version 0.
    238 			 * Let's try version MAX_VERS.
    239 			 */
    240 			addr.sin_port = htons(portnum);
    241 			to.tv_sec = 5;
    242 			to.tv_usec = 0;
    243 			if ((client = clntudp_create(&addr, prognum, MAX_VERS,
    244 			    to, &sock)) == NULL) {
    245 				clnt_pcreateerror("rpcinfo");
    246 				printf("program %lu version %lu is not available\n",
    247 				    prognum, MAX_VERS);
    248 				exit(1);
    249 			}
    250 			to.tv_sec = 10;
    251 			to.tv_usec = 0;
    252 			rpc_stat = clnt_call(client, NULLPROC, xdr_void,
    253 			    (char *)NULL, xdr_void, (char *)NULL, to);
    254 			if (rpc_stat == RPC_PROGVERSMISMATCH) {
    255 				clnt_geterr(client, &rpcerr);
    256 				minvers = rpcerr.re_vers.low;
    257 				maxvers = rpcerr.re_vers.high;
    258 			} else if (rpc_stat == RPC_SUCCESS) {
    259 				/*
    260 				 * It also supports version MAX_VERS.
    261 				 * Looks like we have a wise guy.
    262 				 * OK, we give them information on all
    263 				 * 4 billion versions they support...
    264 				 */
    265 				minvers = 0;
    266 				maxvers = MAX_VERS;
    267 			} else {
    268 				(void) pstatus(client, prognum, MAX_VERS);
    269 				exit(1);
    270 			}
    271 		} else {
    272 			(void) pstatus(client, prognum, (u_long)0);
    273 			exit(1);
    274 		}
    275 		clnt_destroy(client);
    276 		for (vers = minvers; vers <= maxvers; vers++) {
    277 			addr.sin_port = htons(portnum);
    278 			to.tv_sec = 5;
    279 			to.tv_usec = 0;
    280 			if ((client = clntudp_create(&addr, prognum, vers,
    281 			    to, &sock)) == NULL) {
    282 				clnt_pcreateerror("rpcinfo");
    283 				printf("program %lu version %lu is not available\n",
    284 				    prognum, vers);
    285 				exit(1);
    286 			}
    287 			to.tv_sec = 10;
    288 			to.tv_usec = 0;
    289 			rpc_stat = clnt_call(client, NULLPROC, xdr_void,
    290 			    (char *)NULL, xdr_void, (char *)NULL, to);
    291 			if (pstatus(client, prognum, vers) < 0)
    292 				failure = 1;
    293 			clnt_destroy(client);
    294 		}
    295 	}
    296 	else {
    297 		vers = getvers(argv[2]);
    298 		addr.sin_port = htons(portnum);
    299 		to.tv_sec = 5;
    300 		to.tv_usec = 0;
    301 		if ((client = clntudp_create(&addr, prognum, vers,
    302 		    to, &sock)) == NULL) {
    303 			clnt_pcreateerror("rpcinfo");
    304 			printf("program %lu version %lu is not available\n",
    305 			    prognum, vers);
    306 			exit(1);
    307 		}
    308 		to.tv_sec = 10;
    309 		to.tv_usec = 0;
    310 		rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
    311 		    xdr_void, (char *)NULL, to);
    312 		if (pstatus(client, prognum, vers) < 0)
    313 			failure = 1;
    314 	}
    315 	(void) close(sock); /* Close it up again */
    316 	if (failure)
    317 		exit(1);
    318 }
    319 
    320 static void
    321 tcpping(portnum, argc, argv)
    322 	u_short portnum;
    323 	int argc;
    324 	char **argv;
    325 {
    326 	struct timeval to;
    327 	struct sockaddr_in addr;
    328 	enum clnt_stat rpc_stat;
    329 	CLIENT *client;
    330 	u_long prognum, vers, minvers, maxvers;
    331 	int sock = RPC_ANYSOCK;
    332 	struct rpc_err rpcerr;
    333 	int failure;
    334 
    335 	if (argc < 2 || argc > 3) {
    336 		usage();
    337 		exit(1);
    338 	}
    339 	prognum = getprognum(argv[1]);
    340 	get_inet_address(&addr, argv[0]);
    341 	failure = 0;
    342 	if (argc == 2) {
    343 		/*
    344 		 * A call to version 0 should fail with a program/version
    345 		 * mismatch, and give us the range of versions supported.
    346 		 */
    347 		addr.sin_port = htons(portnum);
    348 		if ((client = clnttcp_create(&addr, prognum, MIN_VERS,
    349 		    &sock, 0, 0)) == NULL) {
    350 			clnt_pcreateerror("rpcinfo");
    351 			printf("program %lu is not available\n",
    352 			    prognum);
    353 			exit(1);
    354 		}
    355 		to.tv_sec = 10;
    356 		to.tv_usec = 0;
    357 		rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
    358 		    xdr_void, (char *)NULL, to);
    359 		if (rpc_stat == RPC_PROGVERSMISMATCH) {
    360 			clnt_geterr(client, &rpcerr);
    361 			minvers = rpcerr.re_vers.low;
    362 			maxvers = rpcerr.re_vers.high;
    363 		} else if (rpc_stat == RPC_SUCCESS) {
    364 			/*
    365 			 * Oh dear, it DOES support version 0.
    366 			 * Let's try version MAX_VERS.
    367 			 */
    368 			addr.sin_port = htons(portnum);
    369 			if ((client = clnttcp_create(&addr, prognum, MAX_VERS,
    370 			    &sock, 0, 0)) == NULL) {
    371 				clnt_pcreateerror("rpcinfo");
    372 				printf("program %lu version %lu is not available\n",
    373 				    prognum, MAX_VERS);
    374 				exit(1);
    375 			}
    376 			to.tv_sec = 10;
    377 			to.tv_usec = 0;
    378 			rpc_stat = clnt_call(client, NULLPROC, xdr_void,
    379 			    (char *)NULL, xdr_void, (char *)NULL, to);
    380 			if (rpc_stat == RPC_PROGVERSMISMATCH) {
    381 				clnt_geterr(client, &rpcerr);
    382 				minvers = rpcerr.re_vers.low;
    383 				maxvers = rpcerr.re_vers.high;
    384 			} else if (rpc_stat == RPC_SUCCESS) {
    385 				/*
    386 				 * It also supports version MAX_VERS.
    387 				 * Looks like we have a wise guy.
    388 				 * OK, we give them information on all
    389 				 * 4 billion versions they support...
    390 				 */
    391 				minvers = 0;
    392 				maxvers = MAX_VERS;
    393 			} else {
    394 				(void) pstatus(client, prognum, MAX_VERS);
    395 				exit(1);
    396 			}
    397 		} else {
    398 			(void) pstatus(client, prognum, MIN_VERS);
    399 			exit(1);
    400 		}
    401 		clnt_destroy(client);
    402 		(void) close(sock);
    403 		sock = RPC_ANYSOCK; /* Re-initialize it for later */
    404 		for (vers = minvers; vers <= maxvers; vers++) {
    405 			addr.sin_port = htons(portnum);
    406 			if ((client = clnttcp_create(&addr, prognum, vers,
    407 			    &sock, 0, 0)) == NULL) {
    408 				clnt_pcreateerror("rpcinfo");
    409 				printf("program %lu version %lu is not available\n",
    410 				    prognum, vers);
    411 				exit(1);
    412 			}
    413 			to.tv_usec = 0;
    414 			to.tv_sec = 10;
    415 			rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
    416 			    xdr_void, (char *)NULL, to);
    417 			if (pstatus(client, prognum, vers) < 0)
    418 				failure = 1;
    419 			clnt_destroy(client);
    420 			(void) close(sock);
    421 			sock = RPC_ANYSOCK;
    422 		}
    423 	}
    424 	else {
    425 		vers = getvers(argv[2]);
    426 		addr.sin_port = htons(portnum);
    427 		if ((client = clnttcp_create(&addr, prognum, vers, &sock,
    428 		    0, 0)) == NULL) {
    429 			clnt_pcreateerror("rpcinfo");
    430 			printf("program %lu version %lu is not available\n",
    431 			    prognum, vers);
    432 			exit(1);
    433 		}
    434 		to.tv_usec = 0;
    435 		to.tv_sec = 10;
    436 		rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
    437 		    xdr_void, (char *)NULL, to);
    438 		if (pstatus(client, prognum, vers) < 0)
    439 			failure = 1;
    440 	}
    441 	if (failure)
    442 		exit(1);
    443 }
    444 
    445 /*
    446  * This routine should take a pointer to an "rpc_err" structure, rather than
    447  * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
    448  * a CLIENT structure rather than a pointer to an "rpc_err" structure.
    449  * As such, we have to keep the CLIENT structure around in order to print
    450  * a good error message.
    451  */
    452 static int
    453 pstatus(client, prognum, vers)
    454 	register CLIENT *client;
    455 	u_long prognum;
    456 	u_long vers;
    457 {
    458 	struct rpc_err rpcerr;
    459 
    460 	clnt_geterr(client, &rpcerr);
    461 	if (rpcerr.re_status != RPC_SUCCESS) {
    462 		clnt_perror(client, "rpcinfo");
    463 		printf("program %lu version %lu is not available\n",
    464 		    prognum, vers);
    465 		return (-1);
    466 	} else {
    467 		printf("program %lu version %lu ready and waiting\n",
    468 		    prognum, vers);
    469 		return (0);
    470 	}
    471 }
    472 
    473 static void
    474 pmapdump(argc, argv)
    475 	int argc;
    476 	char **argv;
    477 {
    478 	struct sockaddr_in server_addr;
    479 	register struct hostent *hp;
    480 	struct pmaplist *head = NULL;
    481 	int socket = RPC_ANYSOCK;
    482 	struct timeval minutetimeout;
    483 	register CLIENT *client;
    484 	struct rpcent *rpc;
    485 
    486 	if (argc > 1) {
    487 		usage();
    488 		exit(1);
    489 	}
    490 	if (argc == 1)
    491 		get_inet_address(&server_addr, argv[0]);
    492 	else {
    493 		bzero((char *)&server_addr, sizeof server_addr);
    494 		server_addr.sin_family = AF_INET;
    495 		if ((hp = gethostbyname("localhost")) != NULL)
    496 			bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
    497 			    hp->h_length);
    498 		else
    499 			server_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
    500 	}
    501 	minutetimeout.tv_sec = 60;
    502 	minutetimeout.tv_usec = 0;
    503 	server_addr.sin_port = htons(PMAPPORT);
    504 	if ((client = clnttcp_create(&server_addr, PMAPPROG,
    505 	    PMAPVERS, &socket, 50, 500)) == NULL) {
    506 		clnt_pcreateerror("rpcinfo: can't contact portmapper");
    507 		exit(1);
    508 	}
    509 	if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
    510 	    xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) {
    511 		fprintf(stderr, "rpcinfo: can't contact portmapper: ");
    512 		clnt_perror(client, "rpcinfo");
    513 		exit(1);
    514 	}
    515 	if (head == NULL) {
    516 		printf("No remote programs registered.\n");
    517 	} else {
    518 		printf("   program vers proto   port\n");
    519 		for (; head != NULL; head = head->pml_next) {
    520 			printf("%10ld%5ld",
    521 			    head->pml_map.pm_prog,
    522 			    head->pml_map.pm_vers);
    523 			if (head->pml_map.pm_prot == IPPROTO_UDP)
    524 				printf("%6s",  "udp");
    525 			else if (head->pml_map.pm_prot == IPPROTO_TCP)
    526 				printf("%6s", "tcp");
    527 			else
    528 				printf("%6ld",  head->pml_map.pm_prot);
    529 			printf("%7ld",  head->pml_map.pm_port);
    530 			rpc = getrpcbynumber(head->pml_map.pm_prog);
    531 			if (rpc)
    532 				printf("  %s\n", rpc->r_name);
    533 			else
    534 				printf("\n");
    535 		}
    536 	}
    537 }
    538 
    539 /*
    540  * reply_proc collects replies from the broadcast.
    541  * to get a unique list of responses the output of rpcinfo should
    542  * be piped through sort(1) and then uniq(1).
    543  */
    544 
    545 /*ARGSUSED*/
    546 static bool_t
    547 reply_proc(res, who)
    548 	void *res;		/* Nothing comes back */
    549 	struct sockaddr_in *who; /* Who sent us the reply */
    550 {
    551 	register struct hostent *hp;
    552 
    553 	hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr,
    554 	    AF_INET);
    555 	printf("%s %s\n", inet_ntoa(who->sin_addr),
    556 	    (hp == NULL) ? "(unknown)" : hp->h_name);
    557 	return(FALSE);
    558 }
    559 
    560 static void
    561 brdcst(argc, argv)
    562 	int argc;
    563 	char **argv;
    564 {
    565 	enum clnt_stat rpc_stat;
    566 	u_long prognum, vers;
    567 
    568 	if (argc != 2) {
    569 		usage();
    570 		exit(1);
    571 	}
    572 	prognum = getprognum(argv[0]);
    573 	vers = getvers(argv[1]);
    574 	rpc_stat = clnt_broadcast(prognum, vers, NULLPROC, xdr_void,
    575 	    (char *)NULL, xdr_void, (char *)NULL, reply_proc);
    576 	if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
    577 		fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
    578 		    clnt_sperrno(rpc_stat));
    579 		exit(1);
    580 	}
    581 	exit(0);
    582 }
    583 
    584 static void
    585 deletereg(argc, argv)
    586 	int argc;
    587 	char **argv;
    588 {	u_long prog_num, version_num ;
    589 
    590 	if (argc != 2) {
    591 		usage() ;
    592 		exit(1) ;
    593 	}
    594 	if (getuid()) { /* This command allowed only to root */
    595 		fprintf(stderr, "Sorry. You are not root\n") ;
    596 		exit(1) ;
    597 	}
    598 	prog_num = getprognum(argv[0]);
    599 	version_num = getvers(argv[1]);
    600 	if ((pmap_unset(prog_num, version_num)) == 0) {
    601 		fprintf(stderr, "rpcinfo: Could not delete registration for prog %s version %s\n",
    602 			argv[0], argv[1]) ;
    603 		exit(1) ;
    604 	}
    605 }
    606 
    607 static void
    608 usage()
    609 {
    610 	fprintf(stderr, "Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n");
    611 	fprintf(stderr, "       rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n");
    612 	fprintf(stderr, "       rpcinfo -p [ host ]\n");
    613 	fprintf(stderr, "       rpcinfo -b prognum versnum\n");
    614 	fprintf(stderr, "       rpcinfo -d prognum versnum\n") ;
    615 }
    616 
    617 static u_long
    618 getprognum(arg)
    619 	char *arg;
    620 {
    621 	register struct rpcent *rpc;
    622 	register u_long prognum;
    623 
    624 	if (isalpha(*arg)) {
    625 		rpc = getrpcbyname(arg);
    626 		if (rpc == NULL) {
    627 			fprintf(stderr, "rpcinfo: %s is unknown service\n",
    628 			    arg);
    629 			exit(1);
    630 		}
    631 		prognum = rpc->r_number;
    632 	} else {
    633 		prognum = (u_long) atoi(arg);
    634 	}
    635 
    636 	return (prognum);
    637 }
    638 
    639 static u_long
    640 getvers(arg)
    641 	char *arg;
    642 {
    643 	register u_long vers;
    644 
    645 	vers = (int) atoi(arg);
    646 	return (vers);
    647 }
    648 
    649 static void
    650 get_inet_address(addr, host)
    651 	struct sockaddr_in *addr;
    652 	char *host;
    653 {
    654 	register struct hostent *hp;
    655 
    656 	bzero((char *)addr, sizeof *addr);
    657 	addr->sin_addr.s_addr = (u_long) inet_addr(host);
    658 	if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
    659 		if ((hp = gethostbyname(host)) == NULL) {
    660 			fprintf(stderr, "rpcinfo: %s is unknown host\n", host);
    661 			exit(1);
    662 		}
    663 		bcopy(hp->h_addr, (char *)&addr->sin_addr, hp->h_length);
    664 	}
    665 	addr->sin_family = AF_INET;
    666 }
    667