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