Fix prototypes and parameters for compiling with enabled warnings.
[kopensolaris-gnu/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 #define MAXHOSTLEN 256
62
63 #define MIN_VERS        ((u_long) 0)
64 #define MAX_VERS        ((u_long) 4294967295UL)
65
66 static void udpping (u_short portflag, int argc, char **argv);
67 static void tcpping (u_short portflag, int argc, char **argv);
68 static int pstatus (CLIENT *client, u_long prognum, u_long vers);
69 static void pmapdump (int argc, char **argv);
70 static bool_t reply_proc (void *res, struct sockaddr_in *who);
71 static void brdcst (int argc, char **argv);
72 static void deletereg (int argc, char **argv);
73 static void usage (void);
74 static u_long getprognum (char *arg);
75 static u_long getvers (char *arg);
76 static void get_inet_address (struct sockaddr_in *addr, char *host);
77
78 /*
79  * Functions to be performed.
80  */
81 #define NONE            0       /* no function */
82 #define PMAPDUMP        1       /* dump portmapper registrations */
83 #define TCPPING         2       /* ping TCP service */
84 #define UDPPING         3       /* ping UDP service */
85 #define BRDCST          4       /* ping broadcast UDP service */
86 #define DELETES         5       /* delete registration for the service */
87
88 int
89 main (int argc, char **argv)
90 {
91   register int c;
92   int errflg;
93   int function;
94   u_short portnum;
95
96   setlocale (LC_ALL, "");
97   textdomain (_libc_intl_domainname);
98
99   function = NONE;
100   portnum = 0;
101   errflg = 0;
102   while ((c = getopt (argc, argv, "ptubdn:")) != -1)
103     {
104       switch (c)
105         {
106
107         case 'p':
108           if (function != NONE)
109             errflg = 1;
110           else
111             function = PMAPDUMP;
112           break;
113
114         case 't':
115           if (function != NONE)
116             errflg = 1;
117           else
118             function = TCPPING;
119           break;
120
121         case 'u':
122           if (function != NONE)
123             errflg = 1;
124           else
125             function = UDPPING;
126           break;
127
128         case 'b':
129           if (function != NONE)
130             errflg = 1;
131           else
132             function = BRDCST;
133           break;
134
135         case 'n':
136           portnum = (u_short) atoi (optarg);    /* hope we don't get bogus # */
137           break;
138
139         case 'd':
140           if (function != NONE)
141             errflg = 1;
142           else
143             function = DELETES;
144           break;
145
146         case '?':
147           errflg = 1;
148         }
149     }
150
151   if (errflg || function == NONE)
152     {
153       usage ();
154       return (1);
155     }
156
157   switch (function)
158     {
159
160     case PMAPDUMP:
161       if (portnum != 0)
162         {
163           usage ();
164           return (1);
165         }
166       pmapdump (argc - optind, argv + optind);
167       break;
168
169     case UDPPING:
170       udpping (portnum, argc - optind, argv + optind);
171       break;
172
173     case TCPPING:
174       tcpping (portnum, argc - optind, argv + optind);
175       break;
176
177     case BRDCST:
178       if (portnum != 0)
179         {
180           usage ();
181           return (1);
182         }
183       brdcst (argc - optind, argv + optind);
184       break;
185
186     case DELETES:
187       deletereg (argc - optind, argv + optind);
188       break;
189     }
190
191   return (0);
192 }
193
194 static void
195 udpping (portnum, argc, argv)
196      u_short portnum;
197      int argc;
198      char **argv;
199 {
200   struct timeval to;
201   struct sockaddr_in addr;
202   enum clnt_stat rpc_stat;
203   CLIENT *client;
204   u_long prognum, vers, minvers, maxvers;
205   int sock = RPC_ANYSOCK;
206   struct rpc_err rpcerr;
207   int failure;
208
209   if (argc < 2 || argc > 3)
210     {
211       usage ();
212       exit (1);
213     }
214   prognum = getprognum (argv[1]);
215   get_inet_address (&addr, argv[0]);
216   /* Open the socket here so it will survive calls to clnt_destroy */
217   sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
218   if (sock < 0)
219     {
220       perror ("rpcinfo: socket");
221       exit (1);
222     }
223   failure = 0;
224   if (argc == 2)
225     {
226       /*
227        * A call to version 0 should fail with a program/version
228        * mismatch, and give us the range of versions supported.
229        */
230       addr.sin_port = htons (portnum);
231       to.tv_sec = 5;
232       to.tv_usec = 0;
233       if ((client = clntudp_create (&addr, prognum, (u_long) 0,
234                                     to, &sock)) == NULL)
235         {
236           clnt_pcreateerror ("rpcinfo");
237           printf (_ ("program %lu is not available\n"),
238                   prognum);
239           exit (1);
240         }
241       to.tv_sec = 10;
242       to.tv_usec = 0;
243       rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
244                             (char *) NULL, (xdrproc_t) xdr_void,
245                             (char *) NULL, to);
246       if (rpc_stat == RPC_PROGVERSMISMATCH)
247         {
248           clnt_geterr (client, &rpcerr);
249           minvers = rpcerr.re_vers.low;
250           maxvers = rpcerr.re_vers.high;
251         }
252       else if (rpc_stat == RPC_SUCCESS)
253         {
254           /*
255            * Oh dear, it DOES support version 0.
256            * Let's try version MAX_VERS.
257            */
258           addr.sin_port = htons (portnum);
259           to.tv_sec = 5;
260           to.tv_usec = 0;
261           if ((client = clntudp_create (&addr, prognum, MAX_VERS,
262                                         to, &sock)) == NULL)
263             {
264               clnt_pcreateerror ("rpcinfo");
265               printf (_ ("program %lu version %lu is not available\n"),
266                       prognum, MAX_VERS);
267               exit (1);
268             }
269           to.tv_sec = 10;
270           to.tv_usec = 0;
271           rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
272                                 NULL, (xdrproc_t) xdr_void, NULL, to);
273           if (rpc_stat == RPC_PROGVERSMISMATCH)
274             {
275               clnt_geterr (client, &rpcerr);
276               minvers = rpcerr.re_vers.low;
277               maxvers = rpcerr.re_vers.high;
278             }
279           else if (rpc_stat == RPC_SUCCESS)
280             {
281               /*
282                * It also supports version MAX_VERS.
283                * Looks like we have a wise guy.
284                * OK, we give them information on all
285                * 4 billion versions they support...
286                */
287               minvers = 0;
288               maxvers = MAX_VERS;
289             }
290           else
291             {
292               (void) pstatus (client, prognum, MAX_VERS);
293               exit (1);
294             }
295         }
296       else
297         {
298           (void) pstatus (client, prognum, (u_long) 0);
299           exit (1);
300         }
301       clnt_destroy (client);
302       for (vers = minvers; vers <= maxvers; vers++)
303         {
304           addr.sin_port = htons (portnum);
305           to.tv_sec = 5;
306           to.tv_usec = 0;
307           if ((client = clntudp_create (&addr, prognum, vers,
308                                         to, &sock)) == NULL)
309             {
310               clnt_pcreateerror ("rpcinfo");
311               printf (_ ("program %lu version %lu is not available\n"),
312                       prognum, vers);
313               exit (1);
314             }
315           to.tv_sec = 10;
316           to.tv_usec = 0;
317           rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
318                                 NULL, (xdrproc_t) xdr_void, NULL, to);
319           if (pstatus (client, prognum, vers) < 0)
320             failure = 1;
321           clnt_destroy (client);
322         }
323     }
324   else
325     {
326       vers = getvers (argv[2]);
327       addr.sin_port = htons (portnum);
328       to.tv_sec = 5;
329       to.tv_usec = 0;
330       if ((client = clntudp_create (&addr, prognum, vers,
331                                     to, &sock)) == NULL)
332         {
333           clnt_pcreateerror ("rpcinfo");
334           printf ("program %lu version %lu is not available\n",
335                   prognum, vers);
336           exit (1);
337         }
338       to.tv_sec = 10;
339       to.tv_usec = 0;
340       rpc_stat = clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
341                             (xdrproc_t) xdr_void, NULL, to);
342       if (pstatus (client, prognum, vers) < 0)
343         failure = 1;
344     }
345   (void) close (sock);          /* Close it up again */
346   if (failure)
347     exit (1);
348 }
349
350 static void
351 tcpping (portnum, argc, argv)
352      u_short portnum;
353      int argc;
354      char **argv;
355 {
356   struct timeval to;
357   struct sockaddr_in addr;
358   enum clnt_stat rpc_stat;
359   CLIENT *client;
360   u_long prognum, vers, minvers, maxvers;
361   int sock = RPC_ANYSOCK;
362   struct rpc_err rpcerr;
363   int failure;
364
365   if (argc < 2 || argc > 3)
366     {
367       usage ();
368       exit (1);
369     }
370   prognum = getprognum (argv[1]);
371   get_inet_address (&addr, argv[0]);
372   failure = 0;
373   if (argc == 2)
374     {
375       /*
376        * A call to version 0 should fail with a program/version
377        * mismatch, and give us the range of versions supported.
378        */
379       addr.sin_port = htons (portnum);
380       if ((client = clnttcp_create (&addr, prognum, MIN_VERS,
381                                     &sock, 0, 0)) == NULL)
382         {
383           clnt_pcreateerror ("rpcinfo");
384           printf (_ ("program %lu is not available\n"),
385                   prognum);
386           exit (1);
387         }
388       to.tv_sec = 10;
389       to.tv_usec = 0;
390       rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void, NULL,
391                             (xdrproc_t) xdr_void, NULL, to);
392       if (rpc_stat == RPC_PROGVERSMISMATCH)
393         {
394           clnt_geterr (client, &rpcerr);
395           minvers = rpcerr.re_vers.low;
396           maxvers = rpcerr.re_vers.high;
397         }
398       else if (rpc_stat == RPC_SUCCESS)
399         {
400           /*
401            * Oh dear, it DOES support version 0.
402            * Let's try version MAX_VERS.
403            */
404           addr.sin_port = htons (portnum);
405           if ((client = clnttcp_create (&addr, prognum, MAX_VERS,
406                                         &sock, 0, 0)) == NULL)
407             {
408               clnt_pcreateerror ("rpcinfo");
409               printf (_ ("program %lu version %lu is not available\n"),
410                       prognum, MAX_VERS);
411               exit (1);
412             }
413           to.tv_sec = 10;
414           to.tv_usec = 0;
415           rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
416                                 NULL, (xdrproc_t) xdr_void, NULL, to);
417           if (rpc_stat == RPC_PROGVERSMISMATCH)
418             {
419               clnt_geterr (client, &rpcerr);
420               minvers = rpcerr.re_vers.low;
421               maxvers = rpcerr.re_vers.high;
422             }
423           else if (rpc_stat == RPC_SUCCESS)
424             {
425               /*
426                * It also supports version MAX_VERS.
427                * Looks like we have a wise guy.
428                * OK, we give them information on all
429                * 4 billion versions they support...
430                */
431               minvers = 0;
432               maxvers = MAX_VERS;
433             }
434           else
435             {
436               (void) pstatus (client, prognum, MAX_VERS);
437               exit (1);
438             }
439         }
440       else
441         {
442           (void) pstatus (client, prognum, MIN_VERS);
443           exit (1);
444         }
445       clnt_destroy (client);
446       (void) close (sock);
447       sock = RPC_ANYSOCK;       /* Re-initialize it for later */
448       for (vers = minvers; vers <= maxvers; vers++)
449         {
450           addr.sin_port = htons (portnum);
451           if ((client = clnttcp_create (&addr, prognum, vers,
452                                         &sock, 0, 0)) == NULL)
453             {
454               clnt_pcreateerror ("rpcinfo");
455               printf (_ ("program %lu version %lu is not available\n"),
456                       prognum, vers);
457               exit (1);
458             }
459           to.tv_usec = 0;
460           to.tv_sec = 10;
461           rpc_stat = clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
462                                 (xdrproc_t) xdr_void, NULL, to);
463           if (pstatus (client, prognum, vers) < 0)
464             failure = 1;
465           clnt_destroy (client);
466           (void) close (sock);
467           sock = RPC_ANYSOCK;
468         }
469     }
470   else
471     {
472       vers = getvers (argv[2]);
473       addr.sin_port = htons (portnum);
474       if ((client = clnttcp_create (&addr, prognum, vers, &sock,
475                                     0, 0)) == NULL)
476         {
477           clnt_pcreateerror ("rpcinfo");
478           printf (_ ("program %lu version %lu is not available\n"),
479                   prognum, vers);
480           exit (1);
481         }
482       to.tv_usec = 0;
483       to.tv_sec = 10;
484       rpc_stat = clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
485                             (xdrproc_t) xdr_void, NULL, to);
486       if (pstatus (client, prognum, vers) < 0)
487         failure = 1;
488     }
489   if (failure)
490     exit (1);
491 }
492
493 /*
494  * This routine should take a pointer to an "rpc_err" structure, rather than
495  * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
496  * a CLIENT structure rather than a pointer to an "rpc_err" structure.
497  * As such, we have to keep the CLIENT structure around in order to print
498  * a good error message.
499  */
500 static int
501 pstatus (client, prognum, vers)
502      register CLIENT *client;
503      u_long prognum;
504      u_long vers;
505 {
506   struct rpc_err rpcerr;
507
508   clnt_geterr (client, &rpcerr);
509   if (rpcerr.re_status != RPC_SUCCESS)
510     {
511       clnt_perror (client, "rpcinfo");
512       printf (_ ("program %lu version %lu is not available\n"),
513               prognum, vers);
514       return (-1);
515     }
516   else
517     {
518       printf (_ ("program %lu version %lu ready and waiting\n"),
519               prognum, vers);
520       return (0);
521     }
522 }
523
524 static void
525 pmapdump (argc, argv)
526      int argc;
527      char **argv;
528 {
529   struct sockaddr_in server_addr;
530   register struct hostent *hp;
531   struct pmaplist *head = NULL;
532   int socket = RPC_ANYSOCK;
533   struct timeval minutetimeout;
534   register CLIENT *client;
535   struct rpcent *rpc;
536
537   if (argc > 1)
538     {
539       usage ();
540       exit (1);
541     }
542   if (argc == 1)
543     get_inet_address (&server_addr, argv[0]);
544   else
545     {
546       bzero ((char *) &server_addr, sizeof server_addr);
547       server_addr.sin_family = AF_INET;
548       if ((hp = gethostbyname ("localhost")) != NULL)
549         bcopy (hp->h_addr, (caddr_t) & server_addr.sin_addr,
550                hp->h_length);
551       else
552         server_addr.sin_addr.s_addr = inet_addr ("0.0.0.0");
553     }
554   minutetimeout.tv_sec = 60;
555   minutetimeout.tv_usec = 0;
556   server_addr.sin_port = htons (PMAPPORT);
557   if ((client = clnttcp_create (&server_addr, PMAPPROG,
558                                 PMAPVERS, &socket, 50, 500)) == NULL)
559     {
560       clnt_pcreateerror (_ ("rpcinfo: can't contact portmapper"));
561       exit (1);
562     }
563   if (clnt_call (client, PMAPPROC_DUMP, (xdrproc_t) xdr_void, NULL,
564                  (xdrproc_t) xdr_pmaplist, (caddr_t) &head,
565                  minutetimeout) != RPC_SUCCESS)
566     {
567       fprintf (stderr, _ ("rpcinfo: can't contact portmapper: "));
568       clnt_perror (client, "rpcinfo");
569       exit (1);
570     }
571   if (head == NULL)
572     {
573       printf (_ ("No remote programs registered.\n"));
574     }
575   else
576     {
577       printf (_ ("   program vers proto   port\n"));
578       for (; head != NULL; head = head->pml_next)
579         {
580           printf ("%10ld%5ld",
581                   head->pml_map.pm_prog,
582                   head->pml_map.pm_vers);
583           if (head->pml_map.pm_prot == IPPROTO_UDP)
584             printf ("%6s", "udp");
585           else if (head->pml_map.pm_prot == IPPROTO_TCP)
586             printf ("%6s", "tcp");
587           else
588             printf ("%6ld", head->pml_map.pm_prot);
589           printf ("%7ld", head->pml_map.pm_port);
590           rpc = getrpcbynumber (head->pml_map.pm_prog);
591           if (rpc)
592             printf ("  %s\n", rpc->r_name);
593           else
594             printf ("\n");
595         }
596     }
597 }
598
599 /*
600  * reply_proc collects replies from the broadcast.
601  * to get a unique list of responses the output of rpcinfo should
602  * be piped through sort(1) and then uniq(1).
603  */
604
605 /*ARGSUSED */
606 static bool_t
607 reply_proc (res, who)
608      void *res;                 /* Nothing comes back */
609      struct sockaddr_in *who;   /* Who sent us the reply */
610 {
611   register struct hostent *hp;
612
613   hp = gethostbyaddr ((char *) &who->sin_addr, sizeof who->sin_addr,
614                       AF_INET);
615   printf ("%s %s\n", inet_ntoa (who->sin_addr),
616           (hp == NULL) ? _ ("(unknown)") : hp->h_name);
617   return (FALSE);
618 }
619
620 static void
621 brdcst (argc, argv)
622      int argc;
623      char **argv;
624 {
625   enum clnt_stat rpc_stat;
626   u_long prognum, vers;
627
628   if (argc != 2)
629     {
630       usage ();
631       exit (1);
632     }
633   prognum = getprognum (argv[0]);
634   vers = getvers (argv[1]);
635   rpc_stat = clnt_broadcast (prognum, vers, NULLPROC, (xdrproc_t) xdr_void,
636                              NULL, (xdrproc_t) xdr_void, NULL,
637                              (resultproc_t) reply_proc);
638   if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT))
639     {
640       fprintf (stderr, _ ("rpcinfo: broadcast failed: %s\n"),
641                clnt_sperrno (rpc_stat));
642       exit (1);
643     }
644   exit (0);
645 }
646
647 static void
648 deletereg (argc, argv)
649      int argc;
650      char **argv;
651 {
652   u_long prog_num, version_num;
653
654   if (argc != 2)
655     {
656       usage ();
657       exit (1);
658     }
659   if (getuid ())
660     {                           /* This command allowed only to root */
661       fprintf (stderr, "Sorry. You are not root\n");
662       exit (1);
663     }
664   prog_num = getprognum (argv[0]);
665   version_num = getvers (argv[1]);
666   if ((pmap_unset (prog_num, version_num)) == 0)
667     {
668       fprintf (stderr, _ ("rpcinfo: Could not delete registration for prog %s version %s\n"),
669                argv[0], argv[1]);
670       exit (1);
671     }
672 }
673
674 static void
675 usage ()
676 {
677   fprintf (stderr, _ ("Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n"));
678   fprintf (stderr, _ ("       rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n"));
679   fprintf (stderr, _ ("       rpcinfo -p [ host ]\n"));
680   fprintf (stderr, _ ("       rpcinfo -b prognum versnum\n"));
681   fprintf (stderr, _ ("       rpcinfo -d prognum versnum\n"));
682 }
683
684 static u_long
685 getprognum (arg)
686      char *arg;
687 {
688   register struct rpcent *rpc;
689   register u_long prognum;
690
691   if (isalpha (*arg))
692     {
693       rpc = getrpcbyname (arg);
694       if (rpc == NULL)
695         {
696           fprintf (stderr, _ ("rpcinfo: %s is unknown service\n"),
697                    arg);
698           exit (1);
699         }
700       prognum = rpc->r_number;
701     }
702   else
703     {
704       prognum = (u_long) atoi (arg);
705     }
706
707   return (prognum);
708 }
709
710 static u_long
711 getvers (arg)
712      char *arg;
713 {
714   register u_long vers;
715
716   vers = (int) atoi (arg);
717   return (vers);
718 }
719
720 static void
721 get_inet_address (addr, host)
722      struct sockaddr_in *addr;
723      char *host;
724 {
725   register struct hostent *hp;
726
727   bzero ((char *) addr, sizeof *addr);
728   addr->sin_addr.s_addr = (u_long) inet_addr (host);
729   if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0)
730     {
731       if ((hp = gethostbyname (host)) == NULL)
732         {
733           fprintf (stderr, _ ("rpcinfo: %s is unknown host\n"),
734                    host);
735           exit (1);
736         }
737       bcopy (hp->h_addr, (char *) &addr->sin_addr, hp->h_length);
738     }
739   addr->sin_family = AF_INET;
740 }