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 (portnum
, argc
, argv
)
210 struct sockaddr_in addr
;
211 enum clnt_stat rpc_stat
;
213 u_long prognum
, vers
, minvers
, maxvers
;
214 int sock
= RPC_ANYSOCK
;
215 struct rpc_err rpcerr
;
218 if (argc
< 2 || argc
> 3)
223 prognum
= getprognum (argv
[1]);
224 get_inet_address (&addr
, argv
[0]);
225 /* Open the socket here so it will survive calls to clnt_destroy */
226 sock
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
229 perror ("rpcinfo: socket");
236 * A call to version 0 should fail with a program/version
237 * mismatch, and give us the range of versions supported.
239 addr
.sin_port
= htons (portnum
);
242 if ((client
= clntudp_create (&addr
, prognum
, (u_long
) 0,
245 clnt_pcreateerror ("rpcinfo");
246 printf (_("program %lu is not available\n"), prognum
);
251 rpc_stat
= clnt_call (client
, NULLPROC
, (xdrproc_t
) xdr_void
,
252 (char *) NULL
, (xdrproc_t
) xdr_void
,
254 if (rpc_stat
== RPC_PROGVERSMISMATCH
)
256 clnt_geterr (client
, &rpcerr
);
257 minvers
= rpcerr
.re_vers
.low
;
258 maxvers
= rpcerr
.re_vers
.high
;
260 else if (rpc_stat
== RPC_SUCCESS
)
263 * Oh dear, it DOES support version 0.
264 * Let's try version MAX_VERS.
266 addr
.sin_port
= htons (portnum
);
269 if ((client
= clntudp_create (&addr
, prognum
, MAX_VERS
,
272 clnt_pcreateerror ("rpcinfo");
273 printf (_("program %lu version %lu is not available\n"),
279 rpc_stat
= clnt_call (client
, NULLPROC
, (xdrproc_t
) xdr_void
,
280 NULL
, (xdrproc_t
) xdr_void
, NULL
, to
);
281 if (rpc_stat
== RPC_PROGVERSMISMATCH
)
283 clnt_geterr (client
, &rpcerr
);
284 minvers
= rpcerr
.re_vers
.low
;
285 maxvers
= rpcerr
.re_vers
.high
;
287 else if (rpc_stat
== RPC_SUCCESS
)
290 * It also supports version MAX_VERS.
291 * Looks like we have a wise guy.
292 * OK, we give them information on all
293 * 4 billion versions they support...
300 (void) pstatus (client
, prognum
, MAX_VERS
);
306 (void) pstatus (client
, prognum
, (u_long
) 0);
309 clnt_destroy (client
);
310 for (vers
= minvers
; vers
<= maxvers
; vers
++)
312 addr
.sin_port
= htons (portnum
);
315 if ((client
= clntudp_create (&addr
, prognum
, vers
,
318 clnt_pcreateerror ("rpcinfo");
319 printf (_("program %lu version %lu is not available\n"),
325 rpc_stat
= clnt_call (client
, NULLPROC
, (xdrproc_t
) xdr_void
,
326 NULL
, (xdrproc_t
) xdr_void
, NULL
, to
);
327 if (pstatus (client
, prognum
, vers
) < 0)
329 clnt_destroy (client
);
334 vers
= getvers (argv
[2]);
335 addr
.sin_port
= htons (portnum
);
338 if ((client
= clntudp_create (&addr
, prognum
, vers
,
341 clnt_pcreateerror ("rpcinfo");
342 printf (_("program %lu version %lu is not available\n"),
348 rpc_stat
= clnt_call (client
, 0, (xdrproc_t
) xdr_void
, NULL
,
349 (xdrproc_t
) xdr_void
, NULL
, to
);
350 if (pstatus (client
, prognum
, vers
) < 0)
353 (void) close (sock
); /* Close it up again */
359 tcpping (portnum
, argc
, argv
)
365 struct sockaddr_in addr
;
366 enum clnt_stat rpc_stat
;
368 u_long prognum
, vers
, minvers
, maxvers
;
369 int sock
= RPC_ANYSOCK
;
370 struct rpc_err rpcerr
;
373 if (argc
< 2 || argc
> 3)
378 prognum
= getprognum (argv
[1]);
379 get_inet_address (&addr
, argv
[0]);
384 * A call to version 0 should fail with a program/version
385 * mismatch, and give us the range of versions supported.
387 addr
.sin_port
= htons (portnum
);
388 if ((client
= clnttcp_create (&addr
, prognum
, MIN_VERS
,
389 &sock
, 0, 0)) == NULL
)
391 clnt_pcreateerror ("rpcinfo");
392 printf (_("program %lu is not available\n"), prognum
);
397 rpc_stat
= clnt_call (client
, NULLPROC
, (xdrproc_t
) xdr_void
, NULL
,
398 (xdrproc_t
) xdr_void
, NULL
, to
);
399 if (rpc_stat
== RPC_PROGVERSMISMATCH
)
401 clnt_geterr (client
, &rpcerr
);
402 minvers
= rpcerr
.re_vers
.low
;
403 maxvers
= rpcerr
.re_vers
.high
;
405 else if (rpc_stat
== RPC_SUCCESS
)
408 * Oh dear, it DOES support version 0.
409 * Let's try version MAX_VERS.
411 addr
.sin_port
= htons (portnum
);
412 if ((client
= clnttcp_create (&addr
, prognum
, MAX_VERS
,
413 &sock
, 0, 0)) == NULL
)
415 clnt_pcreateerror ("rpcinfo");
416 printf (_("program %lu version %lu is not available\n"),
422 rpc_stat
= clnt_call (client
, NULLPROC
, (xdrproc_t
) xdr_void
,
423 NULL
, (xdrproc_t
) xdr_void
, NULL
, to
);
424 if (rpc_stat
== RPC_PROGVERSMISMATCH
)
426 clnt_geterr (client
, &rpcerr
);
427 minvers
= rpcerr
.re_vers
.low
;
428 maxvers
= rpcerr
.re_vers
.high
;
430 else if (rpc_stat
== RPC_SUCCESS
)
433 * It also supports version MAX_VERS.
434 * Looks like we have a wise guy.
435 * OK, we give them information on all
436 * 4 billion versions they support...
443 (void) pstatus (client
, prognum
, MAX_VERS
);
449 (void) pstatus (client
, prognum
, MIN_VERS
);
452 clnt_destroy (client
);
454 sock
= RPC_ANYSOCK
; /* Re-initialize it for later */
455 for (vers
= minvers
; vers
<= maxvers
; vers
++)
457 addr
.sin_port
= htons (portnum
);
458 if ((client
= clnttcp_create (&addr
, prognum
, vers
,
459 &sock
, 0, 0)) == NULL
)
461 clnt_pcreateerror ("rpcinfo");
462 printf (_("program %lu version %lu is not available\n"),
468 rpc_stat
= clnt_call (client
, 0, (xdrproc_t
) xdr_void
, NULL
,
469 (xdrproc_t
) xdr_void
, NULL
, to
);
470 if (pstatus (client
, prognum
, vers
) < 0)
472 clnt_destroy (client
);
479 vers
= getvers (argv
[2]);
480 addr
.sin_port
= htons (portnum
);
481 if ((client
= clnttcp_create (&addr
, prognum
, vers
, &sock
,
484 clnt_pcreateerror ("rpcinfo");
485 printf (_("program %lu version %lu is not available\n"),
491 rpc_stat
= clnt_call (client
, 0, (xdrproc_t
) xdr_void
, NULL
,
492 (xdrproc_t
) xdr_void
, NULL
, to
);
493 if (pstatus (client
, prognum
, vers
) < 0)
501 * This routine should take a pointer to an "rpc_err" structure, rather than
502 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
503 * a CLIENT structure rather than a pointer to an "rpc_err" structure.
504 * As such, we have to keep the CLIENT structure around in order to print
505 * a good error message.
508 pstatus (client
, prognum
, vers
)
509 register CLIENT
*client
;
513 struct rpc_err rpcerr
;
515 clnt_geterr (client
, &rpcerr
);
516 if (rpcerr
.re_status
!= RPC_SUCCESS
)
518 clnt_perror (client
, "rpcinfo");
519 printf (_("program %lu version %lu is not available\n"), prognum
, vers
);
524 printf (_("program %lu version %lu ready and waiting\n"), prognum
, vers
);
530 pmapdump (argc
, argv
)
534 struct sockaddr_in server_addr
;
535 register struct hostent
*hp
;
536 struct pmaplist
*head
= NULL
;
537 int socket
= RPC_ANYSOCK
;
538 struct timeval minutetimeout
;
539 register CLIENT
*client
;
548 get_inet_address (&server_addr
, argv
[0]);
551 bzero ((char *) &server_addr
, sizeof server_addr
);
552 server_addr
.sin_family
= AF_INET
;
553 if ((hp
= gethostbyname ("localhost")) != NULL
)
554 memcpy ((caddr_t
) & server_addr
.sin_addr
, hp
->h_addr
,
557 server_addr
.sin_addr
.s_addr
= inet_addr ("0.0.0.0");
559 minutetimeout
.tv_sec
= 60;
560 minutetimeout
.tv_usec
= 0;
561 server_addr
.sin_port
= htons (PMAPPORT
);
562 if ((client
= clnttcp_create (&server_addr
, PMAPPROG
,
563 PMAPVERS
, &socket
, 50, 500)) == NULL
)
565 clnt_pcreateerror (_("rpcinfo: can't contact portmapper"));
568 if (clnt_call (client
, PMAPPROC_DUMP
, (xdrproc_t
) xdr_void
, NULL
,
569 (xdrproc_t
) xdr_pmaplist
, (caddr_t
) &head
,
570 minutetimeout
) != RPC_SUCCESS
)
572 fputs (_("rpcinfo: can't contact portmapper"), stderr
);
573 fputs (": ", stderr
);
574 clnt_perror (client
, "rpcinfo");
579 fputs (_("No remote programs registered.\n"), stdout
);
583 fputs (_(" program vers proto port\n"), stdout
);
584 for (; head
!= NULL
; head
= head
->pml_next
)
587 head
->pml_map
.pm_prog
,
588 head
->pml_map
.pm_vers
);
589 if (head
->pml_map
.pm_prot
== IPPROTO_UDP
)
590 printf ("%6s", "udp");
591 else if (head
->pml_map
.pm_prot
== IPPROTO_TCP
)
592 printf ("%6s", "tcp");
594 printf ("%6ld", head
->pml_map
.pm_prot
);
595 printf ("%7ld", head
->pml_map
.pm_port
);
596 rpc
= getrpcbynumber (head
->pml_map
.pm_prog
);
598 printf (" %s\n", rpc
->r_name
);
606 * reply_proc collects replies from the broadcast.
607 * to get a unique list of responses the output of rpcinfo should
608 * be piped through sort(1) and then uniq(1).
613 reply_proc (res
, who
)
614 void *res
; /* Nothing comes back */
615 struct sockaddr_in
*who
; /* Who sent us the reply */
617 register struct hostent
*hp
;
619 hp
= gethostbyaddr ((char *) &who
->sin_addr
, sizeof who
->sin_addr
,
621 printf ("%s %s\n", inet_ntoa (who
->sin_addr
),
622 (hp
== NULL
) ? _("(unknown)") : hp
->h_name
);
631 enum clnt_stat rpc_stat
;
632 u_long prognum
, vers
;
639 prognum
= getprognum (argv
[0]);
640 vers
= getvers (argv
[1]);
641 rpc_stat
= clnt_broadcast (prognum
, vers
, NULLPROC
, (xdrproc_t
) xdr_void
,
642 NULL
, (xdrproc_t
) xdr_void
, NULL
,
643 (resultproc_t
) reply_proc
);
644 if ((rpc_stat
!= RPC_SUCCESS
) && (rpc_stat
!= RPC_TIMEDOUT
))
646 fprintf (stderr
, _("rpcinfo: broadcast failed: %s\n"),
647 clnt_sperrno (rpc_stat
));
654 deletereg (argc
, argv
)
658 u_long prog_num
, version_num
;
666 { /* This command allowed only to root */
667 fputs (_("Sorry. You are not root\n"), stderr
);
670 prog_num
= getprognum (argv
[0]);
671 version_num
= getvers (argv
[1]);
672 if ((pmap_unset (prog_num
, version_num
)) == 0)
674 fprintf (stderr
, _("rpcinfo: Could not delete registration for prog %s version %s\n"),
683 fputs (_("Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n"),
685 fputs (_(" rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n"),
687 fputs (_(" rpcinfo -p [ host ]\n"), stream
);
688 fputs (_(" rpcinfo -b prognum versnum\n"), stream
);
689 fputs (_(" rpcinfo -d prognum versnum\n"), stream
);
690 fputc ('\n', stream
);
691 fprintf (stream
, _("\
692 For bug reporting instructions, please see:\n\
693 %s.\n"), REPORT_BUGS_TO
);
699 printf ("rpcinfo %s%s\n", PKGVERSION
, VERSION
);
706 register struct rpcent
*rpc
;
707 register u_long prognum
;
711 rpc
= getrpcbyname (arg
);
714 fprintf (stderr
, _("rpcinfo: %s is unknown service\n"), arg
);
717 prognum
= rpc
->r_number
;
721 prognum
= (u_long
) atoi (arg
);
731 register u_long vers
;
733 vers
= (int) atoi (arg
);
738 get_inet_address (addr
, host
)
739 struct sockaddr_in
*addr
;
742 register struct hostent
*hp
;
744 bzero ((char *) addr
, sizeof *addr
);
745 addr
->sin_addr
.s_addr
= (u_long
) inet_addr (host
);
746 if (addr
->sin_addr
.s_addr
== INADDR_NONE
747 || addr
->sin_addr
.s_addr
== INADDR_ANY
)
749 if ((hp
= gethostbyname (host
)) == NULL
)
751 fprintf (stderr
, _("rpcinfo: %s is unknown host\n"),
755 memmove ((char *) &addr
->sin_addr
, hp
->h_addr
, hp
->h_length
);
757 addr
->sin_family
= AF_INET
;