]> git.ipfire.org Git - thirdparty/glibc.git/blob - sunrpc/rpcinfo.c
Support --with-pkgversion and --with-bugurl.
[thirdparty/glibc.git] / sunrpc / rpcinfo.c
1 /*
2 * Copyright (c) 2010, Oracle America, Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
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.
17 *
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.
30 */
31
32 /*
33 * rpcinfo: ping a particular rpc program
34 * or dump the portmapper
35 */
36
37 #include <getopt.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <rpc/rpc.h>
41 #include <stdio.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <netdb.h>
46 #include <rpc/pmap_prot.h>
47 #include <rpc/pmap_clnt.h>
48 #include <signal.h>
49 #include <ctype.h>
50 #include <locale.h>
51 #include <libintl.h>
52
53 #include "../version.h"
54 #define PACKAGE _libc_intl_domainname
55
56 #define MAXHOSTLEN 256
57
58 #define MIN_VERS ((u_long) 0)
59 #define MAX_VERS ((u_long) 4294967295UL)
60
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);
73
74 /*
75 * Functions to be performed.
76 */
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 */
83
84 int
85 main (int argc, char **argv)
86 {
87 register int c;
88 int errflg;
89 int function;
90 u_short portnum;
91 static const struct option long_options[] = {
92 { "help", no_argument, NULL, 'H' },
93 { "version", no_argument, NULL, 'V' },
94 { NULL, 0, NULL, 0 }
95 };
96
97 setlocale (LC_ALL, "");
98 textdomain (_libc_intl_domainname);
99
100 function = NONE;
101 portnum = 0;
102 errflg = 0;
103 while ((c = getopt_long (argc, argv, "ptubdn:", long_options, NULL)) != -1)
104 {
105 switch (c)
106 {
107
108 case 'p':
109 if (function != NONE)
110 errflg = 1;
111 else
112 function = PMAPDUMP;
113 break;
114
115 case 't':
116 if (function != NONE)
117 errflg = 1;
118 else
119 function = TCPPING;
120 break;
121
122 case 'u':
123 if (function != NONE)
124 errflg = 1;
125 else
126 function = UDPPING;
127 break;
128
129 case 'b':
130 if (function != NONE)
131 errflg = 1;
132 else
133 function = BRDCST;
134 break;
135
136 case 'n':
137 portnum = (u_short) atoi (optarg); /* hope we don't get bogus # */
138 break;
139
140 case 'd':
141 if (function != NONE)
142 errflg = 1;
143 else
144 function = DELETES;
145 break;
146
147 case 'H':
148 usage (stdout);
149 return 0;
150
151 case 'V':
152 print_version ();
153 return 0;
154
155 case '?':
156 errflg = 1;
157 }
158 }
159
160 if (errflg || function == NONE)
161 {
162 usage (stderr);
163 return 1;
164 }
165
166 switch (function)
167 {
168
169 case PMAPDUMP:
170 if (portnum != 0)
171 {
172 usage (stderr);
173 return 1;
174 }
175 pmapdump (argc - optind, argv + optind);
176 break;
177
178 case UDPPING:
179 udpping (portnum, argc - optind, argv + optind);
180 break;
181
182 case TCPPING:
183 tcpping (portnum, argc - optind, argv + optind);
184 break;
185
186 case BRDCST:
187 if (portnum != 0)
188 {
189 usage (stderr);
190 return 1;
191 }
192 brdcst (argc - optind, argv + optind);
193 break;
194
195 case DELETES:
196 deletereg (argc - optind, argv + optind);
197 break;
198 }
199
200 return 0;
201 }
202
203 static 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 || argc > 3)
219 {
220 usage (stderr);
221 exit (1);
222 }
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);
227 if (sock < 0)
228 {
229 perror ("rpcinfo: socket");
230 exit (1);
231 }
232 failure = 0;
233 if (argc == 2)
234 {
235 /*
236 * A call to version 0 should fail with a program/version
237 * mismatch, and give us the range of versions supported.
238 */
239 addr.sin_port = htons (portnum);
240 to.tv_sec = 5;
241 to.tv_usec = 0;
242 if ((client = clntudp_create (&addr, prognum, (u_long) 0,
243 to, &sock)) == NULL)
244 {
245 clnt_pcreateerror ("rpcinfo");
246 printf (_("program %lu is not available\n"), prognum);
247 exit (1);
248 }
249 to.tv_sec = 10;
250 to.tv_usec = 0;
251 rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
252 (char *) NULL, (xdrproc_t) xdr_void,
253 (char *) NULL, to);
254 if (rpc_stat == RPC_PROGVERSMISMATCH)
255 {
256 clnt_geterr (client, &rpcerr);
257 minvers = rpcerr.re_vers.low;
258 maxvers = rpcerr.re_vers.high;
259 }
260 else if (rpc_stat == RPC_SUCCESS)
261 {
262 /*
263 * Oh dear, it DOES support version 0.
264 * Let's try version MAX_VERS.
265 */
266 addr.sin_port = htons (portnum);
267 to.tv_sec = 5;
268 to.tv_usec = 0;
269 if ((client = clntudp_create (&addr, prognum, MAX_VERS,
270 to, &sock)) == NULL)
271 {
272 clnt_pcreateerror ("rpcinfo");
273 printf (_("program %lu version %lu is not available\n"),
274 prognum, MAX_VERS);
275 exit (1);
276 }
277 to.tv_sec = 10;
278 to.tv_usec = 0;
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)
282 {
283 clnt_geterr (client, &rpcerr);
284 minvers = rpcerr.re_vers.low;
285 maxvers = rpcerr.re_vers.high;
286 }
287 else if (rpc_stat == RPC_SUCCESS)
288 {
289 /*
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...
294 */
295 minvers = 0;
296 maxvers = MAX_VERS;
297 }
298 else
299 {
300 (void) pstatus (client, prognum, MAX_VERS);
301 exit (1);
302 }
303 }
304 else
305 {
306 (void) pstatus (client, prognum, (u_long) 0);
307 exit (1);
308 }
309 clnt_destroy (client);
310 for (vers = minvers; vers <= maxvers; vers++)
311 {
312 addr.sin_port = htons (portnum);
313 to.tv_sec = 5;
314 to.tv_usec = 0;
315 if ((client = clntudp_create (&addr, prognum, vers,
316 to, &sock)) == NULL)
317 {
318 clnt_pcreateerror ("rpcinfo");
319 printf (_("program %lu version %lu is not available\n"),
320 prognum, vers);
321 exit (1);
322 }
323 to.tv_sec = 10;
324 to.tv_usec = 0;
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)
328 failure = 1;
329 clnt_destroy (client);
330 }
331 }
332 else
333 {
334 vers = getvers (argv[2]);
335 addr.sin_port = htons (portnum);
336 to.tv_sec = 5;
337 to.tv_usec = 0;
338 if ((client = clntudp_create (&addr, prognum, vers,
339 to, &sock)) == NULL)
340 {
341 clnt_pcreateerror ("rpcinfo");
342 printf (_("program %lu version %lu is not available\n"),
343 prognum, vers);
344 exit (1);
345 }
346 to.tv_sec = 10;
347 to.tv_usec = 0;
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)
351 failure = 1;
352 }
353 (void) close (sock); /* Close it up again */
354 if (failure)
355 exit (1);
356 }
357
358 static void
359 tcpping (portnum, argc, argv)
360 u_short portnum;
361 int argc;
362 char **argv;
363 {
364 struct timeval to;
365 struct sockaddr_in addr;
366 enum clnt_stat rpc_stat;
367 CLIENT *client;
368 u_long prognum, vers, minvers, maxvers;
369 int sock = RPC_ANYSOCK;
370 struct rpc_err rpcerr;
371 int failure;
372
373 if (argc < 2 || argc > 3)
374 {
375 usage (stderr);
376 exit (1);
377 }
378 prognum = getprognum (argv[1]);
379 get_inet_address (&addr, argv[0]);
380 failure = 0;
381 if (argc == 2)
382 {
383 /*
384 * A call to version 0 should fail with a program/version
385 * mismatch, and give us the range of versions supported.
386 */
387 addr.sin_port = htons (portnum);
388 if ((client = clnttcp_create (&addr, prognum, MIN_VERS,
389 &sock, 0, 0)) == NULL)
390 {
391 clnt_pcreateerror ("rpcinfo");
392 printf (_("program %lu is not available\n"), prognum);
393 exit (1);
394 }
395 to.tv_sec = 10;
396 to.tv_usec = 0;
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)
400 {
401 clnt_geterr (client, &rpcerr);
402 minvers = rpcerr.re_vers.low;
403 maxvers = rpcerr.re_vers.high;
404 }
405 else if (rpc_stat == RPC_SUCCESS)
406 {
407 /*
408 * Oh dear, it DOES support version 0.
409 * Let's try version MAX_VERS.
410 */
411 addr.sin_port = htons (portnum);
412 if ((client = clnttcp_create (&addr, prognum, MAX_VERS,
413 &sock, 0, 0)) == NULL)
414 {
415 clnt_pcreateerror ("rpcinfo");
416 printf (_("program %lu version %lu is not available\n"),
417 prognum, MAX_VERS);
418 exit (1);
419 }
420 to.tv_sec = 10;
421 to.tv_usec = 0;
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)
425 {
426 clnt_geterr (client, &rpcerr);
427 minvers = rpcerr.re_vers.low;
428 maxvers = rpcerr.re_vers.high;
429 }
430 else if (rpc_stat == RPC_SUCCESS)
431 {
432 /*
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...
437 */
438 minvers = 0;
439 maxvers = MAX_VERS;
440 }
441 else
442 {
443 (void) pstatus (client, prognum, MAX_VERS);
444 exit (1);
445 }
446 }
447 else
448 {
449 (void) pstatus (client, prognum, MIN_VERS);
450 exit (1);
451 }
452 clnt_destroy (client);
453 (void) close (sock);
454 sock = RPC_ANYSOCK; /* Re-initialize it for later */
455 for (vers = minvers; vers <= maxvers; vers++)
456 {
457 addr.sin_port = htons (portnum);
458 if ((client = clnttcp_create (&addr, prognum, vers,
459 &sock, 0, 0)) == NULL)
460 {
461 clnt_pcreateerror ("rpcinfo");
462 printf (_("program %lu version %lu is not available\n"),
463 prognum, vers);
464 exit (1);
465 }
466 to.tv_usec = 0;
467 to.tv_sec = 10;
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)
471 failure = 1;
472 clnt_destroy (client);
473 (void) close (sock);
474 sock = RPC_ANYSOCK;
475 }
476 }
477 else
478 {
479 vers = getvers (argv[2]);
480 addr.sin_port = htons (portnum);
481 if ((client = clnttcp_create (&addr, prognum, vers, &sock,
482 0, 0)) == NULL)
483 {
484 clnt_pcreateerror ("rpcinfo");
485 printf (_("program %lu version %lu is not available\n"),
486 prognum, vers);
487 exit (1);
488 }
489 to.tv_usec = 0;
490 to.tv_sec = 10;
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)
494 failure = 1;
495 }
496 if (failure)
497 exit (1);
498 }
499
500 /*
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.
506 */
507 static int
508 pstatus (client, prognum, vers)
509 register CLIENT *client;
510 u_long prognum;
511 u_long vers;
512 {
513 struct rpc_err rpcerr;
514
515 clnt_geterr (client, &rpcerr);
516 if (rpcerr.re_status != RPC_SUCCESS)
517 {
518 clnt_perror (client, "rpcinfo");
519 printf (_("program %lu version %lu is not available\n"), prognum, vers);
520 return -1;
521 }
522 else
523 {
524 printf (_("program %lu version %lu ready and waiting\n"), prognum, vers);
525 return 0;
526 }
527 }
528
529 static void
530 pmapdump (argc, argv)
531 int argc;
532 char **argv;
533 {
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;
540 struct rpcent *rpc;
541
542 if (argc > 1)
543 {
544 usage (stderr);
545 exit (1);
546 }
547 if (argc == 1)
548 get_inet_address (&server_addr, argv[0]);
549 else
550 {
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,
555 hp->h_length);
556 else
557 server_addr.sin_addr.s_addr = inet_addr ("0.0.0.0");
558 }
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)
564 {
565 clnt_pcreateerror (_("rpcinfo: can't contact portmapper"));
566 exit (1);
567 }
568 if (clnt_call (client, PMAPPROC_DUMP, (xdrproc_t) xdr_void, NULL,
569 (xdrproc_t) xdr_pmaplist, (caddr_t) &head,
570 minutetimeout) != RPC_SUCCESS)
571 {
572 fputs (_("rpcinfo: can't contact portmapper"), stderr);
573 fputs (": ", stderr);
574 clnt_perror (client, "rpcinfo");
575 exit (1);
576 }
577 if (head == NULL)
578 {
579 fputs (_("No remote programs registered.\n"), stdout);
580 }
581 else
582 {
583 fputs (_(" program vers proto port\n"), stdout);
584 for (; head != NULL; head = head->pml_next)
585 {
586 printf ("%10ld%5ld",
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");
593 else
594 printf ("%6ld", head->pml_map.pm_prot);
595 printf ("%7ld", head->pml_map.pm_port);
596 rpc = getrpcbynumber (head->pml_map.pm_prog);
597 if (rpc)
598 printf (" %s\n", rpc->r_name);
599 else
600 printf ("\n");
601 }
602 }
603 }
604
605 /*
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).
609 */
610
611 /*ARGSUSED */
612 static bool_t
613 reply_proc (res, who)
614 void *res; /* Nothing comes back */
615 struct sockaddr_in *who; /* Who sent us the reply */
616 {
617 register struct hostent *hp;
618
619 hp = gethostbyaddr ((char *) &who->sin_addr, sizeof who->sin_addr,
620 AF_INET);
621 printf ("%s %s\n", inet_ntoa (who->sin_addr),
622 (hp == NULL) ? _("(unknown)") : hp->h_name);
623 return FALSE;
624 }
625
626 static void
627 brdcst (argc, argv)
628 int argc;
629 char **argv;
630 {
631 enum clnt_stat rpc_stat;
632 u_long prognum, vers;
633
634 if (argc != 2)
635 {
636 usage (stderr);
637 exit (1);
638 }
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))
645 {
646 fprintf (stderr, _("rpcinfo: broadcast failed: %s\n"),
647 clnt_sperrno (rpc_stat));
648 exit (1);
649 }
650 exit (0);
651 }
652
653 static void
654 deletereg (argc, argv)
655 int argc;
656 char **argv;
657 {
658 u_long prog_num, version_num;
659
660 if (argc != 2)
661 {
662 usage (stderr);
663 exit (1);
664 }
665 if (getuid ())
666 { /* This command allowed only to root */
667 fputs (_("Sorry. You are not root\n"), stderr);
668 exit (1);
669 }
670 prog_num = getprognum (argv[0]);
671 version_num = getvers (argv[1]);
672 if ((pmap_unset (prog_num, version_num)) == 0)
673 {
674 fprintf (stderr, _("rpcinfo: Could not delete registration for prog %s version %s\n"),
675 argv[0], argv[1]);
676 exit (1);
677 }
678 }
679
680 static void
681 usage (FILE *stream)
682 {
683 fputs (_("Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n"),
684 stream);
685 fputs (_(" rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n"),
686 stream);
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);
694 }
695
696 static void
697 print_version (void)
698 {
699 printf ("rpcinfo %s%s\n", PKGVERSION, VERSION);
700 }
701
702 static u_long
703 getprognum (arg)
704 char *arg;
705 {
706 register struct rpcent *rpc;
707 register u_long prognum;
708
709 if (isalpha (*arg))
710 {
711 rpc = getrpcbyname (arg);
712 if (rpc == NULL)
713 {
714 fprintf (stderr, _("rpcinfo: %s is unknown service\n"), arg);
715 exit (1);
716 }
717 prognum = rpc->r_number;
718 }
719 else
720 {
721 prognum = (u_long) atoi (arg);
722 }
723
724 return prognum;
725 }
726
727 static u_long
728 getvers (arg)
729 char *arg;
730 {
731 register u_long vers;
732
733 vers = (int) atoi (arg);
734 return vers;
735 }
736
737 static void
738 get_inet_address (addr, host)
739 struct sockaddr_in *addr;
740 char *host;
741 {
742 register struct hostent *hp;
743
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)
748 {
749 if ((hp = gethostbyname (host)) == NULL)
750 {
751 fprintf (stderr, _("rpcinfo: %s is unknown host\n"),
752 host);
753 exit (1);
754 }
755 memmove ((char *) &addr->sin_addr, hp->h_addr, hp->h_length);
756 }
757 addr->sin_family = AF_INET;
758 }