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