1 /* $NetBSD: rpcinfo.c,v 1.15 2000/10/04 20:09:05 mjl Exp $ */
5 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
6 * unrestricted use provided that this legend is included on all tape
7 * media and as a part of the software program in whole or part. Users
8 * may copy or modify Sun RPC without charge, but are not authorized
9 * to license or distribute it to anyone else except as part of a product or
10 * program developed by the user.
12 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
13 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
14 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
16 * Sun RPC is provided with no support and without any obligation on the
17 * part of Sun Microsystems, Inc. to assist in its use, correction,
18 * modification or enhancement.
20 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
21 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
22 * OR ANY PART THEREOF.
24 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
25 * or profits or other special, indirect and consequential damages, even if
26 * Sun has been advised of the possibility of such damages.
28 * Sun Microsystems, Inc.
30 * Mountain View, California 94043
34 * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
37 /* #ident "@(#)rpcinfo.c 1.18 93/07/05 SMI" */
41 static char sccsid[] = "@(#)rpcinfo.c 1.16 89/04/05 Copyr 1986 Sun Micro";
46 * rpcinfo: ping a particular rpc program
47 * or dump the the registered programs on the remote machine.
51 * We are for now defining PORTMAP here. It doesnt even compile
52 * unless it is defined.
59 * If PORTMAP is defined, rpcinfo will talk to both portmapper and
60 * rpcbind programs; else it talks only to rpcbind. In the latter case
61 * all the portmapper specific options such as -u, -t, -p become void.
63 #include <sys/types.h>
64 #include <sys/param.h>
65 #include <sys/socket.h>
69 #include <rpc/rpcb_prot.h>
70 #include <rpc/rpcent.h>
71 #include <rpc/nettype.h>
72 #include <rpc/rpc_com.h>
79 #ifdef PORTMAP /* Support for version 2 portmapper */
80 #include <netinet/in.h>
82 #include <arpa/inet.h>
83 #include <rpc/pmap_prot.h>
84 #include <rpc/pmap_clnt.h>
87 #define MAXHOSTLEN 256
88 #define MIN_VERS ((u_long) 0)
89 #define MAX_VERS ((u_long) 4294967295UL)
90 #define UNKNOWN "unknown"
93 * Functions to be performed.
95 #define NONE 0 /* no function */
96 #define PMAPDUMP 1 /* dump portmapper registrations */
97 #define TCPPING 2 /* ping TCP service */
98 #define UDPPING 3 /* ping UDP service */
99 #define BROADCAST 4 /* ping broadcast service */
100 #define DELETES 5 /* delete registration for the service */
101 #define ADDRPING 6 /* pings at the given address */
102 #define PROGPING 7 /* pings a program on a given host */
103 #define RPCBDUMP 8 /* dump rpcbind registrations */
104 #define RPCBDUMP_SHORT 9 /* dump rpcbind registrations - short version */
105 #define RPCBADDRLIST 10 /* dump addr list about one prog */
106 #define RPCBGETSTAT 11 /* Get statistics */
110 struct netidlist *next;
115 struct verslist *next;
118 struct rpcbdump_short {
120 struct verslist *vlist;
121 struct netidlist *nlist;
122 struct rpcbdump_short *next;
129 static void ip_ping(u_short, char *, int, char **);
130 static CLIENT *clnt_com_create(struct sockaddr_in *, u_long, u_long, int *,
132 static void pmapdump(int, char **);
133 static void get_inet_address(struct sockaddr_in *, char *);
136 static bool_t reply_proc(void *, struct netbuf *, struct netconfig *);
137 static void brdcst(int, char **);
138 static void addrping(char *, char *, int, char **);
139 static void progping(char *, int, char **);
140 static CLIENT *clnt_addr_create(char *, struct netconfig *, u_long, u_long);
141 static CLIENT *clnt_rpcbind_create(char *, int, struct netbuf **);
142 static CLIENT *getclnthandle(char *, struct netconfig *, u_long,
144 static CLIENT *local_rpcb(u_long, u_long);
145 static int pstatus(CLIENT *, u_long, u_long);
146 static void rpcbdump(int, char *, int, char **);
147 static void rpcbgetstat(int, char **);
148 static void rpcbaddrlist(char *, int, char **);
149 static void deletereg(char *, int, char **);
150 static void print_rmtcallstat(int, rpcb_stat *);
151 static void print_getaddrstat(int, rpcb_stat *);
152 static void usage(void);
153 static u_long getprognum(char *);
154 static u_long getvers(char *);
155 static char *spaces(int);
156 static bool_t add_version(struct rpcbdump_short *, u_long);
157 static bool_t add_netid(struct rpcbdump_short *, char *);
159 int main(int argc, char **argv);
162 main(int argc, char **argv)
168 char *address = NULL;
177 while ((c = getopt(argc, argv, "a:bdlmn:pstT:u")) != -1) {
179 while ((c = getopt(argc, argv, "a:bdlmn:sT:")) != -1) {
184 if (function != NONE)
191 if (function != NONE)
198 if (function != NONE)
205 portnum = (u_short) strtol(optarg, &strptr, 10);
206 if (strptr == optarg || *strptr != '\0') {
208 "rpcinfo: %s is illegal port number\n",
216 if (function != NONE)
222 if (function != NONE)
225 function = BROADCAST;
229 if (function != NONE)
236 if (function != NONE)
239 function = RPCBADDRLIST;
243 if (function != NONE)
246 function = RPCBGETSTAT;
250 if (function != NONE)
253 function = RPCBDUMP_SHORT;
265 if (errflg || ((function == ADDRPING) && !netid)) {
270 if (function == NONE) {
271 if (argc - optind > 1)
284 pmapdump(argc - optind, argv + optind);
288 ip_ping(portnum, "udp", argc - optind, argv + optind);
292 ip_ping(portnum, "tcp", argc - optind, argv + optind);
296 brdcst(argc - optind, argv + optind);
299 deletereg(netid, argc - optind, argv + optind);
302 addrping(address, netid, argc - optind, argv + optind);
305 progping(netid, argc - optind, argv + optind);
309 rpcbdump(function, netid, argc - optind, argv + optind);
312 rpcbgetstat(argc - optind, argv + optind);
315 rpcbaddrlist(netid, argc - optind, argv + optind);
322 local_rpcb(u_long prog, u_long vers)
325 struct sockaddr_un sun;
328 memset(&sun, 0, sizeof sun);
329 sock = socket(AF_LOCAL, SOCK_STREAM, 0);
333 sun.sun_family = AF_LOCAL;
334 strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
335 nbuf.len = sun.sun_len = SUN_LEN(&sun);
336 nbuf.maxlen = sizeof (struct sockaddr_un);
339 return clnt_vc_create(sock, &nbuf, prog, vers, 0, 0);
344 clnt_com_create(struct sockaddr_in *addr, u_long prog, u_long vers,
345 int *fdp, char *trans)
349 if (strcmp(trans, "tcp") == 0) {
350 clnt = clnttcp_create(addr, prog, vers, fdp, 0, 0);
356 clnt = clntudp_create(addr, prog, vers, to, fdp);
358 if (clnt == (CLIENT *)NULL) {
359 clnt_pcreateerror("rpcinfo");
360 if (vers == MIN_VERS)
361 printf("program %lu is not available\n", prog);
363 printf("program %lu version %lu is not available\n",
371 * If portnum is 0, then go and get the address from portmapper, which happens
372 * transparently through clnt*_create(); If version number is not given, it
373 * tries to find out the version number by making a call to version 0 and if
374 * that fails, it obtains the high order and the low order version number. If
375 * version 0 calls succeeds, it tries for MAXVERS call and repeats the same.
378 ip_ping(u_short portnum, char *trans, int argc, char **argv)
383 struct sockaddr_in addr;
384 enum clnt_stat rpc_stat;
385 u_long prognum, vers, minvers, maxvers;
386 struct rpc_err rpcerr;
389 if (argc < 2 || argc > 3) {
395 prognum = getprognum(argv[1]);
396 get_inet_address(&addr, argv[0]);
397 if (argc == 2) { /* Version number not known */
399 * A call to version 0 should fail with a program/version
400 * mismatch, and give us the range of versions supported.
404 vers = getvers(argv[2]);
406 addr.sin_port = htons(portnum);
407 client = clnt_com_create(&addr, prognum, vers, &fd, trans);
408 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
409 (char *)NULL, (xdrproc_t) xdr_void, (char *)NULL,
412 /* Version number was known */
413 if (pstatus(client, prognum, vers) < 0)
415 (void) CLNT_DESTROY(client);
418 /* Version number not known */
419 (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL);
420 if (rpc_stat == RPC_PROGVERSMISMATCH) {
421 clnt_geterr(client, &rpcerr);
422 minvers = rpcerr.re_vers.low;
423 maxvers = rpcerr.re_vers.high;
424 } else if (rpc_stat == RPC_SUCCESS) {
426 * Oh dear, it DOES support version 0.
427 * Let's try version MAX_VERS.
429 (void) CLNT_DESTROY(client);
430 addr.sin_port = htons(portnum);
431 client = clnt_com_create(&addr, prognum, MAX_VERS, &fd, trans);
432 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
433 (char *)NULL, (xdrproc_t) xdr_void,
435 if (rpc_stat == RPC_PROGVERSMISMATCH) {
436 clnt_geterr(client, &rpcerr);
437 minvers = rpcerr.re_vers.low;
438 maxvers = rpcerr.re_vers.high;
439 } else if (rpc_stat == RPC_SUCCESS) {
441 * It also supports version MAX_VERS.
442 * Looks like we have a wise guy.
443 * OK, we give them information on all
444 * 4 billion versions they support...
449 (void) pstatus(client, prognum, MAX_VERS);
453 (void) pstatus(client, prognum, (u_long)0);
456 (void) CLNT_DESTROY(client);
457 for (vers = minvers; vers <= maxvers; vers++) {
458 addr.sin_port = htons(portnum);
459 client = clnt_com_create(&addr, prognum, vers, &fd, trans);
460 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
461 (char *)NULL, (xdrproc_t) xdr_void,
463 if (pstatus(client, prognum, vers) < 0)
465 (void) CLNT_DESTROY(client);
474 * Dump all the portmapper registerations
477 pmapdump(int argc, char **argv)
479 struct sockaddr_in server_addr;
480 struct pmaplist *head = NULL;
481 int socket = RPC_ANYSOCK;
482 struct timeval minutetimeout;
483 register CLIENT *client;
485 enum clnt_stat clnt_st;
495 get_inet_address(&server_addr, host);
496 server_addr.sin_port = htons(PMAPPORT);
497 client = clnttcp_create(&server_addr, PMAPPROG, PMAPVERS,
500 client = local_rpcb(PMAPPROG, PMAPVERS);
502 if (client == NULL) {
503 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
505 * "Misc. TLI error" is not too helpful. Most likely
506 * the connection to the remote server timed out, so
507 * this error is at least less perplexing.
509 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
510 rpc_createerr.cf_error.re_status = RPC_FAILED;
512 clnt_pcreateerror("rpcinfo: can't contact portmapper");
516 minutetimeout.tv_sec = 60;
517 minutetimeout.tv_usec = 0;
519 clnt_st = CLNT_CALL(client, PMAPPROC_DUMP, (xdrproc_t) xdr_void,
520 NULL, (xdrproc_t) xdr_pmaplist_ptr, (char *)&head,
522 if (clnt_st != RPC_SUCCESS) {
523 if ((clnt_st == RPC_PROGVERSMISMATCH) ||
524 (clnt_st == RPC_PROGUNAVAIL)) {
525 CLNT_GETERR(client, &err);
526 if (err.re_vers.low > PMAPVERS)
528 "%s does not support portmapper. Try rpcinfo %s instead\n",
532 clnt_perror(client, "rpcinfo: can't contact portmapper");
536 printf("No remote programs registered.\n");
538 printf(" program vers proto port service\n");
539 for (; head != NULL; head = head->pml_next) {
541 head->pml_map.pm_prog,
542 head->pml_map.pm_vers);
543 if (head->pml_map.pm_prot == IPPROTO_UDP)
544 printf("%6s", "udp");
545 else if (head->pml_map.pm_prot == IPPROTO_TCP)
546 printf("%6s", "tcp");
547 else if (head->pml_map.pm_prot == IPPROTO_ST)
548 printf("%6s", "unix");
550 printf("%6ld", head->pml_map.pm_prot);
551 printf("%7ld", head->pml_map.pm_port);
552 rpc = getrpcbynumber(head->pml_map.pm_prog);
554 printf(" %s\n", rpc->r_name);
562 get_inet_address(struct sockaddr_in *addr, char *host)
564 struct netconfig *nconf;
565 struct addrinfo hints, *res;
568 (void) memset((char *)addr, 0, sizeof (*addr));
569 addr->sin_addr.s_addr = inet_addr(host);
570 if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
571 if ((nconf = __rpc_getconfip("udp")) == NULL &&
572 (nconf = __rpc_getconfip("tcp")) == NULL) {
574 "rpcinfo: couldn't find a suitable transport\n");
577 memset(&hints, 0, sizeof hints);
578 hints.ai_family = AF_INET;
579 if ((error = getaddrinfo(host, "rpcbind", &hints, &res))
581 fprintf(stderr, "rpcinfo: %s: %s\n",
582 host, gai_strerror(error));
585 memcpy(addr, res->ai_addr, res->ai_addrlen);
588 (void) freenetconfigent(nconf);
591 addr->sin_family = AF_INET;
597 * reply_proc collects replies from the broadcast.
598 * to get a unique list of responses the output of rpcinfo should
599 * be piped through sort(1) and then uniq(1).
604 reply_proc(void *res, struct netbuf *who, struct netconfig *nconf)
605 /* void *res; Nothing comes back */
606 /* struct netbuf *who; Who sent us the reply */
607 /* struct netconfig *nconf; On which transport the reply came */
610 char hostbuf[NI_MAXHOST];
612 struct sockaddr *sa = (struct sockaddr *)who->buf;
614 if (getnameinfo(sa, sa->sa_len, hostbuf, NI_MAXHOST, NULL, 0, 0)) {
619 if (!(uaddr = taddr2uaddr(nconf, who))) {
622 printf("%s\t%s\n", uaddr, hostname);
623 if (strcmp(uaddr, UNKNOWN))
629 brdcst(int argc, char **argv)
631 enum clnt_stat rpc_stat;
632 u_long prognum, vers;
638 prognum = getprognum(argv[0]);
639 vers = getvers(argv[1]);
640 rpc_stat = rpc_broadcast(prognum, vers, NULLPROC,
641 (xdrproc_t) xdr_void, (char *)NULL, (xdrproc_t) xdr_void,
642 (char *)NULL, (resultproc_t) reply_proc, NULL);
643 if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
644 fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
645 clnt_sperrno(rpc_stat));
652 add_version(struct rpcbdump_short *rs, u_long vers)
656 for (vl = rs->vlist; vl; vl = vl->next)
657 if (vl->vers == vers)
661 vl = (struct verslist *)malloc(sizeof (struct verslist));
665 vl->next = rs->vlist;
671 add_netid(struct rpcbdump_short *rs, char *netid)
673 struct netidlist *nl;
675 for (nl = rs->nlist; nl; nl = nl->next)
676 if (strcmp(nl->netid, netid) == 0)
680 nl = (struct netidlist *)malloc(sizeof (struct netidlist));
684 nl->next = rs->nlist;
690 rpcbdump(int dumptype, char *netid, int argc, char **argv)
692 rpcblist_ptr head = NULL;
693 struct timeval minutetimeout;
694 register CLIENT *client;
697 struct netidlist *nl;
699 struct rpcbdump_short *rs, *rs_tail;
701 enum clnt_stat clnt_st;
703 struct rpcbdump_short *rs_head = NULL;
712 client = clnt_rpcbind_create(host, RPCBVERS, NULL);
714 struct netconfig *nconf;
716 nconf = getnetconfigent(netid);
718 nc_perror("rpcinfo: invalid transport");
721 client = getclnthandle(host, nconf, RPCBVERS, NULL);
723 (void) freenetconfigent(nconf);
726 client = local_rpcb(PMAPPROG, RPCBVERS);
728 if (client == (CLIENT *)NULL) {
729 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
733 minutetimeout.tv_sec = 60;
734 minutetimeout.tv_usec = 0;
735 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t) xdr_void,
736 NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
738 if (clnt_st != RPC_SUCCESS) {
739 if ((clnt_st == RPC_PROGVERSMISMATCH) ||
740 (clnt_st == RPC_PROGUNAVAIL)) {
743 CLNT_GETERR(client, &err);
744 if (err.re_vers.low == RPCBVERS4) {
746 clnt_control(client, CLSET_VERS, (char *)&vers);
747 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
748 (xdrproc_t) xdr_void, NULL,
749 (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
751 if (clnt_st != RPC_SUCCESS)
754 if (err.re_vers.high == PMAPVERS) {
756 struct pmaplist *pmaphead = NULL;
757 rpcblist_ptr list, prev;
760 clnt_control(client, CLSET_VERS, (char *)&vers);
761 clnt_st = CLNT_CALL(client, PMAPPROC_DUMP,
762 (xdrproc_t) xdr_void, NULL,
763 (xdrproc_t) xdr_pmaplist_ptr,
764 (char *)&pmaphead, minutetimeout);
765 if (clnt_st != RPC_SUCCESS)
768 * convert to rpcblist_ptr format
770 for (head = NULL; pmaphead != NULL;
771 pmaphead = pmaphead->pml_next) {
772 list = (rpcblist *)malloc(sizeof (rpcblist));
778 prev->rpcb_next = (rpcblist_ptr) list;
780 list->rpcb_next = NULL;
781 list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog;
782 list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers;
783 if (pmaphead->pml_map.pm_prot == IPPROTO_UDP)
784 list->rpcb_map.r_netid = "udp";
785 else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP)
786 list->rpcb_map.r_netid = "tcp";
788 #define MAXLONG_AS_STRING "2147483648"
789 list->rpcb_map.r_netid =
790 malloc(strlen(MAXLONG_AS_STRING) + 1);
791 if (list->rpcb_map.r_netid == NULL)
793 sprintf(list->rpcb_map.r_netid, "%6ld",
794 pmaphead->pml_map.pm_prot);
796 list->rpcb_map.r_owner = UNKNOWN;
797 low = pmaphead->pml_map.pm_port & 0xff;
798 high = (pmaphead->pml_map.pm_port >> 8) & 0xff;
799 list->rpcb_map.r_addr = strdup("0.0.0.0.XXX.XXX");
800 sprintf(&list->rpcb_map.r_addr[8], "%d.%d",
806 } else { /* any other error */
808 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
813 printf("No remote programs registered.\n");
814 } else if (dumptype == RPCBDUMP) {
816 " program version netid address service owner\n");
817 for (; head != NULL; head = head->rpcb_next) {
819 head->rpcb_map.r_prog, head->rpcb_map.r_vers);
820 printf("%-9s ", head->rpcb_map.r_netid);
821 printf("%-22s", head->rpcb_map.r_addr);
822 rpc = getrpcbynumber(head->rpcb_map.r_prog);
824 printf(" %-10s", rpc->r_name);
826 printf(" %-10s", "-");
827 printf(" %s\n", head->rpcb_map.r_owner);
829 } else if (dumptype == RPCBDUMP_SHORT) {
830 for (; head != NULL; head = head->rpcb_next) {
831 for (rs = rs_head; rs; rs = rs->next)
832 if (head->rpcb_map.r_prog == rs->prog)
835 rs = (struct rpcbdump_short *)
836 malloc(sizeof (struct rpcbdump_short));
840 if (rs_head == NULL) {
847 rs->prog = head->rpcb_map.r_prog;
848 rs->owner = head->rpcb_map.r_owner;
852 if (add_version(rs, head->rpcb_map.r_vers) == FALSE)
854 if (add_netid(rs, head->rpcb_map.r_netid) == FALSE)
858 " program version(s) netid(s) service owner\n");
859 for (rs = rs_head; rs; rs = rs->next) {
862 printf("%10ld ", rs->prog);
863 for (vl = rs->vlist; vl; vl = vl->next) {
864 sprintf(p, "%d", vl->vers);
869 printf("%-10s", buf);
871 for (nl = rs->nlist; nl; nl = nl->next) {
872 strcat(buf, nl->netid);
876 printf("%-32s", buf);
877 rpc = getrpcbynumber(rs->prog);
879 printf(" %-11s", rpc->r_name);
881 printf(" %-11s", "-");
882 printf(" %s\n", rs->owner);
885 clnt_destroy(client);
887 error: fprintf(stderr, "rpcinfo: no memory\n");
891 static char nullstring[] = "\000";
894 rpcbaddrlist(char *netid, int argc, char **argv)
896 rpcb_entry_list_ptr head = NULL;
897 struct timeval minutetimeout;
898 register CLIENT *client;
902 struct netbuf *targaddr;
910 client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr);
912 struct netconfig *nconf;
914 nconf = getnetconfigent(netid);
916 nc_perror("rpcinfo: invalid transport");
919 client = getclnthandle(host, nconf, RPCBVERS4, &targaddr);
921 (void) freenetconfigent(nconf);
923 if (client == (CLIENT *)NULL) {
924 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
927 minutetimeout.tv_sec = 60;
928 minutetimeout.tv_usec = 0;
930 parms.r_prog = getprognum(argv[1]);
931 parms.r_vers = getvers(argv[2]);
932 parms.r_netid = client->cl_netid;
933 if (targaddr == NULL) {
934 parms.r_addr = nullstring; /* for XDRing */
937 * We also send the remote system the address we
938 * used to contact it in case it can help it
939 * connect back with us
941 struct netconfig *nconf;
943 nconf = getnetconfigent(client->cl_netid);
945 parms.r_addr = taddr2uaddr(nconf, targaddr);
946 if (parms.r_addr == NULL)
947 parms.r_addr = nullstring;
948 freenetconfigent(nconf);
950 parms.r_addr = nullstring; /* for XDRing */
955 parms.r_owner = nullstring;
957 if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb,
958 (char *) &parms, (xdrproc_t) xdr_rpcb_entry_list_ptr,
959 (char *) &head, minutetimeout) != RPC_SUCCESS) {
960 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
964 printf("No remote programs registered.\n");
967 " program vers tp_family/name/class address\t\t service\n");
968 for (; head != NULL; head = head->rpcb_entry_next) {
972 re = &head->rpcb_entry_map;
974 parms.r_prog, parms.r_vers);
975 sprintf(buf, "%s/%s/%s ",
976 re->r_nc_protofmly, re->r_nc_proto,
977 re->r_nc_semantics == NC_TPI_CLTS ? "clts" :
978 re->r_nc_semantics == NC_TPI_COTS ? "cots" :
980 printf("%-24s", buf);
981 printf("%-24s", re->r_maddr);
982 rpc = getrpcbynumber(parms.r_prog);
984 printf(" %-13s", rpc->r_name);
986 printf(" %-13s", "-");
990 clnt_destroy(client);
998 rpcbgetstat(int argc, char **argv)
1000 rpcb_stat_byvers inf;
1001 struct timeval minutetimeout;
1002 register CLIENT *client;
1006 rpcbs_rmtcalllist *pr;
1009 char fieldbuf[MAXFIELD];
1011 char linebuf[MAXLINE];
1014 "NULL", "SET", "UNSET", "GETPORT",
1017 char *rpcb3hdr[] = {
1018 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1021 char *rpcb4hdr[] = {
1022 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1023 "U2T", "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT"
1030 client = clnt_rpcbind_create(host, RPCBVERS4, NULL);
1032 client = local_rpcb(PMAPPROG, RPCBVERS4);
1033 if (client == (CLIENT *)NULL) {
1034 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
1037 minutetimeout.tv_sec = 60;
1038 minutetimeout.tv_usec = 0;
1039 memset((char *)&inf, 0, sizeof (rpcb_stat_byvers));
1040 if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t) xdr_void, NULL,
1041 (xdrproc_t) xdr_rpcb_stat_byvers, (char *)&inf, minutetimeout)
1043 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
1046 printf("PORTMAP (version 2) statistics\n");
1048 for (i = 0; i <= rpcb_highproc_2; i++) {
1052 sprintf(fieldbuf, "%d/", inf[RPCBVERS_2_STAT].setinfo);
1054 case PMAPPROC_UNSET:
1055 sprintf(fieldbuf, "%d/",
1056 inf[RPCBVERS_2_STAT].unsetinfo);
1058 case PMAPPROC_GETPORT:
1060 for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa;
1063 sprintf(fieldbuf, "%d/", cnt);
1065 case PMAPPROC_CALLIT:
1067 for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr;
1070 sprintf(fieldbuf, "%d/", cnt);
1072 default: break; /* For the remaining ones */
1074 cp = &fieldbuf[0] + strlen(fieldbuf);
1075 sprintf(cp, "%d", inf[RPCBVERS_2_STAT].info[i]);
1076 flen = strlen(fieldbuf);
1077 printf("%s%s", pmaphdr[i],
1078 spaces((TABSTOP * (1 + flen / TABSTOP))
1079 - strlen(pmaphdr[i])));
1080 sprintf(lp, "%s%s", fieldbuf,
1081 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1085 printf("\n%s\n\n", linebuf);
1087 if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) {
1088 printf("PMAP_RMTCALL call statistics\n");
1089 print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1093 if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) {
1094 printf("PMAP_GETPORT call statistics\n");
1095 print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1099 printf("RPCBIND (version 3) statistics\n");
1101 for (i = 0; i <= rpcb_highproc_3; i++) {
1105 sprintf(fieldbuf, "%d/", inf[RPCBVERS_3_STAT].setinfo);
1107 case RPCBPROC_UNSET:
1108 sprintf(fieldbuf, "%d/",
1109 inf[RPCBVERS_3_STAT].unsetinfo);
1111 case RPCBPROC_GETADDR:
1113 for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa;
1116 sprintf(fieldbuf, "%d/", cnt);
1118 case RPCBPROC_CALLIT:
1120 for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr;
1123 sprintf(fieldbuf, "%d/", cnt);
1125 default: break; /* For the remaining ones */
1127 cp = &fieldbuf[0] + strlen(fieldbuf);
1128 sprintf(cp, "%d", inf[RPCBVERS_3_STAT].info[i]);
1129 flen = strlen(fieldbuf);
1130 printf("%s%s", rpcb3hdr[i],
1131 spaces((TABSTOP * (1 + flen / TABSTOP))
1132 - strlen(rpcb3hdr[i])));
1133 sprintf(lp, "%s%s", fieldbuf,
1134 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1138 printf("\n%s\n\n", linebuf);
1140 if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) {
1141 printf("RPCB_RMTCALL (version 3) call statistics\n");
1142 print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1146 if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) {
1147 printf("RPCB_GETADDR (version 3) call statistics\n");
1148 print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1152 printf("RPCBIND (version 4) statistics\n");
1154 for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */
1156 for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) {
1160 sprintf(fieldbuf, "%d/",
1161 inf[RPCBVERS_4_STAT].setinfo);
1163 case RPCBPROC_UNSET:
1164 sprintf(fieldbuf, "%d/",
1165 inf[RPCBVERS_4_STAT].unsetinfo);
1167 case RPCBPROC_GETADDR:
1169 for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa;
1172 sprintf(fieldbuf, "%d/", cnt);
1174 case RPCBPROC_CALLIT:
1176 for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr;
1179 sprintf(fieldbuf, "%d/", cnt);
1181 default: break; /* For the remaining ones */
1183 cp = &fieldbuf[0] + strlen(fieldbuf);
1185 * XXX: We also add RPCBPROC_GETADDRLIST queries to
1186 * RPCB_GETADDR because rpcbind includes the
1187 * RPCB_GETADDRLIST successes in RPCB_GETADDR.
1189 if (i != RPCBPROC_GETADDR)
1190 sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i]);
1192 sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i] +
1193 inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]);
1194 flen = strlen(fieldbuf);
1195 printf("%s%s", rpcb4hdr[i],
1196 spaces((TABSTOP * (1 + flen / TABSTOP))
1197 - strlen(rpcb4hdr[i])));
1198 sprintf(lp, "%s%s", fieldbuf,
1199 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1203 printf("\n%s\n", linebuf);
1206 if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] ||
1207 inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) {
1209 printf("RPCB_RMTCALL (version 4) call statistics\n");
1210 print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1213 if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) {
1215 printf("RPCB_GETADDR (version 4) call statistics\n");
1216 print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1218 clnt_destroy(client);
1222 * Delete registeration for this (prog, vers, netid)
1225 deletereg(char *netid, int argc, char **argv)
1227 struct netconfig *nconf = NULL;
1234 nconf = getnetconfigent(netid);
1235 if (nconf == NULL) {
1236 fprintf(stderr, "rpcinfo: netid %s not supported\n",
1241 if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0) {
1243 "rpcinfo: Could not delete registration for prog %s version %s\n",
1250 * Create and return a handle for the given nconf.
1251 * Exit if cannot create handle.
1254 clnt_addr_create(char *address, struct netconfig *nconf,
1255 u_long prog, u_long vers)
1258 static struct netbuf *nbuf;
1259 static int fd = RPC_ANYFD;
1261 if (fd == RPC_ANYFD) {
1262 if ((fd = __rpc_nconf2fd(nconf)) == -1) {
1263 rpc_createerr.cf_stat = RPC_TLIERROR;
1264 clnt_pcreateerror("rpcinfo");
1267 /* Convert the uaddr to taddr */
1268 nbuf = uaddr2taddr(nconf, address);
1270 errx(1, "rpcinfo: no address for client handle");
1274 client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0);
1275 if (client == (CLIENT *)NULL) {
1276 clnt_pcreateerror("rpcinfo");
1283 * If the version number is given, ping that (prog, vers); else try to find
1284 * the version numbers supported for that prog and ping all the versions.
1285 * Remote rpcbind is not contacted for this service. The requests are
1286 * sent directly to the services themselves.
1289 addrping(char *address, char *netid, int argc, char **argv)
1293 enum clnt_stat rpc_stat;
1294 u_long prognum, versnum, minvers, maxvers;
1295 struct rpc_err rpcerr;
1297 struct netconfig *nconf;
1300 if (argc < 1 || argc > 2 || (netid == NULL)) {
1304 nconf = getnetconfigent(netid);
1305 if (nconf == (struct netconfig *)NULL) {
1306 fprintf(stderr, "rpcinfo: Could not find %s\n", netid);
1311 prognum = getprognum(argv[0]);
1312 if (argc == 1) { /* Version number not known */
1314 * A call to version 0 should fail with a program/version
1315 * mismatch, and give us the range of versions supported.
1319 versnum = getvers(argv[1]);
1321 client = clnt_addr_create(address, nconf, prognum, versnum);
1322 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1323 (char *)NULL, (xdrproc_t) xdr_void,
1326 /* Version number was known */
1327 if (pstatus(client, prognum, versnum) < 0)
1329 (void) CLNT_DESTROY(client);
1334 /* Version number not known */
1335 (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL);
1336 (void) CLNT_CONTROL(client, CLGET_FD, (char *)&fd);
1337 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1338 clnt_geterr(client, &rpcerr);
1339 minvers = rpcerr.re_vers.low;
1340 maxvers = rpcerr.re_vers.high;
1341 } else if (rpc_stat == RPC_SUCCESS) {
1343 * Oh dear, it DOES support version 0.
1344 * Let's try version MAX_VERS.
1346 (void) CLNT_DESTROY(client);
1347 client = clnt_addr_create(address, nconf, prognum, MAX_VERS);
1348 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1349 (char *)NULL, (xdrproc_t) xdr_void,
1351 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1352 clnt_geterr(client, &rpcerr);
1353 minvers = rpcerr.re_vers.low;
1354 maxvers = rpcerr.re_vers.high;
1355 } else if (rpc_stat == RPC_SUCCESS) {
1357 * It also supports version MAX_VERS.
1358 * Looks like we have a wise guy.
1359 * OK, we give them information on all
1360 * 4 billion versions they support...
1365 (void) pstatus(client, prognum, MAX_VERS);
1369 (void) pstatus(client, prognum, (u_long)0);
1372 (void) CLNT_DESTROY(client);
1373 for (versnum = minvers; versnum <= maxvers; versnum++) {
1374 client = clnt_addr_create(address, nconf, prognum, versnum);
1375 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1376 (char *)NULL, (xdrproc_t) xdr_void,
1378 if (pstatus(client, prognum, versnum) < 0)
1380 (void) CLNT_DESTROY(client);
1389 * If the version number is given, ping that (prog, vers); else try to find
1390 * the version numbers supported for that prog and ping all the versions.
1391 * Remote rpcbind is *contacted* for this service. The requests are
1392 * then sent directly to the services themselves.
1395 progping(char *netid, int argc, char **argv)
1399 enum clnt_stat rpc_stat;
1400 u_long prognum, versnum, minvers, maxvers;
1401 struct rpc_err rpcerr;
1403 struct netconfig *nconf;
1405 if (argc < 2 || argc > 3 || (netid == NULL)) {
1409 prognum = getprognum(argv[1]);
1410 if (argc == 2) { /* Version number not known */
1412 * A call to version 0 should fail with a program/version
1413 * mismatch, and give us the range of versions supported.
1417 versnum = getvers(argv[2]);
1420 nconf = getnetconfigent(netid);
1421 if (nconf == (struct netconfig *)NULL) {
1422 fprintf(stderr, "rpcinfo: Could not find %s\n", netid);
1425 client = clnt_tp_create(argv[0], prognum, versnum, nconf);
1427 client = clnt_create(argv[0], prognum, versnum, "NETPATH");
1429 if (client == (CLIENT *)NULL) {
1430 clnt_pcreateerror("rpcinfo");
1435 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1436 (char *)NULL, (xdrproc_t) xdr_void,
1439 /* Version number was known */
1440 if (pstatus(client, prognum, versnum) < 0)
1442 (void) CLNT_DESTROY(client);
1447 /* Version number not known */
1448 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1449 clnt_geterr(client, &rpcerr);
1450 minvers = rpcerr.re_vers.low;
1451 maxvers = rpcerr.re_vers.high;
1452 } else if (rpc_stat == RPC_SUCCESS) {
1454 * Oh dear, it DOES support version 0.
1455 * Let's try version MAX_VERS.
1458 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1459 rpc_stat = CLNT_CALL(client, NULLPROC,
1460 (xdrproc_t) xdr_void, (char *)NULL,
1461 (xdrproc_t) xdr_void, (char *)NULL, to);
1462 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1463 clnt_geterr(client, &rpcerr);
1464 minvers = rpcerr.re_vers.low;
1465 maxvers = rpcerr.re_vers.high;
1466 } else if (rpc_stat == RPC_SUCCESS) {
1468 * It also supports version MAX_VERS.
1469 * Looks like we have a wise guy.
1470 * OK, we give them information on all
1471 * 4 billion versions they support...
1476 (void) pstatus(client, prognum, MAX_VERS);
1480 (void) pstatus(client, prognum, (u_long)0);
1483 for (versnum = minvers; versnum <= maxvers; versnum++) {
1484 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1485 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1486 (char *)NULL, (xdrproc_t) xdr_void,
1488 if (pstatus(client, prognum, versnum) < 0)
1491 (void) CLNT_DESTROY(client);
1500 fprintf(stderr, "Usage: rpcinfo [-m | -s] [host]\n");
1502 fprintf(stderr, " rpcinfo -p [host]\n");
1504 fprintf(stderr, " rpcinfo -T netid host prognum [versnum]\n");
1505 fprintf(stderr, " rpcinfo -l host prognum versnum\n");
1508 " rpcinfo [-n portnum] -u | -t host prognum [versnum]\n");
1511 " rpcinfo -a serv_address -T netid prognum [version]\n");
1512 fprintf(stderr, " rpcinfo -b prognum versnum\n");
1513 fprintf(stderr, " rpcinfo -d [-T netid] prognum versnum\n");
1517 getprognum (char *arg)
1520 register struct rpcent *rpc;
1521 register u_long prognum;
1524 while (*tptr && isdigit(*tptr++));
1525 if (*tptr || isalpha(*(tptr - 1))) {
1526 rpc = getrpcbyname(arg);
1528 fprintf(stderr, "rpcinfo: %s is unknown service\n",
1532 prognum = rpc->r_number;
1534 prognum = strtol(arg, &strptr, 10);
1535 if (strptr == arg || *strptr != '\0') {
1537 "rpcinfo: %s is illegal program number\n", arg);
1548 register u_long vers;
1550 vers = (int) strtol(arg, &strptr, 10);
1551 if (strptr == arg || *strptr != '\0') {
1552 fprintf(stderr, "rpcinfo: %s is illegal version number\n",
1560 * This routine should take a pointer to an "rpc_err" structure, rather than
1561 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
1562 * a CLIENT structure rather than a pointer to an "rpc_err" structure.
1563 * As such, we have to keep the CLIENT structure around in order to print
1564 * a good error message.
1567 pstatus(register CLIENT *client, u_long prog, u_long vers)
1569 struct rpc_err rpcerr;
1571 clnt_geterr(client, &rpcerr);
1572 if (rpcerr.re_status != RPC_SUCCESS) {
1573 clnt_perror(client, "rpcinfo");
1574 printf("program %lu version %lu is not available\n",
1578 printf("program %lu version %lu ready and waiting\n",
1585 clnt_rpcbind_create(char *host, int rpcbversnum, struct netbuf **targaddr)
1587 static char *tlist[3] = {
1588 "circuit_n", "circuit_v", "datagram_v"
1591 struct netconfig *nconf;
1592 CLIENT *clnt = NULL;
1595 rpc_createerr.cf_stat = RPC_SUCCESS;
1596 for (i = 0; i < 3; i++) {
1597 if ((handle = __rpc_setconf(tlist[i])) == NULL)
1599 while (clnt == (CLIENT *)NULL) {
1600 if ((nconf = __rpc_getconf(handle)) == NULL) {
1601 if (rpc_createerr.cf_stat == RPC_SUCCESS)
1602 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1605 clnt = getclnthandle(host, nconf, rpcbversnum,
1610 __rpc_endconf(handle);
1616 getclnthandle(char *host, struct netconfig *nconf,
1617 u_long rpcbversnum, struct netbuf **targaddr)
1620 struct addrinfo hints, *res;
1621 CLIENT *client = NULL;
1623 /* Get the address of the rpcbind */
1624 memset(&hints, 0, sizeof hints);
1625 if (getaddrinfo(host, "rpcbind", &hints, &res) != 0) {
1626 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
1629 addr.len = addr.maxlen = res->ai_addrlen;
1630 addr.buf = res->ai_addr;
1631 client = clnt_tli_create(RPC_ANYFD, nconf, &addr, RPCBPROG,
1634 if (targaddr != NULL) {
1636 (struct netbuf *)malloc(sizeof (struct netbuf));
1637 if (*targaddr != NULL) {
1638 (*targaddr)->maxlen = addr.maxlen;
1639 (*targaddr)->len = addr.len;
1640 (*targaddr)->buf = (char *)malloc(addr.len);
1641 if ((*targaddr)->buf != NULL) {
1642 memcpy((*targaddr)->buf, addr.buf,
1648 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1650 * Assume that the other system is dead; this is a
1651 * better error to display to the user.
1653 rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1654 rpc_createerr.cf_error.re_status = RPC_FAILED;
1662 print_rmtcallstat(int rtype, rpcb_stat *infp)
1664 register rpcbs_rmtcalllist_ptr pr;
1667 if (rtype == RPCBVERS_4_STAT)
1669 "prog\t\tvers\tproc\tnetid\tindirect success failure\n");
1671 printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n");
1672 for (pr = infp->rmtinfo; pr; pr = pr->next) {
1673 rpc = getrpcbynumber(pr->prog);
1675 printf("%-16s", rpc->r_name);
1677 printf("%-16d", pr->prog);
1678 printf("%d\t%d\t%s\t",
1679 pr->vers, pr->proc, pr->netid);
1680 if (rtype == RPCBVERS_4_STAT)
1681 printf("%d\t ", pr->indirect);
1682 printf("%d\t%d\n", pr->success, pr->failure);
1687 print_getaddrstat(int rtype, rpcb_stat *infp)
1689 rpcbs_addrlist_ptr al;
1690 register struct rpcent *rpc;
1692 printf("prog\t\tvers\tnetid\t success\tfailure\n");
1693 for (al = infp->addrinfo; al; al = al->next) {
1694 rpc = getrpcbynumber(al->prog);
1696 printf("%-16s", rpc->r_name);
1698 printf("%-16d", al->prog);
1699 printf("%d\t%s\t %-12d\t%d\n",
1700 al->vers, al->netid,
1701 al->success, al->failure);
1708 static char space_array[] = /* 64 spaces */
1711 if (howmany <= 0 || howmany > sizeof (space_array)) {
1714 return (&space_array[sizeof (space_array) - howmany - 1]);