3 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
4 * unrestricted use provided that this legend is included on all tape
5 * media and as a part of the software program in whole or part. Users
6 * may copy or modify Sun RPC without charge, but are not authorized
7 * to license or distribute it to anyone else except as part of a product or
8 * program developed by the user.
10 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
11 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
12 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 * Sun RPC is provided with no support and without any obligation on the
15 * part of Sun Microsystems, Inc. to assist in its use, correction,
16 * modification or enhancement.
18 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
19 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
20 * OR ANY PART THEREOF.
22 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
23 * or profits or other special, indirect and consequential damages, even if
24 * Sun has been advised of the possibility of such damages.
26 * Sun Microsystems, Inc.
28 * Mountain View, California 94043
30 * @(#)rpcinfo.c 1.18 93/07/05 SMI; 1.16 89/04/05 Copyr 1986 Sun Micro
31 * $NetBSD: rpcinfo.c,v 1.15 2000/10/04 20:09:05 mjl Exp $
32 * $FreeBSD: src/usr.bin/rpcinfo/rpcinfo.c,v 1.17 2004/03/11 10:22:25 bde Exp $
33 * $DragonFly: src/usr.bin/rpcinfo/rpcinfo.c,v 1.3 2007/11/25 01:28:23 swildner Exp $
37 * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
41 * rpcinfo: ping a particular rpc program
42 * or dump the the registered programs on the remote machine.
46 * We are for now defining PORTMAP here. It doesnt even compile
47 * unless it is defined.
54 * If PORTMAP is defined, rpcinfo will talk to both portmapper and
55 * rpcbind programs; else it talks only to rpcbind. In the latter case
56 * all the portmapper specific options such as -u, -t, -p become void.
58 #include <sys/types.h>
59 #include <sys/param.h>
60 #include <sys/socket.h>
64 #include <rpc/rpcb_prot.h>
65 #include <rpc/rpcent.h>
66 #include <rpc/nettype.h>
67 #include <rpc/rpc_com.h>
74 #ifdef PORTMAP /* Support for version 2 portmapper */
75 #include <netinet/in.h>
77 #include <arpa/inet.h>
78 #include <rpc/pmap_prot.h>
79 #include <rpc/pmap_clnt.h>
82 #define MAXHOSTLEN 256
83 #define MIN_VERS ((u_long) 0)
84 #define MAX_VERS ((u_long) 4294967295UL)
85 #define UNKNOWN "unknown"
88 * Functions to be performed.
90 #define NONE 0 /* no function */
91 #define PMAPDUMP 1 /* dump portmapper registrations */
92 #define TCPPING 2 /* ping TCP service */
93 #define UDPPING 3 /* ping UDP service */
94 #define BROADCAST 4 /* ping broadcast service */
95 #define DELETES 5 /* delete registration for the service */
96 #define ADDRPING 6 /* pings at the given address */
97 #define PROGPING 7 /* pings a program on a given host */
98 #define RPCBDUMP 8 /* dump rpcbind registrations */
99 #define RPCBDUMP_SHORT 9 /* dump rpcbind registrations - short version */
100 #define RPCBADDRLIST 10 /* dump addr list about one prog */
101 #define RPCBGETSTAT 11 /* Get statistics */
105 struct netidlist *next;
110 struct verslist *next;
113 struct rpcbdump_short {
115 struct verslist *vlist;
116 struct netidlist *nlist;
117 struct rpcbdump_short *next;
124 static void ip_ping(u_short, char *, int, char **);
125 static CLIENT *clnt_com_create(struct sockaddr_in *, u_long, u_long, int *,
127 static void pmapdump(int, char **);
128 static void get_inet_address(struct sockaddr_in *, char *);
131 static bool_t reply_proc(void *, struct netbuf *, struct netconfig *);
132 static void brdcst(int, char **);
133 static void addrping(char *, char *, int, char **);
134 static void progping(char *, int, char **);
135 static CLIENT *clnt_addr_create(char *, struct netconfig *, u_long, u_long);
136 static CLIENT *clnt_rpcbind_create(char *, int, struct netbuf **);
137 static CLIENT *getclnthandle(char *, struct netconfig *, u_long,
139 static CLIENT *local_rpcb(u_long, u_long);
140 static int pstatus(CLIENT *, u_long, u_long);
141 static void rpcbdump(int, char *, int, char **);
142 static void rpcbgetstat(int, char **);
143 static void rpcbaddrlist(char *, int, char **);
144 static void deletereg(char *, int, char **);
145 static void print_rmtcallstat(int, rpcb_stat *);
146 static void print_getaddrstat(int, rpcb_stat *);
147 static void usage(void);
148 static u_long getprognum(char *);
149 static u_long getvers(char *);
150 static char *spaces(int);
151 static bool_t add_version(struct rpcbdump_short *, u_long);
152 static bool_t add_netid(struct rpcbdump_short *, char *);
155 main(int argc, char **argv)
161 char *address = NULL;
170 while ((c = getopt(argc, argv, "a:bdlmn:pstT:u")) != -1) {
172 while ((c = getopt(argc, argv, "a:bdlmn:sT:")) != -1) {
177 if (function != NONE)
184 if (function != NONE)
191 if (function != NONE)
198 portnum = (u_short) strtol(optarg, &strptr, 10);
199 if (strptr == optarg || *strptr != '\0')
200 errx(1, "%s is illegal port number", optarg);
205 if (function != NONE)
211 if (function != NONE)
214 function = BROADCAST;
218 if (function != NONE)
225 if (function != NONE)
228 function = RPCBADDRLIST;
232 if (function != NONE)
235 function = RPCBGETSTAT;
239 if (function != NONE)
242 function = RPCBDUMP_SHORT;
254 if (errflg || ((function == ADDRPING) && !netid))
257 if (function == NONE) {
258 if (argc - optind > 1)
269 pmapdump(argc - optind, argv + optind);
273 ip_ping(portnum, "udp", argc - optind, argv + optind);
277 ip_ping(portnum, "tcp", argc - optind, argv + optind);
281 brdcst(argc - optind, argv + optind);
284 deletereg(netid, argc - optind, argv + optind);
287 addrping(address, netid, argc - optind, argv + optind);
290 progping(netid, argc - optind, argv + optind);
294 rpcbdump(function, netid, argc - optind, argv + optind);
297 rpcbgetstat(argc - optind, argv + optind);
300 rpcbaddrlist(netid, argc - optind, argv + optind);
307 local_rpcb(u_long prog, u_long vers)
310 struct netconfig *nconf;
313 localhandle = setnetconfig();
314 while ((nconf = getnetconfig(localhandle)) != NULL) {
315 if (nconf->nc_protofmly != NULL &&
316 strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
320 warnx("getnetconfig: %s", nc_sperror());
324 clnt = clnt_tp_create(NULL, prog, vers, nconf);
325 endnetconfig(localhandle);
331 clnt_com_create(struct sockaddr_in *addr, u_long prog, u_long vers,
332 int *fdp, char *trans)
336 if (strcmp(trans, "tcp") == 0) {
337 clnt = clnttcp_create(addr, prog, vers, fdp, 0, 0);
343 clnt = clntudp_create(addr, prog, vers, to, fdp);
346 clnt_pcreateerror("rpcinfo");
347 if (vers == MIN_VERS)
348 printf("program %lu is not available\n", prog);
350 printf("program %lu version %lu is not available\n",
358 * If portnum is 0, then go and get the address from portmapper, which happens
359 * transparently through clnt*_create(); If version number is not given, it
360 * tries to find out the version number by making a call to version 0 and if
361 * that fails, it obtains the high order and the low order version number. If
362 * version 0 calls succeeds, it tries for MAXVERS call and repeats the same.
365 ip_ping(u_short portnum, char *trans, int argc, char **argv)
370 struct sockaddr_in addr;
371 enum clnt_stat rpc_stat;
372 u_long prognum, vers, minvers, maxvers;
373 struct rpc_err rpcerr;
376 if (argc < 2 || argc > 3)
380 prognum = getprognum(argv[1]);
381 get_inet_address(&addr, argv[0]);
382 if (argc == 2) { /* Version number not known */
384 * A call to version 0 should fail with a program/version
385 * mismatch, and give us the range of versions supported.
389 vers = getvers(argv[2]);
391 addr.sin_port = htons(portnum);
392 client = clnt_com_create(&addr, prognum, vers, &fd, trans);
393 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
394 NULL, (xdrproc_t) xdr_void, NULL, to);
396 /* Version number was known */
397 if (pstatus(client, prognum, vers) < 0)
399 CLNT_DESTROY(client);
402 /* Version number not known */
403 CLNT_CONTROL(client, CLSET_FD_NCLOSE, NULL);
404 if (rpc_stat == RPC_PROGVERSMISMATCH) {
405 clnt_geterr(client, &rpcerr);
406 minvers = rpcerr.re_vers.low;
407 maxvers = rpcerr.re_vers.high;
408 } else if (rpc_stat == RPC_SUCCESS) {
410 * Oh dear, it DOES support version 0.
411 * Let's try version MAX_VERS.
413 CLNT_DESTROY(client);
414 addr.sin_port = htons(portnum);
415 client = clnt_com_create(&addr, prognum, MAX_VERS, &fd, trans);
416 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
417 NULL, (xdrproc_t) xdr_void, NULL, to);
418 if (rpc_stat == RPC_PROGVERSMISMATCH) {
419 clnt_geterr(client, &rpcerr);
420 minvers = rpcerr.re_vers.low;
421 maxvers = rpcerr.re_vers.high;
422 } else if (rpc_stat == RPC_SUCCESS) {
424 * It also supports version MAX_VERS.
425 * Looks like we have a wise guy.
426 * OK, we give them information on all
427 * 4 billion versions they support...
432 pstatus(client, prognum, MAX_VERS);
436 pstatus(client, prognum, (u_long)0);
439 CLNT_DESTROY(client);
440 for (vers = minvers; vers <= maxvers; vers++) {
441 addr.sin_port = htons(portnum);
442 client = clnt_com_create(&addr, prognum, vers, &fd, trans);
443 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
444 NULL, (xdrproc_t) xdr_void, NULL, to);
445 if (pstatus(client, prognum, vers) < 0)
447 CLNT_DESTROY(client);
456 * Dump all the portmapper registerations
459 pmapdump(int argc, char **argv)
461 struct sockaddr_in server_addr;
462 struct pmaplist *head = NULL;
463 int socket = RPC_ANYSOCK;
464 struct timeval minutetimeout;
467 enum clnt_stat clnt_st;
475 get_inet_address(&server_addr, host);
476 server_addr.sin_port = htons(PMAPPORT);
477 client = clnttcp_create(&server_addr, PMAPPROG, PMAPVERS,
480 client = local_rpcb(PMAPPROG, PMAPVERS);
482 if (client == NULL) {
483 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
485 * "Misc. TLI error" is not too helpful. Most likely
486 * the connection to the remote server timed out, so
487 * this error is at least less perplexing.
489 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
490 rpc_createerr.cf_error.re_status = RPC_FAILED;
492 clnt_pcreateerror("rpcinfo: can't contact portmapper");
496 minutetimeout.tv_sec = 60;
497 minutetimeout.tv_usec = 0;
499 clnt_st = CLNT_CALL(client, PMAPPROC_DUMP, (xdrproc_t) xdr_void,
500 NULL, (xdrproc_t) xdr_pmaplist_ptr, (char *)&head,
502 if (clnt_st != RPC_SUCCESS) {
503 if ((clnt_st == RPC_PROGVERSMISMATCH) ||
504 (clnt_st == RPC_PROGUNAVAIL)) {
505 CLNT_GETERR(client, &err);
506 if (err.re_vers.low > PMAPVERS)
508 "%s does not support portmapper. Try rpcinfo %s instead",
512 clnt_perror(client, "rpcinfo: can't contact portmapper");
516 printf("No remote programs registered.\n");
518 printf(" program vers proto port service\n");
519 for (; head != NULL; head = head->pml_next) {
521 head->pml_map.pm_prog,
522 head->pml_map.pm_vers);
523 if (head->pml_map.pm_prot == IPPROTO_UDP)
524 printf("%6s", "udp");
525 else if (head->pml_map.pm_prot == IPPROTO_TCP)
526 printf("%6s", "tcp");
527 else if (head->pml_map.pm_prot == IPPROTO_ST)
528 printf("%6s", "local");
530 printf("%6ld", head->pml_map.pm_prot);
531 printf("%7ld", head->pml_map.pm_port);
532 rpc = getrpcbynumber(head->pml_map.pm_prog);
534 printf(" %s\n", rpc->r_name);
542 get_inet_address(struct sockaddr_in *addr, char *host)
544 struct netconfig *nconf;
545 struct addrinfo hints, *res;
548 memset((char *)addr, 0, sizeof (*addr));
549 addr->sin_addr.s_addr = inet_addr(host);
550 if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
551 if ((nconf = __rpc_getconfip("udp")) == NULL &&
552 (nconf = __rpc_getconfip("tcp")) == NULL)
553 errx(1, "couldn't find a suitable transport");
555 memset(&hints, 0, sizeof hints);
556 hints.ai_family = AF_INET;
557 if ((error = getaddrinfo(host, "rpcbind", &hints, &res))
559 errx(1, "%s: %s", host, gai_strerror(error));
561 memcpy(addr, res->ai_addr, res->ai_addrlen);
564 freenetconfigent(nconf);
567 addr->sin_family = AF_INET;
573 * reply_proc collects replies from the broadcast.
574 * to get a unique list of responses the output of rpcinfo should
575 * be piped through sort(1) and then uniq(1).
580 reply_proc(void *res, struct netbuf *who, struct netconfig *nconf)
581 /* void *res; Nothing comes back */
582 /* struct netbuf *who; Who sent us the reply */
583 /* struct netconfig *nconf; On which transport the reply came */
586 char hostbuf[NI_MAXHOST];
588 struct sockaddr *sa = (struct sockaddr *)who->buf;
590 if (getnameinfo(sa, sa->sa_len, hostbuf, NI_MAXHOST, NULL, 0, 0)) {
595 if (!(uaddr = taddr2uaddr(nconf, who))) {
598 printf("%s\t%s\n", uaddr, hostname);
599 if (strcmp(uaddr, UNKNOWN))
605 brdcst(int argc, char **argv)
607 enum clnt_stat rpc_stat;
608 u_long prognum, vers;
612 prognum = getprognum(argv[0]);
613 vers = getvers(argv[1]);
614 rpc_stat = rpc_broadcast(prognum, vers, NULLPROC,
615 (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_void,
616 NULL, (resultproc_t) reply_proc, NULL);
617 if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT))
618 errx(1, "broadcast failed: %s", clnt_sperrno(rpc_stat));
623 add_version(struct rpcbdump_short *rs, u_long vers)
627 for (vl = rs->vlist; vl; vl = vl->next)
628 if (vl->vers == vers)
632 vl = (struct verslist *)malloc(sizeof (struct verslist));
636 vl->next = rs->vlist;
642 add_netid(struct rpcbdump_short *rs, char *netid)
644 struct netidlist *nl;
646 for (nl = rs->nlist; nl; nl = nl->next)
647 if (strcmp(nl->netid, netid) == 0)
651 nl = (struct netidlist *)malloc(sizeof (struct netidlist));
655 nl->next = rs->nlist;
661 rpcbdump(int dumptype, char *netid, int argc, char **argv)
663 rpcblist_ptr head = NULL;
664 struct timeval minutetimeout;
668 struct netidlist *nl;
670 struct rpcbdump_short *rs, *rs_tail;
672 enum clnt_stat clnt_st;
674 struct rpcbdump_short *rs_head = NULL;
681 client = clnt_rpcbind_create(host, RPCBVERS, NULL);
683 struct netconfig *nconf;
685 nconf = getnetconfigent(netid);
687 nc_perror("rpcinfo: invalid transport");
690 client = getclnthandle(host, nconf, RPCBVERS, NULL);
692 freenetconfigent(nconf);
695 client = local_rpcb(PMAPPROG, RPCBVERS);
697 if (client == NULL) {
698 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
702 minutetimeout.tv_sec = 60;
703 minutetimeout.tv_usec = 0;
704 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t) xdr_void,
705 NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
707 if (clnt_st != RPC_SUCCESS) {
708 if ((clnt_st == RPC_PROGVERSMISMATCH) ||
709 (clnt_st == RPC_PROGUNAVAIL)) {
712 CLNT_GETERR(client, &err);
713 if (err.re_vers.low == RPCBVERS4) {
715 clnt_control(client, CLSET_VERS, (char *)&vers);
716 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
717 (xdrproc_t) xdr_void, NULL,
718 (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
720 if (clnt_st != RPC_SUCCESS)
723 if (err.re_vers.high == PMAPVERS) {
725 struct pmaplist *pmaphead = NULL;
726 rpcblist_ptr list, prev;
729 clnt_control(client, CLSET_VERS, (char *)&vers);
730 clnt_st = CLNT_CALL(client, PMAPPROC_DUMP,
731 (xdrproc_t) xdr_void, NULL,
732 (xdrproc_t) xdr_pmaplist_ptr,
733 (char *)&pmaphead, minutetimeout);
734 if (clnt_st != RPC_SUCCESS)
737 * convert to rpcblist_ptr format
739 for (head = NULL; pmaphead != NULL;
740 pmaphead = pmaphead->pml_next) {
741 list = (rpcblist *)malloc(sizeof (rpcblist));
747 prev->rpcb_next = (rpcblist_ptr) list;
749 list->rpcb_next = NULL;
750 list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog;
751 list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers;
752 if (pmaphead->pml_map.pm_prot == IPPROTO_UDP)
753 list->rpcb_map.r_netid = "udp";
754 else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP)
755 list->rpcb_map.r_netid = "tcp";
757 #define MAXLONG_AS_STRING "2147483648"
758 list->rpcb_map.r_netid =
759 malloc(strlen(MAXLONG_AS_STRING) + 1);
760 if (list->rpcb_map.r_netid == NULL)
762 sprintf(list->rpcb_map.r_netid, "%6ld",
763 pmaphead->pml_map.pm_prot);
765 list->rpcb_map.r_owner = UNKNOWN;
766 low = pmaphead->pml_map.pm_port & 0xff;
767 high = (pmaphead->pml_map.pm_port >> 8) & 0xff;
768 list->rpcb_map.r_addr = strdup("0.0.0.0.XXX.XXX");
769 sprintf(&list->rpcb_map.r_addr[8], "%d.%d",
775 } else { /* any other error */
777 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
782 printf("No remote programs registered.\n");
783 } else if (dumptype == RPCBDUMP) {
785 " program version netid address service owner\n");
786 for (; head != NULL; head = head->rpcb_next) {
788 head->rpcb_map.r_prog, head->rpcb_map.r_vers);
789 printf("%-9s ", head->rpcb_map.r_netid);
790 printf("%-22s", head->rpcb_map.r_addr);
791 rpc = getrpcbynumber(head->rpcb_map.r_prog);
793 printf(" %-10s", rpc->r_name);
795 printf(" %-10s", "-");
796 printf(" %s\n", head->rpcb_map.r_owner);
798 } else if (dumptype == RPCBDUMP_SHORT) {
799 for (; head != NULL; head = head->rpcb_next) {
800 for (rs = rs_head; rs; rs = rs->next)
801 if (head->rpcb_map.r_prog == rs->prog)
804 rs = (struct rpcbdump_short *)
805 malloc(sizeof (struct rpcbdump_short));
809 if (rs_head == NULL) {
816 rs->prog = head->rpcb_map.r_prog;
817 rs->owner = head->rpcb_map.r_owner;
821 if (add_version(rs, head->rpcb_map.r_vers) == FALSE)
823 if (add_netid(rs, head->rpcb_map.r_netid) == FALSE)
827 " program version(s) netid(s) service owner\n");
828 for (rs = rs_head; rs; rs = rs->next) {
831 printf("%10ld ", rs->prog);
832 for (vl = rs->vlist; vl; vl = vl->next) {
833 sprintf(p, "%d", vl->vers);
838 printf("%-10s", buf);
840 for (nl = rs->nlist; nl; nl = nl->next) {
841 strcat(buf, nl->netid);
845 printf("%-32s", buf);
846 rpc = getrpcbynumber(rs->prog);
848 printf(" %-11s", rpc->r_name);
850 printf(" %-11s", "-");
851 printf(" %s\n", rs->owner);
854 clnt_destroy(client);
856 error: warnx("no memory");
860 static char nullstring[] = "\000";
863 rpcbaddrlist(char *netid, int argc, char **argv)
865 rpcb_entry_list_ptr head = NULL;
866 struct timeval minutetimeout;
871 struct netbuf *targaddr;
877 client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr);
879 struct netconfig *nconf;
881 nconf = getnetconfigent(netid);
883 nc_perror("rpcinfo: invalid transport");
886 client = getclnthandle(host, nconf, RPCBVERS4, &targaddr);
888 freenetconfigent(nconf);
890 if (client == NULL) {
891 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
894 minutetimeout.tv_sec = 60;
895 minutetimeout.tv_usec = 0;
897 parms.r_prog = getprognum(argv[1]);
898 parms.r_vers = getvers(argv[2]);
899 parms.r_netid = client->cl_netid;
900 if (targaddr == NULL) {
901 parms.r_addr = nullstring; /* for XDRing */
904 * We also send the remote system the address we
905 * used to contact it in case it can help it
906 * connect back with us
908 struct netconfig *nconf;
910 nconf = getnetconfigent(client->cl_netid);
912 parms.r_addr = taddr2uaddr(nconf, targaddr);
913 if (parms.r_addr == NULL)
914 parms.r_addr = nullstring;
915 freenetconfigent(nconf);
917 parms.r_addr = nullstring; /* for XDRing */
922 parms.r_owner = nullstring;
924 if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb,
925 (char *) &parms, (xdrproc_t) xdr_rpcb_entry_list_ptr,
926 (char *) &head, minutetimeout) != RPC_SUCCESS) {
927 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
931 printf("No remote programs registered.\n");
934 " program vers tp_family/name/class address\t\t service\n");
935 for (; head != NULL; head = head->rpcb_entry_next) {
939 re = &head->rpcb_entry_map;
941 parms.r_prog, parms.r_vers);
942 sprintf(buf, "%s/%s/%s ",
943 re->r_nc_protofmly, re->r_nc_proto,
944 re->r_nc_semantics == NC_TPI_CLTS ? "clts" :
945 re->r_nc_semantics == NC_TPI_COTS ? "cots" :
947 printf("%-24s", buf);
948 printf("%-24s", re->r_maddr);
949 rpc = getrpcbynumber(parms.r_prog);
951 printf(" %-13s", rpc->r_name);
953 printf(" %-13s", "-");
957 clnt_destroy(client);
965 rpcbgetstat(int argc, char **argv)
967 rpcb_stat_byvers inf;
968 struct timeval minutetimeout;
973 rpcbs_rmtcalllist *pr;
976 char fieldbuf[MAXFIELD];
978 char linebuf[MAXLINE];
981 "NULL", "SET", "UNSET", "GETPORT",
985 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
989 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
990 "U2T", "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT"
997 client = clnt_rpcbind_create(host, RPCBVERS4, NULL);
999 client = local_rpcb(PMAPPROG, RPCBVERS4);
1000 if (client == NULL) {
1001 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
1004 minutetimeout.tv_sec = 60;
1005 minutetimeout.tv_usec = 0;
1006 memset((char *)&inf, 0, sizeof (rpcb_stat_byvers));
1007 if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t) xdr_void, NULL,
1008 (xdrproc_t) xdr_rpcb_stat_byvers, (char *)&inf, minutetimeout)
1010 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
1013 printf("PORTMAP (version 2) statistics\n");
1015 for (i = 0; i <= rpcb_highproc_2; i++) {
1019 sprintf(fieldbuf, "%d/", inf[RPCBVERS_2_STAT].setinfo);
1021 case PMAPPROC_UNSET:
1022 sprintf(fieldbuf, "%d/",
1023 inf[RPCBVERS_2_STAT].unsetinfo);
1025 case PMAPPROC_GETPORT:
1027 for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa;
1030 sprintf(fieldbuf, "%d/", cnt);
1032 case PMAPPROC_CALLIT:
1034 for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr;
1037 sprintf(fieldbuf, "%d/", cnt);
1039 default: break; /* For the remaining ones */
1041 cp = &fieldbuf[0] + strlen(fieldbuf);
1042 sprintf(cp, "%d", inf[RPCBVERS_2_STAT].info[i]);
1043 flen = strlen(fieldbuf);
1044 printf("%s%s", pmaphdr[i],
1045 spaces((TABSTOP * (1 + flen / TABSTOP))
1046 - strlen(pmaphdr[i])));
1047 sprintf(lp, "%s%s", fieldbuf,
1048 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1052 printf("\n%s\n\n", linebuf);
1054 if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) {
1055 printf("PMAP_RMTCALL call statistics\n");
1056 print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1060 if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) {
1061 printf("PMAP_GETPORT call statistics\n");
1062 print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1066 printf("RPCBIND (version 3) statistics\n");
1068 for (i = 0; i <= rpcb_highproc_3; i++) {
1072 sprintf(fieldbuf, "%d/", inf[RPCBVERS_3_STAT].setinfo);
1074 case RPCBPROC_UNSET:
1075 sprintf(fieldbuf, "%d/",
1076 inf[RPCBVERS_3_STAT].unsetinfo);
1078 case RPCBPROC_GETADDR:
1080 for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa;
1083 sprintf(fieldbuf, "%d/", cnt);
1085 case RPCBPROC_CALLIT:
1087 for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr;
1090 sprintf(fieldbuf, "%d/", cnt);
1092 default: break; /* For the remaining ones */
1094 cp = &fieldbuf[0] + strlen(fieldbuf);
1095 sprintf(cp, "%d", inf[RPCBVERS_3_STAT].info[i]);
1096 flen = strlen(fieldbuf);
1097 printf("%s%s", rpcb3hdr[i],
1098 spaces((TABSTOP * (1 + flen / TABSTOP))
1099 - strlen(rpcb3hdr[i])));
1100 sprintf(lp, "%s%s", fieldbuf,
1101 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1105 printf("\n%s\n\n", linebuf);
1107 if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) {
1108 printf("RPCB_RMTCALL (version 3) call statistics\n");
1109 print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1113 if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) {
1114 printf("RPCB_GETADDR (version 3) call statistics\n");
1115 print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1119 printf("RPCBIND (version 4) statistics\n");
1121 for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */
1123 for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) {
1127 sprintf(fieldbuf, "%d/",
1128 inf[RPCBVERS_4_STAT].setinfo);
1130 case RPCBPROC_UNSET:
1131 sprintf(fieldbuf, "%d/",
1132 inf[RPCBVERS_4_STAT].unsetinfo);
1134 case RPCBPROC_GETADDR:
1136 for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa;
1139 sprintf(fieldbuf, "%d/", cnt);
1141 case RPCBPROC_CALLIT:
1143 for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr;
1146 sprintf(fieldbuf, "%d/", cnt);
1148 default: break; /* For the remaining ones */
1150 cp = &fieldbuf[0] + strlen(fieldbuf);
1152 * XXX: We also add RPCBPROC_GETADDRLIST queries to
1153 * RPCB_GETADDR because rpcbind includes the
1154 * RPCB_GETADDRLIST successes in RPCB_GETADDR.
1156 if (i != RPCBPROC_GETADDR)
1157 sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i]);
1159 sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i] +
1160 inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]);
1161 flen = strlen(fieldbuf);
1162 printf("%s%s", rpcb4hdr[i],
1163 spaces((TABSTOP * (1 + flen / TABSTOP))
1164 - strlen(rpcb4hdr[i])));
1165 sprintf(lp, "%s%s", fieldbuf,
1166 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1170 printf("\n%s\n", linebuf);
1173 if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] ||
1174 inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) {
1176 printf("RPCB_RMTCALL (version 4) call statistics\n");
1177 print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1180 if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) {
1182 printf("RPCB_GETADDR (version 4) call statistics\n");
1183 print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1185 clnt_destroy(client);
1189 * Delete registeration for this (prog, vers, netid)
1192 deletereg(char *netid, int argc, char **argv)
1194 struct netconfig *nconf = NULL;
1199 nconf = getnetconfigent(netid);
1201 errx(1, "netid %s not supported", netid);
1203 if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0)
1205 "could not delete registration for prog %s version %s",
1210 * Create and return a handle for the given nconf.
1211 * Exit if cannot create handle.
1214 clnt_addr_create(char *address, struct netconfig *nconf,
1215 u_long prog, u_long vers)
1218 static struct netbuf *nbuf;
1219 static int fd = RPC_ANYFD;
1221 if (fd == RPC_ANYFD) {
1222 if ((fd = __rpc_nconf2fd(nconf)) == -1) {
1223 rpc_createerr.cf_stat = RPC_TLIERROR;
1224 clnt_pcreateerror("rpcinfo");
1227 /* Convert the uaddr to taddr */
1228 nbuf = uaddr2taddr(nconf, address);
1230 errx(1, "no address for client handle");
1232 client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0);
1233 if (client == NULL) {
1234 clnt_pcreateerror("rpcinfo");
1241 * If the version number is given, ping that (prog, vers); else try to find
1242 * the version numbers supported for that prog and ping all the versions.
1243 * Remote rpcbind is not contacted for this service. The requests are
1244 * sent directly to the services themselves.
1247 addrping(char *address, char *netid, int argc, char **argv)
1251 enum clnt_stat rpc_stat;
1252 u_long prognum, versnum, minvers, maxvers;
1253 struct rpc_err rpcerr;
1255 struct netconfig *nconf;
1258 if (argc < 1 || argc > 2 || (netid == NULL))
1260 nconf = getnetconfigent(netid);
1262 errx(1, "could not find %s", netid);
1265 prognum = getprognum(argv[0]);
1266 if (argc == 1) { /* Version number not known */
1268 * A call to version 0 should fail with a program/version
1269 * mismatch, and give us the range of versions supported.
1273 versnum = getvers(argv[1]);
1275 client = clnt_addr_create(address, nconf, prognum, versnum);
1276 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1277 NULL, (xdrproc_t) xdr_void, NULL, to);
1279 /* Version number was known */
1280 if (pstatus(client, prognum, versnum) < 0)
1282 CLNT_DESTROY(client);
1287 /* Version number not known */
1288 CLNT_CONTROL(client, CLSET_FD_NCLOSE, NULL);
1289 CLNT_CONTROL(client, CLGET_FD, (char *)&fd);
1290 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1291 clnt_geterr(client, &rpcerr);
1292 minvers = rpcerr.re_vers.low;
1293 maxvers = rpcerr.re_vers.high;
1294 } else if (rpc_stat == RPC_SUCCESS) {
1296 * Oh dear, it DOES support version 0.
1297 * Let's try version MAX_VERS.
1299 CLNT_DESTROY(client);
1300 client = clnt_addr_create(address, nconf, prognum, MAX_VERS);
1301 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1302 NULL, (xdrproc_t) xdr_void, NULL, to);
1303 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1304 clnt_geterr(client, &rpcerr);
1305 minvers = rpcerr.re_vers.low;
1306 maxvers = rpcerr.re_vers.high;
1307 } else if (rpc_stat == RPC_SUCCESS) {
1309 * It also supports version MAX_VERS.
1310 * Looks like we have a wise guy.
1311 * OK, we give them information on all
1312 * 4 billion versions they support...
1317 pstatus(client, prognum, MAX_VERS);
1321 pstatus(client, prognum, (u_long)0);
1324 CLNT_DESTROY(client);
1325 for (versnum = minvers; versnum <= maxvers; versnum++) {
1326 client = clnt_addr_create(address, nconf, prognum, versnum);
1327 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1328 NULL, (xdrproc_t) xdr_void, NULL, to);
1329 if (pstatus(client, prognum, versnum) < 0)
1331 CLNT_DESTROY(client);
1340 * If the version number is given, ping that (prog, vers); else try to find
1341 * the version numbers supported for that prog and ping all the versions.
1342 * Remote rpcbind is *contacted* for this service. The requests are
1343 * then sent directly to the services themselves.
1346 progping(char *netid, int argc, char **argv)
1350 enum clnt_stat rpc_stat;
1351 u_long prognum, versnum, minvers, maxvers;
1352 struct rpc_err rpcerr;
1354 struct netconfig *nconf;
1356 if (argc < 2 || argc > 3 || (netid == NULL))
1358 prognum = getprognum(argv[1]);
1359 if (argc == 2) { /* Version number not known */
1361 * A call to version 0 should fail with a program/version
1362 * mismatch, and give us the range of versions supported.
1366 versnum = getvers(argv[2]);
1369 nconf = getnetconfigent(netid);
1371 errx(1, "could not find %s", netid);
1372 client = clnt_tp_create(argv[0], prognum, versnum, nconf);
1374 client = clnt_create(argv[0], prognum, versnum, "NETPATH");
1376 if (client == NULL) {
1377 clnt_pcreateerror("rpcinfo");
1382 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1383 NULL, (xdrproc_t) xdr_void, NULL, to);
1385 /* Version number was known */
1386 if (pstatus(client, prognum, versnum) < 0)
1388 CLNT_DESTROY(client);
1393 /* Version number not known */
1394 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1395 clnt_geterr(client, &rpcerr);
1396 minvers = rpcerr.re_vers.low;
1397 maxvers = rpcerr.re_vers.high;
1398 } else if (rpc_stat == RPC_SUCCESS) {
1400 * Oh dear, it DOES support version 0.
1401 * Let's try version MAX_VERS.
1404 CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1405 rpc_stat = CLNT_CALL(client, NULLPROC,
1406 (xdrproc_t) xdr_void, NULL,
1407 (xdrproc_t) xdr_void, NULL, to);
1408 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1409 clnt_geterr(client, &rpcerr);
1410 minvers = rpcerr.re_vers.low;
1411 maxvers = rpcerr.re_vers.high;
1412 } else if (rpc_stat == RPC_SUCCESS) {
1414 * It also supports version MAX_VERS.
1415 * Looks like we have a wise guy.
1416 * OK, we give them information on all
1417 * 4 billion versions they support...
1422 pstatus(client, prognum, MAX_VERS);
1426 pstatus(client, prognum, (u_long)0);
1429 for (versnum = minvers; versnum <= maxvers; versnum++) {
1430 CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1431 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1432 NULL, (xdrproc_t) xdr_void, NULL, to);
1433 if (pstatus(client, prognum, versnum) < 0)
1436 CLNT_DESTROY(client);
1445 fprintf(stderr, "usage: rpcinfo [-m | -s] [host]\n");
1447 fprintf(stderr, " rpcinfo -p [host]\n");
1449 fprintf(stderr, " rpcinfo -T netid host prognum [versnum]\n");
1450 fprintf(stderr, " rpcinfo -l host prognum versnum\n");
1453 " rpcinfo [-n portnum] -u | -t host prognum [versnum]\n");
1456 " rpcinfo -a serv_address -T netid prognum [version]\n");
1457 fprintf(stderr, " rpcinfo -b prognum versnum\n");
1458 fprintf(stderr, " rpcinfo -d [-T netid] prognum versnum\n");
1463 getprognum(char *arg)
1470 while (*tptr && isdigit(*tptr++));
1471 if (*tptr || isalpha(*(tptr - 1))) {
1472 rpc = getrpcbyname(arg);
1474 errx(1, "%s is unknown service", arg);
1475 prognum = rpc->r_number;
1477 prognum = strtol(arg, &strptr, 10);
1478 if (strptr == arg || *strptr != '\0')
1479 errx(1, "%s is illegal program number", arg);
1490 vers = (int) strtol(arg, &strptr, 10);
1491 if (strptr == arg || *strptr != '\0')
1492 errx(1, "%s is illegal version number", arg);
1497 * This routine should take a pointer to an "rpc_err" structure, rather than
1498 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
1499 * a CLIENT structure rather than a pointer to an "rpc_err" structure.
1500 * As such, we have to keep the CLIENT structure around in order to print
1501 * a good error message.
1504 pstatus(CLIENT *client, u_long prog, u_long vers)
1506 struct rpc_err rpcerr;
1508 clnt_geterr(client, &rpcerr);
1509 if (rpcerr.re_status != RPC_SUCCESS) {
1510 clnt_perror(client, "rpcinfo");
1511 printf("program %lu version %lu is not available\n",
1515 printf("program %lu version %lu ready and waiting\n",
1522 clnt_rpcbind_create(char *host, int rpcbversnum, struct netbuf **targaddr)
1524 static char *tlist[3] = {
1525 "circuit_n", "circuit_v", "datagram_v"
1528 struct netconfig *nconf;
1529 CLIENT *clnt = NULL;
1532 rpc_createerr.cf_stat = RPC_SUCCESS;
1533 for (i = 0; i < 3; i++) {
1534 if ((handle = __rpc_setconf(tlist[i])) == NULL)
1536 while (clnt == NULL) {
1537 if ((nconf = __rpc_getconf(handle)) == NULL) {
1538 if (rpc_createerr.cf_stat == RPC_SUCCESS)
1539 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1542 clnt = getclnthandle(host, nconf, rpcbversnum,
1547 __rpc_endconf(handle);
1553 getclnthandle(char *host, struct netconfig *nconf,
1554 u_long rpcbversnum, struct netbuf **targaddr)
1557 struct addrinfo hints, *res;
1558 CLIENT *client = NULL;
1560 /* Get the address of the rpcbind */
1561 memset(&hints, 0, sizeof hints);
1562 if (getaddrinfo(host, "rpcbind", &hints, &res) != 0) {
1563 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
1566 addr.len = addr.maxlen = res->ai_addrlen;
1567 addr.buf = res->ai_addr;
1568 client = clnt_tli_create(RPC_ANYFD, nconf, &addr, RPCBPROG,
1571 if (targaddr != NULL) {
1573 (struct netbuf *)malloc(sizeof (struct netbuf));
1574 if (*targaddr != NULL) {
1575 (*targaddr)->maxlen = addr.maxlen;
1576 (*targaddr)->len = addr.len;
1577 (*targaddr)->buf = (char *)malloc(addr.len);
1578 if ((*targaddr)->buf != NULL) {
1579 memcpy((*targaddr)->buf, addr.buf,
1585 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1587 * Assume that the other system is dead; this is a
1588 * better error to display to the user.
1590 rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1591 rpc_createerr.cf_error.re_status = RPC_FAILED;
1599 print_rmtcallstat(int rtype, rpcb_stat *infp)
1601 rpcbs_rmtcalllist_ptr pr;
1604 if (rtype == RPCBVERS_4_STAT)
1606 "prog\t\tvers\tproc\tnetid\tindirect success failure\n");
1608 printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n");
1609 for (pr = infp->rmtinfo; pr; pr = pr->next) {
1610 rpc = getrpcbynumber(pr->prog);
1612 printf("%-16s", rpc->r_name);
1614 printf("%-16d", pr->prog);
1615 printf("%d\t%d\t%s\t",
1616 pr->vers, pr->proc, pr->netid);
1617 if (rtype == RPCBVERS_4_STAT)
1618 printf("%d\t ", pr->indirect);
1619 printf("%d\t%d\n", pr->success, pr->failure);
1624 print_getaddrstat(int rtype, rpcb_stat *infp)
1626 rpcbs_addrlist_ptr al;
1629 printf("prog\t\tvers\tnetid\t success\tfailure\n");
1630 for (al = infp->addrinfo; al; al = al->next) {
1631 rpc = getrpcbynumber(al->prog);
1633 printf("%-16s", rpc->r_name);
1635 printf("%-16d", al->prog);
1636 printf("%d\t%s\t %-12d\t%d\n",
1637 al->vers, al->netid,
1638 al->success, al->failure);
1645 static char space_array[] = /* 64 spaces */
1648 if (howmany <= 0 || howmany > sizeof (space_array)) {
1651 return (&space_array[sizeof (space_array) - howmany - 1]);