]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.bin/rpcinfo/rpcinfo.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.bin / rpcinfo / rpcinfo.c
1 /*      $NetBSD: rpcinfo.c,v 1.15 2000/10/04 20:09:05 mjl Exp $ */
2
3 /*
4  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5  * unrestricted use provided that this legend is included on all tape
6  * media and as a part of the software program in whole or part.  Users
7  * may copy or modify Sun RPC without charge, but are not authorized
8  * to license or distribute it to anyone else except as part of a product or
9  * program developed by the user.
10  *
11  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14  *
15  * Sun RPC is provided with no support and without any obligation on the
16  * part of Sun Microsystems, Inc. to assist in its use, correction,
17  * modification or enhancement.
18  *
19  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21  * OR ANY PART THEREOF.
22  *
23  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24  * or profits or other special, indirect and consequential damages, even if
25  * Sun has been advised of the possibility of such damages.
26  *
27  * Sun Microsystems, Inc.
28  * 2550 Garcia Avenue
29  * Mountain View, California  94043
30  */
31
32 /*
33  * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
34  */
35
36 /* #ident       "@(#)rpcinfo.c  1.18    93/07/05 SMI" */
37
38 #if 0
39 #ifndef lint
40 static char sccsid[] = "@(#)rpcinfo.c 1.16 89/04/05 Copyr 1986 Sun Micro";
41 #endif
42 #endif
43
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
46
47 /*
48  * rpcinfo: ping a particular rpc program
49  *      or dump the registered programs on the remote machine.
50  */
51
52 /*
53  * We are for now defining PORTMAP here.  It doesn't even compile
54  * unless it is defined.
55  */
56 #ifndef PORTMAP
57 #define PORTMAP
58 #endif
59
60 /*
61  * If PORTMAP is defined, rpcinfo will talk to both portmapper and
62  * rpcbind programs; else it talks only to rpcbind. In the latter case
63  * all the portmapper specific options such as -u, -t, -p become void.
64  */
65 #include <sys/types.h>
66 #include <sys/param.h>
67 #include <sys/socket.h>
68 #include <sys/un.h>
69 #include <rpc/rpc.h>
70 #include <stdio.h>
71 #include <rpc/rpcb_prot.h>
72 #include <rpc/rpcent.h>
73 #include <rpc/nettype.h>
74 #include <rpc/rpc_com.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <unistd.h>
78 #include <err.h>
79 #include <ctype.h>
80
81 #ifdef PORTMAP          /* Support for version 2 portmapper */
82 #include <netinet/in.h>
83 #include <netdb.h>
84 #include <arpa/inet.h>
85 #include <rpc/pmap_prot.h>
86 #include <rpc/pmap_clnt.h>
87 #endif
88
89 #define MAXHOSTLEN 256
90 #define MIN_VERS        ((u_long) 0)
91 #define MAX_VERS        ((u_long) 4294967295UL)
92 #define UNKNOWN         "unknown"
93
94 /*
95  * Functions to be performed.
96  */
97 #define NONE            0       /* no function */
98 #define PMAPDUMP        1       /* dump portmapper registrations */
99 #define TCPPING         2       /* ping TCP service */
100 #define UDPPING         3       /* ping UDP service */
101 #define BROADCAST       4       /* ping broadcast service */
102 #define DELETES         5       /* delete registration for the service */
103 #define ADDRPING        6       /* pings at the given address */
104 #define PROGPING        7       /* pings a program on a given host */
105 #define RPCBDUMP        8       /* dump rpcbind registrations */
106 #define RPCBDUMP_SHORT  9       /* dump rpcbind registrations - short version */
107 #define RPCBADDRLIST    10      /* dump addr list about one prog */
108 #define RPCBGETSTAT     11      /* Get statistics */
109
110 struct netidlist {
111         char *netid;
112         struct netidlist *next;
113 };
114
115 struct verslist {
116         int vers;
117         struct verslist *next;
118 };
119
120 struct rpcbdump_short {
121         u_long prog;
122         struct verslist *vlist;
123         struct netidlist *nlist;
124         struct rpcbdump_short *next;
125         char *owner;
126 };
127
128
129
130 #ifdef PORTMAP
131 static void     ip_ping(u_short, const char *, int, char **);
132 static CLIENT   *clnt_com_create(struct sockaddr_in *, u_long, u_long, int *,
133                                  const char *);
134 static void     pmapdump(int, char **);
135 static void     get_inet_address(struct sockaddr_in *, char *);
136 #endif
137
138 static bool_t   reply_proc(void *, struct netbuf *, struct netconfig *);
139 static void     brdcst(int, char **);
140 static void     addrping(char *, char *, int, char **);
141 static void     progping(char *, int, char **);
142 static CLIENT   *clnt_addr_create(char *, struct netconfig *, u_long, u_long);
143 static CLIENT   *clnt_rpcbind_create(char *, int, struct netbuf **);
144 static CLIENT   *getclnthandle(char *, struct netconfig *, u_long,
145                                struct netbuf **);
146 static CLIENT   *local_rpcb(u_long, u_long);
147 static int      pstatus(CLIENT *, u_long, u_long);
148 static void     rpcbdump(int, char *, int, char **);
149 static void     rpcbgetstat(int, char **);
150 static void     rpcbaddrlist(char *, int, char **);
151 static void     deletereg(char *, int, char **);
152 static void     print_rmtcallstat(int, rpcb_stat *);
153 static void     print_getaddrstat(int, rpcb_stat *);
154 static void     usage(void);
155 static u_long   getprognum(char *);
156 static u_long   getvers(char *);
157 static char     *spaces(int);
158 static bool_t   add_version(struct rpcbdump_short *, u_long);
159 static bool_t   add_netid(struct rpcbdump_short *, char *);
160
161 int
162 main(int argc, char **argv)
163 {
164         register int c;
165         int errflg;
166         int function;
167         char *netid = NULL;
168         char *address = NULL;
169 #ifdef PORTMAP
170         char *strptr;
171         u_short portnum = 0;
172 #endif
173
174         function = NONE;
175         errflg = 0;
176 #ifdef PORTMAP
177         while ((c = getopt(argc, argv, "a:bdlmn:pstT:u")) != -1) {
178 #else
179         while ((c = getopt(argc, argv, "a:bdlmn:sT:")) != -1) {
180 #endif
181                 switch (c) {
182 #ifdef PORTMAP
183                 case 'p':
184                         if (function != NONE)
185                                 errflg = 1;
186                         else
187                                 function = PMAPDUMP;
188                         break;
189
190                 case 't':
191                         if (function != NONE)
192                                 errflg = 1;
193                         else
194                                 function = TCPPING;
195                         break;
196
197                 case 'u':
198                         if (function != NONE)
199                                 errflg = 1;
200                         else
201                                 function = UDPPING;
202                         break;
203
204                 case 'n':
205                         portnum = (u_short) strtol(optarg, &strptr, 10);
206                         if (strptr == optarg || *strptr != '\0')
207                                 errx(1, "%s is illegal port number", optarg);
208                         break;
209 #endif
210                 case 'a':
211                         address = optarg;
212                         if (function != NONE)
213                                 errflg = 1;
214                         else
215                                 function = ADDRPING;
216                         break;
217                 case 'b':
218                         if (function != NONE)
219                                 errflg = 1;
220                         else
221                                 function = BROADCAST;
222                         break;
223
224                 case 'd':
225                         if (function != NONE)
226                                 errflg = 1;
227                         else
228                                 function = DELETES;
229                         break;
230
231                 case 'l':
232                         if (function != NONE)
233                                 errflg = 1;
234                         else
235                                 function = RPCBADDRLIST;
236                         break;
237
238                 case 'm':
239                         if (function != NONE)
240                                 errflg = 1;
241                         else
242                                 function = RPCBGETSTAT;
243                         break;
244
245                 case 's':
246                         if (function != NONE)
247                                 errflg = 1;
248                         else
249                                 function = RPCBDUMP_SHORT;
250                         break;
251
252                 case 'T':
253                         netid = optarg;
254                         break;
255                 case '?':
256                         errflg = 1;
257                         break;
258                 }
259         }
260
261         if (errflg || ((function == ADDRPING) && !netid))
262                 usage();
263
264         if (function == NONE) {
265                 if (argc - optind > 1)
266                         function = PROGPING;
267                 else
268                         function = RPCBDUMP;
269         }
270
271         switch (function) {
272 #ifdef PORTMAP
273         case PMAPDUMP:
274                 if (portnum != 0)
275                         usage();
276                 pmapdump(argc - optind, argv + optind);
277                 break;
278
279         case UDPPING:
280                 ip_ping(portnum, "udp", argc - optind, argv + optind);
281                 break;
282
283         case TCPPING:
284                 ip_ping(portnum, "tcp", argc - optind, argv + optind);
285                 break;
286 #endif
287         case BROADCAST:
288                 brdcst(argc - optind, argv + optind);
289                 break;
290         case DELETES:
291                 deletereg(netid, argc - optind, argv + optind);
292                 break;
293         case ADDRPING:
294                 addrping(address, netid, argc - optind, argv + optind);
295                 break;
296         case PROGPING:
297                 progping(netid, argc - optind, argv + optind);
298                 break;
299         case RPCBDUMP:
300         case RPCBDUMP_SHORT:
301                 rpcbdump(function, netid, argc - optind, argv + optind);
302                 break;
303         case RPCBGETSTAT:
304                 rpcbgetstat(argc - optind, argv + optind);
305                 break;
306         case RPCBADDRLIST:
307                 rpcbaddrlist(netid, argc - optind, argv + optind);
308                 break;
309         }
310         return (0);
311 }
312
313 static CLIENT *
314 local_rpcb(u_long prog, u_long vers)
315 {
316         void *localhandle;
317         struct netconfig *nconf;
318         CLIENT *clnt;
319
320         localhandle = setnetconfig();
321         while ((nconf = getnetconfig(localhandle)) != NULL) {
322                 if (nconf->nc_protofmly != NULL &&
323                     strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
324                         break;
325         }
326         if (nconf == NULL) {
327                 warnx("getnetconfig: %s", nc_sperror());
328                 return (NULL);
329         }
330
331         clnt = clnt_tp_create(NULL, prog, vers, nconf);
332         endnetconfig(localhandle);
333         return clnt;
334 }
335
336 #ifdef PORTMAP
337 static CLIENT *
338 clnt_com_create(struct sockaddr_in *addr, u_long prog, u_long vers,
339     int *fdp, const char *trans)
340 {
341         CLIENT *clnt;
342
343         if (strcmp(trans, "tcp") == 0) {
344                 clnt = clnttcp_create(addr, prog, vers, fdp, 0, 0);
345         } else {
346                 struct timeval to;
347
348                 to.tv_sec = 5;
349                 to.tv_usec = 0;
350                 clnt = clntudp_create(addr, prog, vers, to, fdp);
351         }
352         if (clnt == (CLIENT *)NULL) {
353                 clnt_pcreateerror("rpcinfo");
354                 if (vers == MIN_VERS)
355                         printf("program %lu is not available\n", prog);
356                 else
357                         printf("program %lu version %lu is not available\n",
358                                                         prog, vers);
359                 exit(1);
360         }
361         return (clnt);
362 }
363
364 /*
365  * If portnum is 0, then go and get the address from portmapper, which happens
366  * transparently through clnt*_create(); If version number is not given, it
367  * tries to find out the version number by making a call to version 0 and if
368  * that fails, it obtains the high order and the low order version number. If
369  * version 0 calls succeeds, it tries for MAXVERS call and repeats the same.
370  */
371 static void
372 ip_ping(u_short portnum, const char *trans, int argc, char **argv)
373 {
374         CLIENT *client;
375         int fd = RPC_ANYFD;
376         struct timeval to;
377         struct sockaddr_in addr;
378         enum clnt_stat rpc_stat;
379         u_long prognum, vers, minvers, maxvers;
380         struct rpc_err rpcerr;
381         int failure = 0;
382
383         if (argc < 2 || argc > 3)
384                 usage();
385         to.tv_sec = 10;
386         to.tv_usec = 0;
387         prognum = getprognum(argv[1]);
388         get_inet_address(&addr, argv[0]);
389         if (argc == 2) {        /* Version number not known */
390                 /*
391                  * A call to version 0 should fail with a program/version
392                  * mismatch, and give us the range of versions supported.
393                  */
394                 vers = MIN_VERS;
395         } else {
396                 vers = getvers(argv[2]);
397         }
398         addr.sin_port = htons(portnum);
399         client = clnt_com_create(&addr, prognum, vers, &fd, trans);
400         rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
401                         (char *)NULL, (xdrproc_t) xdr_void, (char *)NULL,
402                         to);
403         if (argc != 2) {
404                 /* Version number was known */
405                 if (pstatus(client, prognum, vers) < 0)
406                         exit(1);
407                 (void) CLNT_DESTROY(client);
408                 return;
409         }
410         /* Version number not known */
411         (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL);
412         if (rpc_stat == RPC_PROGVERSMISMATCH) {
413                 clnt_geterr(client, &rpcerr);
414                 minvers = rpcerr.re_vers.low;
415                 maxvers = rpcerr.re_vers.high;
416         } else if (rpc_stat == RPC_SUCCESS) {
417                 /*
418                  * Oh dear, it DOES support version 0.
419                  * Let's try version MAX_VERS.
420                  */
421                 (void) CLNT_DESTROY(client);
422                 addr.sin_port = htons(portnum);
423                 client = clnt_com_create(&addr, prognum, MAX_VERS, &fd, trans);
424                 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
425                                 (char *)NULL, (xdrproc_t) xdr_void,
426                                 (char *)NULL, to);
427                 if (rpc_stat == RPC_PROGVERSMISMATCH) {
428                         clnt_geterr(client, &rpcerr);
429                         minvers = rpcerr.re_vers.low;
430                         maxvers = rpcerr.re_vers.high;
431                 } else if (rpc_stat == RPC_SUCCESS) {
432                         /*
433                          * It also supports version MAX_VERS.
434                          * Looks like we have a wise guy.
435                          * OK, we give them information on all
436                          * 4 billion versions they support...
437                          */
438                         minvers = 0;
439                         maxvers = MAX_VERS;
440                 } else {
441                         (void) pstatus(client, prognum, MAX_VERS);
442                         exit(1);
443                 }
444         } else {
445                 (void) pstatus(client, prognum, (u_long)0);
446                 exit(1);
447         }
448         (void) CLNT_DESTROY(client);
449         for (vers = minvers; vers <= maxvers; vers++) {
450                 addr.sin_port = htons(portnum);
451                 client = clnt_com_create(&addr, prognum, vers, &fd, trans);
452                 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
453                                 (char *)NULL, (xdrproc_t) xdr_void,
454                                 (char *)NULL, to);
455                 if (pstatus(client, prognum, vers) < 0)
456                                 failure = 1;
457                 (void) CLNT_DESTROY(client);
458         }
459         if (failure)
460                 exit(1);
461         (void) close(fd);
462         return;
463 }
464
465 /*
466  * Dump all the portmapper registerations
467  */
468 static void
469 pmapdump(int argc, char **argv)
470 {
471         struct sockaddr_in server_addr;
472         struct pmaplist *head = NULL;
473         int socket = RPC_ANYSOCK;
474         struct timeval minutetimeout;
475         register CLIENT *client;
476         struct rpcent *rpc;
477         enum clnt_stat clnt_st;
478         struct rpc_err err;
479         char *host = NULL;
480
481         if (argc > 1)
482                 usage();
483         if (argc == 1) {
484                 host = argv[0];
485                 get_inet_address(&server_addr, host);
486                 server_addr.sin_port = htons(PMAPPORT);
487                 client = clnttcp_create(&server_addr, PMAPPROG, PMAPVERS,
488                     &socket, 50, 500);
489         } else
490                 client = local_rpcb(PMAPPROG, PMAPVERS);
491
492         if (client == NULL) {
493                 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
494                         /*
495                          * "Misc. TLI error" is not too helpful. Most likely
496                          * the connection to the remote server timed out, so
497                          * this error is at least less perplexing.
498                          */
499                         rpc_createerr.cf_stat = RPC_PMAPFAILURE;
500                         rpc_createerr.cf_error.re_status = RPC_FAILED;
501                 }
502                 clnt_pcreateerror("rpcinfo: can't contact portmapper");
503                 exit(1);
504         }
505
506         minutetimeout.tv_sec = 60;
507         minutetimeout.tv_usec = 0;
508
509         clnt_st = CLNT_CALL(client, PMAPPROC_DUMP, (xdrproc_t) xdr_void,
510                 NULL, (xdrproc_t) xdr_pmaplist_ptr, (char *)&head,
511                 minutetimeout);
512         if (clnt_st != RPC_SUCCESS) {
513                 if ((clnt_st == RPC_PROGVERSMISMATCH) ||
514                     (clnt_st == RPC_PROGUNAVAIL)) {
515                         CLNT_GETERR(client, &err);
516                         if (err.re_vers.low > PMAPVERS) {
517                                 if (host)
518                                         warnx("%s does not support portmapper."
519                                             "Try rpcinfo %s instead", host,
520                                             host);
521                                 else
522                                         warnx("local host does not support "
523                                             "portmapper.  Try 'rpcinfo' "
524                                             "instead");
525                         }
526                         exit(1);
527                 }
528                 clnt_perror(client, "rpcinfo: can't contact portmapper");
529                 exit(1);
530         }
531         if (head == NULL) {
532                 printf("No remote programs registered.\n");
533         } else {
534                 printf("   program vers proto   port  service\n");
535                 for (; head != NULL; head = head->pml_next) {
536                         printf("%10ld%5ld",
537                                 head->pml_map.pm_prog,
538                                 head->pml_map.pm_vers);
539                         if (head->pml_map.pm_prot == IPPROTO_UDP)
540                                 printf("%6s", "udp");
541                         else if (head->pml_map.pm_prot == IPPROTO_TCP)
542                                 printf("%6s", "tcp");
543                         else if (head->pml_map.pm_prot == IPPROTO_ST)
544                                 printf("%6s", "local");
545                         else
546                                 printf("%6ld", head->pml_map.pm_prot);
547                         printf("%7ld", head->pml_map.pm_port);
548                         rpc = getrpcbynumber(head->pml_map.pm_prog);
549                         if (rpc)
550                                 printf("  %s\n", rpc->r_name);
551                         else
552                                 printf("\n");
553                 }
554         }
555 }
556
557 static void
558 get_inet_address(struct sockaddr_in *addr, char *host)
559 {
560         struct netconfig *nconf;
561         struct addrinfo hints, *res;
562         int error;
563
564         (void) memset((char *)addr, 0, sizeof (*addr));
565         addr->sin_addr.s_addr = inet_addr(host);
566         if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
567                 if ((nconf = __rpc_getconfip("udp")) == NULL &&
568                     (nconf = __rpc_getconfip("tcp")) == NULL)
569                         errx(1, "couldn't find a suitable transport");
570                 else {
571                         memset(&hints, 0, sizeof hints);
572                         hints.ai_family = AF_INET;
573                         if ((error = getaddrinfo(host, "rpcbind", &hints, &res))
574                             != 0)
575                                 errx(1, "%s: %s", host, gai_strerror(error));
576                         else {
577                                 memcpy(addr, res->ai_addr, res->ai_addrlen);
578                                 freeaddrinfo(res);
579                         }
580                         (void) freenetconfigent(nconf);
581                 }
582         } else {
583                 addr->sin_family = AF_INET;
584         }
585 }
586 #endif /* PORTMAP */
587
588 /*
589  * reply_proc collects replies from the broadcast.
590  * to get a unique list of responses the output of rpcinfo should
591  * be piped through sort(1) and then uniq(1).
592  */
593
594 /*ARGSUSED*/
595 static bool_t
596 reply_proc(void *res, struct netbuf *who, struct netconfig *nconf)
597         /* void *res;                   Nothing comes back */
598         /* struct netbuf *who;          Who sent us the reply */
599         /* struct netconfig *nconf;     On which transport the reply came */
600 {
601         char *uaddr;
602         char hostbuf[NI_MAXHOST];
603         const char *hostname;
604         struct sockaddr *sa = (struct sockaddr *)who->buf;
605
606         if (getnameinfo(sa, sa->sa_len, hostbuf, NI_MAXHOST, NULL, 0, 0)) {
607                 hostname = UNKNOWN;
608         } else {
609                 hostname = hostbuf;
610         }
611         if (!(uaddr = taddr2uaddr(nconf, who))) {
612                 uaddr = UNKNOWN;
613         }
614         printf("%s\t%s\n", uaddr, hostname);
615         if (strcmp(uaddr, UNKNOWN))
616                 free((char *)uaddr);
617         return (FALSE);
618 }
619
620 static void
621 brdcst(int argc, char **argv)
622 {
623         enum clnt_stat rpc_stat;
624         u_long prognum, vers;
625
626         if (argc != 2)
627                 usage();
628         prognum = getprognum(argv[0]);
629         vers = getvers(argv[1]);
630         rpc_stat = rpc_broadcast(prognum, vers, NULLPROC,
631                 (xdrproc_t) xdr_void, (char *)NULL, (xdrproc_t) xdr_void,
632                 (char *)NULL, (resultproc_t) reply_proc, NULL);
633         if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT))
634                 errx(1, "broadcast failed: %s", clnt_sperrno(rpc_stat));
635         exit(0);
636 }
637
638 static bool_t
639 add_version(struct rpcbdump_short *rs, u_long vers)
640 {
641         struct verslist *vl;
642
643         for (vl = rs->vlist; vl; vl = vl->next)
644                 if (vl->vers == vers)
645                         break;
646         if (vl)
647                 return (TRUE);
648         vl = (struct verslist *)malloc(sizeof (struct verslist));
649         if (vl == NULL)
650                 return (FALSE);
651         vl->vers = vers;
652         vl->next = rs->vlist;
653         rs->vlist = vl;
654         return (TRUE);
655 }
656
657 static bool_t
658 add_netid(struct rpcbdump_short *rs, char *netid)
659 {
660         struct netidlist *nl;
661
662         for (nl = rs->nlist; nl; nl = nl->next)
663                 if (strcmp(nl->netid, netid) == 0)
664                         break;
665         if (nl)
666                 return (TRUE);
667         nl = (struct netidlist *)malloc(sizeof (struct netidlist));
668         if (nl == NULL)
669                 return (FALSE);
670         nl->netid = netid;
671         nl->next = rs->nlist;
672         rs->nlist = nl;
673         return (TRUE);
674 }
675
676 static void
677 rpcbdump(int dumptype, char *netid, int argc, char **argv)
678 {
679         rpcblist_ptr head = NULL;
680         struct timeval minutetimeout;
681         register CLIENT *client;
682         struct rpcent *rpc;
683         char *host;
684         struct netidlist *nl;
685         struct verslist *vl;
686         struct rpcbdump_short *rs, *rs_tail;
687         char buf[256];
688         enum clnt_stat clnt_st;
689         struct rpc_err err;
690         struct rpcbdump_short *rs_head = NULL;
691
692         if (argc > 1)
693                 usage();
694         if (argc == 1) {
695                 host = argv[0];
696                 if (netid == NULL) {
697                         client = clnt_rpcbind_create(host, RPCBVERS, NULL);
698                 } else {
699                         struct netconfig *nconf;
700         
701                         nconf = getnetconfigent(netid);
702                         if (nconf == NULL) {
703                                 nc_perror("rpcinfo: invalid transport");
704                                 exit(1);
705                         }
706                         client = getclnthandle(host, nconf, RPCBVERS, NULL);
707                         if (nconf)
708                                 (void) freenetconfigent(nconf);
709                 }
710         } else
711                 client = local_rpcb(PMAPPROG, RPCBVERS);
712
713         if (client == (CLIENT *)NULL) {
714                 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
715                 exit(1);
716         }
717
718         minutetimeout.tv_sec = 60;
719         minutetimeout.tv_usec = 0;
720         clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t) xdr_void,
721                 NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
722                 minutetimeout);
723         if (clnt_st != RPC_SUCCESS) {
724             if ((clnt_st == RPC_PROGVERSMISMATCH) ||
725                 (clnt_st == RPC_PROGUNAVAIL)) {
726                 int vers;
727
728                 CLNT_GETERR(client, &err);
729                 if (err.re_vers.low == RPCBVERS4) {
730                     vers = RPCBVERS4;
731                     clnt_control(client, CLSET_VERS, (char *)&vers);
732                     clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
733                         (xdrproc_t) xdr_void, NULL,
734                         (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
735                         minutetimeout);
736                     if (clnt_st != RPC_SUCCESS)
737                         goto failed;
738                 } else {
739                     if (err.re_vers.high == PMAPVERS) {
740                         int high, low;
741                         struct pmaplist *pmaphead = NULL;
742                         rpcblist_ptr list, prev;
743
744                         vers = PMAPVERS;
745                         clnt_control(client, CLSET_VERS, (char *)&vers);
746                         clnt_st = CLNT_CALL(client, PMAPPROC_DUMP,
747                                 (xdrproc_t) xdr_void, NULL,
748                                 (xdrproc_t) xdr_pmaplist_ptr,
749                                 (char *)&pmaphead, minutetimeout);
750                         if (clnt_st != RPC_SUCCESS)
751                                 goto failed;
752                         /*
753                          * convert to rpcblist_ptr format
754                          */
755                         for (head = NULL; pmaphead != NULL;
756                                 pmaphead = pmaphead->pml_next) {
757                             list = (rpcblist *)malloc(sizeof (rpcblist));
758                             if (list == NULL)
759                                 goto error;
760                             if (head == NULL)
761                                 head = list;
762                             else
763                                 prev->rpcb_next = (rpcblist_ptr) list;
764
765                             list->rpcb_next = NULL;
766                             list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog;
767                             list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers;
768                             if (pmaphead->pml_map.pm_prot == IPPROTO_UDP)
769                                 list->rpcb_map.r_netid = "udp";
770                             else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP)
771                                 list->rpcb_map.r_netid = "tcp";
772                             else {
773 #define MAXLONG_AS_STRING       "2147483648"
774                                 list->rpcb_map.r_netid =
775                                         malloc(strlen(MAXLONG_AS_STRING) + 1);
776                                 if (list->rpcb_map.r_netid == NULL)
777                                         goto error;
778                                 sprintf(list->rpcb_map.r_netid, "%6ld",
779                                         pmaphead->pml_map.pm_prot);
780                             }
781                             list->rpcb_map.r_owner = UNKNOWN;
782                             low = pmaphead->pml_map.pm_port & 0xff;
783                             high = (pmaphead->pml_map.pm_port >> 8) & 0xff;
784                             list->rpcb_map.r_addr = strdup("0.0.0.0.XXX.XXX");
785                             sprintf(&list->rpcb_map.r_addr[8], "%d.%d",
786                                 high, low);
787                             prev = list;
788                         }
789                     }
790                 }
791             } else {    /* any other error */
792 failed:
793                     clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
794                     exit(1);
795             }
796         }
797         if (head == NULL) {
798                 printf("No remote programs registered.\n");
799         } else if (dumptype == RPCBDUMP) {
800                 printf(
801 "   program version netid     address                service    owner\n");
802                 for (; head != NULL; head = head->rpcb_next) {
803                         printf("%10u%5u    ",
804                                 head->rpcb_map.r_prog, head->rpcb_map.r_vers);
805                         printf("%-9s ", head->rpcb_map.r_netid);
806                         printf("%-22s", head->rpcb_map.r_addr);
807                         rpc = getrpcbynumber(head->rpcb_map.r_prog);
808                         if (rpc)
809                                 printf(" %-10s", rpc->r_name);
810                         else
811                                 printf(" %-10s", "-");
812                         printf(" %s\n", head->rpcb_map.r_owner);
813                 }
814         } else if (dumptype == RPCBDUMP_SHORT) {
815                 for (; head != NULL; head = head->rpcb_next) {
816                         for (rs = rs_head; rs; rs = rs->next)
817                                 if (head->rpcb_map.r_prog == rs->prog)
818                                         break;
819                         if (rs == NULL) {
820                                 rs = (struct rpcbdump_short *)
821                                         malloc(sizeof (struct rpcbdump_short));
822                                 if (rs == NULL)
823                                         goto error;
824                                 rs->next = NULL;
825                                 if (rs_head == NULL) {
826                                         rs_head = rs;
827                                         rs_tail = rs;
828                                 } else {
829                                         rs_tail->next = rs;
830                                         rs_tail = rs;
831                                 }
832                                 rs->prog = head->rpcb_map.r_prog;
833                                 rs->owner = head->rpcb_map.r_owner;
834                                 rs->nlist = NULL;
835                                 rs->vlist = NULL;
836                         }
837                         if (add_version(rs, head->rpcb_map.r_vers) == FALSE)
838                                 goto error;
839                         if (add_netid(rs, head->rpcb_map.r_netid) == FALSE)
840                                 goto error;
841                 }
842                 printf(
843 "   program version(s) netid(s)                         service     owner\n");
844                 for (rs = rs_head; rs; rs = rs->next) {
845                         char *p = buf;
846
847                         printf("%10ld  ", rs->prog);
848                         for (vl = rs->vlist; vl; vl = vl->next) {
849                                 sprintf(p, "%d", vl->vers);
850                                 p = p + strlen(p);
851                                 if (vl->next)
852                                         sprintf(p++, ",");
853                         }
854                         printf("%-10s", buf);
855                         buf[0] = '\0';
856                         for (nl = rs->nlist; nl; nl = nl->next) {
857                                 strcat(buf, nl->netid);
858                                 if (nl->next)
859                                         strcat(buf, ",");
860                         }
861                         printf("%-32s", buf);
862                         rpc = getrpcbynumber(rs->prog);
863                         if (rpc)
864                                 printf(" %-11s", rpc->r_name);
865                         else
866                                 printf(" %-11s", "-");
867                         printf(" %s\n", rs->owner);
868                 }
869         }
870         clnt_destroy(client);
871         return;
872 error:  warnx("no memory");
873         return;
874 }
875
876 static char nullstring[] = "\000";
877
878 static void
879 rpcbaddrlist(char *netid, int argc, char **argv)
880 {
881         rpcb_entry_list_ptr head = NULL;
882         struct timeval minutetimeout;
883         register CLIENT *client;
884         struct rpcent *rpc;
885         char *host;
886         RPCB parms;
887         struct netbuf *targaddr;
888
889         if (argc != 3)
890                 usage();
891         host = argv[0];
892         if (netid == NULL) {
893                 client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr);
894         } else {
895                 struct netconfig *nconf;
896
897                 nconf = getnetconfigent(netid);
898                 if (nconf == NULL) {
899                         nc_perror("rpcinfo: invalid transport");
900                         exit(1);
901                 }
902                 client = getclnthandle(host, nconf, RPCBVERS4, &targaddr);
903                 if (nconf)
904                         (void) freenetconfigent(nconf);
905         }
906         if (client == (CLIENT *)NULL) {
907                 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
908                 exit(1);
909         }
910         minutetimeout.tv_sec = 60;
911         minutetimeout.tv_usec = 0;
912
913         parms.r_prog =  getprognum(argv[1]);
914         parms.r_vers =  getvers(argv[2]);
915         parms.r_netid = client->cl_netid;
916         if (targaddr == NULL) {
917                 parms.r_addr = nullstring;      /* for XDRing */
918         } else {
919                 /*
920                  * We also send the remote system the address we
921                  * used to contact it in case it can help it
922                  * connect back with us
923                  */
924                 struct netconfig *nconf;
925
926                 nconf = getnetconfigent(client->cl_netid);
927                 if (nconf != NULL) {
928                         parms.r_addr = taddr2uaddr(nconf, targaddr);
929                         if (parms.r_addr == NULL)
930                                 parms.r_addr = nullstring;
931                         freenetconfigent(nconf);
932                 } else {
933                         parms.r_addr = nullstring;      /* for XDRing */
934                 }
935                 free(targaddr->buf);
936                 free(targaddr);
937         }
938         parms.r_owner = nullstring;
939
940         if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb,
941                 (char *) &parms, (xdrproc_t) xdr_rpcb_entry_list_ptr,
942                 (char *) &head, minutetimeout) != RPC_SUCCESS) {
943                 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
944                 exit(1);
945         }
946         if (head == NULL) {
947                 printf("No remote programs registered.\n");
948         } else {
949                 printf(
950         "   program vers  tp_family/name/class    address\t\t  service\n");
951                 for (; head != NULL; head = head->rpcb_entry_next) {
952                         rpcb_entry *re;
953                         char buf[128];
954
955                         re = &head->rpcb_entry_map;
956                         printf("%10u%3u    ",
957                                 parms.r_prog, parms.r_vers);
958                         sprintf(buf, "%s/%s/%s ",
959                                 re->r_nc_protofmly, re->r_nc_proto,
960                                 re->r_nc_semantics == NC_TPI_CLTS ? "clts" :
961                                 re->r_nc_semantics == NC_TPI_COTS ? "cots" :
962                                                 "cots_ord");
963                         printf("%-24s", buf);
964                         printf("%-24s", re->r_maddr);
965                         rpc = getrpcbynumber(parms.r_prog);
966                         if (rpc)
967                                 printf(" %-13s", rpc->r_name);
968                         else
969                                 printf(" %-13s", "-");
970                         printf("\n");
971                 }
972         }
973         clnt_destroy(client);
974         return;
975 }
976
977 /*
978  * monitor rpcbind
979  */
980 static void
981 rpcbgetstat(int argc, char **argv)
982 {
983         rpcb_stat_byvers inf;
984         struct timeval minutetimeout;
985         register CLIENT *client;
986         char *host;
987         int i, j;
988         rpcbs_addrlist *pa;
989         rpcbs_rmtcalllist *pr;
990         int cnt, flen;
991 #define MAXFIELD        64
992         char fieldbuf[MAXFIELD];
993 #define MAXLINE         256
994         char linebuf[MAXLINE];
995         char *cp, *lp;
996         const char *pmaphdr[] = {
997                 "NULL", "SET", "UNSET", "GETPORT",
998                 "DUMP", "CALLIT"
999         };
1000         const char *rpcb3hdr[] = {
1001                 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1002                 "U2T", "T2U"
1003         };
1004         const char *rpcb4hdr[] = {
1005                 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1006                 "U2T",  "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT"
1007         };
1008
1009 #define TABSTOP 8
1010
1011         if (argc >= 1) {
1012                 host = argv[0];
1013                 client = clnt_rpcbind_create(host, RPCBVERS4, NULL);
1014         } else
1015                 client = local_rpcb(PMAPPROG, RPCBVERS4);
1016         if (client == (CLIENT *)NULL) {
1017                 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
1018                 exit(1);
1019         }
1020         minutetimeout.tv_sec = 60;
1021         minutetimeout.tv_usec = 0;
1022         memset((char *)&inf, 0, sizeof (rpcb_stat_byvers));
1023         if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t) xdr_void, NULL,
1024                 (xdrproc_t) xdr_rpcb_stat_byvers, (char *)&inf, minutetimeout)
1025                         != RPC_SUCCESS) {
1026                 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
1027                 exit(1);
1028         }
1029         printf("PORTMAP (version 2) statistics\n");
1030         lp = linebuf;
1031         for (i = 0; i <= rpcb_highproc_2; i++) {
1032                 fieldbuf[0] = '\0';
1033                 switch (i) {
1034                 case PMAPPROC_SET:
1035                         sprintf(fieldbuf, "%d/", inf[RPCBVERS_2_STAT].setinfo);
1036                         break;
1037                 case PMAPPROC_UNSET:
1038                         sprintf(fieldbuf, "%d/",
1039                                 inf[RPCBVERS_2_STAT].unsetinfo);
1040                         break;
1041                 case PMAPPROC_GETPORT:
1042                         cnt = 0;
1043                         for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa;
1044                                 pa = pa->next)
1045                                 cnt += pa->success;
1046                         sprintf(fieldbuf, "%d/", cnt);
1047                         break;
1048                 case PMAPPROC_CALLIT:
1049                         cnt = 0;
1050                         for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr;
1051                                 pr = pr->next)
1052                                 cnt += pr->success;
1053                         sprintf(fieldbuf, "%d/", cnt);
1054                         break;
1055                 default: break;  /* For the remaining ones */
1056                 }
1057                 cp = &fieldbuf[0] + strlen(fieldbuf);
1058                 sprintf(cp, "%d", inf[RPCBVERS_2_STAT].info[i]);
1059                 flen = strlen(fieldbuf);
1060                 printf("%s%s", pmaphdr[i],
1061                         spaces((TABSTOP * (1 + flen / TABSTOP))
1062                         - strlen(pmaphdr[i])));
1063                 sprintf(lp, "%s%s", fieldbuf,
1064                         spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1065                         - flen)));
1066                 lp += (flen + cnt);
1067         }
1068         printf("\n%s\n\n", linebuf);
1069
1070         if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) {
1071                 printf("PMAP_RMTCALL call statistics\n");
1072                 print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1073                 printf("\n");
1074         }
1075
1076         if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) {
1077                 printf("PMAP_GETPORT call statistics\n");
1078                 print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1079                 printf("\n");
1080         }
1081
1082         printf("RPCBIND (version 3) statistics\n");
1083         lp = linebuf;
1084         for (i = 0; i <= rpcb_highproc_3; i++) {
1085                 fieldbuf[0] = '\0';
1086                 switch (i) {
1087                 case RPCBPROC_SET:
1088                         sprintf(fieldbuf, "%d/", inf[RPCBVERS_3_STAT].setinfo);
1089                         break;
1090                 case RPCBPROC_UNSET:
1091                         sprintf(fieldbuf, "%d/",
1092                                 inf[RPCBVERS_3_STAT].unsetinfo);
1093                         break;
1094                 case RPCBPROC_GETADDR:
1095                         cnt = 0;
1096                         for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa;
1097                                 pa = pa->next)
1098                                 cnt += pa->success;
1099                         sprintf(fieldbuf, "%d/", cnt);
1100                         break;
1101                 case RPCBPROC_CALLIT:
1102                         cnt = 0;
1103                         for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr;
1104                                 pr = pr->next)
1105                                 cnt += pr->success;
1106                         sprintf(fieldbuf, "%d/", cnt);
1107                         break;
1108                 default: break;  /* For the remaining ones */
1109                 }
1110                 cp = &fieldbuf[0] + strlen(fieldbuf);
1111                 sprintf(cp, "%d", inf[RPCBVERS_3_STAT].info[i]);
1112                 flen = strlen(fieldbuf);
1113                 printf("%s%s", rpcb3hdr[i],
1114                         spaces((TABSTOP * (1 + flen / TABSTOP))
1115                         - strlen(rpcb3hdr[i])));
1116                 sprintf(lp, "%s%s", fieldbuf,
1117                         spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1118                         - flen)));
1119                 lp += (flen + cnt);
1120         }
1121         printf("\n%s\n\n", linebuf);
1122
1123         if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) {
1124                 printf("RPCB_RMTCALL (version 3) call statistics\n");
1125                 print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1126                 printf("\n");
1127         }
1128
1129         if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) {
1130                 printf("RPCB_GETADDR (version 3) call statistics\n");
1131                 print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1132                 printf("\n");
1133         }
1134
1135         printf("RPCBIND (version 4) statistics\n");
1136
1137         for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */
1138                 lp = linebuf;
1139                 for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) {
1140                         fieldbuf[0] = '\0';
1141                         switch (i) {
1142                         case RPCBPROC_SET:
1143                                 sprintf(fieldbuf, "%d/",
1144                                         inf[RPCBVERS_4_STAT].setinfo);
1145                                 break;
1146                         case RPCBPROC_UNSET:
1147                                 sprintf(fieldbuf, "%d/",
1148                                         inf[RPCBVERS_4_STAT].unsetinfo);
1149                                 break;
1150                         case RPCBPROC_GETADDR:
1151                                 cnt = 0;
1152                                 for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa;
1153                                         pa = pa->next)
1154                                         cnt += pa->success;
1155                                 sprintf(fieldbuf, "%d/", cnt);
1156                                 break;
1157                         case RPCBPROC_CALLIT:
1158                                 cnt = 0;
1159                                 for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr;
1160                                         pr = pr->next)
1161                                         cnt += pr->success;
1162                                 sprintf(fieldbuf, "%d/", cnt);
1163                                 break;
1164                         default: break;  /* For the remaining ones */
1165                         }
1166                         cp = &fieldbuf[0] + strlen(fieldbuf);
1167                         /*
1168                          * XXX: We also add RPCBPROC_GETADDRLIST queries to
1169                          * RPCB_GETADDR because rpcbind includes the
1170                          * RPCB_GETADDRLIST successes in RPCB_GETADDR.
1171                          */
1172                         if (i != RPCBPROC_GETADDR)
1173                             sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i]);
1174                         else
1175                             sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i] +
1176                             inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]);
1177                         flen = strlen(fieldbuf);
1178                         printf("%s%s", rpcb4hdr[i],
1179                                 spaces((TABSTOP * (1 + flen / TABSTOP))
1180                                 - strlen(rpcb4hdr[i])));
1181                         sprintf(lp, "%s%s", fieldbuf,
1182                                 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1183                                 - flen)));
1184                         lp += (flen + cnt);
1185                 }
1186                 printf("\n%s\n", linebuf);
1187         }
1188
1189         if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] ||
1190                             inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) {
1191                 printf("\n");
1192                 printf("RPCB_RMTCALL (version 4) call statistics\n");
1193                 print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1194         }
1195
1196         if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) {
1197                 printf("\n");
1198                 printf("RPCB_GETADDR (version 4) call statistics\n");
1199                 print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1200         }
1201         clnt_destroy(client);
1202 }
1203
1204 /*
1205  * Delete registeration for this (prog, vers, netid)
1206  */
1207 static void
1208 deletereg(char *netid, int argc, char **argv)
1209 {
1210         struct netconfig *nconf = NULL;
1211
1212         if (argc != 2)
1213                 usage();
1214         if (netid) {
1215                 nconf = getnetconfigent(netid);
1216                 if (nconf == NULL)
1217                         errx(1, "netid %s not supported", netid);
1218         }
1219         if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0)
1220                 errx(1,
1221         "could not delete registration for prog %s version %s",
1222                         argv[0], argv[1]);
1223 }
1224
1225 /*
1226  * Create and return a handle for the given nconf.
1227  * Exit if cannot create handle.
1228  */
1229 static CLIENT *
1230 clnt_addr_create(char *address, struct netconfig *nconf,
1231     u_long prog, u_long vers)
1232 {
1233         CLIENT *client;
1234         static struct netbuf *nbuf;
1235         static int fd = RPC_ANYFD;
1236
1237         if (fd == RPC_ANYFD) {
1238                 if ((fd = __rpc_nconf2fd(nconf)) == -1) {
1239                         rpc_createerr.cf_stat = RPC_TLIERROR;
1240                         clnt_pcreateerror("rpcinfo");
1241                         exit(1);
1242                 }
1243                 /* Convert the uaddr to taddr */
1244                 nbuf = uaddr2taddr(nconf, address);
1245                 if (nbuf == NULL)
1246                         errx(1, "no address for client handle");
1247         }
1248         client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0);
1249         if (client == (CLIENT *)NULL) {
1250                 clnt_pcreateerror("rpcinfo");
1251                 exit(1);
1252         }
1253         return (client);
1254 }
1255
1256 /*
1257  * If the version number is given, ping that (prog, vers); else try to find
1258  * the version numbers supported for that prog and ping all the versions.
1259  * Remote rpcbind is not contacted for this service. The requests are
1260  * sent directly to the services themselves.
1261  */
1262 static void
1263 addrping(char *address, char *netid, int argc, char **argv)
1264 {
1265         CLIENT *client;
1266         struct timeval to;
1267         enum clnt_stat rpc_stat;
1268         u_long prognum, versnum, minvers, maxvers;
1269         struct rpc_err rpcerr;
1270         int failure = 0;
1271         struct netconfig *nconf;
1272         int fd;
1273
1274         if (argc < 1 || argc > 2 || (netid == NULL))
1275                 usage();
1276         nconf = getnetconfigent(netid);
1277         if (nconf == (struct netconfig *)NULL)
1278                 errx(1, "could not find %s", netid);
1279         to.tv_sec = 10;
1280         to.tv_usec = 0;
1281         prognum = getprognum(argv[0]);
1282         if (argc == 1) {        /* Version number not known */
1283                 /*
1284                  * A call to version 0 should fail with a program/version
1285                  * mismatch, and give us the range of versions supported.
1286                  */
1287                 versnum = MIN_VERS;
1288         } else {
1289                 versnum = getvers(argv[1]);
1290         }
1291         client = clnt_addr_create(address, nconf, prognum, versnum);
1292         rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1293                         (char *)NULL, (xdrproc_t) xdr_void,
1294                         (char *)NULL, to);
1295         if (argc == 2) {
1296                 /* Version number was known */
1297                 if (pstatus(client, prognum, versnum) < 0)
1298                         failure = 1;
1299                 (void) CLNT_DESTROY(client);
1300                 if (failure)
1301                         exit(1);
1302                 return;
1303         }
1304         /* Version number not known */
1305         (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL);
1306         (void) CLNT_CONTROL(client, CLGET_FD, (char *)&fd);
1307         if (rpc_stat == RPC_PROGVERSMISMATCH) {
1308                 clnt_geterr(client, &rpcerr);
1309                 minvers = rpcerr.re_vers.low;
1310                 maxvers = rpcerr.re_vers.high;
1311         } else if (rpc_stat == RPC_SUCCESS) {
1312                 /*
1313                  * Oh dear, it DOES support version 0.
1314                  * Let's try version MAX_VERS.
1315                  */
1316                 (void) CLNT_DESTROY(client);
1317                 client = clnt_addr_create(address, nconf, prognum, MAX_VERS);
1318                 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1319                                 (char *)NULL, (xdrproc_t) xdr_void,
1320                                 (char *)NULL, to);
1321                 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1322                         clnt_geterr(client, &rpcerr);
1323                         minvers = rpcerr.re_vers.low;
1324                         maxvers = rpcerr.re_vers.high;
1325                 } else if (rpc_stat == RPC_SUCCESS) {
1326                         /*
1327                          * It also supports version MAX_VERS.
1328                          * Looks like we have a wise guy.
1329                          * OK, we give them information on all
1330                          * 4 billion versions they support...
1331                          */
1332                         minvers = 0;
1333                         maxvers = MAX_VERS;
1334                 } else {
1335                         (void) pstatus(client, prognum, MAX_VERS);
1336                         exit(1);
1337                 }
1338         } else {
1339                 (void) pstatus(client, prognum, (u_long)0);
1340                 exit(1);
1341         }
1342         (void) CLNT_DESTROY(client);
1343         for (versnum = minvers; versnum <= maxvers; versnum++) {
1344                 client = clnt_addr_create(address, nconf, prognum, versnum);
1345                 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1346                                 (char *)NULL, (xdrproc_t) xdr_void,
1347                                 (char *)NULL, to);
1348                 if (pstatus(client, prognum, versnum) < 0)
1349                                 failure = 1;
1350                 (void) CLNT_DESTROY(client);
1351         }
1352         (void) close(fd);
1353         if (failure)
1354                 exit(1);
1355         return;
1356 }
1357
1358 /*
1359  * If the version number is given, ping that (prog, vers); else try to find
1360  * the version numbers supported for that prog and ping all the versions.
1361  * Remote rpcbind is *contacted* for this service. The requests are
1362  * then sent directly to the services themselves.
1363  */
1364 static void
1365 progping(char *netid, int argc, char **argv)
1366 {
1367         CLIENT *client;
1368         struct timeval to;
1369         enum clnt_stat rpc_stat;
1370         u_long prognum, versnum, minvers, maxvers;
1371         struct rpc_err rpcerr;
1372         int failure = 0;
1373         struct netconfig *nconf;
1374
1375         if (argc < 2 || argc > 3 || (netid == NULL))
1376                 usage();
1377         prognum = getprognum(argv[1]);
1378         if (argc == 2) { /* Version number not known */
1379                 /*
1380                  * A call to version 0 should fail with a program/version
1381                  * mismatch, and give us the range of versions supported.
1382                  */
1383                 versnum = MIN_VERS;
1384         } else {
1385                 versnum = getvers(argv[2]);
1386         }
1387         if (netid) {
1388                 nconf = getnetconfigent(netid);
1389                 if (nconf == (struct netconfig *)NULL)
1390                         errx(1, "could not find %s", netid);
1391                 client = clnt_tp_create(argv[0], prognum, versnum, nconf);
1392         } else {
1393                 client = clnt_create(argv[0], prognum, versnum, "NETPATH");
1394         }
1395         if (client == (CLIENT *)NULL) {
1396                 clnt_pcreateerror("rpcinfo");
1397                 exit(1);
1398         }
1399         to.tv_sec = 10;
1400         to.tv_usec = 0;
1401         rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1402                         (char *)NULL, (xdrproc_t) xdr_void,
1403                         (char *)NULL, to);
1404         if (argc == 3) {
1405                 /* Version number was known */
1406                 if (pstatus(client, prognum, versnum) < 0)
1407                         failure = 1;
1408                 (void) CLNT_DESTROY(client);
1409                 if (failure)
1410                         exit(1);
1411                 return;
1412         }
1413         /* Version number not known */
1414         if (rpc_stat == RPC_PROGVERSMISMATCH) {
1415                 clnt_geterr(client, &rpcerr);
1416                 minvers = rpcerr.re_vers.low;
1417                 maxvers = rpcerr.re_vers.high;
1418         } else if (rpc_stat == RPC_SUCCESS) {
1419                 /*
1420                  * Oh dear, it DOES support version 0.
1421                  * Let's try version MAX_VERS.
1422                  */
1423                 versnum = MAX_VERS;
1424                 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1425                 rpc_stat = CLNT_CALL(client, NULLPROC,
1426                                 (xdrproc_t) xdr_void, (char *)NULL,
1427                                 (xdrproc_t)  xdr_void, (char *)NULL, to);
1428                 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1429                         clnt_geterr(client, &rpcerr);
1430                         minvers = rpcerr.re_vers.low;
1431                         maxvers = rpcerr.re_vers.high;
1432                 } else if (rpc_stat == RPC_SUCCESS) {
1433                         /*
1434                          * It also supports version MAX_VERS.
1435                          * Looks like we have a wise guy.
1436                          * OK, we give them information on all
1437                          * 4 billion versions they support...
1438                          */
1439                         minvers = 0;
1440                         maxvers = MAX_VERS;
1441                 } else {
1442                         (void) pstatus(client, prognum, MAX_VERS);
1443                         exit(1);
1444                 }
1445         } else {
1446                 (void) pstatus(client, prognum, (u_long)0);
1447                 exit(1);
1448         }
1449         for (versnum = minvers; versnum <= maxvers; versnum++) {
1450                 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1451                 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1452                                         (char *)NULL, (xdrproc_t) xdr_void,
1453                                         (char *)NULL, to);
1454                 if (pstatus(client, prognum, versnum) < 0)
1455                                 failure = 1;
1456         }
1457         (void) CLNT_DESTROY(client);
1458         if (failure)
1459                 exit(1);
1460         return;
1461 }
1462
1463 static void
1464 usage(void)
1465 {
1466         fprintf(stderr, "usage: rpcinfo [-m | -s] [host]\n");
1467 #ifdef PORTMAP
1468         fprintf(stderr, "       rpcinfo -p [host]\n");
1469 #endif
1470         fprintf(stderr, "       rpcinfo -T netid host prognum [versnum]\n");
1471         fprintf(stderr, "       rpcinfo -l host prognum versnum\n");
1472 #ifdef PORTMAP
1473         fprintf(stderr,
1474 "       rpcinfo [-n portnum] -u | -t host prognum [versnum]\n");
1475 #endif
1476         fprintf(stderr,
1477 "       rpcinfo -a serv_address -T netid prognum [version]\n");
1478         fprintf(stderr, "       rpcinfo -b prognum versnum\n");
1479         fprintf(stderr, "       rpcinfo -d [-T netid] prognum versnum\n");
1480         exit(1);
1481 }
1482
1483 static u_long
1484 getprognum (char *arg)
1485 {
1486         char *strptr;
1487         register struct rpcent *rpc;
1488         register u_long prognum;
1489         char *tptr = arg;
1490
1491         while (*tptr && isdigit(*tptr++));
1492         if (*tptr || isalpha(*(tptr - 1))) {
1493                 rpc = getrpcbyname(arg);
1494                 if (rpc == NULL)
1495                         errx(1, "%s is unknown service", arg);
1496                 prognum = rpc->r_number;
1497         } else {
1498                 prognum = strtol(arg, &strptr, 10);
1499                 if (strptr == arg || *strptr != '\0')
1500                         errx(1, "%s is illegal program number", arg);
1501         }
1502         return (prognum);
1503 }
1504
1505 static u_long
1506 getvers(char *arg)
1507 {
1508         char *strptr;
1509         register u_long vers;
1510
1511         vers = (int) strtol(arg, &strptr, 10);
1512         if (strptr == arg || *strptr != '\0')
1513                 errx(1, "%s is illegal version number", arg);
1514         return (vers);
1515 }
1516
1517 /*
1518  * This routine should take a pointer to an "rpc_err" structure, rather than
1519  * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
1520  * a CLIENT structure rather than a pointer to an "rpc_err" structure.
1521  * As such, we have to keep the CLIENT structure around in order to print
1522  * a good error message.
1523  */
1524 static int
1525 pstatus(register CLIENT *client, u_long prog, u_long vers)
1526 {
1527         struct rpc_err rpcerr;
1528
1529         clnt_geterr(client, &rpcerr);
1530         if (rpcerr.re_status != RPC_SUCCESS) {
1531                 clnt_perror(client, "rpcinfo");
1532                 printf("program %lu version %lu is not available\n",
1533                         prog, vers);
1534                 return (-1);
1535         } else {
1536                 printf("program %lu version %lu ready and waiting\n",
1537                         prog, vers);
1538                 return (0);
1539         }
1540 }
1541
1542 static CLIENT *
1543 clnt_rpcbind_create(char *host, int rpcbversnum, struct netbuf **targaddr)
1544 {
1545         static const char *tlist[3] = {
1546                 "circuit_n", "circuit_v", "datagram_v"
1547         };
1548         int i;
1549         struct netconfig *nconf;
1550         CLIENT *clnt = NULL;
1551         void *handle;
1552
1553         rpc_createerr.cf_stat = RPC_SUCCESS;
1554         for (i = 0; i < 3; i++) {
1555                 if ((handle = __rpc_setconf(tlist[i])) == NULL)
1556                         continue;
1557                 while (clnt == (CLIENT *)NULL) {
1558                         if ((nconf = __rpc_getconf(handle)) == NULL) {
1559                                 if (rpc_createerr.cf_stat == RPC_SUCCESS)
1560                                     rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1561                                 break;
1562                         }
1563                         clnt = getclnthandle(host, nconf, rpcbversnum,
1564                                         targaddr);
1565                 }
1566                 if (clnt)
1567                         break;
1568                 __rpc_endconf(handle);
1569         }
1570         return (clnt);
1571 }
1572
1573 static CLIENT*
1574 getclnthandle(char *host, struct netconfig *nconf,
1575     u_long rpcbversnum, struct netbuf **targaddr)
1576 {
1577         struct netbuf addr;
1578         struct addrinfo hints, *res;
1579         CLIENT *client = NULL;
1580
1581         /* Get the address of the rpcbind */
1582         memset(&hints, 0, sizeof hints);
1583         if (getaddrinfo(host, "rpcbind", &hints, &res) != 0) {
1584                 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
1585                 return (NULL);
1586         }
1587         addr.len = addr.maxlen = res->ai_addrlen;
1588         addr.buf = res->ai_addr;
1589         client = clnt_tli_create(RPC_ANYFD, nconf, &addr, RPCBPROG,
1590                         rpcbversnum, 0, 0);
1591         if (client) {
1592                 if (targaddr != NULL) {
1593                         *targaddr =
1594                             (struct netbuf *)malloc(sizeof (struct netbuf));
1595                         if (*targaddr != NULL) {
1596                                 (*targaddr)->maxlen = addr.maxlen;
1597                                 (*targaddr)->len = addr.len;
1598                                 (*targaddr)->buf = (char *)malloc(addr.len);
1599                                 if ((*targaddr)->buf != NULL) {
1600                                         memcpy((*targaddr)->buf, addr.buf,
1601                                                 addr.len);
1602                                 }
1603                         }
1604                 }
1605         } else {
1606                 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1607                         /*
1608                          * Assume that the other system is dead; this is a
1609                          * better error to display to the user.
1610                          */
1611                         rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1612                         rpc_createerr.cf_error.re_status = RPC_FAILED;
1613                 }
1614         }
1615         freeaddrinfo(res);
1616         return (client);
1617 }
1618
1619 static void
1620 print_rmtcallstat(int rtype, rpcb_stat *infp)
1621 {
1622         register rpcbs_rmtcalllist_ptr pr;
1623         struct rpcent *rpc;
1624
1625         if (rtype == RPCBVERS_4_STAT)
1626                 printf(
1627                 "prog\t\tvers\tproc\tnetid\tindirect success failure\n");
1628         else
1629                 printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n");
1630         for (pr = infp->rmtinfo; pr; pr = pr->next) {
1631                 rpc = getrpcbynumber(pr->prog);
1632                 if (rpc)
1633                         printf("%-16s", rpc->r_name);
1634                 else
1635                         printf("%-16d", pr->prog);
1636                 printf("%d\t%d\t%s\t",
1637                         pr->vers, pr->proc, pr->netid);
1638                 if (rtype == RPCBVERS_4_STAT)
1639                         printf("%d\t ", pr->indirect);
1640                 printf("%d\t%d\n", pr->success, pr->failure);
1641         }
1642 }
1643
1644 static void
1645 print_getaddrstat(int rtype, rpcb_stat *infp)
1646 {
1647         rpcbs_addrlist_ptr al;
1648         register struct rpcent *rpc;
1649
1650         printf("prog\t\tvers\tnetid\t  success\tfailure\n");
1651         for (al = infp->addrinfo; al; al = al->next) {
1652                 rpc = getrpcbynumber(al->prog);
1653                 if (rpc)
1654                         printf("%-16s", rpc->r_name);
1655                 else
1656                         printf("%-16d", al->prog);
1657                 printf("%d\t%s\t  %-12d\t%d\n",
1658                         al->vers, al->netid,
1659                         al->success, al->failure);
1660         }
1661 }
1662
1663 static char *
1664 spaces(int howmany)
1665 {
1666         static char space_array[] =             /* 64 spaces */
1667         "                                                                ";
1668
1669         if (howmany <= 0 || howmany > sizeof (space_array)) {
1670                 return ("");
1671         }
1672         return (&space_array[sizeof (space_array) - howmany - 1]);
1673 }