fdwalk should return 0 on an empty directory
[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) __attribute__ ((noreturn));
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"), prognum);
238           exit (1);
239         }
240       to.tv_sec = 10;
241       to.tv_usec = 0;
242       rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
243                             (char *) NULL, (xdrproc_t) xdr_void,
244                             (char *) NULL, to);
245       if (rpc_stat == RPC_PROGVERSMISMATCH)
246         {
247           clnt_geterr (client, &rpcerr);
248           minvers = rpcerr.re_vers.low;
249           maxvers = rpcerr.re_vers.high;
250         }
251       else if (rpc_stat == RPC_SUCCESS)
252         {
253           /*
254            * Oh dear, it DOES support version 0.
255            * Let's try version MAX_VERS.
256            */
257           addr.sin_port = htons (portnum);
258           to.tv_sec = 5;
259           to.tv_usec = 0;
260           if ((client = clntudp_create (&addr, prognum, MAX_VERS,
261                                         to, &sock)) == NULL)
262             {
263               clnt_pcreateerror ("rpcinfo");
264               printf (_("program %lu version %lu is not available\n"),
265                       prognum, MAX_VERS);
266               exit (1);
267             }
268           to.tv_sec = 10;
269           to.tv_usec = 0;
270           rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
271                                 NULL, (xdrproc_t) xdr_void, NULL, to);
272           if (rpc_stat == RPC_PROGVERSMISMATCH)
273             {
274               clnt_geterr (client, &rpcerr);
275               minvers = rpcerr.re_vers.low;
276               maxvers = rpcerr.re_vers.high;
277             }
278           else if (rpc_stat == RPC_SUCCESS)
279             {
280               /*
281                * It also supports version MAX_VERS.
282                * Looks like we have a wise guy.
283                * OK, we give them information on all
284                * 4 billion versions they support...
285                */
286               minvers = 0;
287               maxvers = MAX_VERS;
288             }
289           else
290             {
291               (void) pstatus (client, prognum, MAX_VERS);
292               exit (1);
293             }
294         }
295       else
296         {
297           (void) pstatus (client, prognum, (u_long) 0);
298           exit (1);
299         }
300       clnt_destroy (client);
301       for (vers = minvers; vers <= maxvers; vers++)
302         {
303           addr.sin_port = htons (portnum);
304           to.tv_sec = 5;
305           to.tv_usec = 0;
306           if ((client = clntudp_create (&addr, prognum, vers,
307                                         to, &sock)) == NULL)
308             {
309               clnt_pcreateerror ("rpcinfo");
310               printf (_("program %lu version %lu is not available\n"),
311                       prognum, vers);
312               exit (1);
313             }
314           to.tv_sec = 10;
315           to.tv_usec = 0;
316           rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
317                                 NULL, (xdrproc_t) xdr_void, NULL, to);
318           if (pstatus (client, prognum, vers) < 0)
319             failure = 1;
320           clnt_destroy (client);
321         }
322     }
323   else
324     {
325       vers = getvers (argv[2]);
326       addr.sin_port = htons (portnum);
327       to.tv_sec = 5;
328       to.tv_usec = 0;
329       if ((client = clntudp_create (&addr, prognum, vers,
330                                     to, &sock)) == NULL)
331         {
332           clnt_pcreateerror ("rpcinfo");
333           printf (_("program %lu version %lu is not available\n"),
334                   prognum, vers);
335           exit (1);
336         }
337       to.tv_sec = 10;
338       to.tv_usec = 0;
339       rpc_stat = clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
340                             (xdrproc_t) xdr_void, NULL, to);
341       if (pstatus (client, prognum, vers) < 0)
342         failure = 1;
343     }
344   (void) close (sock);          /* Close it up again */
345   if (failure)
346     exit (1);
347 }
348
349 static void
350 tcpping (portnum, argc, argv)
351      u_short portnum;
352      int argc;
353      char **argv;
354 {
355   struct timeval to;
356   struct sockaddr_in addr;
357   enum clnt_stat rpc_stat;
358   CLIENT *client;
359   u_long prognum, vers, minvers, maxvers;
360   int sock = RPC_ANYSOCK;
361   struct rpc_err rpcerr;
362   int failure;
363
364   if (argc < 2 || argc > 3)
365     {
366       usage ();
367       exit (1);
368     }
369   prognum = getprognum (argv[1]);
370   get_inet_address (&addr, argv[0]);
371   failure = 0;
372   if (argc == 2)
373     {
374       /*
375        * A call to version 0 should fail with a program/version
376        * mismatch, and give us the range of versions supported.
377        */
378       addr.sin_port = htons (portnum);
379       if ((client = clnttcp_create (&addr, prognum, MIN_VERS,
380                                     &sock, 0, 0)) == NULL)
381         {
382           clnt_pcreateerror ("rpcinfo");
383           printf (_("program %lu is not available\n"), prognum);
384           exit (1);
385         }
386       to.tv_sec = 10;
387       to.tv_usec = 0;
388       rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void, NULL,
389                             (xdrproc_t) xdr_void, NULL, to);
390       if (rpc_stat == RPC_PROGVERSMISMATCH)
391         {
392           clnt_geterr (client, &rpcerr);
393           minvers = rpcerr.re_vers.low;
394           maxvers = rpcerr.re_vers.high;
395         }
396       else if (rpc_stat == RPC_SUCCESS)
397         {
398           /*
399            * Oh dear, it DOES support version 0.
400            * Let's try version MAX_VERS.
401            */
402           addr.sin_port = htons (portnum);
403           if ((client = clnttcp_create (&addr, prognum, MAX_VERS,
404                                         &sock, 0, 0)) == NULL)
405             {
406               clnt_pcreateerror ("rpcinfo");
407               printf (_("program %lu version %lu is not available\n"),
408                       prognum, MAX_VERS);
409               exit (1);
410             }
411           to.tv_sec = 10;
412           to.tv_usec = 0;
413           rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
414                                 NULL, (xdrproc_t) xdr_void, NULL, to);
415           if (rpc_stat == RPC_PROGVERSMISMATCH)
416             {
417               clnt_geterr (client, &rpcerr);
418               minvers = rpcerr.re_vers.low;
419               maxvers = rpcerr.re_vers.high;
420             }
421           else if (rpc_stat == RPC_SUCCESS)
422             {
423               /*
424                * It also supports version MAX_VERS.
425                * Looks like we have a wise guy.
426                * OK, we give them information on all
427                * 4 billion versions they support...
428                */
429               minvers = 0;
430               maxvers = MAX_VERS;
431             }
432           else
433             {
434               (void) pstatus (client, prognum, MAX_VERS);
435               exit (1);
436             }
437         }
438       else
439         {
440           (void) pstatus (client, prognum, MIN_VERS);
441           exit (1);
442         }
443       clnt_destroy (client);
444       (void) close (sock);
445       sock = RPC_ANYSOCK;       /* Re-initialize it for later */
446       for (vers = minvers; vers <= maxvers; vers++)
447         {
448           addr.sin_port = htons (portnum);
449           if ((client = clnttcp_create (&addr, prognum, vers,
450                                         &sock, 0, 0)) == NULL)
451             {
452               clnt_pcreateerror ("rpcinfo");
453               printf (_("program %lu version %lu is not available\n"),
454                       prognum, vers);
455               exit (1);
456             }
457           to.tv_usec = 0;
458           to.tv_sec = 10;
459           rpc_stat = clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
460                                 (xdrproc_t) xdr_void, NULL, to);
461           if (pstatus (client, prognum, vers) < 0)
462             failure = 1;
463           clnt_destroy (client);
464           (void) close (sock);
465           sock = RPC_ANYSOCK;
466         }
467     }
468   else
469     {
470       vers = getvers (argv[2]);
471       addr.sin_port = htons (portnum);
472       if ((client = clnttcp_create (&addr, prognum, vers, &sock,
473                                     0, 0)) == NULL)
474         {
475           clnt_pcreateerror ("rpcinfo");
476           printf (_("program %lu version %lu is not available\n"),
477                   prognum, vers);
478           exit (1);
479         }
480       to.tv_usec = 0;
481       to.tv_sec = 10;
482       rpc_stat = clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
483                             (xdrproc_t) xdr_void, NULL, to);
484       if (pstatus (client, prognum, vers) < 0)
485         failure = 1;
486     }
487   if (failure)
488     exit (1);
489 }
490
491 /*
492  * This routine should take a pointer to an "rpc_err" structure, rather than
493  * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
494  * a CLIENT structure rather than a pointer to an "rpc_err" structure.
495  * As such, we have to keep the CLIENT structure around in order to print
496  * a good error message.
497  */
498 static int
499 pstatus (client, prognum, vers)
500      register CLIENT *client;
501      u_long prognum;
502      u_long vers;
503 {
504   struct rpc_err rpcerr;
505
506   clnt_geterr (client, &rpcerr);
507   if (rpcerr.re_status != RPC_SUCCESS)
508     {
509       clnt_perror (client, "rpcinfo");
510       printf (_("program %lu version %lu is not available\n"), prognum, vers);
511       return -1;
512     }
513   else
514     {
515       printf (_("program %lu version %lu ready and waiting\n"), prognum, vers);
516       return 0;
517     }
518 }
519
520 static void
521 pmapdump (argc, argv)
522      int argc;
523      char **argv;
524 {
525   struct sockaddr_in server_addr;
526   register struct hostent *hp;
527   struct pmaplist *head = NULL;
528   int socket = RPC_ANYSOCK;
529   struct timeval minutetimeout;
530   register CLIENT *client;
531   struct rpcent *rpc;
532
533   if (argc > 1)
534     {
535       usage ();
536       exit (1);
537     }
538   if (argc == 1)
539     get_inet_address (&server_addr, argv[0]);
540   else
541     {
542       bzero ((char *) &server_addr, sizeof server_addr);
543       server_addr.sin_family = AF_INET;
544       if ((hp = gethostbyname ("localhost")) != NULL)
545         memcpy ((caddr_t) & server_addr.sin_addr, hp->h_addr,
546                  hp->h_length);
547       else
548         server_addr.sin_addr.s_addr = inet_addr ("0.0.0.0");
549     }
550   minutetimeout.tv_sec = 60;
551   minutetimeout.tv_usec = 0;
552   server_addr.sin_port = htons (PMAPPORT);
553   if ((client = clnttcp_create (&server_addr, PMAPPROG,
554                                 PMAPVERS, &socket, 50, 500)) == NULL)
555     {
556       clnt_pcreateerror (_("rpcinfo: can't contact portmapper"));
557       exit (1);
558     }
559   if (clnt_call (client, PMAPPROC_DUMP, (xdrproc_t) xdr_void, NULL,
560                  (xdrproc_t) xdr_pmaplist, (caddr_t) &head,
561                  minutetimeout) != RPC_SUCCESS)
562     {
563       fputs (_("rpcinfo: can't contact portmapper"), stderr);
564       fputs (": ", stderr);
565       clnt_perror (client, "rpcinfo");
566       exit (1);
567     }
568   if (head == NULL)
569     {
570       fputs (_("No remote programs registered.\n"), stdout);
571     }
572   else
573     {
574       fputs (_("   program vers proto   port\n"), stdout);
575       for (; head != NULL; head = head->pml_next)
576         {
577           printf ("%10ld%5ld",
578                   head->pml_map.pm_prog,
579                   head->pml_map.pm_vers);
580           if (head->pml_map.pm_prot == IPPROTO_UDP)
581             printf ("%6s", "udp");
582           else if (head->pml_map.pm_prot == IPPROTO_TCP)
583             printf ("%6s", "tcp");
584           else
585             printf ("%6ld", head->pml_map.pm_prot);
586           printf ("%7ld", head->pml_map.pm_port);
587           rpc = getrpcbynumber (head->pml_map.pm_prog);
588           if (rpc)
589             printf ("  %s\n", rpc->r_name);
590           else
591             printf ("\n");
592         }
593     }
594 }
595
596 /*
597  * reply_proc collects replies from the broadcast.
598  * to get a unique list of responses the output of rpcinfo should
599  * be piped through sort(1) and then uniq(1).
600  */
601
602 /*ARGSUSED */
603 static bool_t
604 reply_proc (res, who)
605      void *res;                 /* Nothing comes back */
606      struct sockaddr_in *who;   /* Who sent us the reply */
607 {
608   register struct hostent *hp;
609
610   hp = gethostbyaddr ((char *) &who->sin_addr, sizeof who->sin_addr,
611                       AF_INET);
612   printf ("%s %s\n", inet_ntoa (who->sin_addr),
613           (hp == NULL) ? _("(unknown)") : hp->h_name);
614   return FALSE;
615 }
616
617 static void
618 brdcst (argc, argv)
619      int argc;
620      char **argv;
621 {
622   enum clnt_stat rpc_stat;
623   u_long prognum, vers;
624
625   if (argc != 2)
626     {
627       usage ();
628       exit (1);
629     }
630   prognum = getprognum (argv[0]);
631   vers = getvers (argv[1]);
632   rpc_stat = clnt_broadcast (prognum, vers, NULLPROC, (xdrproc_t) xdr_void,
633                              NULL, (xdrproc_t) xdr_void, NULL,
634                              (resultproc_t) reply_proc);
635   if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT))
636     {
637       fprintf (stderr, _("rpcinfo: broadcast failed: %s\n"),
638                clnt_sperrno (rpc_stat));
639       exit (1);
640     }
641   exit (0);
642 }
643
644 static void
645 deletereg (argc, argv)
646      int argc;
647      char **argv;
648 {
649   u_long prog_num, version_num;
650
651   if (argc != 2)
652     {
653       usage ();
654       exit (1);
655     }
656   if (getuid ())
657     {                           /* This command allowed only to root */
658       fputs (_("Sorry. You are not root\n"), stderr);
659       exit (1);
660     }
661   prog_num = getprognum (argv[0]);
662   version_num = getvers (argv[1]);
663   if ((pmap_unset (prog_num, version_num)) == 0)
664     {
665       fprintf (stderr, _("rpcinfo: Could not delete registration for prog %s version %s\n"),
666                argv[0], argv[1]);
667       exit (1);
668     }
669 }
670
671 static void
672 usage ()
673 {
674   fputs (_("Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n"),
675          stderr);
676   fputs (_("       rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n"),
677          stderr);
678   fputs (_("       rpcinfo -p [ host ]\n"), stderr);
679   fputs (_("       rpcinfo -b prognum versnum\n"), stderr);
680   fputs (_("       rpcinfo -d prognum versnum\n"), stderr);
681 }
682
683 static u_long
684 getprognum (arg)
685      char *arg;
686 {
687   register struct rpcent *rpc;
688   register u_long prognum;
689
690   if (isalpha (*arg))
691     {
692       rpc = getrpcbyname (arg);
693       if (rpc == NULL)
694         {
695           fprintf (stderr, _("rpcinfo: %s is unknown service\n"), arg);
696           exit (1);
697         }
698       prognum = rpc->r_number;
699     }
700   else
701     {
702       prognum = (u_long) atoi (arg);
703     }
704
705   return prognum;
706 }
707
708 static u_long
709 getvers (arg)
710      char *arg;
711 {
712   register u_long vers;
713
714   vers = (int) atoi (arg);
715   return vers;
716 }
717
718 static void
719 get_inet_address (addr, host)
720      struct sockaddr_in *addr;
721      char *host;
722 {
723   register struct hostent *hp;
724
725   bzero ((char *) addr, sizeof *addr);
726   addr->sin_addr.s_addr = (u_long) inet_addr (host);
727   if (addr->sin_addr.s_addr == INADDR_NONE
728       || addr->sin_addr.s_addr == INADDR_ANY)
729     {
730       if ((hp = gethostbyname (host)) == NULL)
731         {
732           fprintf (stderr, _("rpcinfo: %s is unknown host\n"),
733                    host);
734           exit (1);
735         }
736       memmove ((char *) &addr->sin_addr, hp->h_addr, hp->h_length);
737     }
738   addr->sin_family = AF_INET;
739 }