No cancel signal in unsafe places.
[glibc.git] / sunrpc / rpcinfo.c
blob91f360c2f3691c8003cbe71a04b63753db1de157
2 /* @(#)rpcinfo.c 2.2 88/08/11 4.0 RPCSRC */
3 #if !defined(lint) && defined (SCCSID)
4 static char sccsid[] = "@(#)rpcinfo.c 1.22 87/08/12 SMI";
5 #endif
7 /*
8 * Copyright (C) 1986, Sun Microsystems, Inc.
9 */
12 * rpcinfo: ping a particular rpc program
13 * or dump the portmapper
17 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
18 * unrestricted use provided that this legend is included on all tape
19 * media and as a part of the software program in whole or part. Users
20 * may copy or modify Sun RPC without charge, but are not authorized
21 * to license or distribute it to anyone else except as part of a product or
22 * program developed by the user.
24 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
25 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
28 * Sun RPC is provided with no support and without any obligation on the
29 * part of Sun Microsystems, Inc. to assist in its use, correction,
30 * modification or enhancement.
32 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
33 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
34 * OR ANY PART THEREOF.
36 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
37 * or profits or other special, indirect and consequential damages, even if
38 * Sun has been advised of the possibility of such damages.
40 * Sun Microsystems, Inc.
41 * 2550 Garcia Avenue
42 * Mountain View, California 94043
45 #include <getopt.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <rpc/rpc.h>
49 #include <stdio.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <netdb.h>
54 #include <rpc/pmap_prot.h>
55 #include <rpc/pmap_clnt.h>
56 #include <signal.h>
57 #include <ctype.h>
58 #include <locale.h>
59 #include <libintl.h>
61 #include "../version.h"
62 #define PACKAGE _libc_intl_domainname
64 #define MAXHOSTLEN 256
66 #define MIN_VERS ((u_long) 0)
67 #define MAX_VERS ((u_long) 4294967295UL)
69 static void udpping (u_short portflag, int argc, char **argv);
70 static void tcpping (u_short portflag, int argc, char **argv);
71 static int pstatus (CLIENT *client, u_long prognum, u_long vers);
72 static void pmapdump (int argc, char **argv);
73 static bool_t reply_proc (void *res, struct sockaddr_in *who);
74 static void brdcst (int argc, char **argv) __attribute__ ((noreturn));
75 static void deletereg (int argc, char **argv);
76 static void usage (FILE *stream);
77 static void print_version (void);
78 static u_long getprognum (char *arg);
79 static u_long getvers (char *arg);
80 static void get_inet_address (struct sockaddr_in *addr, char *host);
83 * Functions to be performed.
85 #define NONE 0 /* no function */
86 #define PMAPDUMP 1 /* dump portmapper registrations */
87 #define TCPPING 2 /* ping TCP service */
88 #define UDPPING 3 /* ping UDP service */
89 #define BRDCST 4 /* ping broadcast UDP service */
90 #define DELETES 5 /* delete registration for the service */
92 int
93 main (int argc, char **argv)
95 register int c;
96 int errflg;
97 int function;
98 u_short portnum;
99 static const struct option long_options[] = {
100 { "help", no_argument, NULL, 'H' },
101 { "version", no_argument, NULL, 'V' },
102 { NULL, 0, NULL, 0 }
105 setlocale (LC_ALL, "");
106 textdomain (_libc_intl_domainname);
108 function = NONE;
109 portnum = 0;
110 errflg = 0;
111 while ((c = getopt_long (argc, argv, "ptubdn:", long_options, NULL)) != -1)
113 switch (c)
116 case 'p':
117 if (function != NONE)
118 errflg = 1;
119 else
120 function = PMAPDUMP;
121 break;
123 case 't':
124 if (function != NONE)
125 errflg = 1;
126 else
127 function = TCPPING;
128 break;
130 case 'u':
131 if (function != NONE)
132 errflg = 1;
133 else
134 function = UDPPING;
135 break;
137 case 'b':
138 if (function != NONE)
139 errflg = 1;
140 else
141 function = BRDCST;
142 break;
144 case 'n':
145 portnum = (u_short) atoi (optarg); /* hope we don't get bogus # */
146 break;
148 case 'd':
149 if (function != NONE)
150 errflg = 1;
151 else
152 function = DELETES;
153 break;
155 case 'H':
156 usage (stdout);
157 return 0;
159 case 'V':
160 print_version ();
161 return 0;
163 case '?':
164 errflg = 1;
168 if (errflg || function == NONE)
170 usage (stderr);
171 return 1;
174 switch (function)
177 case PMAPDUMP:
178 if (portnum != 0)
180 usage (stderr);
181 return 1;
183 pmapdump (argc - optind, argv + optind);
184 break;
186 case UDPPING:
187 udpping (portnum, argc - optind, argv + optind);
188 break;
190 case TCPPING:
191 tcpping (portnum, argc - optind, argv + optind);
192 break;
194 case BRDCST:
195 if (portnum != 0)
197 usage (stderr);
198 return 1;
200 brdcst (argc - optind, argv + optind);
201 break;
203 case DELETES:
204 deletereg (argc - optind, argv + optind);
205 break;
208 return 0;
211 static void
212 udpping (portnum, argc, argv)
213 u_short portnum;
214 int argc;
215 char **argv;
217 struct timeval to;
218 struct sockaddr_in addr;
219 enum clnt_stat rpc_stat;
220 CLIENT *client;
221 u_long prognum, vers, minvers, maxvers;
222 int sock = RPC_ANYSOCK;
223 struct rpc_err rpcerr;
224 int failure;
226 if (argc < 2 || argc > 3)
228 usage (stderr);
229 exit (1);
231 prognum = getprognum (argv[1]);
232 get_inet_address (&addr, argv[0]);
233 /* Open the socket here so it will survive calls to clnt_destroy */
234 sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
235 if (sock < 0)
237 perror ("rpcinfo: socket");
238 exit (1);
240 failure = 0;
241 if (argc == 2)
244 * A call to version 0 should fail with a program/version
245 * mismatch, and give us the range of versions supported.
247 addr.sin_port = htons (portnum);
248 to.tv_sec = 5;
249 to.tv_usec = 0;
250 if ((client = clntudp_create (&addr, prognum, (u_long) 0,
251 to, &sock)) == NULL)
253 clnt_pcreateerror ("rpcinfo");
254 printf (_("program %lu is not available\n"), prognum);
255 exit (1);
257 to.tv_sec = 10;
258 to.tv_usec = 0;
259 rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
260 (char *) NULL, (xdrproc_t) xdr_void,
261 (char *) NULL, to);
262 if (rpc_stat == RPC_PROGVERSMISMATCH)
264 clnt_geterr (client, &rpcerr);
265 minvers = rpcerr.re_vers.low;
266 maxvers = rpcerr.re_vers.high;
268 else if (rpc_stat == RPC_SUCCESS)
271 * Oh dear, it DOES support version 0.
272 * Let's try version MAX_VERS.
274 addr.sin_port = htons (portnum);
275 to.tv_sec = 5;
276 to.tv_usec = 0;
277 if ((client = clntudp_create (&addr, prognum, MAX_VERS,
278 to, &sock)) == NULL)
280 clnt_pcreateerror ("rpcinfo");
281 printf (_("program %lu version %lu is not available\n"),
282 prognum, MAX_VERS);
283 exit (1);
285 to.tv_sec = 10;
286 to.tv_usec = 0;
287 rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
288 NULL, (xdrproc_t) xdr_void, NULL, to);
289 if (rpc_stat == RPC_PROGVERSMISMATCH)
291 clnt_geterr (client, &rpcerr);
292 minvers = rpcerr.re_vers.low;
293 maxvers = rpcerr.re_vers.high;
295 else if (rpc_stat == RPC_SUCCESS)
298 * It also supports version MAX_VERS.
299 * Looks like we have a wise guy.
300 * OK, we give them information on all
301 * 4 billion versions they support...
303 minvers = 0;
304 maxvers = MAX_VERS;
306 else
308 (void) pstatus (client, prognum, MAX_VERS);
309 exit (1);
312 else
314 (void) pstatus (client, prognum, (u_long) 0);
315 exit (1);
317 clnt_destroy (client);
318 for (vers = minvers; vers <= maxvers; vers++)
320 addr.sin_port = htons (portnum);
321 to.tv_sec = 5;
322 to.tv_usec = 0;
323 if ((client = clntudp_create (&addr, prognum, vers,
324 to, &sock)) == NULL)
326 clnt_pcreateerror ("rpcinfo");
327 printf (_("program %lu version %lu is not available\n"),
328 prognum, vers);
329 exit (1);
331 to.tv_sec = 10;
332 to.tv_usec = 0;
333 rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
334 NULL, (xdrproc_t) xdr_void, NULL, to);
335 if (pstatus (client, prognum, vers) < 0)
336 failure = 1;
337 clnt_destroy (client);
340 else
342 vers = getvers (argv[2]);
343 addr.sin_port = htons (portnum);
344 to.tv_sec = 5;
345 to.tv_usec = 0;
346 if ((client = clntudp_create (&addr, prognum, vers,
347 to, &sock)) == NULL)
349 clnt_pcreateerror ("rpcinfo");
350 printf (_("program %lu version %lu is not available\n"),
351 prognum, vers);
352 exit (1);
354 to.tv_sec = 10;
355 to.tv_usec = 0;
356 rpc_stat = clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
357 (xdrproc_t) xdr_void, NULL, to);
358 if (pstatus (client, prognum, vers) < 0)
359 failure = 1;
361 (void) close (sock); /* Close it up again */
362 if (failure)
363 exit (1);
366 static void
367 tcpping (portnum, argc, argv)
368 u_short portnum;
369 int argc;
370 char **argv;
372 struct timeval to;
373 struct sockaddr_in addr;
374 enum clnt_stat rpc_stat;
375 CLIENT *client;
376 u_long prognum, vers, minvers, maxvers;
377 int sock = RPC_ANYSOCK;
378 struct rpc_err rpcerr;
379 int failure;
381 if (argc < 2 || argc > 3)
383 usage (stderr);
384 exit (1);
386 prognum = getprognum (argv[1]);
387 get_inet_address (&addr, argv[0]);
388 failure = 0;
389 if (argc == 2)
392 * A call to version 0 should fail with a program/version
393 * mismatch, and give us the range of versions supported.
395 addr.sin_port = htons (portnum);
396 if ((client = clnttcp_create (&addr, prognum, MIN_VERS,
397 &sock, 0, 0)) == NULL)
399 clnt_pcreateerror ("rpcinfo");
400 printf (_("program %lu is not available\n"), prognum);
401 exit (1);
403 to.tv_sec = 10;
404 to.tv_usec = 0;
405 rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void, NULL,
406 (xdrproc_t) xdr_void, NULL, to);
407 if (rpc_stat == RPC_PROGVERSMISMATCH)
409 clnt_geterr (client, &rpcerr);
410 minvers = rpcerr.re_vers.low;
411 maxvers = rpcerr.re_vers.high;
413 else if (rpc_stat == RPC_SUCCESS)
416 * Oh dear, it DOES support version 0.
417 * Let's try version MAX_VERS.
419 addr.sin_port = htons (portnum);
420 if ((client = clnttcp_create (&addr, prognum, MAX_VERS,
421 &sock, 0, 0)) == NULL)
423 clnt_pcreateerror ("rpcinfo");
424 printf (_("program %lu version %lu is not available\n"),
425 prognum, MAX_VERS);
426 exit (1);
428 to.tv_sec = 10;
429 to.tv_usec = 0;
430 rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
431 NULL, (xdrproc_t) xdr_void, NULL, to);
432 if (rpc_stat == RPC_PROGVERSMISMATCH)
434 clnt_geterr (client, &rpcerr);
435 minvers = rpcerr.re_vers.low;
436 maxvers = rpcerr.re_vers.high;
438 else if (rpc_stat == RPC_SUCCESS)
441 * It also supports version MAX_VERS.
442 * Looks like we have a wise guy.
443 * OK, we give them information on all
444 * 4 billion versions they support...
446 minvers = 0;
447 maxvers = MAX_VERS;
449 else
451 (void) pstatus (client, prognum, MAX_VERS);
452 exit (1);
455 else
457 (void) pstatus (client, prognum, MIN_VERS);
458 exit (1);
460 clnt_destroy (client);
461 (void) close (sock);
462 sock = RPC_ANYSOCK; /* Re-initialize it for later */
463 for (vers = minvers; vers <= maxvers; vers++)
465 addr.sin_port = htons (portnum);
466 if ((client = clnttcp_create (&addr, prognum, vers,
467 &sock, 0, 0)) == NULL)
469 clnt_pcreateerror ("rpcinfo");
470 printf (_("program %lu version %lu is not available\n"),
471 prognum, vers);
472 exit (1);
474 to.tv_usec = 0;
475 to.tv_sec = 10;
476 rpc_stat = clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
477 (xdrproc_t) xdr_void, NULL, to);
478 if (pstatus (client, prognum, vers) < 0)
479 failure = 1;
480 clnt_destroy (client);
481 (void) close (sock);
482 sock = RPC_ANYSOCK;
485 else
487 vers = getvers (argv[2]);
488 addr.sin_port = htons (portnum);
489 if ((client = clnttcp_create (&addr, prognum, vers, &sock,
490 0, 0)) == NULL)
492 clnt_pcreateerror ("rpcinfo");
493 printf (_("program %lu version %lu is not available\n"),
494 prognum, vers);
495 exit (1);
497 to.tv_usec = 0;
498 to.tv_sec = 10;
499 rpc_stat = clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
500 (xdrproc_t) xdr_void, NULL, to);
501 if (pstatus (client, prognum, vers) < 0)
502 failure = 1;
504 if (failure)
505 exit (1);
509 * This routine should take a pointer to an "rpc_err" structure, rather than
510 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
511 * a CLIENT structure rather than a pointer to an "rpc_err" structure.
512 * As such, we have to keep the CLIENT structure around in order to print
513 * a good error message.
515 static int
516 pstatus (client, prognum, vers)
517 register CLIENT *client;
518 u_long prognum;
519 u_long vers;
521 struct rpc_err rpcerr;
523 clnt_geterr (client, &rpcerr);
524 if (rpcerr.re_status != RPC_SUCCESS)
526 clnt_perror (client, "rpcinfo");
527 printf (_("program %lu version %lu is not available\n"), prognum, vers);
528 return -1;
530 else
532 printf (_("program %lu version %lu ready and waiting\n"), prognum, vers);
533 return 0;
537 static void
538 pmapdump (argc, argv)
539 int argc;
540 char **argv;
542 struct sockaddr_in server_addr;
543 register struct hostent *hp;
544 struct pmaplist *head = NULL;
545 int socket = RPC_ANYSOCK;
546 struct timeval minutetimeout;
547 register CLIENT *client;
548 struct rpcent *rpc;
550 if (argc > 1)
552 usage (stderr);
553 exit (1);
555 if (argc == 1)
556 get_inet_address (&server_addr, argv[0]);
557 else
559 bzero ((char *) &server_addr, sizeof server_addr);
560 server_addr.sin_family = AF_INET;
561 if ((hp = gethostbyname ("localhost")) != NULL)
562 memcpy ((caddr_t) & server_addr.sin_addr, hp->h_addr,
563 hp->h_length);
564 else
565 server_addr.sin_addr.s_addr = inet_addr ("0.0.0.0");
567 minutetimeout.tv_sec = 60;
568 minutetimeout.tv_usec = 0;
569 server_addr.sin_port = htons (PMAPPORT);
570 if ((client = clnttcp_create (&server_addr, PMAPPROG,
571 PMAPVERS, &socket, 50, 500)) == NULL)
573 clnt_pcreateerror (_("rpcinfo: can't contact portmapper"));
574 exit (1);
576 if (clnt_call (client, PMAPPROC_DUMP, (xdrproc_t) xdr_void, NULL,
577 (xdrproc_t) xdr_pmaplist, (caddr_t) &head,
578 minutetimeout) != RPC_SUCCESS)
580 fputs (_("rpcinfo: can't contact portmapper"), stderr);
581 fputs (": ", stderr);
582 clnt_perror (client, "rpcinfo");
583 exit (1);
585 if (head == NULL)
587 fputs (_("No remote programs registered.\n"), stdout);
589 else
591 fputs (_(" program vers proto port\n"), stdout);
592 for (; head != NULL; head = head->pml_next)
594 printf ("%10ld%5ld",
595 head->pml_map.pm_prog,
596 head->pml_map.pm_vers);
597 if (head->pml_map.pm_prot == IPPROTO_UDP)
598 printf ("%6s", "udp");
599 else if (head->pml_map.pm_prot == IPPROTO_TCP)
600 printf ("%6s", "tcp");
601 else
602 printf ("%6ld", head->pml_map.pm_prot);
603 printf ("%7ld", head->pml_map.pm_port);
604 rpc = getrpcbynumber (head->pml_map.pm_prog);
605 if (rpc)
606 printf (" %s\n", rpc->r_name);
607 else
608 printf ("\n");
614 * reply_proc collects replies from the broadcast.
615 * to get a unique list of responses the output of rpcinfo should
616 * be piped through sort(1) and then uniq(1).
619 /*ARGSUSED */
620 static bool_t
621 reply_proc (res, who)
622 void *res; /* Nothing comes back */
623 struct sockaddr_in *who; /* Who sent us the reply */
625 register struct hostent *hp;
627 hp = gethostbyaddr ((char *) &who->sin_addr, sizeof who->sin_addr,
628 AF_INET);
629 printf ("%s %s\n", inet_ntoa (who->sin_addr),
630 (hp == NULL) ? _("(unknown)") : hp->h_name);
631 return FALSE;
634 static void
635 brdcst (argc, argv)
636 int argc;
637 char **argv;
639 enum clnt_stat rpc_stat;
640 u_long prognum, vers;
642 if (argc != 2)
644 usage (stderr);
645 exit (1);
647 prognum = getprognum (argv[0]);
648 vers = getvers (argv[1]);
649 rpc_stat = clnt_broadcast (prognum, vers, NULLPROC, (xdrproc_t) xdr_void,
650 NULL, (xdrproc_t) xdr_void, NULL,
651 (resultproc_t) reply_proc);
652 if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT))
654 fprintf (stderr, _("rpcinfo: broadcast failed: %s\n"),
655 clnt_sperrno (rpc_stat));
656 exit (1);
658 exit (0);
661 static void
662 deletereg (argc, argv)
663 int argc;
664 char **argv;
666 u_long prog_num, version_num;
668 if (argc != 2)
670 usage (stderr);
671 exit (1);
673 if (getuid ())
674 { /* This command allowed only to root */
675 fputs (_("Sorry. You are not root\n"), stderr);
676 exit (1);
678 prog_num = getprognum (argv[0]);
679 version_num = getvers (argv[1]);
680 if ((pmap_unset (prog_num, version_num)) == 0)
682 fprintf (stderr, _("rpcinfo: Could not delete registration for prog %s version %s\n"),
683 argv[0], argv[1]);
684 exit (1);
688 static void
689 usage (FILE *stream)
691 fputs (_("Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n"),
692 stream);
693 fputs (_(" rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n"),
694 stream);
695 fputs (_(" rpcinfo -p [ host ]\n"), stream);
696 fputs (_(" rpcinfo -b prognum versnum\n"), stream);
697 fputs (_(" rpcinfo -d prognum versnum\n"), stream);
698 fputc ('\n', stream);
699 fprintf (stream, _("\
700 For bug reporting instructions, please see:\n\
701 <http://www.gnu.org/software/libc/bugs.html>.\n"));
704 static void
705 print_version (void)
707 printf ("rpcinfo (GNU %s) %s\n", PACKAGE, VERSION);
710 static u_long
711 getprognum (arg)
712 char *arg;
714 register struct rpcent *rpc;
715 register u_long prognum;
717 if (isalpha (*arg))
719 rpc = getrpcbyname (arg);
720 if (rpc == NULL)
722 fprintf (stderr, _("rpcinfo: %s is unknown service\n"), arg);
723 exit (1);
725 prognum = rpc->r_number;
727 else
729 prognum = (u_long) atoi (arg);
732 return prognum;
735 static u_long
736 getvers (arg)
737 char *arg;
739 register u_long vers;
741 vers = (int) atoi (arg);
742 return vers;
745 static void
746 get_inet_address (addr, host)
747 struct sockaddr_in *addr;
748 char *host;
750 register struct hostent *hp;
752 bzero ((char *) addr, sizeof *addr);
753 addr->sin_addr.s_addr = (u_long) inet_addr (host);
754 if (addr->sin_addr.s_addr == INADDR_NONE
755 || addr->sin_addr.s_addr == INADDR_ANY)
757 if ((hp = gethostbyname (host)) == NULL)
759 fprintf (stderr, _("rpcinfo: %s is unknown host\n"),
760 host);
761 exit (1);
763 memmove ((char *) &addr->sin_addr, hp->h_addr, hp->h_length);
765 addr->sin_family = AF_INET;