GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/rpcinfo/rpcinfo.c Lines: 0 349 0.0 %
Date: 2017-11-07 Branches: 0 178 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: rpcinfo.c,v 1.14 2010/09/01 14:43:34 millert 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
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
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 < 0) {
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
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
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
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
/*ARGSUSED*/
547
bool_t
548
reply_proc(caddr_t res, struct sockaddr_in *who)
549
{
550
	struct hostent *hp;
551
552
	hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr,
553
	    AF_INET);
554
	printf("%s %s\n", inet_ntoa(who->sin_addr),
555
	    (hp == NULL) ? "(unknown)" : hp->h_name);
556
	return(FALSE);
557
}
558
559
void
560
brdcst(int argc, char **argv)
561
{
562
	enum clnt_stat rpc_stat;
563
	u_long prognum, vers_num;
564
565
	if (argc != 2)
566
		usage("incorrect number of arguments");
567
	if (getprognum(argv[1], &prognum))
568
		usage("program number out of range");
569
	if (getul(argv[1], &vers_num))
570
		usage("version number out of range");
571
572
	rpc_stat = clnt_broadcast(prognum, vers_num, NULLPROC, xdr_void,
573
	    (char *)NULL, xdr_void, (char *)NULL, reply_proc);
574
	if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
575
		fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
576
		    clnt_sperrno(rpc_stat));
577
		exit(1);
578
	}
579
	exit(0);
580
}
581
582
void
583
deletereg(int argc, char **argv)
584
{
585
	u_long prog_num, version_num;
586
587
	if (argc != 2)
588
		usage("incorrect number of arguments");
589
	if (getprognum(argv[0], &prog_num))
590
		usage("program number out of range");
591
	if (getul(argv[1], &version_num))
592
		usage("version number out of range");
593
594
	if ((pmap_unset(prog_num, version_num)) == 0) {
595
		fprintf(stderr, "rpcinfo: Could not delete "
596
		    "registration for prog %s version %s\n",
597
		    argv[0], argv[1]);
598
		exit(1);
599
	}
600
}
601
602
void
603
setreg(int argc, char **argv)
604
{
605
	u_long prog_num, version_num, port_num;
606
607
	if (argc != 3)
608
		usage("incorrect number of arguments");
609
	if (getprognum(argv[0], &prog_num))
610
		usage("cannot parse program number");
611
	if (getul(argv[1], &version_num))
612
		usage("cannot parse version number");
613
	if (getul(argv[2], &port_num))
614
		usage("cannot parse port number");
615
	if (port_num >= 65536)
616
		usage("port number out of range");
617
618
	if ((pmap_set(prog_num, version_num, IPPROTO_TCP,
619
	    (u_short)port_num)) == 0) {
620
		fprintf(stderr, "rpcinfo: Could not set registration "
621
		    "for prog %s version %s port %s protocol IPPROTO_TCP\n",
622
		    argv[0], argv[1], argv[2]);
623
		exit(1);
624
	}
625
	if ((pmap_set(prog_num, version_num, IPPROTO_UDP,
626
	    (u_short)port_num)) == 0) {
627
		fprintf(stderr, "rpcinfo: Could not set registration "
628
		    "for prog %s version %s port %s protocol IPPROTO_UDP\n",
629
		    argv[0], argv[1], argv[2]);
630
		exit(1);
631
	}
632
}
633
634
void
635
usage(char *msg)
636
{
637
	if (msg)
638
		fprintf(stderr,
639
		    "rpcinfo: %s\n", msg);
640
	fprintf(stderr, "usage: rpcinfo -b program version\n");
641
	fprintf(stderr, "       rpcinfo -d program version\n");
642
	fprintf(stderr, "       rpcinfo -p [host]\n");
643
	fprintf(stderr, "       rpcinfo -s program version port\n");
644
	fprintf(stderr,
645
	    "       rpcinfo [-n portnum] -t host program [version]\n");
646
	fprintf(stderr,
647
	    "       rpcinfo [-n portnum] -u host program [version]\n");
648
	exit(1);
649
}
650
651
int
652
getprognum(char *arg, u_long *ulp)
653
{
654
	struct rpcent *rpc;
655
656
	if (isalpha(*arg)) {
657
		rpc = getrpcbyname(arg);
658
		if (rpc == NULL) {
659
			fprintf(stderr, "rpcinfo: %s is unknown service\n",
660
			    arg);
661
			exit(1);
662
		}
663
		*ulp = rpc->r_number;
664
		return 0;
665
	}
666
	return getul(arg, ulp);
667
}
668
669
int
670
getul(char *arg, u_long *ulp)
671
{
672
	u_long ul;
673
	int save_errno = errno;
674
	char *ep;
675
	int ret = 1;
676
677
	errno = 0;
678
	ul = strtoul(arg, &ep, 10);
679
	if (arg[0] == '\0' || *ep != '\0')
680
		goto fail;
681
	if (errno == ERANGE && ul == ULONG_MAX)
682
		goto fail;
683
	*ulp = ul;
684
	ret = 0;
685
fail:
686
	errno = save_errno;
687
	return (ret);
688
}
689
690
void
691
get_inet_address(struct sockaddr_in *addr, char *host)
692
{
693
	struct hostent *hp;
694
695
	bzero((char *)addr, sizeof *addr);
696
	if (inet_aton(host, &addr->sin_addr) == 0) {
697
		if ((hp = gethostbyname(host)) == NULL) {
698
			fprintf(stderr, "rpcinfo: %s is unknown host\n",
699
			    host);
700
			exit(1);
701
		}
702
		bcopy(hp->h_addr, (char *)&addr->sin_addr, hp->h_length);
703
	}
704
	addr->sin_family = AF_INET;
705
}