update from main archive 970121
[kopensolaris-gnu/glibc.git] / sunrpc / rpcinfo.c
1 /* @(#)rpcinfo.c        2.2 88/08/11 4.0 RPCSRC */
2 #ifndef lint
3 static  char sccsid[] = "@(#)rpcinfo.c 1.22 87/08/12 SMI";
4 #endif
5
6 /*
7  * Copyright (C) 1986, Sun Microsystems, Inc.
8  */
9
10 /*
11  * rpcinfo: ping a particular rpc program
12  *     or dump the portmapper
13  */
14
15 /*
16  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
17  * unrestricted use provided that this legend is included on all tape
18  * media and as a part of the software program in whole or part.  Users
19  * may copy or modify Sun RPC without charge, but are not authorized
20  * to license or distribute it to anyone else except as part of a product or
21  * program developed by the user.
22  *
23  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
24  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
26  *
27  * Sun RPC is provided with no support and without any obligation on the
28  * part of Sun Microsystems, Inc. to assist in its use, correction,
29  * modification or enhancement.
30  *
31  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
32  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
33  * OR ANY PART THEREOF.
34  *
35  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
36  * or profits or other special, indirect and consequential damages, even if
37  * Sun has been advised of the possibility of such damages.
38  *
39  * Sun Microsystems, Inc.
40  * 2550 Garcia Avenue
41  * Mountain View, California  94043
42  */
43
44 #include <rpc/rpc.h>
45 #include <stdio.h>
46 #include <sys/socket.h>
47 #include <netdb.h>
48 #include <rpc/pmap_prot.h>
49 #include <rpc/pmap_clnt.h>
50 #include <signal.h>
51 #include <ctype.h>
52
53 #define MAXHOSTLEN 256
54
55 #define MIN_VERS        ((u_long) 0)
56 #define MAX_VERS        ((u_long) 4294967295L)
57
58 static void     udpping(/*u_short portflag, int argc, char **argv*/);
59 static void     tcpping(/*u_short portflag, int argc, char **argv*/);
60 static int      pstatus(/*CLIENT *client, u_long prognum, u_long vers*/);
61 static void     pmapdump(/*int argc, char **argv*/);
62 static bool_t   reply_proc(/*void *res, struct sockaddr_in *who*/);
63 static void     brdcst(/*int argc, char **argv*/);
64 static void     deletereg(/* int argc, char **argv */) ;
65 static void     usage(/*void*/);
66 static u_long   getprognum(/*char *arg*/);
67 static u_long   getvers(/*char *arg*/);
68 static void     get_inet_address(/*struct sockaddr_in *addr, char *host*/);
69 extern u_long inet_addr();  /* in 4.2BSD, arpa/inet.h called that a in_addr */
70 extern char *inet_ntoa();
71
72 /*
73  * Functions to be performed.
74  */
75 #define NONE            0       /* no function */
76 #define PMAPDUMP        1       /* dump portmapper registrations */
77 #define TCPPING         2       /* ping TCP service */
78 #define UDPPING         3       /* ping UDP service */
79 #define BRDCST          4       /* ping broadcast UDP service */
80 #define DELETES         5       /* delete registration for the service */
81
82 int
83 main(argc, argv)
84         int argc;
85         char **argv;
86 {
87         register int c;
88         extern char *optarg;
89         extern int optind;
90         int errflg;
91         int function;
92         u_short portnum;
93
94         function = NONE;
95         portnum = 0;
96         errflg = 0;
97         while ((c = getopt(argc, argv, "ptubdn:")) != -1) {
98                 switch (c) {
99
100                 case 'p':
101                         if (function != NONE)
102                                 errflg = 1;
103                         else
104                                 function = PMAPDUMP;
105                         break;
106
107                 case 't':
108                         if (function != NONE)
109                                 errflg = 1;
110                         else
111                                 function = TCPPING;
112                         break;
113
114                 case 'u':
115                         if (function != NONE)
116                                 errflg = 1;
117                         else
118                                 function = UDPPING;
119                         break;
120
121                 case 'b':
122                         if (function != NONE)
123                                 errflg = 1;
124                         else
125                                 function = BRDCST;
126                         break;
127
128                 case 'n':
129                         portnum = (u_short) atoi(optarg);   /* hope we don't get bogus # */
130                         break;
131
132                 case 'd':
133                         if (function != NONE)
134                                 errflg = 1;
135                         else
136                                 function = DELETES;
137                         break;
138
139                 case '?':
140                         errflg = 1;
141                 }
142         }
143
144         if (errflg || function == NONE) {
145                 usage();
146                 return (1);
147         }
148
149         switch (function) {
150
151         case PMAPDUMP:
152                 if (portnum != 0) {
153                         usage();
154                         return (1);
155                 }
156                 pmapdump(argc - optind, argv + optind);
157                 break;
158
159         case UDPPING:
160                 udpping(portnum, argc - optind, argv + optind);
161                 break;
162
163         case TCPPING:
164                 tcpping(portnum, argc - optind, argv + optind);
165                 break;
166
167         case BRDCST:
168                 if (portnum != 0) {
169                         usage();
170                         return (1);
171                 }
172                 brdcst(argc - optind, argv + optind);
173                 break;
174
175         case DELETES:
176                 deletereg(argc - optind, argv + optind);
177                 break;
178         }
179
180         return (0);
181 }
182
183 static void
184 udpping(portnum, argc, argv)
185         u_short portnum;
186         int argc;
187         char **argv;
188 {
189         struct timeval to;
190         struct sockaddr_in addr;
191         enum clnt_stat rpc_stat;
192         CLIENT *client;
193         u_long prognum, vers, minvers, maxvers;
194         int sock = RPC_ANYSOCK;
195         struct rpc_err rpcerr;
196         int failure;
197
198         if (argc < 2 || argc > 3) {
199                 usage();
200                 exit(1);
201         }
202         prognum = getprognum(argv[1]);
203         get_inet_address(&addr, argv[0]);
204         /* Open the socket here so it will survive calls to clnt_destroy */
205         sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP);
206         if (sock < 0) {
207                 perror("rpcinfo: socket");
208                 exit(1);
209         }
210         failure = 0;
211         if (argc == 2) {
212                 /*
213                  * A call to version 0 should fail with a program/version
214                  * mismatch, and give us the range of versions supported.
215                  */
216                 addr.sin_port = htons(portnum);
217                 to.tv_sec = 5;
218                 to.tv_usec = 0;
219                 if ((client = clntudp_create(&addr, prognum, (u_long)0,
220                     to, &sock)) == NULL) {
221                         clnt_pcreateerror("rpcinfo");
222                         printf(_("program %lu is not available\n"),
223                             prognum);
224                         exit(1);
225                 }
226                 to.tv_sec = 10;
227                 to.tv_usec = 0;
228                 rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
229                     xdr_void, (char *)NULL, to);
230                 if (rpc_stat == RPC_PROGVERSMISMATCH) {
231                         clnt_geterr(client, &rpcerr);
232                         minvers = rpcerr.re_vers.low;
233                         maxvers = rpcerr.re_vers.high;
234                 } else if (rpc_stat == RPC_SUCCESS) {
235                         /*
236                          * Oh dear, it DOES support version 0.
237                          * Let's try version MAX_VERS.
238                          */
239                         addr.sin_port = htons(portnum);
240                         to.tv_sec = 5;
241                         to.tv_usec = 0;
242                         if ((client = clntudp_create(&addr, prognum, MAX_VERS,
243                             to, &sock)) == NULL) {
244                                 clnt_pcreateerror("rpcinfo");
245                                 printf(_("program %lu version %lu is not available\n"),
246                                     prognum, MAX_VERS);
247                                 exit(1);
248                         }
249                         to.tv_sec = 10;
250                         to.tv_usec = 0;
251                         rpc_stat = clnt_call(client, NULLPROC, xdr_void,
252                             (char *)NULL, xdr_void, (char *)NULL, to);
253                         if (rpc_stat == RPC_PROGVERSMISMATCH) {
254                                 clnt_geterr(client, &rpcerr);
255                                 minvers = rpcerr.re_vers.low;
256                                 maxvers = rpcerr.re_vers.high;
257                         } else if (rpc_stat == RPC_SUCCESS) {
258                                 /*
259                                  * It also supports version MAX_VERS.
260                                  * Looks like we have a wise guy.
261                                  * OK, we give them information on all
262                                  * 4 billion versions they support...
263                                  */
264                                 minvers = 0;
265                                 maxvers = MAX_VERS;
266                         } else {
267                                 (void) pstatus(client, prognum, MAX_VERS);
268                                 exit(1);
269                         }
270                 } else {
271                         (void) pstatus(client, prognum, (u_long)0);
272                         exit(1);
273                 }
274                 clnt_destroy(client);
275                 for (vers = minvers; vers <= maxvers; vers++) {
276                         addr.sin_port = htons(portnum);
277                         to.tv_sec = 5;
278                         to.tv_usec = 0;
279                         if ((client = clntudp_create(&addr, prognum, vers,
280                             to, &sock)) == NULL) {
281                                 clnt_pcreateerror("rpcinfo");
282                                 printf(_("program %lu version %lu is not available\n"),
283                                     prognum, vers);
284                                 exit(1);
285                         }
286                         to.tv_sec = 10;
287                         to.tv_usec = 0;
288                         rpc_stat = clnt_call(client, NULLPROC, xdr_void,
289                             (char *)NULL, xdr_void, (char *)NULL, to);
290                         if (pstatus(client, prognum, vers) < 0)
291                                 failure = 1;
292                         clnt_destroy(client);
293                 }
294         }
295         else {
296                 vers = getvers(argv[2]);
297                 addr.sin_port = htons(portnum);
298                 to.tv_sec = 5;
299                 to.tv_usec = 0;
300                 if ((client = clntudp_create(&addr, prognum, vers,
301                     to, &sock)) == NULL) {
302                         clnt_pcreateerror("rpcinfo");
303                         printf("program %lu version %lu is not available\n",
304                             prognum, vers);
305                         exit(1);
306                 }
307                 to.tv_sec = 10;
308                 to.tv_usec = 0;
309                 rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
310                     xdr_void, (char *)NULL, to);
311                 if (pstatus(client, prognum, vers) < 0)
312                         failure = 1;
313         }
314         (void) close(sock); /* Close it up again */
315         if (failure)
316                 exit(1);
317 }
318
319 static void
320 tcpping(portnum, argc, argv)
321         u_short portnum;
322         int argc;
323         char **argv;
324 {
325         struct timeval to;
326         struct sockaddr_in addr;
327         enum clnt_stat rpc_stat;
328         CLIENT *client;
329         u_long prognum, vers, minvers, maxvers;
330         int sock = RPC_ANYSOCK;
331         struct rpc_err rpcerr;
332         int failure;
333
334         if (argc < 2 || argc > 3) {
335                 usage();
336                 exit(1);
337         }
338         prognum = getprognum(argv[1]);
339         get_inet_address(&addr, argv[0]);
340         failure = 0;
341         if (argc == 2) {
342                 /*
343                  * A call to version 0 should fail with a program/version
344                  * mismatch, and give us the range of versions supported.
345                  */
346                 addr.sin_port = htons(portnum);
347                 if ((client = clnttcp_create(&addr, prognum, MIN_VERS,
348                     &sock, 0, 0)) == NULL) {
349                         clnt_pcreateerror("rpcinfo");
350                         printf(_("program %lu is not available\n"),
351                             prognum);
352                         exit(1);
353                 }
354                 to.tv_sec = 10;
355                 to.tv_usec = 0;
356                 rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
357                     xdr_void, (char *)NULL, to);
358                 if (rpc_stat == RPC_PROGVERSMISMATCH) {
359                         clnt_geterr(client, &rpcerr);
360                         minvers = rpcerr.re_vers.low;
361                         maxvers = rpcerr.re_vers.high;
362                 } else if (rpc_stat == RPC_SUCCESS) {
363                         /*
364                          * Oh dear, it DOES support version 0.
365                          * Let's try version MAX_VERS.
366                          */
367                         addr.sin_port = htons(portnum);
368                         if ((client = clnttcp_create(&addr, prognum, MAX_VERS,
369                             &sock, 0, 0)) == NULL) {
370                                 clnt_pcreateerror("rpcinfo");
371                                 printf(_("program %lu version %lu is not available\n"),
372                                     prognum, MAX_VERS);
373                                 exit(1);
374                         }
375                         to.tv_sec = 10;
376                         to.tv_usec = 0;
377                         rpc_stat = clnt_call(client, NULLPROC, xdr_void,
378                             (char *)NULL, xdr_void, (char *)NULL, to);
379                         if (rpc_stat == RPC_PROGVERSMISMATCH) {
380                                 clnt_geterr(client, &rpcerr);
381                                 minvers = rpcerr.re_vers.low;
382                                 maxvers = rpcerr.re_vers.high;
383                         } else if (rpc_stat == RPC_SUCCESS) {
384                                 /*
385                                  * It also supports version MAX_VERS.
386                                  * Looks like we have a wise guy.
387                                  * OK, we give them information on all
388                                  * 4 billion versions they support...
389                                  */
390                                 minvers = 0;
391                                 maxvers = MAX_VERS;
392                         } else {
393                                 (void) pstatus(client, prognum, MAX_VERS);
394                                 exit(1);
395                         }
396                 } else {
397                         (void) pstatus(client, prognum, MIN_VERS);
398                         exit(1);
399                 }
400                 clnt_destroy(client);
401                 (void) close(sock);
402                 sock = RPC_ANYSOCK; /* Re-initialize it for later */
403                 for (vers = minvers; vers <= maxvers; vers++) {
404                         addr.sin_port = htons(portnum);
405                         if ((client = clnttcp_create(&addr, prognum, vers,
406                             &sock, 0, 0)) == NULL) {
407                                 clnt_pcreateerror("rpcinfo");
408                                 printf(_("program %lu version %lu is not available\n"),
409                                     prognum, vers);
410                                 exit(1);
411                         }
412                         to.tv_usec = 0;
413                         to.tv_sec = 10;
414                         rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
415                             xdr_void, (char *)NULL, to);
416                         if (pstatus(client, prognum, vers) < 0)
417                                 failure = 1;
418                         clnt_destroy(client);
419                         (void) close(sock);
420                         sock = RPC_ANYSOCK;
421                 }
422         }
423         else {
424                 vers = getvers(argv[2]);
425                 addr.sin_port = htons(portnum);
426                 if ((client = clnttcp_create(&addr, prognum, vers, &sock,
427                     0, 0)) == NULL) {
428                         clnt_pcreateerror("rpcinfo");
429                         printf(_("program %lu version %lu is not available\n"),
430                             prognum, vers);
431                         exit(1);
432                 }
433                 to.tv_usec = 0;
434                 to.tv_sec = 10;
435                 rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
436                     xdr_void, (char *)NULL, to);
437                 if (pstatus(client, prognum, vers) < 0)
438                         failure = 1;
439         }
440         if (failure)
441                 exit(1);
442 }
443
444 /*
445  * This routine should take a pointer to an "rpc_err" structure, rather than
446  * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
447  * a CLIENT structure rather than a pointer to an "rpc_err" structure.
448  * As such, we have to keep the CLIENT structure around in order to print
449  * a good error message.
450  */
451 static int
452 pstatus(client, prognum, vers)
453         register CLIENT *client;
454         u_long prognum;
455         u_long vers;
456 {
457         struct rpc_err rpcerr;
458
459         clnt_geterr(client, &rpcerr);
460         if (rpcerr.re_status != RPC_SUCCESS) {
461                 clnt_perror(client, "rpcinfo");
462                 printf(_("program %lu version %lu is not available\n"),
463                     prognum, vers);
464                 return (-1);
465         } else {
466                 printf(_("program %lu version %lu ready and waiting\n"),
467                     prognum, vers);
468                 return (0);
469         }
470 }
471
472 static void
473 pmapdump(argc, argv)
474         int argc;
475         char **argv;
476 {
477         struct sockaddr_in server_addr;
478         register struct hostent *hp;
479         struct pmaplist *head = NULL;
480         int socket = RPC_ANYSOCK;
481         struct timeval minutetimeout;
482         register CLIENT *client;
483         struct rpcent *rpc;
484
485         if (argc > 1) {
486                 usage();
487                 exit(1);
488         }
489         if (argc == 1)
490                 get_inet_address(&server_addr, argv[0]);
491         else {
492                 bzero((char *)&server_addr, sizeof server_addr);
493                 server_addr.sin_family = AF_INET;
494                 if ((hp = gethostbyname("localhost")) != NULL)
495                         bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
496                             hp->h_length);
497                 else
498                         server_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
499         }
500         minutetimeout.tv_sec = 60;
501         minutetimeout.tv_usec = 0;
502         server_addr.sin_port = htons(PMAPPORT);
503         if ((client = clnttcp_create(&server_addr, PMAPPROG,
504             PMAPVERS, &socket, 50, 500)) == NULL) {
505                 clnt_pcreateerror(_("rpcinfo: can't contact portmapper"));
506                 exit(1);
507         }
508         if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
509             xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) {
510                 fprintf(stderr, _("rpcinfo: can't contact portmapper: "));
511                 clnt_perror(client, "rpcinfo");
512                 exit(1);
513         }
514         if (head == NULL) {
515                 printf(_("No remote programs registered.\n"));
516         } else {
517                 printf(_("   program vers proto   port\n"));
518                 for (; head != NULL; head = head->pml_next) {
519                         printf("%10ld%5ld",
520                             head->pml_map.pm_prog,
521                             head->pml_map.pm_vers);
522                         if (head->pml_map.pm_prot == IPPROTO_UDP)
523                                 printf("%6s",  "udp");
524                         else if (head->pml_map.pm_prot == IPPROTO_TCP)
525                                 printf("%6s", "tcp");
526                         else
527                                 printf("%6ld",  head->pml_map.pm_prot);
528                         printf("%7ld",  head->pml_map.pm_port);
529                         rpc = getrpcbynumber(head->pml_map.pm_prog);
530                         if (rpc)
531                                 printf("  %s\n", rpc->r_name);
532                         else
533                                 printf("\n");
534                 }
535         }
536 }
537
538 /*
539  * reply_proc collects replies from the broadcast.
540  * to get a unique list of responses the output of rpcinfo should
541  * be piped through sort(1) and then uniq(1).
542  */
543
544 /*ARGSUSED*/
545 static bool_t
546 reply_proc(res, who)
547         void *res;              /* Nothing comes back */
548         struct sockaddr_in *who; /* Who sent us the reply */
549 {
550         register struct hostent *hp;
551
552         hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr,
553             AF_INET);
554         printf("%s %s\n", inet_ntoa(who->sin_addr),
555             (hp == NULL) ? _("(unknown)") : hp->h_name);
556         return(FALSE);
557 }
558
559 static void
560 brdcst(argc, argv)
561         int argc;
562         char **argv;
563 {
564         enum clnt_stat rpc_stat;
565         u_long prognum, vers;
566
567         if (argc != 2) {
568                 usage();
569                 exit(1);
570         }
571         prognum = getprognum(argv[0]);
572         vers = getvers(argv[1]);
573         rpc_stat = clnt_broadcast(prognum, vers, NULLPROC, xdr_void,
574             (char *)NULL, xdr_void, (char *)NULL, reply_proc);
575         if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
576                 fprintf(stderr, _("rpcinfo: broadcast failed: %s\n"),
577                     clnt_sperrno(rpc_stat));
578                 exit(1);
579         }
580         exit(0);
581 }
582
583 static void
584 deletereg(argc, argv)
585         int argc;
586         char **argv;
587 {       u_long prog_num, version_num ;
588
589         if (argc != 2) {
590                 usage() ;
591                 exit(1) ;
592         }
593         if (getuid()) { /* This command allowed only to root */
594                 fprintf(stderr, "Sorry. You are not root\n") ;
595                 exit(1) ;
596         }
597         prog_num = getprognum(argv[0]);
598         version_num = getvers(argv[1]);
599         if ((pmap_unset(prog_num, version_num)) == 0) {
600                 fprintf(stderr, _("rpcinfo: Could not delete registration for prog %s version %s\n"),
601                         argv[0], argv[1]) ;
602                 exit(1) ;
603         }
604 }
605
606 static void
607 usage()
608 {
609         fprintf(stderr, _("Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n"));
610         fprintf(stderr, _("       rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n"));
611         fprintf(stderr, _("       rpcinfo -p [ host ]\n"));
612         fprintf(stderr, _("       rpcinfo -b prognum versnum\n"));
613         fprintf(stderr, _("       rpcinfo -d prognum versnum\n")) ;
614 }
615
616 static u_long
617 getprognum(arg)
618         char *arg;
619 {
620         register struct rpcent *rpc;
621         register u_long prognum;
622
623         if (isalpha(*arg)) {
624                 rpc = getrpcbyname(arg);
625                 if (rpc == NULL) {
626                         fprintf(stderr, _("rpcinfo: %s is unknown service\n"),
627                             arg);
628                         exit(1);
629                 }
630                 prognum = rpc->r_number;
631         } else {
632                 prognum = (u_long) atoi(arg);
633         }
634
635         return (prognum);
636 }
637
638 static u_long
639 getvers(arg)
640         char *arg;
641 {
642         register u_long vers;
643
644         vers = (int) atoi(arg);
645         return (vers);
646 }
647
648 static void
649 get_inet_address(addr, host)
650         struct sockaddr_in *addr;
651         char *host;
652 {
653         register struct hostent *hp;
654
655         bzero((char *)addr, sizeof *addr);
656         addr->sin_addr.s_addr = (u_long) inet_addr(host);
657         if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
658                 if ((hp = gethostbyname(host)) == NULL) {
659                         fprintf(stderr, _("rpcinfo: %s is unknown host\n"),
660                                 host);
661                         exit(1);
662                 }
663                 bcopy(hp->h_addr, (char *)&addr->sin_addr, hp->h_length);
664         }
665         addr->sin_family = AF_INET;
666 }