remove COPYING* from .gitignore files
[platform/upstream/glibc.git] / sunrpc / rpcinfo.c
1
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
6
7 /*
8  * Copyright (C) 1986, Sun Microsystems, Inc.
9  */
10
11 /*
12  * rpcinfo: ping a particular rpc program
13  *     or dump the portmapper
14  */
15
16 /*
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.
23  *
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.
27  *
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.
31  *
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.
35  *
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.
39  *
40  * Sun Microsystems, Inc.
41  * 2550 Garcia Avenue
42  * Mountain View, California  94043
43  */
44
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>
60
61 #include "../version.h"
62 #define PACKAGE _libc_intl_domainname
63
64 #define MAXHOSTLEN 256
65
66 #define MIN_VERS        ((u_long) 0)
67 #define MAX_VERS        ((u_long) 4294967295UL)
68
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);
81
82 /*
83  * Functions to be performed.
84  */
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 */
91
92 int
93 main (int argc, char **argv)
94 {
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 }
103   };
104
105   setlocale (LC_ALL, "");
106   textdomain (_libc_intl_domainname);
107
108   function = NONE;
109   portnum = 0;
110   errflg = 0;
111   while ((c = getopt_long (argc, argv, "ptubdn:", long_options, NULL)) != -1)
112     {
113       switch (c)
114         {
115
116         case 'p':
117           if (function != NONE)
118             errflg = 1;
119           else
120             function = PMAPDUMP;
121           break;
122
123         case 't':
124           if (function != NONE)
125             errflg = 1;
126           else
127             function = TCPPING;
128           break;
129
130         case 'u':
131           if (function != NONE)
132             errflg = 1;
133           else
134             function = UDPPING;
135           break;
136
137         case 'b':
138           if (function != NONE)
139             errflg = 1;
140           else
141             function = BRDCST;
142           break;
143
144         case 'n':
145           portnum = (u_short) atoi (optarg);    /* hope we don't get bogus # */
146           break;
147
148         case 'd':
149           if (function != NONE)
150             errflg = 1;
151           else
152             function = DELETES;
153           break;
154
155         case 'H':
156           usage (stdout);
157           return 0;
158
159         case 'V':
160           print_version ();
161           return 0;
162
163         case '?':
164           errflg = 1;
165         }
166     }
167
168   if (errflg || function == NONE)
169     {
170       usage (stderr);
171       return 1;
172     }
173
174   switch (function)
175     {
176
177     case PMAPDUMP:
178       if (portnum != 0)
179         {
180           usage (stderr);
181           return 1;
182         }
183       pmapdump (argc - optind, argv + optind);
184       break;
185
186     case UDPPING:
187       udpping (portnum, argc - optind, argv + optind);
188       break;
189
190     case TCPPING:
191       tcpping (portnum, argc - optind, argv + optind);
192       break;
193
194     case BRDCST:
195       if (portnum != 0)
196         {
197           usage (stderr);
198           return 1;
199         }
200       brdcst (argc - optind, argv + optind);
201       break;
202
203     case DELETES:
204       deletereg (argc - optind, argv + optind);
205       break;
206     }
207
208   return 0;
209 }
210
211 static void
212 udpping (portnum, argc, argv)
213      u_short portnum;
214      int argc;
215      char **argv;
216 {
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;
225
226   if (argc < 2 || argc > 3)
227     {
228       usage (stderr);
229       exit (1);
230     }
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)
236     {
237       perror ("rpcinfo: socket");
238       exit (1);
239     }
240   failure = 0;
241   if (argc == 2)
242     {
243       /*
244        * A call to version 0 should fail with a program/version
245        * mismatch, and give us the range of versions supported.
246        */
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)
252         {
253           clnt_pcreateerror ("rpcinfo");
254           printf (_("program %lu is not available\n"), prognum);
255           exit (1);
256         }
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)
263         {
264           clnt_geterr (client, &rpcerr);
265           minvers = rpcerr.re_vers.low;
266           maxvers = rpcerr.re_vers.high;
267         }
268       else if (rpc_stat == RPC_SUCCESS)
269         {
270           /*
271            * Oh dear, it DOES support version 0.
272            * Let's try version MAX_VERS.
273            */
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)
279             {
280               clnt_pcreateerror ("rpcinfo");
281               printf (_("program %lu version %lu is not available\n"),
282                       prognum, MAX_VERS);
283               exit (1);
284             }
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)
290             {
291               clnt_geterr (client, &rpcerr);
292               minvers = rpcerr.re_vers.low;
293               maxvers = rpcerr.re_vers.high;
294             }
295           else if (rpc_stat == RPC_SUCCESS)
296             {
297               /*
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...
302                */
303               minvers = 0;
304               maxvers = MAX_VERS;
305             }
306           else
307             {
308               (void) pstatus (client, prognum, MAX_VERS);
309               exit (1);
310             }
311         }
312       else
313         {
314           (void) pstatus (client, prognum, (u_long) 0);
315           exit (1);
316         }
317       clnt_destroy (client);
318       for (vers = minvers; vers <= maxvers; vers++)
319         {
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)
325             {
326               clnt_pcreateerror ("rpcinfo");
327               printf (_("program %lu version %lu is not available\n"),
328                       prognum, vers);
329               exit (1);
330             }
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);
338         }
339     }
340   else
341     {
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)
348         {
349           clnt_pcreateerror ("rpcinfo");
350           printf (_("program %lu version %lu is not available\n"),
351                   prognum, vers);
352           exit (1);
353         }
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;
360     }
361   (void) close (sock);          /* Close it up again */
362   if (failure)
363     exit (1);
364 }
365
366 static void
367 tcpping (portnum, argc, argv)
368      u_short portnum;
369      int argc;
370      char **argv;
371 {
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;
380
381   if (argc < 2 || argc > 3)
382     {
383       usage (stderr);
384       exit (1);
385     }
386   prognum = getprognum (argv[1]);
387   get_inet_address (&addr, argv[0]);
388   failure = 0;
389   if (argc == 2)
390     {
391       /*
392        * A call to version 0 should fail with a program/version
393        * mismatch, and give us the range of versions supported.
394        */
395       addr.sin_port = htons (portnum);
396       if ((client = clnttcp_create (&addr, prognum, MIN_VERS,
397                                     &sock, 0, 0)) == NULL)
398         {
399           clnt_pcreateerror ("rpcinfo");
400           printf (_("program %lu is not available\n"), prognum);
401           exit (1);
402         }
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)
408         {
409           clnt_geterr (client, &rpcerr);
410           minvers = rpcerr.re_vers.low;
411           maxvers = rpcerr.re_vers.high;
412         }
413       else if (rpc_stat == RPC_SUCCESS)
414         {
415           /*
416            * Oh dear, it DOES support version 0.
417            * Let's try version MAX_VERS.
418            */
419           addr.sin_port = htons (portnum);
420           if ((client = clnttcp_create (&addr, prognum, MAX_VERS,
421                                         &sock, 0, 0)) == NULL)
422             {
423               clnt_pcreateerror ("rpcinfo");
424               printf (_("program %lu version %lu is not available\n"),
425                       prognum, MAX_VERS);
426               exit (1);
427             }
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)
433             {
434               clnt_geterr (client, &rpcerr);
435               minvers = rpcerr.re_vers.low;
436               maxvers = rpcerr.re_vers.high;
437             }
438           else if (rpc_stat == RPC_SUCCESS)
439             {
440               /*
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...
445                */
446               minvers = 0;
447               maxvers = MAX_VERS;
448             }
449           else
450             {
451               (void) pstatus (client, prognum, MAX_VERS);
452               exit (1);
453             }
454         }
455       else
456         {
457           (void) pstatus (client, prognum, MIN_VERS);
458           exit (1);
459         }
460       clnt_destroy (client);
461       (void) close (sock);
462       sock = RPC_ANYSOCK;       /* Re-initialize it for later */
463       for (vers = minvers; vers <= maxvers; vers++)
464         {
465           addr.sin_port = htons (portnum);
466           if ((client = clnttcp_create (&addr, prognum, vers,
467                                         &sock, 0, 0)) == NULL)
468             {
469               clnt_pcreateerror ("rpcinfo");
470               printf (_("program %lu version %lu is not available\n"),
471                       prognum, vers);
472               exit (1);
473             }
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;
483         }
484     }
485   else
486     {
487       vers = getvers (argv[2]);
488       addr.sin_port = htons (portnum);
489       if ((client = clnttcp_create (&addr, prognum, vers, &sock,
490                                     0, 0)) == NULL)
491         {
492           clnt_pcreateerror ("rpcinfo");
493           printf (_("program %lu version %lu is not available\n"),
494                   prognum, vers);
495           exit (1);
496         }
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;
503     }
504   if (failure)
505     exit (1);
506 }
507
508 /*
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.
514  */
515 static int
516 pstatus (client, prognum, vers)
517      register CLIENT *client;
518      u_long prognum;
519      u_long vers;
520 {
521   struct rpc_err rpcerr;
522
523   clnt_geterr (client, &rpcerr);
524   if (rpcerr.re_status != RPC_SUCCESS)
525     {
526       clnt_perror (client, "rpcinfo");
527       printf (_("program %lu version %lu is not available\n"), prognum, vers);
528       return -1;
529     }
530   else
531     {
532       printf (_("program %lu version %lu ready and waiting\n"), prognum, vers);
533       return 0;
534     }
535 }
536
537 static void
538 pmapdump (argc, argv)
539      int argc;
540      char **argv;
541 {
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;
549
550   if (argc > 1)
551     {
552       usage (stderr);
553       exit (1);
554     }
555   if (argc == 1)
556     get_inet_address (&server_addr, argv[0]);
557   else
558     {
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");
566     }
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)
572     {
573       clnt_pcreateerror (_("rpcinfo: can't contact portmapper"));
574       exit (1);
575     }
576   if (clnt_call (client, PMAPPROC_DUMP, (xdrproc_t) xdr_void, NULL,
577                  (xdrproc_t) xdr_pmaplist, (caddr_t) &head,
578                  minutetimeout) != RPC_SUCCESS)
579     {
580       fputs (_("rpcinfo: can't contact portmapper"), stderr);
581       fputs (": ", stderr);
582       clnt_perror (client, "rpcinfo");
583       exit (1);
584     }
585   if (head == NULL)
586     {
587       fputs (_("No remote programs registered.\n"), stdout);
588     }
589   else
590     {
591       fputs (_("   program vers proto   port\n"), stdout);
592       for (; head != NULL; head = head->pml_next)
593         {
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");
609         }
610     }
611 }
612
613 /*
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).
617  */
618
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 */
624 {
625   register struct hostent *hp;
626
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;
632 }
633
634 static void
635 brdcst (argc, argv)
636      int argc;
637      char **argv;
638 {
639   enum clnt_stat rpc_stat;
640   u_long prognum, vers;
641
642   if (argc != 2)
643     {
644       usage (stderr);
645       exit (1);
646     }
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))
653     {
654       fprintf (stderr, _("rpcinfo: broadcast failed: %s\n"),
655                clnt_sperrno (rpc_stat));
656       exit (1);
657     }
658   exit (0);
659 }
660
661 static void
662 deletereg (argc, argv)
663      int argc;
664      char **argv;
665 {
666   u_long prog_num, version_num;
667
668   if (argc != 2)
669     {
670       usage (stderr);
671       exit (1);
672     }
673   if (getuid ())
674     {                           /* This command allowed only to root */
675       fputs (_("Sorry. You are not root\n"), stderr);
676       exit (1);
677     }
678   prog_num = getprognum (argv[0]);
679   version_num = getvers (argv[1]);
680   if ((pmap_unset (prog_num, version_num)) == 0)
681     {
682       fprintf (stderr, _("rpcinfo: Could not delete registration for prog %s version %s\n"),
683                argv[0], argv[1]);
684       exit (1);
685     }
686 }
687
688 static void
689 usage (FILE *stream)
690 {
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"));
702 }
703
704 static void
705 print_version (void)
706 {
707   printf ("rpcinfo (GNU %s) %s\n", PACKAGE, VERSION);
708 }
709
710 static u_long
711 getprognum (arg)
712      char *arg;
713 {
714   register struct rpcent *rpc;
715   register u_long prognum;
716
717   if (isalpha (*arg))
718     {
719       rpc = getrpcbyname (arg);
720       if (rpc == NULL)
721         {
722           fprintf (stderr, _("rpcinfo: %s is unknown service\n"), arg);
723           exit (1);
724         }
725       prognum = rpc->r_number;
726     }
727   else
728     {
729       prognum = (u_long) atoi (arg);
730     }
731
732   return prognum;
733 }
734
735 static u_long
736 getvers (arg)
737      char *arg;
738 {
739   register u_long vers;
740
741   vers = (int) atoi (arg);
742   return vers;
743 }
744
745 static void
746 get_inet_address (addr, host)
747      struct sockaddr_in *addr;
748      char *host;
749 {
750   register struct hostent *hp;
751
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)
756     {
757       if ((hp = gethostbyname (host)) == NULL)
758         {
759           fprintf (stderr, _("rpcinfo: %s is unknown host\n"),
760                    host);
761           exit (1);
762         }
763       memmove ((char *) &addr->sin_addr, hp->h_addr, hp->h_length);
764     }
765   addr->sin_family = AF_INET;
766 }