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