No empty .Rs/.Re
[netbsd-mini2440.git] / usr.bin / rpcinfo / rpcinfo.c
blob564e81c4d55925e715b5fceb145058288693675e
1 /* $NetBSD: rpcinfo.c,v 1.28 2009/04/13 07:04:54 lukem Exp $ */
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.
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.
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.
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.
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.
27 * Sun Microsystems, Inc.
28 * 2550 Garcia Avenue
29 * Mountain View, California 94043
33 * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
36 /* #ident "@(#)rpcinfo.c 1.18 93/07/05 SMI" */
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
45 * rpcinfo: ping a particular rpc program
46 * or dump the registered programs on the remote machine.
50 * We are for now defining PORTMAP here. It doesnt even compile
51 * unless it is defined.
53 #ifndef PORTMAP
54 #define PORTMAP
55 #endif
58 * If PORTMAP is defined, rpcinfo will talk to both portmapper and
59 * rpcbind programs; else it talks only to rpcbind. In the latter case
60 * all the portmapper specific options such as -u, -t, -p become void.
62 #include <sys/types.h>
63 #include <sys/socket.h>
64 #include <sys/param.h>
65 #include <sys/un.h>
66 #include <rpc/rpc.h>
67 #include <stdio.h>
68 #include <rpc/rpcb_prot.h>
69 #include <rpc/rpcent.h>
70 #include <rpc/nettype.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <unistd.h>
74 #include <err.h>
75 #include <ctype.h>
77 #ifdef PORTMAP /* Support for version 2 portmapper */
78 #include <netinet/in.h>
79 #include <netdb.h>
80 #include <arpa/inet.h>
81 #include <rpc/pmap_prot.h>
82 #include <rpc/pmap_clnt.h>
83 #endif
85 #define MIN_VERS ((u_long)0)
86 #define MAX_VERS ((u_long)4294967295UL)
87 #define UNKNOWN "unknown"
90 * Functions to be performed.
92 #define NONE 0 /* no function */
93 #define PMAPDUMP 1 /* dump portmapper registrations */
94 #define TCPPING 2 /* ping TCP service */
95 #define UDPPING 3 /* ping UDP service */
96 #define BROADCAST 4 /* ping broadcast service */
97 #define DELETES 5 /* delete registration for the service */
98 #define ADDRPING 6 /* pings at the given address */
99 #define PROGPING 7 /* pings a program on a given host */
100 #define RPCBDUMP 8 /* dump rpcbind registrations */
101 #define RPCBDUMP_SHORT 9 /* dump rpcbind registrations - short version */
102 #define RPCBADDRLIST 10 /* dump addr list about one prog */
103 #define RPCBGETSTAT 11 /* Get statistics */
105 struct netidlist {
106 char *netid;
107 struct netidlist *next;
110 struct verslist {
111 int vers;
112 struct verslist *next;
115 struct rpcbdump_short {
116 u_long prog;
117 struct verslist *vlist;
118 struct netidlist *nlist;
119 struct rpcbdump_short *next;
120 char *owner;
125 #ifdef PORTMAP
126 static void ip_ping(u_short, const char *, int, char **);
127 static CLIENT *clnt_com_create(struct sockaddr_in *, u_long, u_long, int *,
128 const char *);
129 static void pmapdump(int, char **);
130 static void get_inet_address(struct sockaddr_in *, const char *);
131 #endif
133 static bool_t reply_proc(void *, struct netbuf *, struct netconfig *);
134 static void brdcst(int, char **);
135 static void addrping(char *, char *, int, char **);
136 static void progping(char *, int, char **);
137 static CLIENT *clnt_addr_create(char *, struct netconfig *, u_long, u_long);
138 static CLIENT *clnt_rpcbind_create(char *, int, struct netbuf **);
139 static CLIENT *getclnthandle(char *, struct netconfig *, u_long,
140 struct netbuf **);
141 static CLIENT *local_rpcb(u_long, u_long);
142 static int pstatus(CLIENT *, u_long, u_long);
143 static void rpcbdump(int, char *, int, char **);
144 static void rpcbgetstat(int, char **);
145 static void rpcbaddrlist(char *, int, char **);
146 static void deletereg(char *, int, char **);
147 static void print_rmtcallstat(int, rpcb_stat *);
148 static void print_getaddrstat(int, rpcb_stat *);
149 static void usage(void);
150 static u_long getprognum(char *);
151 static u_long getvers(char *);
152 static char *spaces(int);
153 static bool_t add_version(struct rpcbdump_short *, u_long);
154 static bool_t add_netid(struct rpcbdump_short *, char *);
156 int main(int argc, char **argv);
159 main(int argc, char **argv)
161 register int c;
162 int errflg;
163 int function;
164 char *netid = NULL;
165 char *address = NULL;
166 #ifdef PORTMAP
167 char *strptr;
168 u_short portnum = 0;
169 #endif
171 function = NONE;
172 errflg = 0;
173 #ifdef PORTMAP
174 while ((c = getopt(argc, argv, "a:bdlmn:pstT:u")) != -1) {
175 #else
176 while ((c = getopt(argc, argv, "a:bdlmn:sT:")) != -1) {
177 #endif
178 switch (c) {
179 #ifdef PORTMAP
180 case 'p':
181 if (function != NONE)
182 errflg = 1;
183 else
184 function = PMAPDUMP;
185 break;
187 case 't':
188 if (function != NONE)
189 errflg = 1;
190 else
191 function = TCPPING;
192 break;
194 case 'u':
195 if (function != NONE)
196 errflg = 1;
197 else
198 function = UDPPING;
199 break;
201 case 'n':
202 portnum = (u_short) strtol(optarg, &strptr, 10);
203 if (strptr == optarg || *strptr != '\0')
204 errx(1, "Illegal port number `%s'", optarg);
205 break;
206 #endif
207 case 'a':
208 address = optarg;
209 if (function != NONE)
210 errflg = 1;
211 else
212 function = ADDRPING;
213 break;
214 case 'b':
215 if (function != NONE)
216 errflg = 1;
217 else
218 function = BROADCAST;
219 break;
221 case 'd':
222 if (function != NONE)
223 errflg = 1;
224 else
225 function = DELETES;
226 break;
228 case 'l':
229 if (function != NONE)
230 errflg = 1;
231 else
232 function = RPCBADDRLIST;
233 break;
235 case 'm':
236 if (function != NONE)
237 errflg = 1;
238 else
239 function = RPCBGETSTAT;
240 break;
242 case 's':
243 if (function != NONE)
244 errflg = 1;
245 else
246 function = RPCBDUMP_SHORT;
247 break;
249 case 'T':
250 netid = optarg;
251 break;
252 case '?':
253 errflg = 1;
254 break;
258 if (errflg || ((function == ADDRPING) && !netid)) {
259 usage();
260 return (1);
263 if (function == NONE) {
264 if (argc - optind > 1)
265 function = PROGPING;
266 else
267 function = RPCBDUMP;
270 switch (function) {
271 #ifdef PORTMAP
272 case PMAPDUMP:
273 if (portnum != 0) {
274 usage();
275 return (1);
277 pmapdump(argc - optind, argv + optind);
278 break;
280 case UDPPING:
281 ip_ping(portnum, "udp", argc - optind, argv + optind);
282 break;
284 case TCPPING:
285 ip_ping(portnum, "tcp", argc - optind, argv + optind);
286 break;
287 #endif
288 case BROADCAST:
289 brdcst(argc - optind, argv + optind);
290 break;
291 case DELETES:
292 deletereg(netid, argc - optind, argv + optind);
293 break;
294 case ADDRPING:
295 addrping(address, netid, argc - optind, argv + optind);
296 break;
297 case PROGPING:
298 progping(netid, argc - optind, argv + optind);
299 break;
300 case RPCBDUMP:
301 case RPCBDUMP_SHORT:
302 rpcbdump(function, netid, argc - optind, argv + optind);
303 break;
304 case RPCBGETSTAT:
305 rpcbgetstat(argc - optind, argv + optind);
306 break;
307 case RPCBADDRLIST:
308 rpcbaddrlist(netid, argc - optind, argv + optind);
309 break;
311 return (0);
314 static CLIENT *
315 local_rpcb(u_long prog, u_long vers)
317 struct netbuf nbuf;
318 struct sockaddr_un sun;
319 int sock;
321 memset(&sun, 0, sizeof sun);
322 sock = socket(AF_LOCAL, SOCK_STREAM, 0);
323 if (sock < 0)
324 return NULL;
326 sun.sun_family = AF_LOCAL;
327 strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
328 nbuf.len = sun.sun_len = SUN_LEN(&sun);
329 nbuf.maxlen = sizeof (struct sockaddr_un);
330 nbuf.buf = &sun;
332 return clnt_vc_create(sock, &nbuf, prog, vers, 0, 0);
335 #ifdef PORTMAP
336 static CLIENT *
337 clnt_com_create(struct sockaddr_in *addr, u_long prog, u_long vers,
338 int *fdp, const char *trans)
340 CLIENT *clnt;
342 if (strcmp(trans, "tcp") == 0) {
343 clnt = clnttcp_create(addr, prog, vers, fdp, 0, 0);
344 } else {
345 struct timeval to;
347 to.tv_sec = 5;
348 to.tv_usec = 0;
349 clnt = clntudp_create(addr, prog, vers, to, fdp);
351 if (clnt == NULL) {
352 clnt_pcreateerror(getprogname());
353 if (vers == MIN_VERS)
354 printf("program %lu is not available\n", prog);
355 else
356 printf("program %lu version %lu is not available\n",
357 prog, vers);
358 exit(1);
360 return (clnt);
364 * If portnum is 0, then go and get the address from portmapper, which happens
365 * transparently through clnt*_create(); If version number is not given, it
366 * tries to find out the version number by making a call to version 0 and if
367 * that fails, it obtains the high order and the low order version number. If
368 * version 0 calls succeeds, it tries for MAXVERS call and repeats the same.
370 static void
371 ip_ping(u_short portnum, const char *trans, int argc, char **argv)
373 CLIENT *client;
374 int fd = RPC_ANYFD;
375 struct timeval to;
376 struct sockaddr_in addr;
377 enum clnt_stat rpc_stat;
378 u_long prognum, vers, minvers, maxvers;
379 struct rpc_err rpcerr;
380 int failure = 0;
382 if (argc < 2 || argc > 3) {
383 usage();
384 exit(1);
386 to.tv_sec = 10;
387 to.tv_usec = 0;
388 prognum = getprognum(argv[1]);
389 get_inet_address(&addr, argv[0]);
390 if (argc == 2) { /* Version number not known */
392 * A call to version 0 should fail with a program/version
393 * mismatch, and give us the range of versions supported.
395 vers = MIN_VERS;
396 } else {
397 vers = getvers(argv[2]);
399 addr.sin_port = htons(portnum);
400 client = clnt_com_create(&addr, prognum, vers, &fd, trans);
401 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
402 NULL, (xdrproc_t) xdr_void, NULL, 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;
410 /* Version number not known */
411 (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, 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) {
418 * Oh dear, it DOES support version 0.
419 * Let's try version MAX_VERS.
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 NULL, (xdrproc_t) xdr_void, NULL, to);
426 if (rpc_stat == RPC_PROGVERSMISMATCH) {
427 clnt_geterr(client, &rpcerr);
428 minvers = rpcerr.re_vers.low;
429 maxvers = rpcerr.re_vers.high;
430 } else if (rpc_stat == RPC_SUCCESS) {
432 * It also supports version MAX_VERS.
433 * Looks like we have a wise guy.
434 * OK, we give them information on all
435 * 4 billion versions they support...
437 minvers = 0;
438 maxvers = MAX_VERS;
439 } else {
440 (void) pstatus(client, prognum, MAX_VERS);
441 exit(1);
443 } else {
444 (void) pstatus(client, prognum, (u_long)0);
445 exit(1);
447 (void) CLNT_DESTROY(client);
448 for (vers = minvers; vers <= maxvers; vers++) {
449 addr.sin_port = htons(portnum);
450 client = clnt_com_create(&addr, prognum, vers, &fd, trans);
451 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
452 NULL, (xdrproc_t) xdr_void, NULL, to);
453 if (pstatus(client, prognum, vers) < 0)
454 failure = 1;
455 (void) CLNT_DESTROY(client);
457 if (failure)
458 exit(1);
459 (void) close(fd);
460 return;
464 * Dump all the portmapper registerations
466 static void
467 pmapdump(int argc, char **argv)
469 struct sockaddr_in server_addr;
470 struct pmaplist *head = NULL;
471 int sock = RPC_ANYSOCK;
472 struct timeval minutetimeout;
473 register CLIENT *client;
474 struct rpcent *rpc;
475 enum clnt_stat clnt_st;
476 struct rpc_err error;
477 char *host = NULL;
479 if (argc > 1) {
480 usage();
481 exit(1);
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 &sock, 50, 500);
489 } else
490 client = local_rpcb(PMAPPROG, PMAPVERS);
492 if (client == NULL) {
493 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
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.
499 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
500 rpc_createerr.cf_error.re_status = RPC_FAILED;
502 clnt_pcreateerror("rpcinfo: can't contact portmapper");
503 exit(1);
506 minutetimeout.tv_sec = 60;
507 minutetimeout.tv_usec = 0;
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, &error);
516 if (error.re_vers.low > PMAPVERS) {
517 if (host)
518 fprintf(stderr,
519 "%s does not support portmapper. Try 'rpcinfo %s' instead\n",
520 host, host);
521 else
522 fprintf(stderr,
523 "local host does not support portmapper. Try 'rpcinfo' instead\n");
525 exit(1);
527 clnt_perror(client, "rpcinfo: can't contact portmapper");
528 exit(1);
530 if (head == NULL) {
531 printf("No remote programs registered.\n");
532 } else {
533 printf(" program vers proto port service\n");
534 for (; head != NULL; head = head->pml_next) {
535 printf("%10ld%5ld",
536 head->pml_map.pm_prog,
537 head->pml_map.pm_vers);
538 if (head->pml_map.pm_prot == IPPROTO_UDP)
539 printf("%6s", "udp");
540 else if (head->pml_map.pm_prot == IPPROTO_TCP)
541 printf("%6s", "tcp");
542 else
543 printf("%6ld", head->pml_map.pm_prot);
544 printf("%7ld", head->pml_map.pm_port);
545 rpc = getrpcbynumber(head->pml_map.pm_prog);
546 if (rpc)
547 printf(" %s\n", rpc->r_name);
548 else
549 printf("\n");
554 static void
555 get_inet_address(struct sockaddr_in *addr, const char *host)
557 struct netconfig *nconf;
558 struct addrinfo hints, *res;
559 int error;
561 (void) memset((char *)addr, 0, sizeof (*addr));
562 addr->sin_addr.s_addr = inet_addr(host);
563 if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
564 if ((nconf = __rpc_getconfip("udp")) == NULL &&
565 (nconf = __rpc_getconfip("tcp")) == NULL) {
566 errx(1, "Couldn't find a suitable transport");
567 } else {
568 memset(&hints, 0, sizeof hints);
569 hints.ai_family = AF_INET;
570 if ((error = getaddrinfo(host, "rpcbind", &hints, &res))
571 != 0) {
572 errx(1, "%s: %s", host, gai_strerror(error));
573 } else {
574 memcpy(addr, res->ai_addr, res->ai_addrlen);
575 freeaddrinfo(res);
577 (void) freenetconfigent(nconf);
579 } else {
580 addr->sin_family = AF_INET;
583 #endif /* PORTMAP */
586 * reply_proc collects replies from the broadcast.
587 * to get a unique list of responses the output of rpcinfo should
588 * be piped through sort(1) and then uniq(1).
591 /*ARGSUSED*/
592 static bool_t
593 reply_proc(res, who, nconf)
594 void *res; /* Nothing comes back */
595 struct netbuf *who; /* Who sent us the reply */
596 struct netconfig *nconf; /* On which transport the reply came */
598 char *uaddr;
599 char hostbuf[NI_MAXHOST];
600 char *hostname;
601 struct sockaddr *sa = (struct sockaddr *)who->buf;
603 if (getnameinfo(sa, sa->sa_len, hostbuf, NI_MAXHOST, NULL, 0, 0)) {
604 hostname = UNKNOWN;
605 } else {
606 hostname = hostbuf;
608 if (!(uaddr = taddr2uaddr(nconf, who))) {
609 uaddr = UNKNOWN;
611 printf("%s\t%s\n", uaddr, hostname);
612 if (strcmp(uaddr, UNKNOWN))
613 free((char *)uaddr);
614 return (FALSE);
617 static void
618 brdcst(argc, argv)
619 int argc;
620 char **argv;
622 enum clnt_stat rpc_stat;
623 u_long prognum, vers;
625 if (argc != 2) {
626 usage();
627 exit(1);
629 prognum = getprognum(argv[0]);
630 vers = getvers(argv[1]);
631 rpc_stat = rpc_broadcast(prognum, vers, NULLPROC,
632 (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_void,
633 NULL, (resultproc_t) reply_proc, NULL);
634 if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT))
635 errx(1, "broadcast failed: %s", clnt_sperrno(rpc_stat));
636 exit(0);
639 static bool_t
640 add_version(rs, vers)
641 struct rpcbdump_short *rs;
642 u_long vers;
644 struct verslist *vl;
646 for (vl = rs->vlist; vl; vl = vl->next)
647 if (vl->vers == vers)
648 break;
649 if (vl)
650 return (TRUE);
651 vl = malloc(sizeof (struct verslist));
652 if (vl == NULL)
653 return (FALSE);
654 vl->vers = vers;
655 vl->next = rs->vlist;
656 rs->vlist = vl;
657 return (TRUE);
660 static bool_t
661 add_netid(rs, netid)
662 struct rpcbdump_short *rs;
663 char *netid;
665 struct netidlist *nl;
667 for (nl = rs->nlist; nl; nl = nl->next)
668 if (strcmp(nl->netid, netid) == 0)
669 break;
670 if (nl)
671 return (TRUE);
672 nl = malloc(sizeof (struct netidlist));
673 if (nl == NULL)
674 return (FALSE);
675 nl->netid = netid;
676 nl->next = rs->nlist;
677 rs->nlist = nl;
678 return (TRUE);
681 static void
682 rpcbdump(dumptype, netid, argc, argv)
683 int dumptype;
684 char *netid;
685 int argc;
686 char **argv;
688 rpcblist_ptr head = NULL, p;
689 struct timeval minutetimeout;
690 register CLIENT *client = NULL;
691 struct rpcent *rpc;
692 char *host;
693 struct netidlist *nl;
694 struct verslist *vl;
695 struct rpcbdump_short *rs, *rs_tail = NULL;
696 char buf[256];
697 enum clnt_stat clnt_st;
698 struct rpc_err error;
699 struct rpcbdump_short *rs_head = NULL;
701 if (argc > 1) {
702 usage();
703 exit(1);
705 if (argc == 1) {
706 host = argv[0];
707 if (netid == NULL) {
708 client = clnt_rpcbind_create(host, RPCBVERS, NULL);
709 } else {
710 struct netconfig *nconf;
712 nconf = getnetconfigent(netid);
713 if (nconf == NULL) {
714 nc_perror("rpcinfo: invalid transport");
715 exit(1);
717 client = getclnthandle(host, nconf, RPCBVERS, NULL);
718 if (nconf)
719 (void) freenetconfigent(nconf);
721 } else
722 client = local_rpcb(PMAPPROG, RPCBVERS);
724 if (client == NULL) {
725 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
726 exit(1);
728 minutetimeout.tv_sec = 60;
729 minutetimeout.tv_usec = 0;
730 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t) xdr_void,
731 NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
732 minutetimeout);
733 if (clnt_st != RPC_SUCCESS) {
734 if ((clnt_st == RPC_PROGVERSMISMATCH) ||
735 (clnt_st == RPC_PROGUNAVAIL)) {
736 int vers;
738 CLNT_GETERR(client, &error);
739 if (error.re_vers.low == RPCBVERS4) {
740 vers = RPCBVERS4;
741 clnt_control(client, CLSET_VERS, (char *)&vers);
742 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
743 (xdrproc_t) xdr_void, NULL,
744 (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
745 minutetimeout);
746 if (clnt_st != RPC_SUCCESS)
747 goto failed;
748 } else {
749 if (error.re_vers.high == PMAPVERS) {
750 int high, low;
751 struct pmaplist *pmaphead = NULL;
752 rpcblist_ptr list, prev = NULL;
754 vers = PMAPVERS;
755 clnt_control(client, CLSET_VERS, (char *)&vers);
756 clnt_st = CLNT_CALL(client, PMAPPROC_DUMP,
757 (xdrproc_t) xdr_void, NULL,
758 (xdrproc_t) xdr_pmaplist_ptr,
759 (char *)&pmaphead, minutetimeout);
760 if (clnt_st != RPC_SUCCESS)
761 goto failed;
763 * convert to rpcblist_ptr format
765 for (head = NULL; pmaphead != NULL;
766 pmaphead = pmaphead->pml_next) {
767 list = malloc(sizeof (rpcblist));
768 if (list == NULL)
769 goto error;
770 if (head == NULL)
771 head = list;
772 else
773 prev->rpcb_next = (rpcblist_ptr) list;
775 list->rpcb_next = NULL;
776 list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog;
777 list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers;
778 if (pmaphead->pml_map.pm_prot == IPPROTO_UDP)
779 list->rpcb_map.r_netid = strdup("udp");
780 else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP)
781 list->rpcb_map.r_netid = strdup("tcp");
782 else {
783 #define MAXLONG_AS_STRING "2147483648"
784 list->rpcb_map.r_netid =
785 malloc(strlen(MAXLONG_AS_STRING) + 1);
786 if (list->rpcb_map.r_netid == NULL)
787 goto error;
788 sprintf(list->rpcb_map.r_netid, "%6ld",
789 pmaphead->pml_map.pm_prot);
791 list->rpcb_map.r_owner = UNKNOWN;
792 low = pmaphead->pml_map.pm_port & 0xff;
793 high = (pmaphead->pml_map.pm_port >> 8) & 0xff;
794 list->rpcb_map.r_addr = strdup("0.0.0.0.XXX.XXX");
795 sprintf(&list->rpcb_map.r_addr[8], "%d.%d",
796 high, low);
797 prev = list;
801 } else { /* any other error */
802 failed:
803 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
804 exit(1);
807 if (head == NULL) {
808 printf("No remote programs registered.\n");
809 } else if (dumptype == RPCBDUMP) {
810 printf(
811 " program version netid address service owner\n");
812 for (p = head; p != NULL; p = p->rpcb_next) {
813 printf("%10u%5u ",
814 p->rpcb_map.r_prog, p->rpcb_map.r_vers);
815 printf("%-9s ", p->rpcb_map.r_netid);
816 printf("%-22s", p->rpcb_map.r_addr);
817 rpc = getrpcbynumber(p->rpcb_map.r_prog);
818 if (rpc)
819 printf(" %-10s", rpc->r_name);
820 else
821 printf(" %-10s", "-");
822 printf(" %s\n", p->rpcb_map.r_owner);
824 } else if (dumptype == RPCBDUMP_SHORT) {
825 for (p = head; p != NULL; p = p->rpcb_next) {
826 for (rs = rs_head; rs; rs = rs->next)
827 if (p->rpcb_map.r_prog == rs->prog)
828 break;
829 if (rs == NULL) {
830 rs = malloc(sizeof (struct rpcbdump_short));
831 if (rs == NULL)
832 goto error;
833 rs->next = NULL;
834 if (rs_head == NULL) {
835 rs_head = rs;
836 rs_tail = rs;
837 } else {
838 rs_tail->next = rs;
839 rs_tail = rs;
841 rs->prog = p->rpcb_map.r_prog;
842 rs->owner = p->rpcb_map.r_owner;
843 rs->nlist = NULL;
844 rs->vlist = NULL;
846 if (add_version(rs, p->rpcb_map.r_vers) == FALSE)
847 goto error;
848 if (add_netid(rs, p->rpcb_map.r_netid) == FALSE)
849 goto error;
851 printf(
852 " program version(s) netid(s) service owner\n");
853 for (rs = rs_head; rs; rs = rs->next) {
854 char *bp = buf;
856 printf("%10ld ", rs->prog);
857 for (vl = rs->vlist; vl; vl = vl->next) {
858 sprintf(bp, "%d", vl->vers);
859 bp = bp + strlen(bp);
860 if (vl->next)
861 sprintf(bp++, ",");
863 printf("%-10s", buf);
864 buf[0] = 0;
865 for (nl = rs->nlist; nl; nl = nl->next) {
866 strcat(buf, nl->netid);
867 if (nl->next)
868 strcat(buf, ",");
870 printf("%-32s", buf);
871 rpc = getrpcbynumber(rs->prog);
872 if (rpc)
873 printf(" %-11s", rpc->r_name);
874 else
875 printf(" %-11s", "-");
876 printf(" %s\n", rs->owner);
879 if (client)
880 clnt_destroy(client);
881 while (head != NULL) {
882 rpcblist_ptr list = head->rpcb_next;
883 if (head->rpcb_map.r_addr)
884 free(head->rpcb_map.r_addr);
885 if (head->rpcb_map.r_netid)
886 free(head->rpcb_map.r_netid);
887 free(head);
888 head = list;
890 while (rs_head) {
891 rs = rs_head;
892 rs_head = rs_head->next;
893 free(rs);
895 return;
896 error: err(1, "Cannot allocate memory");
899 static char nullstring[] = "\000";
901 static void
902 rpcbaddrlist(netid, argc, argv)
903 char *netid;
904 int argc;
905 char **argv;
907 rpcb_entry_list_ptr head = NULL;
908 struct timeval minutetimeout;
909 register CLIENT *client;
910 struct rpcent *rpc;
911 char *host;
912 RPCB parms;
913 struct netbuf *targaddr;
915 if (argc != 3) {
916 usage();
917 exit(1);
919 host = argv[0];
920 if (netid == NULL) {
921 client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr);
922 } else {
923 struct netconfig *nconf;
925 nconf = getnetconfigent(netid);
926 if (nconf == NULL) {
927 nc_perror("rpcinfo: invalid transport");
928 exit(1);
930 client = getclnthandle(host, nconf, RPCBVERS4, &targaddr);
931 if (nconf)
932 (void) freenetconfigent(nconf);
934 if (client == NULL) {
935 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
936 exit(1);
938 minutetimeout.tv_sec = 60;
939 minutetimeout.tv_usec = 0;
941 parms.r_prog = getprognum(argv[1]);
942 parms.r_vers = getvers(argv[2]);
943 parms.r_netid = client->cl_netid;
944 if (targaddr == NULL) {
945 parms.r_addr = nullstring; /* for XDRing */
946 } else {
948 * We also send the remote system the address we
949 * used to contact it in case it can help it
950 * connect back with us
952 struct netconfig *nconf;
954 nconf = getnetconfigent(client->cl_netid);
955 if (nconf != NULL) {
956 parms.r_addr = taddr2uaddr(nconf, targaddr);
957 if (parms.r_addr == NULL)
958 parms.r_addr = nullstring;
959 freenetconfigent(nconf);
960 } else {
961 parms.r_addr = nullstring; /* for XDRing */
963 free(targaddr->buf);
964 free(targaddr);
966 parms.r_owner = nullstring;
968 if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb,
969 (char *) &parms, (xdrproc_t) xdr_rpcb_entry_list_ptr,
970 (char *) &head, minutetimeout) != RPC_SUCCESS) {
971 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
972 exit(1);
974 if (head == NULL) {
975 printf("No remote programs registered.\n");
976 } else {
977 printf(
978 " program vers tp_family/name/class address\t\t service\n");
979 for (; head != NULL; head = head->rpcb_entry_next) {
980 rpcb_entry *re;
981 char buf[128];
983 re = &head->rpcb_entry_map;
984 printf("%10u%3u ",
985 parms.r_prog, parms.r_vers);
986 sprintf(buf, "%s/%s/%s ",
987 re->r_nc_protofmly, re->r_nc_proto,
988 re->r_nc_semantics == NC_TPI_CLTS ? "clts" :
989 re->r_nc_semantics == NC_TPI_COTS ? "cots" :
990 "cots_ord");
991 printf("%-24s", buf);
992 printf("%-24s", re->r_maddr);
993 rpc = getrpcbynumber(parms.r_prog);
994 if (rpc)
995 printf(" %-13s", rpc->r_name);
996 else
997 printf(" %-13s", "-");
998 printf("\n");
1001 clnt_destroy(client);
1002 return;
1006 * monitor rpcbind
1008 static void
1009 rpcbgetstat(argc, argv)
1010 int argc;
1011 char **argv;
1013 rpcb_stat_byvers inf;
1014 struct timeval minutetimeout;
1015 register CLIENT *client;
1016 char *host;
1017 int i, j;
1018 rpcbs_addrlist *pa;
1019 rpcbs_rmtcalllist *pr;
1020 int cnt, flen;
1021 #define MAXFIELD 64
1022 char fieldbuf[MAXFIELD];
1023 #define MAXLINE 256
1024 char linebuf[MAXLINE];
1025 char *cp, *lp;
1026 char *pmaphdr[] = {
1027 "NULL", "SET", "UNSET", "GETPORT",
1028 "DUMP", "CALLIT"
1030 char *rpcb3hdr[] = {
1031 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1032 "U2T", "T2U"
1034 char *rpcb4hdr[] = {
1035 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1036 "U2T", "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT"
1039 #define TABSTOP 8
1041 if (argc >= 1) {
1042 host = argv[0];
1043 client = clnt_rpcbind_create(host, RPCBVERS4, NULL);
1044 } else
1045 client = local_rpcb(PMAPPROG, RPCBVERS4);
1046 if (client == NULL) {
1047 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
1048 exit(1);
1050 minutetimeout.tv_sec = 60;
1051 minutetimeout.tv_usec = 0;
1052 memset((char *)&inf, 0, sizeof (rpcb_stat_byvers));
1053 if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t) xdr_void, NULL,
1054 (xdrproc_t) xdr_rpcb_stat_byvers, (char *)&inf, minutetimeout)
1055 != RPC_SUCCESS) {
1056 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
1057 exit(1);
1059 printf("PORTMAP (version 2) statistics\n");
1060 lp = linebuf;
1061 for (i = 0; i <= rpcb_highproc_2; i++) {
1062 fieldbuf[0] = '\0';
1063 switch (i) {
1064 case PMAPPROC_SET:
1065 sprintf(fieldbuf, "%d/", inf[RPCBVERS_2_STAT].setinfo);
1066 break;
1067 case PMAPPROC_UNSET:
1068 sprintf(fieldbuf, "%d/",
1069 inf[RPCBVERS_2_STAT].unsetinfo);
1070 break;
1071 case PMAPPROC_GETPORT:
1072 cnt = 0;
1073 for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa;
1074 pa = pa->next)
1075 cnt += pa->success;
1076 sprintf(fieldbuf, "%d/", cnt);
1077 break;
1078 case PMAPPROC_CALLIT:
1079 cnt = 0;
1080 for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr;
1081 pr = pr->next)
1082 cnt += pr->success;
1083 sprintf(fieldbuf, "%d/", cnt);
1084 break;
1085 default: break; /* For the remaining ones */
1087 cp = &fieldbuf[0] + strlen(fieldbuf);
1088 sprintf(cp, "%d", inf[RPCBVERS_2_STAT].info[i]);
1089 flen = strlen(fieldbuf);
1090 printf("%s%s", pmaphdr[i],
1091 spaces((TABSTOP * (1 + flen / TABSTOP))
1092 - strlen(pmaphdr[i])));
1093 sprintf(lp, "%s%s", fieldbuf,
1094 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1095 - flen)));
1096 lp += (flen + cnt);
1098 printf("\n%s\n\n", linebuf);
1100 if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) {
1101 printf("PMAP_RMTCALL call statistics\n");
1102 print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1103 printf("\n");
1106 if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) {
1107 printf("PMAP_GETPORT call statistics\n");
1108 print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1109 printf("\n");
1112 printf("RPCBIND (version 3) statistics\n");
1113 lp = linebuf;
1114 for (i = 0; i <= rpcb_highproc_3; i++) {
1115 fieldbuf[0] = '\0';
1116 switch (i) {
1117 case RPCBPROC_SET:
1118 sprintf(fieldbuf, "%d/", inf[RPCBVERS_3_STAT].setinfo);
1119 break;
1120 case RPCBPROC_UNSET:
1121 sprintf(fieldbuf, "%d/",
1122 inf[RPCBVERS_3_STAT].unsetinfo);
1123 break;
1124 case RPCBPROC_GETADDR:
1125 cnt = 0;
1126 for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa;
1127 pa = pa->next)
1128 cnt += pa->success;
1129 sprintf(fieldbuf, "%d/", cnt);
1130 break;
1131 case RPCBPROC_CALLIT:
1132 cnt = 0;
1133 for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr;
1134 pr = pr->next)
1135 cnt += pr->success;
1136 sprintf(fieldbuf, "%d/", cnt);
1137 break;
1138 default: break; /* For the remaining ones */
1140 cp = &fieldbuf[0] + strlen(fieldbuf);
1141 sprintf(cp, "%d", inf[RPCBVERS_3_STAT].info[i]);
1142 flen = strlen(fieldbuf);
1143 printf("%s%s", rpcb3hdr[i],
1144 spaces((TABSTOP * (1 + flen / TABSTOP))
1145 - strlen(rpcb3hdr[i])));
1146 sprintf(lp, "%s%s", fieldbuf,
1147 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1148 - flen)));
1149 lp += (flen + cnt);
1151 printf("\n%s\n\n", linebuf);
1153 if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) {
1154 printf("RPCB_RMTCALL (version 3) call statistics\n");
1155 print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1156 printf("\n");
1159 if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) {
1160 printf("RPCB_GETADDR (version 3) call statistics\n");
1161 print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1162 printf("\n");
1165 printf("RPCBIND (version 4) statistics\n");
1167 for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */
1168 lp = linebuf;
1169 for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) {
1170 fieldbuf[0] = '\0';
1171 switch (i) {
1172 case RPCBPROC_SET:
1173 sprintf(fieldbuf, "%d/",
1174 inf[RPCBVERS_4_STAT].setinfo);
1175 break;
1176 case RPCBPROC_UNSET:
1177 sprintf(fieldbuf, "%d/",
1178 inf[RPCBVERS_4_STAT].unsetinfo);
1179 break;
1180 case RPCBPROC_GETADDR:
1181 cnt = 0;
1182 for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa;
1183 pa = pa->next)
1184 cnt += pa->success;
1185 sprintf(fieldbuf, "%d/", cnt);
1186 break;
1187 case RPCBPROC_CALLIT:
1188 cnt = 0;
1189 for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr;
1190 pr = pr->next)
1191 cnt += pr->success;
1192 sprintf(fieldbuf, "%d/", cnt);
1193 break;
1194 default: break; /* For the remaining ones */
1196 cp = &fieldbuf[0] + strlen(fieldbuf);
1198 * XXX: We also add RPCBPROC_GETADDRLIST queries to
1199 * RPCB_GETADDR because rpcbind includes the
1200 * RPCB_GETADDRLIST successes in RPCB_GETADDR.
1202 if (i != RPCBPROC_GETADDR)
1203 sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i]);
1204 else
1205 sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i] +
1206 inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]);
1207 flen = strlen(fieldbuf);
1208 printf("%s%s", rpcb4hdr[i],
1209 spaces((TABSTOP * (1 + flen / TABSTOP))
1210 - strlen(rpcb4hdr[i])));
1211 sprintf(lp, "%s%s", fieldbuf,
1212 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1213 - flen)));
1214 lp += (flen + cnt);
1216 printf("\n%s\n", linebuf);
1219 if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] ||
1220 inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) {
1221 printf("\n");
1222 printf("RPCB_RMTCALL (version 4) call statistics\n");
1223 print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1226 if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) {
1227 printf("\n");
1228 printf("RPCB_GETADDR (version 4) call statistics\n");
1229 print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1231 clnt_destroy(client);
1235 * Delete registeration for this (prog, vers, netid)
1237 static void
1238 deletereg(netid, argc, argv)
1239 char *netid;
1240 int argc;
1241 char **argv;
1243 struct netconfig *nconf = NULL;
1245 if (argc != 2) {
1246 usage();
1247 exit(1);
1249 if (netid) {
1250 nconf = getnetconfigent(netid);
1251 if (nconf == NULL) {
1252 fprintf(stderr, "rpcinfo: netid %s not supported\n",
1253 netid);
1254 exit(1);
1257 if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0) {
1258 fprintf(stderr,
1259 "rpcinfo: Could not delete registration for prog %s version %s\n",
1260 argv[0], argv[1]);
1261 exit(1);
1266 * Create and return a handle for the given nconf.
1267 * Exit if cannot create handle.
1269 static CLIENT *
1270 clnt_addr_create(address, nconf, prog, vers)
1271 char *address;
1272 struct netconfig *nconf;
1273 u_long prog;
1274 u_long vers;
1276 CLIENT *client;
1277 static struct netbuf *nbuf;
1278 static int fd = RPC_ANYFD;
1280 if (fd == RPC_ANYFD) {
1281 if ((fd = __rpc_nconf2fd(nconf)) == -1) {
1282 rpc_createerr.cf_stat = RPC_TLIERROR;
1283 clnt_pcreateerror("rpcinfo");
1284 exit(1);
1286 /* Convert the uaddr to taddr */
1287 nbuf = uaddr2taddr(nconf, address);
1288 if (nbuf == NULL) {
1289 errx(1, "No address for client handle");
1290 exit(1);
1293 client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0);
1294 if (client == NULL) {
1295 clnt_pcreateerror(getprogname());
1296 exit(1);
1298 return (client);
1302 * If the version number is given, ping that (prog, vers); else try to find
1303 * the version numbers supported for that prog and ping all the versions.
1304 * Remote rpcbind is not contacted for this service. The requests are
1305 * sent directly to the services themselves.
1307 static void
1308 addrping(address, netid, argc, argv)
1309 char *address;
1310 char *netid;
1311 int argc;
1312 char **argv;
1314 CLIENT *client;
1315 struct timeval to;
1316 enum clnt_stat rpc_stat;
1317 u_long prognum, versnum, minvers, maxvers;
1318 struct rpc_err rpcerr;
1319 int failure = 0;
1320 struct netconfig *nconf;
1321 int fd;
1323 if (argc < 1 || argc > 2 || (netid == NULL)) {
1324 usage();
1325 exit(1);
1327 nconf = getnetconfigent(netid);
1328 if (nconf == NULL)
1329 errx(1, "Could not find %s", netid);
1330 to.tv_sec = 10;
1331 to.tv_usec = 0;
1332 prognum = getprognum(argv[0]);
1333 if (argc == 1) { /* Version number not known */
1335 * A call to version 0 should fail with a program/version
1336 * mismatch, and give us the range of versions supported.
1338 versnum = MIN_VERS;
1339 } else {
1340 versnum = getvers(argv[1]);
1342 client = clnt_addr_create(address, nconf, prognum, versnum);
1343 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1344 NULL, (xdrproc_t) xdr_void, NULL, to);
1345 if (argc == 2) {
1346 /* Version number was known */
1347 if (pstatus(client, prognum, versnum) < 0)
1348 failure = 1;
1349 (void) CLNT_DESTROY(client);
1350 if (failure)
1351 exit(1);
1352 return;
1354 /* Version number not known */
1355 (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, NULL);
1356 (void) CLNT_CONTROL(client, CLGET_FD, (char *)&fd);
1357 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1358 clnt_geterr(client, &rpcerr);
1359 minvers = rpcerr.re_vers.low;
1360 maxvers = rpcerr.re_vers.high;
1361 } else if (rpc_stat == RPC_SUCCESS) {
1363 * Oh dear, it DOES support version 0.
1364 * Let's try version MAX_VERS.
1366 (void) CLNT_DESTROY(client);
1367 client = clnt_addr_create(address, nconf, prognum, MAX_VERS);
1368 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1369 NULL, (xdrproc_t) xdr_void, NULL, to);
1370 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1371 clnt_geterr(client, &rpcerr);
1372 minvers = rpcerr.re_vers.low;
1373 maxvers = rpcerr.re_vers.high;
1374 } else if (rpc_stat == RPC_SUCCESS) {
1376 * It also supports version MAX_VERS.
1377 * Looks like we have a wise guy.
1378 * OK, we give them information on all
1379 * 4 billion versions they support...
1381 minvers = 0;
1382 maxvers = MAX_VERS;
1383 } else {
1384 (void) pstatus(client, prognum, MAX_VERS);
1385 exit(1);
1387 } else {
1388 (void) pstatus(client, prognum, (u_long)0);
1389 exit(1);
1391 (void) CLNT_DESTROY(client);
1392 for (versnum = minvers; versnum <= maxvers; versnum++) {
1393 client = clnt_addr_create(address, nconf, prognum, versnum);
1394 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1395 NULL, (xdrproc_t) xdr_void, NULL, to);
1396 if (pstatus(client, prognum, versnum) < 0)
1397 failure = 1;
1398 (void) CLNT_DESTROY(client);
1400 (void) close(fd);
1401 if (failure)
1402 exit(1);
1403 return;
1407 * If the version number is given, ping that (prog, vers); else try to find
1408 * the version numbers supported for that prog and ping all the versions.
1409 * Remote rpcbind is *contacted* for this service. The requests are
1410 * then sent directly to the services themselves.
1412 static void
1413 progping(netid, argc, argv)
1414 char *netid;
1415 int argc;
1416 char **argv;
1418 CLIENT *client;
1419 struct timeval to;
1420 enum clnt_stat rpc_stat;
1421 u_long prognum, versnum, minvers, maxvers;
1422 struct rpc_err rpcerr;
1423 int failure = 0;
1424 struct netconfig *nconf;
1426 if (argc < 2 || argc > 3 || (netid == NULL)) {
1427 usage();
1428 exit(1);
1430 prognum = getprognum(argv[1]);
1431 if (argc == 2) { /* Version number not known */
1433 * A call to version 0 should fail with a program/version
1434 * mismatch, and give us the range of versions supported.
1436 versnum = MIN_VERS;
1437 } else {
1438 versnum = getvers(argv[2]);
1440 if (netid) {
1441 nconf = getnetconfigent(netid);
1442 if (nconf == NULL)
1443 errx(1, "Could not find `%s'", netid);
1444 client = clnt_tp_create(argv[0], prognum, versnum, nconf);
1445 } else {
1446 client = clnt_create(argv[0], prognum, versnum, "NETPATH");
1448 if (client == NULL) {
1449 clnt_pcreateerror(getprogname());
1450 exit(1);
1452 to.tv_sec = 10;
1453 to.tv_usec = 0;
1454 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1455 NULL, (xdrproc_t) xdr_void, NULL, to);
1456 if (argc == 3) {
1457 /* Version number was known */
1458 if (pstatus(client, prognum, versnum) < 0)
1459 failure = 1;
1460 (void) CLNT_DESTROY(client);
1461 if (failure)
1462 exit(1);
1463 return;
1465 /* Version number not known */
1466 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1467 clnt_geterr(client, &rpcerr);
1468 minvers = rpcerr.re_vers.low;
1469 maxvers = rpcerr.re_vers.high;
1470 } else if (rpc_stat == RPC_SUCCESS) {
1472 * Oh dear, it DOES support version 0.
1473 * Let's try version MAX_VERS.
1475 versnum = MAX_VERS;
1476 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1477 rpc_stat = CLNT_CALL(client, NULLPROC,
1478 (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_void, NULL, to);
1479 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1480 clnt_geterr(client, &rpcerr);
1481 minvers = rpcerr.re_vers.low;
1482 maxvers = rpcerr.re_vers.high;
1483 } else if (rpc_stat == RPC_SUCCESS) {
1485 * It also supports version MAX_VERS.
1486 * Looks like we have a wise guy.
1487 * OK, we give them information on all
1488 * 4 billion versions they support...
1490 minvers = 0;
1491 maxvers = MAX_VERS;
1492 } else {
1493 (void) pstatus(client, prognum, MAX_VERS);
1494 exit(1);
1496 } else {
1497 (void) pstatus(client, prognum, (u_long)0);
1498 exit(1);
1500 for (versnum = minvers; versnum <= maxvers; versnum++) {
1501 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1502 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1503 NULL, (xdrproc_t) xdr_void, NULL, to);
1504 if (pstatus(client, prognum, versnum) < 0)
1505 failure = 1;
1507 (void) CLNT_DESTROY(client);
1508 if (failure)
1509 exit(1);
1510 return;
1513 static void
1514 usage()
1516 fprintf(stderr, "usage: rpcinfo [-m | -s] [host]\n");
1517 #ifdef PORTMAP
1518 fprintf(stderr, " rpcinfo -p [host]\n");
1519 #endif
1520 fprintf(stderr, " rpcinfo -T netid host prognum [versnum]\n");
1521 fprintf(stderr, " rpcinfo -l host prognum versnum\n");
1522 #ifdef PORTMAP
1523 fprintf(stderr,
1524 " rpcinfo [-n portnum] -u | -t host prognum [versnum]\n");
1525 #endif
1526 fprintf(stderr,
1527 " rpcinfo -a serv_address -T netid prognum [version]\n");
1528 fprintf(stderr, " rpcinfo -b prognum versnum\n");
1529 fprintf(stderr, " rpcinfo -d [-T netid] prognum versnum\n");
1532 static u_long
1533 getprognum (arg)
1534 char *arg;
1536 char *strptr;
1537 register struct rpcent *rpc;
1538 register u_long prognum;
1539 char *tptr = arg;
1541 while (*tptr && isdigit((unsigned char)*tptr++));
1542 if (*tptr || isalpha((unsigned char)*(tptr - 1))) {
1543 rpc = getrpcbyname(arg);
1544 if (rpc == NULL)
1545 errx(1, "Unknown service `%s'", arg);
1546 prognum = rpc->r_number;
1547 } else {
1548 prognum = strtol(arg, &strptr, 10);
1549 if (strptr == arg || *strptr != '\0')
1550 errx(1, "Illegal program number `%s'", arg);
1552 return (prognum);
1555 static u_long
1556 getvers(arg)
1557 char *arg;
1559 char *strptr;
1560 register u_long vers;
1562 vers = (int) strtol(arg, &strptr, 10);
1563 if (strptr == arg || *strptr != '\0')
1564 errx(1, "Illegal version number `%s'", arg);
1565 return (vers);
1569 * This routine should take a pointer to an "rpc_err" structure, rather than
1570 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
1571 * a CLIENT structure rather than a pointer to an "rpc_err" structure.
1572 * As such, we have to keep the CLIENT structure around in order to print
1573 * a good error message.
1575 static int
1576 pstatus(client, prog, vers)
1577 register CLIENT *client;
1578 u_long prog;
1579 u_long vers;
1581 struct rpc_err rpcerr;
1583 clnt_geterr(client, &rpcerr);
1584 if (rpcerr.re_status != RPC_SUCCESS) {
1585 clnt_perror(client, getprogname());
1586 printf("program %lu version %lu is not available\n",
1587 prog, vers);
1588 return (-1);
1589 } else {
1590 printf("program %lu version %lu ready and waiting\n",
1591 prog, vers);
1592 return (0);
1596 static CLIENT *
1597 clnt_rpcbind_create(host, rpcbversnum, targaddr)
1598 char *host;
1599 int rpcbversnum;
1600 struct netbuf **targaddr;
1602 static char *tlist[3] = {
1603 "circuit_n", "circuit_v", "datagram_v"
1605 int i;
1606 struct netconfig *nconf;
1607 CLIENT *clnt = NULL;
1608 void *handle;
1610 rpc_createerr.cf_stat = RPC_SUCCESS;
1611 for (i = 0; i < 3; i++) {
1612 if ((handle = __rpc_setconf(tlist[i])) == NULL)
1613 continue;
1614 while (clnt == NULL) {
1615 if ((nconf = __rpc_getconf(handle)) == NULL) {
1616 if (rpc_createerr.cf_stat == RPC_SUCCESS)
1617 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1618 break;
1620 clnt = getclnthandle(host, nconf, rpcbversnum,
1621 targaddr);
1623 if (clnt)
1624 break;
1625 __rpc_endconf(handle);
1627 return (clnt);
1630 static CLIENT*
1631 getclnthandle(host, nconf, rpcbversnum, targaddr)
1632 char *host;
1633 struct netconfig *nconf;
1634 u_long rpcbversnum;
1635 struct netbuf **targaddr;
1637 struct netbuf addr;
1638 struct addrinfo hints, *res;
1639 CLIENT *client = NULL;
1641 /* Get the address of the rpcbind */
1642 memset(&hints, 0, sizeof hints);
1643 if (getaddrinfo(host, "rpcbind", &hints, &res) != 0) {
1644 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
1645 return (NULL);
1647 addr.len = addr.maxlen = res->ai_addrlen;
1648 addr.buf = res->ai_addr;
1649 client = clnt_tli_create(RPC_ANYFD, nconf, &addr, RPCBPROG,
1650 rpcbversnum, 0, 0);
1651 if (client) {
1652 if (targaddr != NULL) {
1653 *targaddr = malloc(sizeof (struct netbuf));
1654 if (*targaddr != NULL) {
1655 (*targaddr)->maxlen = addr.maxlen;
1656 (*targaddr)->len = addr.len;
1657 (*targaddr)->buf = malloc(addr.len);
1658 if ((*targaddr)->buf != NULL) {
1659 memcpy((*targaddr)->buf, addr.buf,
1660 addr.len);
1664 } else {
1665 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1667 * Assume that the other system is dead; this is a
1668 * better error to display to the user.
1670 rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1671 rpc_createerr.cf_error.re_status = RPC_FAILED;
1674 freeaddrinfo(res);
1675 return (client);
1678 static void
1679 print_rmtcallstat(rtype, infp)
1680 int rtype;
1681 rpcb_stat *infp;
1683 register rpcbs_rmtcalllist_ptr pr;
1684 struct rpcent *rpc;
1686 if (rtype == RPCBVERS_4_STAT)
1687 printf(
1688 "prog\t\tvers\tproc\tnetid\tindirect success failure\n");
1689 else
1690 printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n");
1691 for (pr = infp->rmtinfo; pr; pr = pr->next) {
1692 rpc = getrpcbynumber(pr->prog);
1693 if (rpc)
1694 printf("%-16s", rpc->r_name);
1695 else
1696 printf("%-16d", pr->prog);
1697 printf("%d\t%d\t%s\t",
1698 pr->vers, pr->proc, pr->netid);
1699 if (rtype == RPCBVERS_4_STAT)
1700 printf("%d\t ", pr->indirect);
1701 printf("%d\t%d\n", pr->success, pr->failure);
1705 static void
1706 print_getaddrstat(rtype, infp)
1707 int rtype;
1708 rpcb_stat *infp;
1710 rpcbs_addrlist_ptr al;
1711 register struct rpcent *rpc;
1713 printf("prog\t\tvers\tnetid\t success\tfailure\n");
1714 for (al = infp->addrinfo; al; al = al->next) {
1715 rpc = getrpcbynumber(al->prog);
1716 if (rpc)
1717 printf("%-16s", rpc->r_name);
1718 else
1719 printf("%-16d", al->prog);
1720 printf("%d\t%s\t %-12d\t%d\n",
1721 al->vers, al->netid,
1722 al->success, al->failure);
1726 static char *
1727 spaces(howmany)
1728 int howmany;
1730 static char space_array[] = /* 64 spaces */
1731 " ";
1733 if (howmany <= 0 || howmany > sizeof (space_array)) {
1734 return ("");
1736 return (&space_array[sizeof (space_array) - howmany - 1]);