1 /* @(#)rpcinfo.c 2.2 88/08/11 4.0 RPCSRC */
3 static char sccsid
[] = "@(#)rpcinfo.c 1.22 87/08/12 SMI";
7 * Copyright (C) 1986, Sun Microsystems, Inc.
11 * rpcinfo: ping a particular rpc program
12 * or dump the portmapper
16 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
17 * unrestricted use provided that this legend is included on all tape
18 * media and as a part of the software program in whole or part. Users
19 * may copy or modify Sun RPC without charge, but are not authorized
20 * to license or distribute it to anyone else except as part of a product or
21 * program developed by the user.
23 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
24 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
27 * Sun RPC is provided with no support and without any obligation on the
28 * part of Sun Microsystems, Inc. to assist in its use, correction,
29 * modification or enhancement.
31 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
32 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
33 * OR ANY PART THEREOF.
35 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
36 * or profits or other special, indirect and consequential damages, even if
37 * Sun has been advised of the possibility of such damages.
39 * Sun Microsystems, Inc.
41 * Mountain View, California 94043
46 #include <sys/socket.h>
48 #include <rpc/pmap_prot.h>
49 #include <rpc/pmap_clnt.h>
53 #define MAXHOSTLEN 256
55 #define MIN_VERS ((u_long) 0)
56 #define MAX_VERS ((u_long) 4294967295L)
58 static void udpping(/*u_short portflag, int argc, char **argv*/);
59 static void tcpping(/*u_short portflag, int argc, char **argv*/);
60 static int pstatus(/*CLIENT *client, u_long prognum, u_long vers*/);
61 static void pmapdump(/*int argc, char **argv*/);
62 static bool_t
reply_proc(/*void *res, struct sockaddr_in *who*/);
63 static void brdcst(/*int argc, char **argv*/);
64 static void deletereg(/* int argc, char **argv */) ;
65 static void usage(/*void*/);
66 static u_long
getprognum(/*char *arg*/);
67 static u_long
getvers(/*char *arg*/);
68 static void get_inet_address(/*struct sockaddr_in *addr, char *host*/);
69 extern u_long
inet_addr(); /* in 4.2BSD, arpa/inet.h called that a in_addr */
70 extern char *inet_ntoa();
73 * Functions to be performed.
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 */
97 while ((c
= getopt(argc
, argv
, "ptubdn:")) != EOF
) {
101 if (function
!= NONE
)
108 if (function
!= NONE
)
115 if (function
!= NONE
)
122 if (function
!= NONE
)
129 portnum
= (u_short
) atoi(optarg
); /* hope we don't get bogus # */
133 if (function
!= NONE
)
144 if (errflg
|| function
== NONE
) {
156 pmapdump(argc
- optind
, argv
+ optind
);
160 udpping(portnum
, argc
- optind
, argv
+ optind
);
164 tcpping(portnum
, argc
- optind
, argv
+ optind
);
172 brdcst(argc
- optind
, argv
+ optind
);
176 deletereg(argc
- optind
, argv
+ optind
);
184 udpping(portnum
, argc
, argv
)
190 struct sockaddr_in addr
;
191 enum clnt_stat rpc_stat
;
193 u_long prognum
, vers
, minvers
, maxvers
;
194 int sock
= RPC_ANYSOCK
;
195 struct rpc_err rpcerr
;
198 if (argc
< 2 || argc
> 3) {
202 prognum
= getprognum(argv
[1]);
203 get_inet_address(&addr
, argv
[0]);
204 /* Open the socket here so it will survive calls to clnt_destroy */
205 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
207 perror("rpcinfo: socket");
213 * A call to version 0 should fail with a program/version
214 * mismatch, and give us the range of versions supported.
216 addr
.sin_port
= htons(portnum
);
219 if ((client
= clntudp_create(&addr
, prognum
, (u_long
)0,
220 to
, &sock
)) == NULL
) {
221 clnt_pcreateerror("rpcinfo");
222 printf("program %lu is not available\n",
228 rpc_stat
= clnt_call(client
, NULLPROC
, xdr_void
, (char *)NULL
,
229 xdr_void
, (char *)NULL
, to
);
230 if (rpc_stat
== RPC_PROGVERSMISMATCH
) {
231 clnt_geterr(client
, &rpcerr
);
232 minvers
= rpcerr
.re_vers
.low
;
233 maxvers
= rpcerr
.re_vers
.high
;
234 } else if (rpc_stat
== RPC_SUCCESS
) {
236 * Oh dear, it DOES support version 0.
237 * Let's try version MAX_VERS.
239 addr
.sin_port
= htons(portnum
);
242 if ((client
= clntudp_create(&addr
, prognum
, MAX_VERS
,
243 to
, &sock
)) == NULL
) {
244 clnt_pcreateerror("rpcinfo");
245 printf("program %lu version %lu is not available\n",
251 rpc_stat
= clnt_call(client
, NULLPROC
, xdr_void
,
252 (char *)NULL
, xdr_void
, (char *)NULL
, to
);
253 if (rpc_stat
== RPC_PROGVERSMISMATCH
) {
254 clnt_geterr(client
, &rpcerr
);
255 minvers
= rpcerr
.re_vers
.low
;
256 maxvers
= rpcerr
.re_vers
.high
;
257 } else if (rpc_stat
== RPC_SUCCESS
) {
259 * It also supports version MAX_VERS.
260 * Looks like we have a wise guy.
261 * OK, we give them information on all
262 * 4 billion versions they support...
267 (void) pstatus(client
, prognum
, MAX_VERS
);
271 (void) pstatus(client
, prognum
, (u_long
)0);
274 clnt_destroy(client
);
275 for (vers
= minvers
; vers
<= maxvers
; vers
++) {
276 addr
.sin_port
= htons(portnum
);
279 if ((client
= clntudp_create(&addr
, prognum
, vers
,
280 to
, &sock
)) == NULL
) {
281 clnt_pcreateerror("rpcinfo");
282 printf("program %lu version %lu is not available\n",
288 rpc_stat
= clnt_call(client
, NULLPROC
, xdr_void
,
289 (char *)NULL
, xdr_void
, (char *)NULL
, to
);
290 if (pstatus(client
, prognum
, vers
) < 0)
292 clnt_destroy(client
);
296 vers
= getvers(argv
[2]);
297 addr
.sin_port
= htons(portnum
);
300 if ((client
= clntudp_create(&addr
, prognum
, vers
,
301 to
, &sock
)) == NULL
) {
302 clnt_pcreateerror("rpcinfo");
303 printf("program %lu version %lu is not available\n",
309 rpc_stat
= clnt_call(client
, 0, xdr_void
, (char *)NULL
,
310 xdr_void
, (char *)NULL
, to
);
311 if (pstatus(client
, prognum
, vers
) < 0)
314 (void) close(sock
); /* Close it up again */
320 tcpping(portnum
, argc
, argv
)
326 struct sockaddr_in addr
;
327 enum clnt_stat rpc_stat
;
329 u_long prognum
, vers
, minvers
, maxvers
;
330 int sock
= RPC_ANYSOCK
;
331 struct rpc_err rpcerr
;
334 if (argc
< 2 || argc
> 3) {
338 prognum
= getprognum(argv
[1]);
339 get_inet_address(&addr
, argv
[0]);
343 * A call to version 0 should fail with a program/version
344 * mismatch, and give us the range of versions supported.
346 addr
.sin_port
= htons(portnum
);
347 if ((client
= clnttcp_create(&addr
, prognum
, MIN_VERS
,
348 &sock
, 0, 0)) == NULL
) {
349 clnt_pcreateerror("rpcinfo");
350 printf("program %lu is not available\n",
356 rpc_stat
= clnt_call(client
, NULLPROC
, xdr_void
, (char *)NULL
,
357 xdr_void
, (char *)NULL
, to
);
358 if (rpc_stat
== RPC_PROGVERSMISMATCH
) {
359 clnt_geterr(client
, &rpcerr
);
360 minvers
= rpcerr
.re_vers
.low
;
361 maxvers
= rpcerr
.re_vers
.high
;
362 } else if (rpc_stat
== RPC_SUCCESS
) {
364 * Oh dear, it DOES support version 0.
365 * Let's try version MAX_VERS.
367 addr
.sin_port
= htons(portnum
);
368 if ((client
= clnttcp_create(&addr
, prognum
, MAX_VERS
,
369 &sock
, 0, 0)) == NULL
) {
370 clnt_pcreateerror("rpcinfo");
371 printf("program %lu version %lu is not available\n",
377 rpc_stat
= clnt_call(client
, NULLPROC
, xdr_void
,
378 (char *)NULL
, xdr_void
, (char *)NULL
, to
);
379 if (rpc_stat
== RPC_PROGVERSMISMATCH
) {
380 clnt_geterr(client
, &rpcerr
);
381 minvers
= rpcerr
.re_vers
.low
;
382 maxvers
= rpcerr
.re_vers
.high
;
383 } else if (rpc_stat
== RPC_SUCCESS
) {
385 * It also supports version MAX_VERS.
386 * Looks like we have a wise guy.
387 * OK, we give them information on all
388 * 4 billion versions they support...
393 (void) pstatus(client
, prognum
, MAX_VERS
);
397 (void) pstatus(client
, prognum
, MIN_VERS
);
400 clnt_destroy(client
);
402 sock
= RPC_ANYSOCK
; /* Re-initialize it for later */
403 for (vers
= minvers
; vers
<= maxvers
; vers
++) {
404 addr
.sin_port
= htons(portnum
);
405 if ((client
= clnttcp_create(&addr
, prognum
, vers
,
406 &sock
, 0, 0)) == NULL
) {
407 clnt_pcreateerror("rpcinfo");
408 printf("program %lu version %lu is not available\n",
414 rpc_stat
= clnt_call(client
, 0, xdr_void
, (char *)NULL
,
415 xdr_void
, (char *)NULL
, to
);
416 if (pstatus(client
, prognum
, vers
) < 0)
418 clnt_destroy(client
);
424 vers
= getvers(argv
[2]);
425 addr
.sin_port
= htons(portnum
);
426 if ((client
= clnttcp_create(&addr
, prognum
, vers
, &sock
,
428 clnt_pcreateerror("rpcinfo");
429 printf("program %lu version %lu is not available\n",
435 rpc_stat
= clnt_call(client
, 0, xdr_void
, (char *)NULL
,
436 xdr_void
, (char *)NULL
, to
);
437 if (pstatus(client
, prognum
, vers
) < 0)
445 * This routine should take a pointer to an "rpc_err" structure, rather than
446 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
447 * a CLIENT structure rather than a pointer to an "rpc_err" structure.
448 * As such, we have to keep the CLIENT structure around in order to print
449 * a good error message.
452 pstatus(client
, prognum
, vers
)
453 register CLIENT
*client
;
457 struct rpc_err rpcerr
;
459 clnt_geterr(client
, &rpcerr
);
460 if (rpcerr
.re_status
!= RPC_SUCCESS
) {
461 clnt_perror(client
, "rpcinfo");
462 printf("program %lu version %lu is not available\n",
466 printf("program %lu version %lu ready and waiting\n",
477 struct sockaddr_in server_addr
;
478 register struct hostent
*hp
;
479 struct pmaplist
*head
= NULL
;
480 int socket
= RPC_ANYSOCK
;
481 struct timeval minutetimeout
;
482 register CLIENT
*client
;
490 get_inet_address(&server_addr
, argv
[0]);
492 bzero((char *)&server_addr
, sizeof server_addr
);
493 server_addr
.sin_family
= AF_INET
;
494 if ((hp
= gethostbyname("localhost")) != NULL
)
495 bcopy(hp
->h_addr
, (caddr_t
)&server_addr
.sin_addr
,
498 server_addr
.sin_addr
.s_addr
= inet_addr("0.0.0.0");
500 minutetimeout
.tv_sec
= 60;
501 minutetimeout
.tv_usec
= 0;
502 server_addr
.sin_port
= htons(PMAPPORT
);
503 if ((client
= clnttcp_create(&server_addr
, PMAPPROG
,
504 PMAPVERS
, &socket
, 50, 500)) == NULL
) {
505 clnt_pcreateerror("rpcinfo: can't contact portmapper");
508 if (clnt_call(client
, PMAPPROC_DUMP
, xdr_void
, NULL
,
509 xdr_pmaplist
, &head
, minutetimeout
) != RPC_SUCCESS
) {
510 fprintf(stderr
, "rpcinfo: can't contact portmapper: ");
511 clnt_perror(client
, "rpcinfo");
515 printf("No remote programs registered.\n");
517 printf(" program vers proto port\n");
518 for (; head
!= NULL
; head
= head
->pml_next
) {
520 head
->pml_map
.pm_prog
,
521 head
->pml_map
.pm_vers
);
522 if (head
->pml_map
.pm_prot
== IPPROTO_UDP
)
523 printf("%6s", "udp");
524 else if (head
->pml_map
.pm_prot
== IPPROTO_TCP
)
525 printf("%6s", "tcp");
527 printf("%6ld", head
->pml_map
.pm_prot
);
528 printf("%7ld", head
->pml_map
.pm_port
);
529 rpc
= getrpcbynumber(head
->pml_map
.pm_prog
);
531 printf(" %s\n", rpc
->r_name
);
539 * reply_proc collects replies from the broadcast.
540 * to get a unique list of responses the output of rpcinfo should
541 * be piped through sort(1) and then uniq(1).
547 void *res
; /* Nothing comes back */
548 struct sockaddr_in
*who
; /* Who sent us the reply */
550 register struct hostent
*hp
;
552 hp
= gethostbyaddr((char *) &who
->sin_addr
, sizeof who
->sin_addr
,
554 printf("%s %s\n", inet_ntoa(who
->sin_addr
),
555 (hp
== NULL
) ? "(unknown)" : hp
->h_name
);
564 enum clnt_stat rpc_stat
;
565 u_long prognum
, vers
;
571 prognum
= getprognum(argv
[0]);
572 vers
= getvers(argv
[1]);
573 rpc_stat
= clnt_broadcast(prognum
, vers
, NULLPROC
, xdr_void
,
574 (char *)NULL
, xdr_void
, (char *)NULL
, reply_proc
);
575 if ((rpc_stat
!= RPC_SUCCESS
) && (rpc_stat
!= RPC_TIMEDOUT
)) {
576 fprintf(stderr
, "rpcinfo: broadcast failed: %s\n",
577 clnt_sperrno(rpc_stat
));
584 deletereg(argc
, argv
)
587 { u_long prog_num
, version_num
;
593 if (getuid()) { /* This command allowed only to root */
594 fprintf(stderr
, "Sorry. You are not root\n") ;
597 prog_num
= getprognum(argv
[0]);
598 version_num
= getvers(argv
[1]);
599 if ((pmap_unset(prog_num
, version_num
)) == 0) {
600 fprintf(stderr
, "rpcinfo: Could not delete registration for prog %s version %s\n",
609 fprintf(stderr
, "Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n");
610 fprintf(stderr
, " rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n");
611 fprintf(stderr
, " rpcinfo -p [ host ]\n");
612 fprintf(stderr
, " rpcinfo -b prognum versnum\n");
613 fprintf(stderr
, " rpcinfo -d prognum versnum\n") ;
620 register struct rpcent
*rpc
;
621 register u_long prognum
;
624 rpc
= getrpcbyname(arg
);
626 fprintf(stderr
, "rpcinfo: %s is unknown service\n",
630 prognum
= rpc
->r_number
;
632 prognum
= (u_long
) atoi(arg
);
642 register u_long vers
;
644 vers
= (int) atoi(arg
);
649 get_inet_address(addr
, host
)
650 struct sockaddr_in
*addr
;
653 register struct hostent
*hp
;
655 bzero((char *)addr
, sizeof *addr
);
656 addr
->sin_addr
.s_addr
= (u_long
) inet_addr(host
);
657 if (addr
->sin_addr
.s_addr
== -1 || addr
->sin_addr
.s_addr
== 0) {
658 if ((hp
= gethostbyname(host
)) == NULL
) {
659 fprintf(stderr
, "rpcinfo: %s is unknown host\n", host
);
662 bcopy(hp
->h_addr
, (char *)&addr
->sin_addr
, hp
->h_length
);
664 addr
->sin_family
= AF_INET
;