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