xref: /openbsd/usr.bin/rpcinfo/rpcinfo.c (revision 5b133f3f)
1 /*	$OpenBSD: rpcinfo.c,v 1.16 2023/03/08 04:43:12 guenther Exp $	*/
2 
3 /*
4  * Copyright (c) 2010, Oracle America, Inc.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  *       copyright notice, this list of conditions and the following
14  *       disclaimer in the documentation and/or other materials
15  *       provided with the distribution.
16  *     * Neither the name of the "Oracle America, Inc." nor the names of its
17  *       contributors may be used to endorse or promote products derived
18  *       from this software without specific prior written permission.
19  *
20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * rpcinfo: ping a particular rpc program
36  *     or dump the portmapper
37  */
38 
39 #include <rpc/rpc.h>
40 #include <stdio.h>
41 #include <sys/socket.h>
42 #include <netdb.h>
43 #include <rpc/pmap_prot.h>
44 #include <rpc/pmap_clnt.h>
45 #include <signal.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 #include <ctype.h>
50 #include <errno.h>
51 #include <limits.h>
52 #include <arpa/inet.h>
53 
54 #define MAXHOSTLEN 256
55 
56 #define	MIN_VERS	((u_long) 0)
57 #define	MAX_VERS	((u_long) 4294967295UL)
58 
59 void	udpping(u_short portflag, int argc, char **argv);
60 void	tcpping(u_short portflag, int argc, char **argv);
61 int	pstatus(CLIENT *client, u_long prognum, u_long vers);
62 void	pmapdump(int argc, char **argv);
63 bool_t	reply_proc(caddr_t res, struct sockaddr_in *who);
64 void	brdcst(int argc, char **argv);
65 void	deletereg(int argc, char **argv);
66 void	setreg(int argc, char **argv);
67 void	usage(char *);
68 int	getprognum(char *arg, u_long *ulp);
69 int	getul(char *arg, u_long *ulp);
70 void	get_inet_address(struct sockaddr_in *addr, char *host);
71 
72 /*
73  * Functions to be performed.
74  */
75 #define	NONE		0	/* no function */
76 #define	PMAPDUMP	1	/* dump portmapper registrations */
77 #define	TCPPING		2	/* ping TCP service */
78 #define	UDPPING		3	/* ping UDP service */
79 #define	BRDCST		4	/* ping broadcast UDP service */
80 #define DELETES		5	/* delete registration for the service */
81 #define SETS		6	/* set registration for the service */
82 
83 int
main(int argc,char * argv[])84 main(int argc, char *argv[])
85 {
86 	int c;
87 	extern char *optarg;
88 	extern int optind;
89 	int errflg;
90 	int function;
91 	u_short portnum;
92 	u_long tmp;
93 
94 	function = NONE;
95 	portnum = 0;
96 	errflg = 0;
97 	while ((c = getopt(argc, argv, "ptubdsn:")) != -1) {
98 		switch (c) {
99 
100 		case 'p':
101 			if (function != NONE)
102 				errflg = 1;
103 			else
104 				function = PMAPDUMP;
105 			break;
106 
107 		case 't':
108 			if (function != NONE)
109 				errflg = 1;
110 			else
111 				function = TCPPING;
112 			break;
113 
114 		case 'u':
115 			if (function != NONE)
116 				errflg = 1;
117 			else
118 				function = UDPPING;
119 			break;
120 
121 		case 'b':
122 			if (function != NONE)
123 				errflg = 1;
124 			else
125 				function = BRDCST;
126 			break;
127 
128 		case 'n':
129 			if (getul(optarg, &tmp))
130 				usage("invalid port number");
131 			if (tmp >= 65536)
132 				usage("port number out of range");
133 			portnum = (u_short)tmp;
134 			break;
135 
136 		case 'd':
137 			if (function != NONE)
138 				errflg = 1;
139 			else
140 				function = DELETES;
141 			break;
142 
143 		case 's':
144 			if (function != NONE)
145 				errflg = 1;
146 			else
147 				function = SETS;
148 			break;
149 
150 
151 		case '?':
152 			errflg = 1;
153 		}
154 	}
155 
156 	if (errflg || function == NONE)
157 		usage(NULL);
158 
159 	switch (function) {
160 
161 	case PMAPDUMP:
162 		if (portnum != 0)
163 			usage(NULL);
164 		pmapdump(argc - optind, argv + optind);
165 		break;
166 
167 	case UDPPING:
168 		udpping(portnum, argc - optind, argv + optind);
169 		break;
170 
171 	case TCPPING:
172 		tcpping(portnum, argc - optind, argv + optind);
173 		break;
174 
175 	case BRDCST:
176 		if (portnum != 0)
177 			usage(NULL);
178 
179 		brdcst(argc - optind, argv + optind);
180 		break;
181 
182 	case DELETES:
183 		deletereg(argc - optind, argv + optind);
184 		break;
185 
186 	case SETS:
187 		setreg(argc - optind, argv + optind);
188 		break;
189 	}
190 
191 	return (0);
192 }
193 
194 void
udpping(u_short portnum,int argc,char ** argv)195 udpping(u_short portnum, int argc, char **argv)
196 {
197 	struct timeval to;
198 	struct sockaddr_in addr;
199 	enum clnt_stat rpc_stat;
200 	CLIENT *client;
201 	u_long prognum, vers, minvers, maxvers;
202 	int sock = RPC_ANYSOCK;
203 	struct rpc_err rpcerr;
204 	int failure;
205 
206 	if (argc < 2)
207 		usage("too few arguments");
208 	if (argc > 3)
209 		usage("too many arguments");
210 	if (getprognum(argv[1], &prognum))
211 		usage("program number out of range");
212 
213 	get_inet_address(&addr, argv[0]);
214 	/* Open the socket here so it will survive calls to clnt_destroy */
215 	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
216 	if (sock == -1) {
217 		perror("rpcinfo: socket");
218 		exit(1);
219 	}
220 	if (getuid() == 0)
221 		bindresvport(sock, NULL);
222 	failure = 0;
223 	if (argc == 2) {
224 		/*
225 		 * A call to version 0 should fail with a program/version
226 		 * mismatch, and give us the range of versions supported.
227 		 */
228 		addr.sin_port = htons(portnum);
229 		to.tv_sec = 5;
230 		to.tv_usec = 0;
231 		if ((client = clntudp_create(&addr, prognum, (u_long)0,
232 		    to, &sock)) == NULL) {
233 			clnt_pcreateerror("rpcinfo");
234 			printf("program %lu is not available\n",
235 			    prognum);
236 			exit(1);
237 		}
238 		to.tv_sec = 10;
239 		to.tv_usec = 0;
240 		rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
241 		    xdr_void, (char *)NULL, to);
242 		if (rpc_stat == RPC_PROGVERSMISMATCH) {
243 			clnt_geterr(client, &rpcerr);
244 			minvers = rpcerr.re_vers.low;
245 			maxvers = rpcerr.re_vers.high;
246 		} else if (rpc_stat == RPC_SUCCESS) {
247 			/*
248 			 * Oh dear, it DOES support version 0.
249 			 * Let's try version MAX_VERS.
250 			 */
251 			addr.sin_port = htons(portnum);
252 			to.tv_sec = 5;
253 			to.tv_usec = 0;
254 			if ((client = clntudp_create(&addr, prognum, MAX_VERS,
255 			    to, &sock)) == NULL) {
256 				clnt_pcreateerror("rpcinfo");
257 				printf("program %lu version %lu is not available\n",
258 				    prognum, MAX_VERS);
259 				exit(1);
260 			}
261 			to.tv_sec = 10;
262 			to.tv_usec = 0;
263 			rpc_stat = clnt_call(client, NULLPROC, xdr_void,
264 			    (char *)NULL, xdr_void, (char *)NULL, to);
265 			if (rpc_stat == RPC_PROGVERSMISMATCH) {
266 				clnt_geterr(client, &rpcerr);
267 				minvers = rpcerr.re_vers.low;
268 				maxvers = rpcerr.re_vers.high;
269 			} else if (rpc_stat == RPC_SUCCESS) {
270 				/*
271 				 * It also supports version MAX_VERS.
272 				 * Looks like we have a wise guy.
273 				 * OK, we give them information on all
274 				 * 4 billion versions they support...
275 				 */
276 				minvers = 0;
277 				maxvers = MAX_VERS;
278 			} else {
279 				(void) pstatus(client, prognum, MAX_VERS);
280 				exit(1);
281 			}
282 		} else {
283 			(void) pstatus(client, prognum, (u_long)0);
284 			exit(1);
285 		}
286 		clnt_destroy(client);
287 		for (vers = minvers; vers <= maxvers; vers++) {
288 			addr.sin_port = htons(portnum);
289 			to.tv_sec = 5;
290 			to.tv_usec = 0;
291 			if ((client = clntudp_create(&addr, prognum, vers,
292 			    to, &sock)) == NULL) {
293 				clnt_pcreateerror("rpcinfo");
294 				printf("program %lu version %lu is not available\n",
295 				    prognum, vers);
296 				exit(1);
297 			}
298 			to.tv_sec = 10;
299 			to.tv_usec = 0;
300 			rpc_stat = clnt_call(client, NULLPROC, xdr_void,
301 			    (char *)NULL, xdr_void, (char *)NULL, to);
302 			if (pstatus(client, prognum, vers) < 0)
303 				failure = 1;
304 			clnt_destroy(client);
305 		}
306 	} else {
307 		getul(argv[2], &vers);		/* XXX */
308 		addr.sin_port = htons(portnum);
309 		to.tv_sec = 5;
310 		to.tv_usec = 0;
311 		if ((client = clntudp_create(&addr, prognum, vers,
312 		    to, &sock)) == NULL) {
313 			clnt_pcreateerror("rpcinfo");
314 			printf("program %lu version %lu is not available\n",
315 			    prognum, vers);
316 			exit(1);
317 		}
318 		to.tv_sec = 10;
319 		to.tv_usec = 0;
320 		rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
321 		    xdr_void, (char *)NULL, to);
322 		if (pstatus(client, prognum, vers) < 0)
323 			failure = 1;
324 	}
325 	(void) close(sock); /* Close it up again */
326 	if (failure)
327 		exit(1);
328 }
329 
330 void
tcpping(u_short portnum,int argc,char ** argv)331 tcpping(u_short portnum, int argc, char **argv)
332 {
333 	struct timeval to;
334 	struct sockaddr_in addr;
335 	enum clnt_stat rpc_stat;
336 	CLIENT *client;
337 	u_long prognum, vers, minvers, maxvers;
338 	int sock = RPC_ANYSOCK;
339 	struct rpc_err rpcerr;
340 	int failure;
341 
342 	if (argc < 2)
343 		usage("too few arguments");
344 	if (argc > 3)
345 		usage("too many arguments");
346 	if (getprognum(argv[1], &prognum))
347 		usage("program number out of range");
348 
349 	get_inet_address(&addr, argv[0]);
350 	failure = 0;
351 	if (argc == 2) {
352 		/*
353 		 * A call to version 0 should fail with a program/version
354 		 * mismatch, and give us the range of versions supported.
355 		 */
356 		addr.sin_port = htons(portnum);
357 		if ((client = clnttcp_create(&addr, prognum, MIN_VERS,
358 		    &sock, 0, 0)) == NULL) {
359 			clnt_pcreateerror("rpcinfo");
360 			printf("program %lu is not available\n",
361 			    prognum);
362 			exit(1);
363 		}
364 		to.tv_sec = 10;
365 		to.tv_usec = 0;
366 		rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
367 		    xdr_void, (char *)NULL, to);
368 		if (rpc_stat == RPC_PROGVERSMISMATCH) {
369 			clnt_geterr(client, &rpcerr);
370 			minvers = rpcerr.re_vers.low;
371 			maxvers = rpcerr.re_vers.high;
372 		} else if (rpc_stat == RPC_SUCCESS) {
373 			/*
374 			 * Oh dear, it DOES support version 0.
375 			 * Let's try version MAX_VERS.
376 			 */
377 			addr.sin_port = htons(portnum);
378 			if ((client = clnttcp_create(&addr, prognum, MAX_VERS,
379 			    &sock, 0, 0)) == NULL) {
380 				clnt_pcreateerror("rpcinfo");
381 				printf("program %lu version %lu is not available\n",
382 				    prognum, MAX_VERS);
383 				exit(1);
384 			}
385 			to.tv_sec = 10;
386 			to.tv_usec = 0;
387 			rpc_stat = clnt_call(client, NULLPROC, xdr_void,
388 			    (char *)NULL, xdr_void, (char *)NULL, to);
389 			if (rpc_stat == RPC_PROGVERSMISMATCH) {
390 				clnt_geterr(client, &rpcerr);
391 				minvers = rpcerr.re_vers.low;
392 				maxvers = rpcerr.re_vers.high;
393 			} else if (rpc_stat == RPC_SUCCESS) {
394 				/*
395 				 * It also supports version MAX_VERS.
396 				 * Looks like we have a wise guy.
397 				 * OK, we give them information on all
398 				 * 4 billion versions they support...
399 				 */
400 				minvers = 0;
401 				maxvers = MAX_VERS;
402 			} else {
403 				(void) pstatus(client, prognum, MAX_VERS);
404 				exit(1);
405 			}
406 		} else {
407 			(void) pstatus(client, prognum, MIN_VERS);
408 			exit(1);
409 		}
410 		clnt_destroy(client);
411 		(void) close(sock);
412 		sock = RPC_ANYSOCK; /* Re-initialize it for later */
413 		for (vers = minvers; vers <= maxvers; vers++) {
414 			addr.sin_port = htons(portnum);
415 			if ((client = clnttcp_create(&addr, prognum, vers,
416 			    &sock, 0, 0)) == NULL) {
417 				clnt_pcreateerror("rpcinfo");
418 				printf("program %lu version %lu is not available\n",
419 				    prognum, vers);
420 				exit(1);
421 			}
422 			to.tv_usec = 0;
423 			to.tv_sec = 10;
424 			rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
425 			    xdr_void, (char *)NULL, to);
426 			if (pstatus(client, prognum, vers) < 0)
427 				failure = 1;
428 			clnt_destroy(client);
429 			(void) close(sock);
430 			sock = RPC_ANYSOCK;
431 		}
432 	} else {
433 		getul(argv[2], &vers);		/* XXX */
434 		addr.sin_port = htons(portnum);
435 		if ((client = clnttcp_create(&addr, prognum, vers, &sock,
436 		    0, 0)) == NULL) {
437 			clnt_pcreateerror("rpcinfo");
438 			printf("program %lu version %lu is not available\n",
439 			    prognum, vers);
440 			exit(1);
441 		}
442 		to.tv_usec = 0;
443 		to.tv_sec = 10;
444 		rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
445 		    xdr_void, (char *)NULL, to);
446 		if (pstatus(client, prognum, vers) < 0)
447 			failure = 1;
448 	}
449 	if (failure)
450 		exit(1);
451 }
452 
453 /*
454  * This routine should take a pointer to an "rpc_err" structure, rather than
455  * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
456  * a CLIENT structure rather than a pointer to an "rpc_err" structure.
457  * As such, we have to keep the CLIENT structure around in order to print
458  * a good error message.
459  */
460 int
pstatus(CLIENT * client,u_long prognum,u_long vers)461 pstatus(CLIENT *client, u_long prognum, u_long vers)
462 {
463 	struct rpc_err rpcerr;
464 
465 	clnt_geterr(client, &rpcerr);
466 	if (rpcerr.re_status != RPC_SUCCESS) {
467 		clnt_perror(client, "rpcinfo");
468 		printf("program %lu version %lu is not available\n",
469 		    prognum, vers);
470 		return (-1);
471 	} else {
472 		printf("program %lu version %lu ready and waiting\n",
473 		    prognum, vers);
474 		return (0);
475 	}
476 }
477 
478 void
pmapdump(int argc,char ** argv)479 pmapdump(int argc, char **argv)
480 {
481 	struct sockaddr_in server_addr;
482 	struct hostent *hp;
483 	struct pmaplist *head = NULL;
484 	int socket = RPC_ANYSOCK;
485 	struct timeval minutetimeout;
486 	CLIENT *client;
487 	struct rpcent *rpc;
488 
489 	if (argc > 1)
490 		usage("too many arguments");
491 
492 	if (argc == 1)
493 		get_inet_address(&server_addr, argv[0]);
494 	else {
495 		bzero((char *)&server_addr, sizeof server_addr);
496 		server_addr.sin_family = AF_INET;
497 		if ((hp = gethostbyname("localhost")) != NULL)
498 			bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
499 			    hp->h_length);
500 		else
501 			(void) inet_aton("0.0.0.0", &server_addr.sin_addr);
502 	}
503 	minutetimeout.tv_sec = 60;
504 	minutetimeout.tv_usec = 0;
505 	server_addr.sin_port = htons(PMAPPORT);
506 	if ((client = clnttcp_create(&server_addr, PMAPPROG,
507 	    PMAPVERS, &socket, 50, 500)) == NULL) {
508 		clnt_pcreateerror("rpcinfo: can't contact portmapper");
509 		exit(1);
510 	}
511 	if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
512 	    xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) {
513 		fprintf(stderr, "rpcinfo: can't contact portmapper: ");
514 		clnt_perror(client, "rpcinfo");
515 		exit(1);
516 	}
517 	if (head == NULL) {
518 		printf("No remote programs registered.\n");
519 	} else {
520 		printf("   program vers proto   port\n");
521 		for (; head != NULL; head = head->pml_next) {
522 			printf("%10ld%5ld",
523 			    head->pml_map.pm_prog,
524 			    head->pml_map.pm_vers);
525 			if (head->pml_map.pm_prot == IPPROTO_UDP)
526 				printf("%6s",  "udp");
527 			else if (head->pml_map.pm_prot == IPPROTO_TCP)
528 				printf("%6s", "tcp");
529 			else
530 				printf("%6ld",  head->pml_map.pm_prot);
531 			printf("%7ld",  head->pml_map.pm_port);
532 			rpc = getrpcbynumber(head->pml_map.pm_prog);
533 			if (rpc)
534 				printf("  %s\n", rpc->r_name);
535 			else
536 				printf("\n");
537 		}
538 	}
539 }
540 
541 /*
542  * reply_proc collects replies from the broadcast.
543  * to get a unique list of responses the output of rpcinfo should
544  * be piped through sort(1) and then uniq(1).
545  */
546 bool_t
reply_proc(caddr_t res,struct sockaddr_in * who)547 reply_proc(caddr_t res, struct sockaddr_in *who)
548 {
549 	struct hostent *hp;
550 
551 	hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr,
552 	    AF_INET);
553 	printf("%s %s\n", inet_ntoa(who->sin_addr),
554 	    (hp == NULL) ? "(unknown)" : hp->h_name);
555 	return(FALSE);
556 }
557 
558 void
brdcst(int argc,char ** argv)559 brdcst(int argc, char **argv)
560 {
561 	enum clnt_stat rpc_stat;
562 	u_long prognum, vers_num;
563 
564 	if (argc != 2)
565 		usage("incorrect number of arguments");
566 	if (getprognum(argv[1], &prognum))
567 		usage("program number out of range");
568 	if (getul(argv[1], &vers_num))
569 		usage("version number out of range");
570 
571 	rpc_stat = clnt_broadcast(prognum, vers_num, NULLPROC, xdr_void,
572 	    (char *)NULL, xdr_void, (char *)NULL, reply_proc);
573 	if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
574 		fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
575 		    clnt_sperrno(rpc_stat));
576 		exit(1);
577 	}
578 	exit(0);
579 }
580 
581 void
deletereg(int argc,char ** argv)582 deletereg(int argc, char **argv)
583 {
584 	u_long prog_num, version_num;
585 
586 	if (argc != 2)
587 		usage("incorrect number of arguments");
588 	if (getprognum(argv[0], &prog_num))
589 		usage("program number out of range");
590 	if (getul(argv[1], &version_num))
591 		usage("version number out of range");
592 
593 	if ((pmap_unset(prog_num, version_num)) == 0) {
594 		fprintf(stderr, "rpcinfo: Could not delete "
595 		    "registration for prog %s version %s\n",
596 		    argv[0], argv[1]);
597 		exit(1);
598 	}
599 }
600 
601 void
setreg(int argc,char ** argv)602 setreg(int argc, char **argv)
603 {
604 	u_long prog_num, version_num, port_num;
605 
606 	if (argc != 3)
607 		usage("incorrect number of arguments");
608 	if (getprognum(argv[0], &prog_num))
609 		usage("cannot parse program number");
610 	if (getul(argv[1], &version_num))
611 		usage("cannot parse version number");
612 	if (getul(argv[2], &port_num))
613 		usage("cannot parse port number");
614 	if (port_num >= 65536)
615 		usage("port number out of range");
616 
617 	if ((pmap_set(prog_num, version_num, IPPROTO_TCP,
618 	    (u_short)port_num)) == 0) {
619 		fprintf(stderr, "rpcinfo: Could not set registration "
620 		    "for prog %s version %s port %s protocol IPPROTO_TCP\n",
621 		    argv[0], argv[1], argv[2]);
622 		exit(1);
623 	}
624 	if ((pmap_set(prog_num, version_num, IPPROTO_UDP,
625 	    (u_short)port_num)) == 0) {
626 		fprintf(stderr, "rpcinfo: Could not set registration "
627 		    "for prog %s version %s port %s protocol IPPROTO_UDP\n",
628 		    argv[0], argv[1], argv[2]);
629 		exit(1);
630 	}
631 }
632 
633 void
usage(char * msg)634 usage(char *msg)
635 {
636 	if (msg)
637 		fprintf(stderr,
638 		    "rpcinfo: %s\n", msg);
639 	fprintf(stderr, "usage: rpcinfo -b program version\n");
640 	fprintf(stderr, "       rpcinfo -d program version\n");
641 	fprintf(stderr, "       rpcinfo -p [host]\n");
642 	fprintf(stderr, "       rpcinfo -s program version port\n");
643 	fprintf(stderr,
644 	    "       rpcinfo [-n portnum] -t host program [version]\n");
645 	fprintf(stderr,
646 	    "       rpcinfo [-n portnum] -u host program [version]\n");
647 	exit(1);
648 }
649 
650 int
getprognum(char * arg,u_long * ulp)651 getprognum(char *arg, u_long *ulp)
652 {
653 	struct rpcent *rpc;
654 
655 	if (isalpha(*arg)) {
656 		rpc = getrpcbyname(arg);
657 		if (rpc == NULL) {
658 			fprintf(stderr, "rpcinfo: %s is unknown service\n",
659 			    arg);
660 			exit(1);
661 		}
662 		*ulp = rpc->r_number;
663 		return 0;
664 	}
665 	return getul(arg, ulp);
666 }
667 
668 int
getul(char * arg,u_long * ulp)669 getul(char *arg, u_long *ulp)
670 {
671 	u_long ul;
672 	int save_errno = errno;
673 	char *ep;
674 	int ret = 1;
675 
676 	errno = 0;
677 	ul = strtoul(arg, &ep, 10);
678 	if (arg[0] == '\0' || *ep != '\0')
679 		goto fail;
680 	if (errno == ERANGE && ul == ULONG_MAX)
681 		goto fail;
682 	*ulp = ul;
683 	ret = 0;
684 fail:
685 	errno = save_errno;
686 	return (ret);
687 }
688 
689 void
get_inet_address(struct sockaddr_in * addr,char * host)690 get_inet_address(struct sockaddr_in *addr, char *host)
691 {
692 	struct hostent *hp;
693 
694 	bzero((char *)addr, sizeof *addr);
695 	if (inet_aton(host, &addr->sin_addr) == 0) {
696 		if ((hp = gethostbyname(host)) == NULL) {
697 			fprintf(stderr, "rpcinfo: %s is unknown host\n",
698 			    host);
699 			exit(1);
700 		}
701 		bcopy(hp->h_addr, (char *)&addr->sin_addr, hp->h_length);
702 	}
703 	addr->sin_family = AF_INET;
704 }
705