2 * Copyright (c) 2010, Oracle America, Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 * * Neither the name of the "Oracle America, Inc." nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * rpcinfo: ping a particular rpc program
34 * or dump the portmapper
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
46 #include <rpc/pmap_prot.h>
47 #include <rpc/pmap_clnt.h>
53 #include "../version.h"
54 #define PACKAGE _libc_intl_domainname
56 #define MAXHOSTLEN 256
58 #define MIN_VERS ((u_long) 0)
59 #define MAX_VERS ((u_long) 4294967295UL)
61 static void udpping (u_short portflag
, int argc
, char **argv
);
62 static void tcpping (u_short portflag
, int argc
, char **argv
);
63 static int pstatus (CLIENT
*client
, u_long prognum
, u_long vers
);
64 static void pmapdump (int argc
, char **argv
);
65 static bool_t
reply_proc (void *res
, struct sockaddr_in
*who
);
66 static void brdcst (int argc
, char **argv
) __attribute__ ((noreturn
));
67 static void deletereg (int argc
, char **argv
);
68 static void usage (FILE *stream
);
69 static void print_version (void);
70 static u_long
getprognum (char *arg
);
71 static u_long
getvers (char *arg
);
72 static void get_inet_address (struct sockaddr_in
*addr
, char *host
);
75 * Functions to be performed.
77 #define NONE 0 /* no function */
78 #define PMAPDUMP 1 /* dump portmapper registrations */
79 #define TCPPING 2 /* ping TCP service */
80 #define UDPPING 3 /* ping UDP service */
81 #define BRDCST 4 /* ping broadcast UDP service */
82 #define DELETES 5 /* delete registration for the service */
85 main (int argc
, char **argv
)
91 static const struct option long_options
[] = {
92 { "help", no_argument
, NULL
, 'H' },
93 { "version", no_argument
, NULL
, 'V' },
97 setlocale (LC_ALL
, "");
98 textdomain (_libc_intl_domainname
);
103 while ((c
= getopt_long (argc
, argv
, "ptubdn:", long_options
, NULL
)) != -1)
109 if (function
!= NONE
)
116 if (function
!= NONE
)
123 if (function
!= NONE
)
130 if (function
!= NONE
)
137 portnum
= (u_short
) atoi (optarg
); /* hope we don't get bogus # */
141 if (function
!= NONE
)
160 if (errflg
|| function
== NONE
)
175 pmapdump (argc
- optind
, argv
+ optind
);
179 udpping (portnum
, argc
- optind
, argv
+ optind
);
183 tcpping (portnum
, argc
- optind
, argv
+ optind
);
192 brdcst (argc
- optind
, argv
+ optind
);
196 deletereg (argc
- optind
, argv
+ optind
);
204 udpping (u_short portnum
, int argc
, char **argv
)
207 struct sockaddr_in addr
;
208 enum clnt_stat rpc_stat
;
210 u_long prognum
, vers
, minvers
, maxvers
;
211 int sock
= RPC_ANYSOCK
;
212 struct rpc_err rpcerr
;
215 if (argc
< 2 || argc
> 3)
220 prognum
= getprognum (argv
[1]);
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
);
226 perror ("rpcinfo: socket");
233 * A call to version 0 should fail with a program/version
234 * mismatch, and give us the range of versions supported.
236 addr
.sin_port
= htons (portnum
);
239 if ((client
= clntudp_create (&addr
, prognum
, (u_long
) 0,
242 clnt_pcreateerror ("rpcinfo");
243 printf (_("program %lu is not available\n"), prognum
);
248 rpc_stat
= clnt_call (client
, NULLPROC
, (xdrproc_t
) xdr_void
,
249 (char *) NULL
, (xdrproc_t
) xdr_void
,
251 if (rpc_stat
== RPC_PROGVERSMISMATCH
)
253 clnt_geterr (client
, &rpcerr
);
254 minvers
= rpcerr
.re_vers
.low
;
255 maxvers
= rpcerr
.re_vers
.high
;
257 else if (rpc_stat
== RPC_SUCCESS
)
260 * Oh dear, it DOES support version 0.
261 * Let's try version MAX_VERS.
263 addr
.sin_port
= htons (portnum
);
266 if ((client
= clntudp_create (&addr
, prognum
, MAX_VERS
,
269 clnt_pcreateerror ("rpcinfo");
270 printf (_("program %lu version %lu is not available\n"),
276 rpc_stat
= clnt_call (client
, NULLPROC
, (xdrproc_t
) xdr_void
,
277 NULL
, (xdrproc_t
) xdr_void
, NULL
, to
);
278 if (rpc_stat
== RPC_PROGVERSMISMATCH
)
280 clnt_geterr (client
, &rpcerr
);
281 minvers
= rpcerr
.re_vers
.low
;
282 maxvers
= rpcerr
.re_vers
.high
;
284 else if (rpc_stat
== RPC_SUCCESS
)
287 * It also supports version MAX_VERS.
288 * Looks like we have a wise guy.
289 * OK, we give them information on all
290 * 4 billion versions they support...
297 (void) pstatus (client
, prognum
, MAX_VERS
);
303 (void) pstatus (client
, prognum
, (u_long
) 0);
306 clnt_destroy (client
);
307 for (vers
= minvers
; vers
<= maxvers
; vers
++)
309 addr
.sin_port
= htons (portnum
);
312 if ((client
= clntudp_create (&addr
, prognum
, vers
,
315 clnt_pcreateerror ("rpcinfo");
316 printf (_("program %lu version %lu is not available\n"),
322 rpc_stat
= clnt_call (client
, NULLPROC
, (xdrproc_t
) xdr_void
,
323 NULL
, (xdrproc_t
) xdr_void
, NULL
, to
);
324 if (pstatus (client
, prognum
, vers
) < 0)
326 clnt_destroy (client
);
331 vers
= getvers (argv
[2]);
332 addr
.sin_port
= htons (portnum
);
335 if ((client
= clntudp_create (&addr
, prognum
, vers
,
338 clnt_pcreateerror ("rpcinfo");
339 printf (_("program %lu version %lu is not available\n"),
345 rpc_stat
= clnt_call (client
, 0, (xdrproc_t
) xdr_void
, NULL
,
346 (xdrproc_t
) xdr_void
, NULL
, to
);
347 if (pstatus (client
, prognum
, vers
) < 0)
350 (void) close (sock
); /* Close it up again */
356 tcpping (u_short portnum
, int argc
, char **argv
)
359 struct sockaddr_in addr
;
360 enum clnt_stat rpc_stat
;
362 u_long prognum
, vers
, minvers
, maxvers
;
363 int sock
= RPC_ANYSOCK
;
364 struct rpc_err rpcerr
;
367 if (argc
< 2 || argc
> 3)
372 prognum
= getprognum (argv
[1]);
373 get_inet_address (&addr
, argv
[0]);
378 * A call to version 0 should fail with a program/version
379 * mismatch, and give us the range of versions supported.
381 addr
.sin_port
= htons (portnum
);
382 if ((client
= clnttcp_create (&addr
, prognum
, MIN_VERS
,
383 &sock
, 0, 0)) == NULL
)
385 clnt_pcreateerror ("rpcinfo");
386 printf (_("program %lu is not available\n"), prognum
);
391 rpc_stat
= clnt_call (client
, NULLPROC
, (xdrproc_t
) xdr_void
, NULL
,
392 (xdrproc_t
) xdr_void
, NULL
, to
);
393 if (rpc_stat
== RPC_PROGVERSMISMATCH
)
395 clnt_geterr (client
, &rpcerr
);
396 minvers
= rpcerr
.re_vers
.low
;
397 maxvers
= rpcerr
.re_vers
.high
;
399 else if (rpc_stat
== RPC_SUCCESS
)
402 * Oh dear, it DOES support version 0.
403 * Let's try version MAX_VERS.
405 addr
.sin_port
= htons (portnum
);
406 if ((client
= clnttcp_create (&addr
, prognum
, MAX_VERS
,
407 &sock
, 0, 0)) == NULL
)
409 clnt_pcreateerror ("rpcinfo");
410 printf (_("program %lu version %lu is not available\n"),
416 rpc_stat
= clnt_call (client
, NULLPROC
, (xdrproc_t
) xdr_void
,
417 NULL
, (xdrproc_t
) xdr_void
, NULL
, to
);
418 if (rpc_stat
== RPC_PROGVERSMISMATCH
)
420 clnt_geterr (client
, &rpcerr
);
421 minvers
= rpcerr
.re_vers
.low
;
422 maxvers
= rpcerr
.re_vers
.high
;
424 else if (rpc_stat
== RPC_SUCCESS
)
427 * It also supports version MAX_VERS.
428 * Looks like we have a wise guy.
429 * OK, we give them information on all
430 * 4 billion versions they support...
437 (void) pstatus (client
, prognum
, MAX_VERS
);
443 (void) pstatus (client
, prognum
, MIN_VERS
);
446 clnt_destroy (client
);
448 sock
= RPC_ANYSOCK
; /* Re-initialize it for later */
449 for (vers
= minvers
; vers
<= maxvers
; vers
++)
451 addr
.sin_port
= htons (portnum
);
452 if ((client
= clnttcp_create (&addr
, prognum
, vers
,
453 &sock
, 0, 0)) == NULL
)
455 clnt_pcreateerror ("rpcinfo");
456 printf (_("program %lu version %lu is not available\n"),
462 rpc_stat
= clnt_call (client
, 0, (xdrproc_t
) xdr_void
, NULL
,
463 (xdrproc_t
) xdr_void
, NULL
, to
);
464 if (pstatus (client
, prognum
, vers
) < 0)
466 clnt_destroy (client
);
473 vers
= getvers (argv
[2]);
474 addr
.sin_port
= htons (portnum
);
475 if ((client
= clnttcp_create (&addr
, prognum
, vers
, &sock
,
478 clnt_pcreateerror ("rpcinfo");
479 printf (_("program %lu version %lu is not available\n"),
485 rpc_stat
= clnt_call (client
, 0, (xdrproc_t
) xdr_void
, NULL
,
486 (xdrproc_t
) xdr_void
, NULL
, to
);
487 if (pstatus (client
, prognum
, vers
) < 0)
495 * This routine should take a pointer to an "rpc_err" structure, rather than
496 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
497 * a CLIENT structure rather than a pointer to an "rpc_err" structure.
498 * As such, we have to keep the CLIENT structure around in order to print
499 * a good error message.
502 pstatus (register CLIENT
*client
, u_long prognum
, u_long vers
)
504 struct rpc_err rpcerr
;
506 clnt_geterr (client
, &rpcerr
);
507 if (rpcerr
.re_status
!= RPC_SUCCESS
)
509 clnt_perror (client
, "rpcinfo");
510 printf (_("program %lu version %lu is not available\n"), prognum
, vers
);
515 printf (_("program %lu version %lu ready and waiting\n"), prognum
, vers
);
521 pmapdump (int argc
, char **argv
)
523 struct sockaddr_in server_addr
;
524 register struct hostent
*hp
;
525 struct pmaplist
*head
= NULL
;
526 int socket
= RPC_ANYSOCK
;
527 struct timeval minutetimeout
;
528 register CLIENT
*client
;
537 get_inet_address (&server_addr
, argv
[0]);
540 bzero ((char *) &server_addr
, sizeof server_addr
);
541 server_addr
.sin_family
= AF_INET
;
542 if ((hp
= gethostbyname ("localhost")) != NULL
)
543 memcpy ((caddr_t
) & server_addr
.sin_addr
, hp
->h_addr
,
546 server_addr
.sin_addr
.s_addr
= inet_addr ("0.0.0.0");
548 minutetimeout
.tv_sec
= 60;
549 minutetimeout
.tv_usec
= 0;
550 server_addr
.sin_port
= htons (PMAPPORT
);
551 if ((client
= clnttcp_create (&server_addr
, PMAPPROG
,
552 PMAPVERS
, &socket
, 50, 500)) == NULL
)
554 clnt_pcreateerror (_("rpcinfo: can't contact portmapper"));
557 if (clnt_call (client
, PMAPPROC_DUMP
, (xdrproc_t
) xdr_void
, NULL
,
558 (xdrproc_t
) xdr_pmaplist
, (caddr_t
) &head
,
559 minutetimeout
) != RPC_SUCCESS
)
561 fputs (_("rpcinfo: can't contact portmapper"), stderr
);
562 fputs (": ", stderr
);
563 clnt_perror (client
, "rpcinfo");
568 fputs (_("No remote programs registered.\n"), stdout
);
572 fputs (_(" program vers proto port\n"), stdout
);
573 for (; head
!= NULL
; head
= head
->pml_next
)
576 head
->pml_map
.pm_prog
,
577 head
->pml_map
.pm_vers
);
578 if (head
->pml_map
.pm_prot
== IPPROTO_UDP
)
579 printf ("%6s", "udp");
580 else if (head
->pml_map
.pm_prot
== IPPROTO_TCP
)
581 printf ("%6s", "tcp");
583 printf ("%6ld", head
->pml_map
.pm_prot
);
584 printf ("%7ld", head
->pml_map
.pm_port
);
585 rpc
= getrpcbynumber (head
->pml_map
.pm_prog
);
587 printf (" %s\n", rpc
->r_name
);
595 * reply_proc collects replies from the broadcast.
596 * to get a unique list of responses the output of rpcinfo should
597 * be piped through sort(1) and then uniq(1).
602 reply_proc (res
, who
)
603 void *res
; /* Nothing comes back */
604 struct sockaddr_in
*who
; /* Who sent us the reply */
606 register struct hostent
*hp
;
608 hp
= gethostbyaddr ((char *) &who
->sin_addr
, sizeof who
->sin_addr
,
610 printf ("%s %s\n", inet_ntoa (who
->sin_addr
),
611 (hp
== NULL
) ? _("(unknown)") : hp
->h_name
);
616 brdcst (int argc
, char **argv
)
618 enum clnt_stat rpc_stat
;
619 u_long prognum
, vers
;
626 prognum
= getprognum (argv
[0]);
627 vers
= getvers (argv
[1]);
628 rpc_stat
= clnt_broadcast (prognum
, vers
, NULLPROC
, (xdrproc_t
) xdr_void
,
629 NULL
, (xdrproc_t
) xdr_void
, NULL
,
630 (resultproc_t
) reply_proc
);
631 if ((rpc_stat
!= RPC_SUCCESS
) && (rpc_stat
!= RPC_TIMEDOUT
))
633 fprintf (stderr
, _("rpcinfo: broadcast failed: %s\n"),
634 clnt_sperrno (rpc_stat
));
641 deletereg (int argc
, char **argv
)
643 u_long prog_num
, version_num
;
651 { /* This command allowed only to root */
652 fputs (_("Sorry. You are not root\n"), stderr
);
655 prog_num
= getprognum (argv
[0]);
656 version_num
= getvers (argv
[1]);
657 if ((pmap_unset (prog_num
, version_num
)) == 0)
659 fprintf (stderr
, _("rpcinfo: Could not delete registration for prog %s version %s\n"),
668 fputs (_("Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n"),
670 fputs (_(" rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n"),
672 fputs (_(" rpcinfo -p [ host ]\n"), stream
);
673 fputs (_(" rpcinfo -b prognum versnum\n"), stream
);
674 fputs (_(" rpcinfo -d prognum versnum\n"), stream
);
675 fputc ('\n', stream
);
676 fprintf (stream
, _("\
677 For bug reporting instructions, please see:\n\
678 %s.\n"), REPORT_BUGS_TO
);
684 printf ("rpcinfo %s%s\n", PKGVERSION
, VERSION
);
688 getprognum (char *arg
)
690 register struct rpcent
*rpc
;
691 register u_long prognum
;
695 rpc
= getrpcbyname (arg
);
698 fprintf (stderr
, _("rpcinfo: %s is unknown service\n"), arg
);
701 prognum
= rpc
->r_number
;
705 prognum
= (u_long
) atoi (arg
);
714 register u_long vers
;
716 vers
= (int) atoi (arg
);
721 get_inet_address (struct sockaddr_in
*addr
, char *host
)
723 register struct hostent
*hp
;
725 bzero ((char *) addr
, sizeof *addr
);
726 addr
->sin_addr
.s_addr
= (u_long
) inet_addr (host
);
727 if (addr
->sin_addr
.s_addr
== INADDR_NONE
728 || addr
->sin_addr
.s_addr
== INADDR_ANY
)
730 if ((hp
= gethostbyname (host
)) == NULL
)
732 fprintf (stderr
, _("rpcinfo: %s is unknown host\n"),
736 memmove ((char *) &addr
->sin_addr
, hp
->h_addr
, hp
->h_length
);
738 addr
->sin_family
= AF_INET
;