dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / rpcinfo / rpcinfo.c
blob0f93d2678fea84587aec16356a5bfd1b29bc8719
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
30 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
31 /* All Rights Reserved */
33 * University Copyright- Copyright (c) 1982, 1986, 1988
34 * The Regents of the University of California
35 * All Rights Reserved
37 * University Acknowledgment- Portions of this document are derived from
38 * software developed by the University of California, Berkeley, and its
39 * contributors.
43 * rpcinfo: ping a particular rpc program
44 * or dump the the registered programs on the remote machine.
48 * We are for now defining PORTMAP here. It doesn't even compile
49 * unless it is defined.
51 #ifndef PORTMAP
52 #define PORTMAP
53 #endif
56 * If PORTMAP is defined, rpcinfo will talk to both portmapper and
57 * rpcbind programs; else it talks only to rpcbind. In the latter case
58 * all the portmapper specific options such as -u, -t, -p become void.
60 #include <rpc/rpc.h>
61 #include <stdio.h>
62 #include <rpc/rpcb_prot.h>
63 #include <rpc/nettype.h>
64 #include <netdir.h>
65 #include <rpc/rpcent.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <ctype.h>
70 #ifdef PORTMAP /* Support for version 2 portmapper */
71 #include <netinet/in.h>
72 #include <sys/socket.h>
73 #include <netdb.h>
74 #include <arpa/inet.h>
75 #include <rpc/pmap_prot.h>
76 #include <rpc/pmap_clnt.h>
77 #endif
79 #define MAXHOSTLEN 256
80 #define MIN_VERS ((ulong_t)0)
81 #define MAX_VERS (4294967295UL)
82 #define UNKNOWN "unknown"
84 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
86 extern int t_errno;
87 extern long strtol();
88 static char *spaces();
90 #ifdef PORTMAP
91 static void ip_ping(/*ushort_t portflag, char *trans,
92 int argc, char **argv*/);
93 static CLIENT *clnt_com_create(/* struct sockaddr_in *addr, long prog,
94 long vers, int *fd, char *trans*/);
95 static void pmapdump(/*int argc, char **argv*/);
96 static void get_inet_address(/*struct sockaddr_in *addr, char *host*/);
97 #endif
99 static bool_t reply_proc(/*void *res, struct netbuf *who*,
100 struct netconfig *nconf*/);
101 static void brdcst(/*int argc, char **argv*/);
102 static void addrping(/*char *address, char *netid,
103 int argc, char **argv*/);
104 static void progping(/* char *netid, int argc, char **argv*/);
105 static CLIENT *clnt_addr_create(/* char *addr, struct netconfig *nconf,
106 long prog, long vers*/);
107 static CLIENT *clnt_rpcbind_create(/* char *host, int vers */);
108 static CLIENT *getclnthandle(/* host, nconf, rpcbversnum */);
109 static int pstatus(/*CLIENT *client, ulong_t prognum, ulong_t vers*/);
110 static void rpcbdump(/*char *netid, int argc, char **argv*/);
111 static void rpcbgetstat(/* int argc, char **argv*/);
112 static void rpcbaddrlist(/*char *netid, int argc, char **argv*/);
113 static void deletereg(/*char *netid, int argc, char **argv */);
114 static void print_rmtcallstat(/* rtype, infp */);
115 static void print_getaddrstat(/* rtype, infp */);
116 static void usage(/*void*/);
117 static ulong_t getprognum(/*char *arg*/);
118 static ulong_t getvers(/*char *arg*/);
121 * Functions to be performed.
123 #define NONE 0 /* no function */
124 #define PMAPDUMP 1 /* dump portmapper registrations */
125 #define TCPPING 2 /* ping TCP service */
126 #define UDPPING 3 /* ping UDP service */
127 #define BROADCAST 4 /* ping broadcast service */
128 #define DELETES 5 /* delete registration for the service */
129 #define ADDRPING 6 /* pings at the given address */
130 #define PROGPING 7 /* pings a program on a given host */
131 #define RPCBDUMP 8 /* dump rpcbind registrations */
132 #define RPCBDUMP_SHORT 9 /* dump rpcbind registrations - short version */
133 #define RPCBADDRLIST 10 /* dump addr list about one prog */
134 #define RPCBGETSTAT 11 /* Get statistics */
136 struct netidlist {
137 char *netid;
138 struct netidlist *next;
141 struct verslist {
142 int vers;
143 struct verslist *next;
146 struct rpcbdump_short {
147 ulong_t prog;
148 struct verslist *vlist;
149 struct netidlist *nlist;
150 struct rpcbdump_short *next;
151 char *owner;
155 char *loopback_netid = NULL;
156 struct netconfig *loopback_nconf;
159 main(argc, argv)
160 int argc;
161 char **argv;
163 register int c;
164 extern char *optarg;
165 extern int optind;
166 int errflg;
167 int function;
168 char *netid = NULL;
169 char *address = NULL;
170 void *handle;
171 #ifdef PORTMAP
172 char *strptr;
173 ushort_t portnum = 0;
174 #endif
176 function = NONE;
177 errflg = 0;
178 #ifdef PORTMAP
179 while ((c = getopt(argc, argv, "a:bdlmn:pstT:u")) != EOF) {
180 #else
181 while ((c = getopt(argc, argv, "a:bdlmn:sT:")) != EOF) {
182 #endif
183 switch (c) {
184 #ifdef PORTMAP
185 case 'p':
186 if (function != NONE)
187 errflg = 1;
188 else
189 function = PMAPDUMP;
190 break;
192 case 't':
193 if (function != NONE)
194 errflg = 1;
195 else
196 function = TCPPING;
197 break;
199 case 'u':
200 if (function != NONE)
201 errflg = 1;
202 else
203 function = UDPPING;
204 break;
206 case 'n':
207 portnum = (ushort_t)strtol(optarg, &strptr, 10);
208 if (strptr == optarg || *strptr != '\0') {
209 (void) fprintf(stderr,
210 "rpcinfo: %s is illegal port number\n",
211 optarg);
212 exit(1);
214 break;
215 #endif
216 case 'a':
217 address = optarg;
218 if (function != NONE)
219 errflg = 1;
220 else
221 function = ADDRPING;
222 break;
223 case 'b':
224 if (function != NONE)
225 errflg = 1;
226 else
227 function = BROADCAST;
228 break;
230 case 'd':
231 if (function != NONE)
232 errflg = 1;
233 else
234 function = DELETES;
235 break;
237 case 'l':
238 if (function != NONE)
239 errflg = 1;
240 else
241 function = RPCBADDRLIST;
242 break;
244 case 'm':
245 if (function != NONE)
246 errflg = 1;
247 else
248 function = RPCBGETSTAT;
249 break;
251 case 's':
252 if (function != NONE)
253 errflg = 1;
254 else
255 function = RPCBDUMP_SHORT;
256 break;
258 case 'T':
259 netid = optarg;
260 break;
261 case '?':
262 errflg = 1;
263 break;
267 if (errflg || ((function == ADDRPING) && !netid)) {
268 usage();
269 return (1);
271 if (netid == NULL) { /* user has not selected transport to use */
273 * See if a COTS loopback transport is available, in case we
274 * will be talking to the local system.
276 handle = setnetconfig();
277 while ((loopback_nconf = getnetconfig(handle)) != NULL) {
278 if (strcmp(loopback_nconf->nc_protofmly,
279 NC_LOOPBACK) == 0 &&
280 (loopback_nconf->nc_semantics == NC_TPI_COTS ||
281 loopback_nconf->nc_semantics == NC_TPI_COTS_ORD)) {
282 loopback_netid = loopback_nconf->nc_netid;
283 break;
286 if (loopback_netid == NULL) {
287 (void) endnetconfig(handle);
290 if (function == NONE) {
291 if (argc - optind > 1)
292 function = PROGPING;
293 else
294 function = RPCBDUMP;
297 switch (function) {
298 #ifdef PORTMAP
299 case PMAPDUMP:
300 if (portnum != 0) {
301 usage();
302 return (1);
304 pmapdump(argc - optind, argv + optind);
305 break;
307 case UDPPING:
308 ip_ping(portnum, "udp", argc - optind, argv + optind);
309 break;
311 case TCPPING:
312 ip_ping(portnum, "tcp", argc - optind, argv + optind);
313 break;
314 #endif
315 case BROADCAST:
316 brdcst(argc - optind, argv + optind);
317 break;
318 case DELETES:
319 deletereg(netid, argc - optind, argv + optind);
320 break;
321 case ADDRPING:
322 addrping(address, netid, argc - optind, argv + optind);
323 break;
324 case PROGPING:
325 progping(netid, argc - optind, argv + optind);
326 break;
327 case RPCBDUMP:
328 case RPCBDUMP_SHORT:
329 rpcbdump(function, netid, argc - optind, argv + optind);
330 break;
331 case RPCBGETSTAT:
332 rpcbgetstat(argc - optind, argv + optind);
333 break;
334 case RPCBADDRLIST:
335 rpcbaddrlist(netid, argc - optind, argv + optind);
336 break;
338 return (0);
341 #ifdef PORTMAP
342 static CLIENT *
343 clnt_com_create(addr, prog, vers, fdp, trans)
344 struct sockaddr_in *addr;
345 ulong_t prog;
346 ulong_t vers;
347 int *fdp;
348 char *trans;
350 CLIENT *clnt;
352 if (strcmp(trans, "tcp") == 0) {
353 clnt = clnttcp_create(addr, prog, vers, fdp, 0, 0);
354 } else {
355 struct timeval to;
357 to.tv_sec = 5;
358 to.tv_usec = 0;
359 clnt = clntudp_create(addr, prog, vers, to, fdp);
361 if (clnt == (CLIENT *)NULL) {
362 clnt_pcreateerror("rpcinfo");
363 if (vers == MIN_VERS)
364 (void) printf("program %lu is not available\n", prog);
365 else
366 (void) printf(
367 "program %lu version %lu is not available\n",
368 prog, vers);
369 exit(1);
371 return (clnt);
375 * If portnum is 0, then go and get the address from portmapper, which happens
376 * transparently through clnt*_create(); If version number is not given, it
377 * tries to find out the version number by making a call to version 0 and if
378 * that fails, it obtains the high order and the low order version number. If
379 * version 0 calls succeeds, it tries for MAXVERS call and repeats the same.
381 static void
382 ip_ping(portnum, trans, argc, argv)
383 ushort_t portnum;
384 char *trans;
385 int argc;
386 char **argv;
388 CLIENT *client;
389 int fd = RPC_ANYFD;
390 struct timeval to;
391 struct sockaddr_in addr;
392 enum clnt_stat rpc_stat;
393 ulong_t prognum, vers, minvers, maxvers;
394 struct rpc_err rpcerr;
395 int failure = 0;
397 if (argc < 2 || argc > 3) {
398 usage();
399 exit(1);
401 to.tv_sec = 10;
402 to.tv_usec = 0;
403 prognum = getprognum(argv[1]);
404 get_inet_address(&addr, argv[0]);
405 if (argc == 2) { /* Version number not known */
407 * A call to version 0 should fail with a program/version
408 * mismatch, and give us the range of versions supported.
410 vers = MIN_VERS;
411 } else {
412 vers = getvers(argv[2]);
414 addr.sin_port = htons(portnum);
415 client = clnt_com_create(&addr, prognum, vers, &fd, trans);
416 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
417 NULL, (xdrproc_t)xdr_void, NULL,
418 to);
419 if (argc != 2) {
420 /* Version number was known */
421 if (pstatus(client, prognum, vers) < 0)
422 exit(1);
423 (void) CLNT_DESTROY(client);
424 return;
426 /* Version number not known */
427 (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, NULL);
428 if (rpc_stat == RPC_PROGVERSMISMATCH) {
429 clnt_geterr(client, &rpcerr);
430 minvers = rpcerr.re_vers.low;
431 maxvers = rpcerr.re_vers.high;
432 } else if (rpc_stat == RPC_SUCCESS) {
434 * Oh dear, it DOES support version 0.
435 * Let's try version MAX_VERS.
437 (void) CLNT_DESTROY(client);
438 addr.sin_port = htons(portnum);
439 client = clnt_com_create(&addr, prognum, MAX_VERS, &fd, trans);
440 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
441 NULL, (xdrproc_t)xdr_void,
442 NULL, to);
443 if (rpc_stat == RPC_PROGVERSMISMATCH) {
444 clnt_geterr(client, &rpcerr);
445 minvers = rpcerr.re_vers.low;
446 maxvers = rpcerr.re_vers.high;
447 } else if (rpc_stat == RPC_SUCCESS) {
449 * It also supports version MAX_VERS.
450 * Looks like we have a wise guy.
451 * OK, we give them information on all
452 * 4 billion versions they support...
454 minvers = 0;
455 maxvers = MAX_VERS;
456 } else {
457 (void) pstatus(client, prognum, MAX_VERS);
458 exit(1);
460 } else {
461 (void) pstatus(client, prognum, (ulong_t)0);
462 exit(1);
464 (void) CLNT_DESTROY(client);
465 for (vers = minvers; vers <= maxvers; vers++) {
466 addr.sin_port = htons(portnum);
467 client = clnt_com_create(&addr, prognum, vers, &fd, trans);
468 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
469 NULL, (xdrproc_t)xdr_void,
470 NULL, to);
471 if (pstatus(client, prognum, vers) < 0)
472 failure = 1;
473 (void) CLNT_DESTROY(client);
475 if (failure)
476 exit(1);
477 (void) t_close(fd);
481 * Dump all the portmapper registerations
483 static void
484 pmapdump(argc, argv)
485 int argc;
486 char **argv;
488 struct sockaddr_in server_addr;
489 pmaplist_ptr head = NULL;
490 int socket = RPC_ANYSOCK;
491 struct timeval minutetimeout;
492 register CLIENT *client;
493 struct rpcent *rpc;
494 enum clnt_stat clnt_st;
495 struct rpc_err err;
496 char *host;
498 if (argc > 1) {
499 usage();
500 exit(1);
502 if (argc == 1) {
503 host = argv[0];
504 } else {
505 host = HOST_SELF_CONNECT;
507 get_inet_address(&server_addr, host);
509 minutetimeout.tv_sec = 60;
510 minutetimeout.tv_usec = 0;
511 server_addr.sin_port = htons(PMAPPORT);
512 if ((client = clnttcp_create(&server_addr, PMAPPROG,
513 PMAPVERS, &socket, 50, 500)) == NULL) {
514 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
516 * "Misc. TLI error" is not too helpful. Most likely
517 * the connection to the remote server timed out, so
518 * this error is at least less perplexing.
520 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
521 rpc_createerr.cf_error.re_status = RPC_FAILED;
523 clnt_pcreateerror("rpcinfo: can't contact portmapper");
524 exit(1);
526 clnt_st = CLNT_CALL(client, PMAPPROC_DUMP, (xdrproc_t)xdr_void,
527 NULL, (xdrproc_t)xdr_pmaplist_ptr, (char *)&head,
528 minutetimeout);
529 if (clnt_st != RPC_SUCCESS) {
530 if ((clnt_st == RPC_PROGVERSMISMATCH) ||
531 (clnt_st == RPC_PROGUNAVAIL)) {
532 CLNT_GETERR(client, &err);
533 if (err.re_vers.low > PMAPVERS)
534 (void) fprintf(stderr,
535 "%s does not support portmapper. Try rpcinfo %s instead\n",
536 host, host);
537 exit(1);
539 clnt_perror(client, "rpcinfo: can't contact portmapper");
540 exit(1);
542 if (head == NULL) {
543 (void) printf("No remote programs registered.\n");
544 } else {
545 (void) printf(" program vers proto port service\n");
546 for (; head != NULL; head = head->pml_next) {
547 (void) printf("%10ld%5ld",
548 head->pml_map.pm_prog,
549 head->pml_map.pm_vers);
550 if (head->pml_map.pm_prot == IPPROTO_UDP)
551 (void) printf("%6s", "udp");
552 else if (head->pml_map.pm_prot == IPPROTO_TCP)
553 (void) printf("%6s", "tcp");
554 else
555 (void) printf("%6ld", head->pml_map.pm_prot);
556 (void) printf("%7ld", head->pml_map.pm_port);
557 rpc = getrpcbynumber(head->pml_map.pm_prog);
558 if (rpc)
559 (void) printf(" %s\n", rpc->r_name);
560 else
561 (void) printf("\n");
566 static void
567 get_inet_address(addr, host)
568 struct sockaddr_in *addr;
569 char *host;
571 struct netconfig *nconf;
572 struct nd_hostserv service;
573 struct nd_addrlist *naddrs;
575 (void) memset((char *)addr, 0, sizeof (*addr));
576 addr->sin_addr.s_addr = inet_addr(host);
577 if (addr->sin_addr.s_addr == (uint32_t)-1 ||
578 addr->sin_addr.s_addr == 0) {
579 if ((nconf = __rpc_getconfip("udp")) == NULL &&
580 (nconf = __rpc_getconfip("tcp")) == NULL) {
581 (void) fprintf(stderr,
582 "rpcinfo: couldn't find a suitable transport\n");
583 exit(1);
584 } else {
585 service.h_host = host;
586 service.h_serv = "rpcbind";
587 if (netdir_getbyname(nconf, &service, &naddrs)) {
588 (void) fprintf(stderr, "rpcinfo: %s: %s\n",
589 host, netdir_sperror());
590 exit(1);
591 } else {
592 (void) memcpy((caddr_t)addr,
593 naddrs->n_addrs->buf, naddrs->n_addrs->len);
594 (void) netdir_free((char *)naddrs, ND_ADDRLIST);
596 (void) freenetconfigent(nconf);
598 } else {
599 addr->sin_family = AF_INET;
602 #endif /* PORTMAP */
605 * reply_proc collects replies from the broadcast.
606 * to get a unique list of responses the output of rpcinfo should
607 * be piped through sort(1) and then uniq(1).
610 /*ARGSUSED*/
611 static bool_t
612 reply_proc(res, who, nconf)
613 void *res; /* Nothing comes back */
614 struct netbuf *who; /* Who sent us the reply */
615 struct netconfig *nconf; /* On which transport the reply came */
617 struct nd_hostservlist *serv;
618 char *uaddr;
619 char *hostname;
621 if (netdir_getbyaddr(nconf, &serv, who)) {
622 hostname = UNKNOWN;
623 } else {
624 hostname = serv->h_hostservs->h_host;
626 if (!(uaddr = taddr2uaddr(nconf, who))) {
627 uaddr = UNKNOWN;
629 (void) printf("%s\t%s\n", uaddr, hostname);
630 if (strcmp(hostname, UNKNOWN))
631 netdir_free((char *)serv, ND_HOSTSERVLIST);
632 if (strcmp(uaddr, UNKNOWN))
633 free((char *)uaddr);
634 return (FALSE);
637 static void
638 brdcst(argc, argv)
639 int argc;
640 char **argv;
642 enum clnt_stat rpc_stat;
643 ulong_t prognum, vers;
645 if (argc != 2) {
646 usage();
647 exit(1);
649 prognum = getprognum(argv[0]);
650 vers = getvers(argv[1]);
651 rpc_stat = rpc_broadcast(prognum, vers, NULLPROC,
652 (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_void,
653 NULL, (resultproc_t)reply_proc, NULL);
654 if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
655 (void) fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
656 clnt_sperrno(rpc_stat));
657 exit(1);
659 exit(0);
662 static bool_t
663 add_version(rs, vers)
664 struct rpcbdump_short *rs;
665 ulong_t vers;
667 struct verslist *vl;
669 for (vl = rs->vlist; vl; vl = vl->next)
670 if (vl->vers == vers)
671 break;
672 if (vl)
673 return (TRUE);
674 vl = (struct verslist *)malloc(sizeof (struct verslist));
675 if (vl == NULL)
676 return (FALSE);
677 vl->vers = vers;
678 vl->next = rs->vlist;
679 rs->vlist = vl;
680 return (TRUE);
683 static bool_t
684 add_netid(rs, netid)
685 struct rpcbdump_short *rs;
686 char *netid;
688 struct netidlist *nl;
690 for (nl = rs->nlist; nl; nl = nl->next)
691 if (strcmp(nl->netid, netid) == 0)
692 break;
693 if (nl)
694 return (TRUE);
695 nl = (struct netidlist *)malloc(sizeof (struct netidlist));
696 if (nl == NULL)
697 return (FALSE);
698 nl->netid = netid;
699 nl->next = rs->nlist;
700 rs->nlist = nl;
701 return (TRUE);
704 static void
705 rpcbdump(dumptype, netid, argc, argv)
706 int dumptype;
707 char *netid;
708 int argc;
709 char **argv;
711 rpcblist_ptr head = NULL;
712 struct timeval minutetimeout;
713 register CLIENT *client;
714 struct rpcent *rpc;
715 char *host;
716 struct netidlist *nl;
717 struct verslist *vl;
718 struct rpcbdump_short *rs, *rs_tail;
719 enum clnt_stat clnt_st;
720 struct rpc_err err;
721 struct rpcbdump_short *rs_head = NULL;
723 if (argc > 1) {
724 usage();
725 exit(1);
727 if (argc == 1) {
728 host = argv[0];
729 } else {
730 host = HOST_SELF_CONNECT;
732 if (netid == NULL) {
733 if (loopback_netid == NULL) {
734 client = clnt_rpcbind_create(host, RPCBVERS, NULL);
735 } else {
736 client = getclnthandle(host, loopback_nconf, RPCBVERS, NULL);
737 if (client == NULL && rpc_createerr.cf_stat ==
738 RPC_N2AXLATEFAILURE) {
739 client = clnt_rpcbind_create(host, RPCBVERS, NULL);
742 } else {
743 struct netconfig *nconf;
745 nconf = getnetconfigent(netid);
746 if (nconf == NULL) {
747 nc_perror("rpcinfo: invalid transport");
748 exit(1);
750 client = getclnthandle(host, nconf, RPCBVERS, NULL);
751 if (nconf)
752 (void) freenetconfigent(nconf);
754 if (client == (CLIENT *)NULL) {
755 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
756 exit(1);
758 minutetimeout.tv_sec = 60;
759 minutetimeout.tv_usec = 0;
760 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t)xdr_void,
761 NULL, (xdrproc_t)xdr_rpcblist_ptr, (char *)&head,
762 minutetimeout);
763 if (clnt_st != RPC_SUCCESS) {
764 if ((clnt_st == RPC_PROGVERSMISMATCH) ||
765 (clnt_st == RPC_PROGUNAVAIL)) {
766 int vers;
768 CLNT_GETERR(client, &err);
769 if (err.re_vers.low == RPCBVERS4) {
770 vers = RPCBVERS4;
771 clnt_control(client, CLSET_VERS, (char *)&vers);
772 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
773 (xdrproc_t)xdr_void, NULL,
774 (xdrproc_t)xdr_rpcblist_ptr, (char *)&head,
775 minutetimeout);
776 if (clnt_st != RPC_SUCCESS)
777 goto failed;
778 } else {
779 if (err.re_vers.high == PMAPVERS) {
780 int high, low;
781 pmaplist_ptr pmaphead = NULL;
782 rpcblist_ptr list, prev = NULL;
784 vers = PMAPVERS;
785 clnt_control(client, CLSET_VERS, (char *)&vers);
786 clnt_st = CLNT_CALL(client, PMAPPROC_DUMP,
787 (xdrproc_t)xdr_void, NULL,
788 (xdrproc_t)xdr_pmaplist_ptr,
789 (char *)&pmaphead, minutetimeout);
790 if (clnt_st != RPC_SUCCESS)
791 goto failed;
793 * convert to rpcblist_ptr format
795 for (head = NULL; pmaphead != NULL;
796 pmaphead = pmaphead->pml_next) {
797 list = (rpcblist *)malloc(sizeof (rpcblist));
798 if (list == NULL)
799 goto error;
800 if (head == NULL)
801 head = list;
802 else
803 prev->rpcb_next = (rpcblist_ptr) list;
805 list->rpcb_next = NULL;
806 list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog;
807 list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers;
808 if (pmaphead->pml_map.pm_prot == IPPROTO_UDP)
809 list->rpcb_map.r_netid = "udp";
810 else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP)
811 list->rpcb_map.r_netid = "tcp";
812 else {
813 #define MAXLONG_AS_STRING "2147483648"
814 list->rpcb_map.r_netid =
815 malloc(strlen(MAXLONG_AS_STRING) + 1);
816 if (list->rpcb_map.r_netid == NULL)
817 goto error;
818 (void) sprintf(list->rpcb_map.r_netid, "%6ld",
819 pmaphead->pml_map.pm_prot);
821 list->rpcb_map.r_owner = UNKNOWN;
822 low = pmaphead->pml_map.pm_port & 0xff;
823 high = (pmaphead->pml_map.pm_port >> 8) & 0xff;
824 list->rpcb_map.r_addr = strdup("0.0.0.0.XXX.XXX");
825 (void) sprintf(&list->rpcb_map.r_addr[8], "%d.%d",
826 high, low);
827 prev = list;
831 } else { /* any other error */
832 failed:
833 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
834 exit(1);
837 if (head == NULL) {
838 (void) printf("No remote programs registered.\n");
839 } else if (dumptype == RPCBDUMP) {
840 (void) printf(
841 " program version netid address service owner\n");
842 for (; head != NULL; head = head->rpcb_next) {
843 (void) printf("%10ld%5ld ",
844 head->rpcb_map.r_prog, head->rpcb_map.r_vers);
845 (void) printf("%-9s ", head->rpcb_map.r_netid);
846 (void) printf("%-19s", head->rpcb_map.r_addr);
847 rpc = getrpcbynumber(head->rpcb_map.r_prog);
848 if (rpc)
849 (void) printf(" %-10s", rpc->r_name);
850 else
851 (void) printf(" %-10s", "-");
852 (void) printf(" %s\n", head->rpcb_map.r_owner);
854 } else if (dumptype == RPCBDUMP_SHORT) {
855 for (; head != NULL; head = head->rpcb_next) {
856 for (rs = rs_head; rs; rs = rs->next)
857 if (head->rpcb_map.r_prog == rs->prog)
858 break;
859 if (rs == NULL) {
860 rs = (struct rpcbdump_short *)
861 malloc(sizeof (struct rpcbdump_short));
862 if (rs == NULL)
863 goto error;
864 rs->next = NULL;
865 if (rs_head == NULL) {
866 rs_head = rs;
867 rs_tail = rs;
868 } else {
869 rs_tail->next = rs;
870 rs_tail = rs;
872 rs->prog = head->rpcb_map.r_prog;
873 rs->owner = head->rpcb_map.r_owner;
874 rs->nlist = NULL;
875 rs->vlist = NULL;
877 if (add_version(rs, head->rpcb_map.r_vers) == FALSE)
878 goto error;
879 if (add_netid(rs, head->rpcb_map.r_netid) == FALSE)
880 goto error;
882 (void) printf(
883 " program version(s) netid(s) service owner\n");
884 for (rs = rs_head; rs; rs = rs->next) {
885 int bytes_trans = 0;
886 int len;
888 (void) printf("%10ld ", rs->prog);
889 for (vl = rs->vlist; vl; vl = vl->next) {
890 bytes_trans += (len = printf("%d", vl->vers))
891 < 0 ? 0 : len;
892 if (vl->next)
893 bytes_trans += (len = printf(",")) < 0
894 ? 0 : len;
897 * If number of bytes transferred is less than 10,
898 * align 10 bytes for version(s) column. If bytes
899 * transferred is more than 10, add a trailing white
900 * space.
902 if (bytes_trans < 10)
903 (void) printf("%*s", (bytes_trans - 10), " ");
904 else
905 (void) printf(" ");
907 bytes_trans = 0;
908 for (nl = rs->nlist; nl; nl = nl->next) {
909 bytes_trans += (len = printf("%s", nl->netid))
910 < 0 ? 0 : len;
911 if (nl->next)
912 bytes_trans += (len = printf(",")) < 0
913 ? 0 : len;
916 * Align netid(s) column output for 32 bytes.
918 if (bytes_trans < 32)
919 (void) printf("%*s", (bytes_trans - 32), " ");
921 rpc = getrpcbynumber(rs->prog);
922 if (rpc)
923 (void) printf(" %-11s", rpc->r_name);
924 else
925 (void) printf(" %-11s", "-");
926 (void) printf(" %s\n", rs->owner);
929 clnt_destroy(client);
930 return;
932 error: (void) fprintf(stderr, "rpcinfo: no memory\n");
935 static char nullstring[] = "\000";
937 static void
938 rpcbaddrlist(netid, argc, argv)
939 char *netid;
940 int argc;
941 char **argv;
943 rpcb_entry_list_ptr head = NULL;
944 struct timeval minutetimeout;
945 register CLIENT *client;
946 struct rpcent *rpc;
947 char *host;
948 RPCB parms;
949 struct netbuf *targaddr;
951 if (argc != 3) {
952 usage();
953 exit(1);
955 host = argv[0];
956 if (netid == NULL) {
957 if (loopback_netid == NULL) {
958 client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr);
959 } else {
960 client = getclnthandle(host, loopback_nconf, RPCBVERS4,
961 &targaddr);
962 if (client == NULL && rpc_createerr.cf_stat ==
963 RPC_N2AXLATEFAILURE) {
964 client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr);
967 } else {
968 struct netconfig *nconf;
970 nconf = getnetconfigent(netid);
971 if (nconf == NULL) {
972 nc_perror("rpcinfo: invalid transport");
973 exit(1);
975 client = getclnthandle(host, nconf, RPCBVERS4, &targaddr);
976 if (nconf)
977 (void) freenetconfigent(nconf);
979 if (client == (CLIENT *)NULL) {
980 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
981 exit(1);
983 minutetimeout.tv_sec = 60;
984 minutetimeout.tv_usec = 0;
986 parms.r_prog = getprognum(argv[1]);
987 parms.r_vers = getvers(argv[2]);
988 parms.r_netid = client->cl_netid;
989 if (targaddr == NULL) {
990 parms.r_addr = nullstring; /* for XDRing */
991 } else {
993 * We also send the remote system the address we
994 * used to contact it in case it can help it
995 * connect back with us
997 struct netconfig *nconf;
999 nconf = getnetconfigent(client->cl_netid);
1000 if (nconf != NULL) {
1001 parms.r_addr = taddr2uaddr(nconf, targaddr);
1002 if (parms.r_addr == NULL)
1003 parms.r_addr = nullstring;
1004 freenetconfigent(nconf);
1005 } else {
1006 parms.r_addr = nullstring; /* for XDRing */
1008 free(targaddr->buf);
1009 free(targaddr);
1011 parms.r_owner = nullstring;
1013 if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t)xdr_rpcb,
1014 (char *)&parms, (xdrproc_t)xdr_rpcb_entry_list_ptr,
1015 (char *)&head, minutetimeout) != RPC_SUCCESS) {
1016 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
1017 exit(1);
1019 if (head == NULL) {
1020 (void) printf("No remote programs registered.\n");
1021 } else {
1022 (void) printf(
1023 " program vers tp_family/name/class address\t\t service\n");
1024 for (; head != NULL; head = head->rpcb_entry_next) {
1025 rpcb_entry *re;
1026 char buf[128];
1028 re = &head->rpcb_entry_map;
1029 (void) printf("%10ld%3ld ",
1030 parms.r_prog, parms.r_vers);
1031 (void) snprintf(buf, sizeof (buf), "%s/%s/%s ",
1032 re->r_nc_protofmly, re->r_nc_proto,
1033 re->r_nc_semantics == NC_TPI_CLTS ? "clts" :
1034 re->r_nc_semantics == NC_TPI_COTS ? "cots" :
1035 "cots_ord");
1036 (void) printf("%-24s", buf);
1037 (void) printf("%-24s", re->r_maddr);
1038 rpc = getrpcbynumber(parms.r_prog);
1039 if (rpc)
1040 (void) printf(" %-13s", rpc->r_name);
1041 else
1042 (void) printf(" %-13s", "-");
1043 (void) printf("\n");
1046 clnt_destroy(client);
1050 * monitor rpcbind
1052 static void
1053 rpcbgetstat(argc, argv)
1054 int argc;
1055 char **argv;
1057 rpcb_stat_byvers inf;
1058 struct timeval minutetimeout;
1059 register CLIENT *client;
1060 char *host;
1061 int i, j;
1062 rpcbs_addrlist *pa;
1063 rpcbs_rmtcalllist *pr;
1064 int cnt, flen;
1065 #define MAXFIELD 64
1066 char fieldbuf[MAXFIELD];
1067 #define MAXLINE 256
1068 char linebuf[MAXLINE];
1069 char *cp, *lp;
1070 char *pmaphdr[] = {
1071 "NULL", "SET", "UNSET", "GETPORT",
1072 "DUMP", "CALLIT"
1074 char *rpcb3hdr[] = {
1075 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1076 "U2T", "T2U"
1078 char *rpcb4hdr[] = {
1079 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1080 "U2T", "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT"
1083 #define TABSTOP 8
1085 if (argc >= 1) {
1086 host = argv[0];
1087 } else {
1088 host = HOST_SELF_CONNECT;
1090 if (loopback_netid != NULL) {
1091 client = getclnthandle(host, loopback_nconf, RPCBVERS4, NULL);
1092 if (client == NULL && rpc_createerr.cf_stat ==
1093 RPC_N2AXLATEFAILURE) {
1094 client = clnt_rpcbind_create(host, RPCBVERS4, NULL);
1096 } else {
1097 client = clnt_rpcbind_create(host, RPCBVERS4, NULL);
1099 if (client == (CLIENT *)NULL) {
1100 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
1101 exit(1);
1103 minutetimeout.tv_sec = 60;
1104 minutetimeout.tv_usec = 0;
1105 (void) memset((char *)&inf, 0, sizeof (rpcb_stat_byvers));
1106 if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t)xdr_void, NULL,
1107 (xdrproc_t)xdr_rpcb_stat_byvers, (char *)&inf, minutetimeout)
1108 != RPC_SUCCESS) {
1109 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
1110 exit(1);
1112 (void) printf("PORTMAP (version 2) statistics\n");
1113 lp = linebuf;
1114 for (i = 0; i <= rpcb_highproc_2; i++) {
1115 fieldbuf[0] = '\0';
1116 switch (i) {
1117 case PMAPPROC_SET:
1118 (void) sprintf(fieldbuf, "%d/",
1119 inf[RPCBVERS_2_STAT].setinfo);
1120 break;
1121 case PMAPPROC_UNSET:
1122 (void) sprintf(fieldbuf, "%d/",
1123 inf[RPCBVERS_2_STAT].unsetinfo);
1124 break;
1125 case PMAPPROC_GETPORT:
1126 cnt = 0;
1127 for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa;
1128 pa = pa->next)
1129 cnt += pa->success;
1130 (void) sprintf(fieldbuf, "%d/", cnt);
1131 break;
1132 case PMAPPROC_CALLIT:
1133 cnt = 0;
1134 for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr;
1135 pr = pr->next)
1136 cnt += pr->success;
1137 (void) sprintf(fieldbuf, "%d/", cnt);
1138 break;
1139 default: break; /* For the remaining ones */
1141 cp = &fieldbuf[0] + strlen(fieldbuf);
1142 (void) sprintf(cp, "%d", inf[RPCBVERS_2_STAT].info[i]);
1143 flen = strlen(fieldbuf);
1144 (void) printf("%s%s", pmaphdr[i],
1145 spaces((int)((TABSTOP * (1 + flen / TABSTOP))
1146 - strlen(pmaphdr[i]))));
1147 (void) snprintf(lp, (MAXLINE - (lp - linebuf)), "%s%s",
1148 fieldbuf, spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1149 - flen)));
1150 lp += (flen + cnt);
1152 (void) printf("\n%s\n\n", linebuf);
1154 if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) {
1155 (void) printf("PMAP_RMTCALL call statistics\n");
1156 print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1157 (void) printf("\n");
1160 if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) {
1161 (void) printf("PMAP_GETPORT call statistics\n");
1162 print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1163 (void) printf("\n");
1166 (void) printf("RPCBIND (version 3) statistics\n");
1167 lp = linebuf;
1168 for (i = 0; i <= rpcb_highproc_3; i++) {
1169 fieldbuf[0] = '\0';
1170 switch (i) {
1171 case RPCBPROC_SET:
1172 (void) sprintf(fieldbuf, "%d/",
1173 inf[RPCBVERS_3_STAT].setinfo);
1174 break;
1175 case RPCBPROC_UNSET:
1176 (void) sprintf(fieldbuf, "%d/",
1177 inf[RPCBVERS_3_STAT].unsetinfo);
1178 break;
1179 case RPCBPROC_GETADDR:
1180 cnt = 0;
1181 for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa;
1182 pa = pa->next)
1183 cnt += pa->success;
1184 (void) sprintf(fieldbuf, "%d/", cnt);
1185 break;
1186 case RPCBPROC_CALLIT:
1187 cnt = 0;
1188 for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr;
1189 pr = pr->next)
1190 cnt += pr->success;
1191 (void) sprintf(fieldbuf, "%d/", cnt);
1192 break;
1193 default: break; /* For the remaining ones */
1195 cp = &fieldbuf[0] + strlen(fieldbuf);
1196 (void) sprintf(cp, "%d", inf[RPCBVERS_3_STAT].info[i]);
1197 flen = strlen(fieldbuf);
1198 (void) printf("%s%s", rpcb3hdr[i],
1199 spaces((int)((TABSTOP * (1 + flen / TABSTOP))
1200 - strlen(rpcb3hdr[i]))));
1201 (void) snprintf(lp, (MAXLINE - (lp - linebuf)), "%s%s",
1202 fieldbuf, spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1203 - flen)));
1204 lp += (flen + cnt);
1206 (void) printf("\n%s\n\n", linebuf);
1208 if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) {
1209 (void) printf("RPCB_RMTCALL (version 3) call statistics\n");
1210 print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1211 (void) printf("\n");
1214 if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) {
1215 (void) printf("RPCB_GETADDR (version 3) call statistics\n");
1216 print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1217 (void) printf("\n");
1220 (void) printf("RPCBIND (version 4) statistics\n");
1222 for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */
1223 lp = linebuf;
1224 for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) {
1225 fieldbuf[0] = '\0';
1226 switch (i) {
1227 case RPCBPROC_SET:
1228 (void) sprintf(fieldbuf, "%d/",
1229 inf[RPCBVERS_4_STAT].setinfo);
1230 break;
1231 case RPCBPROC_UNSET:
1232 (void) sprintf(fieldbuf, "%d/",
1233 inf[RPCBVERS_4_STAT].unsetinfo);
1234 break;
1235 case RPCBPROC_GETADDR:
1236 cnt = 0;
1237 for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa;
1238 pa = pa->next)
1239 cnt += pa->success;
1240 (void) sprintf(fieldbuf, "%d/", cnt);
1241 break;
1242 case RPCBPROC_CALLIT:
1243 cnt = 0;
1244 for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr;
1245 pr = pr->next)
1246 cnt += pr->success;
1247 (void) sprintf(fieldbuf, "%d/", cnt);
1248 break;
1249 default: break; /* For the remaining ones */
1251 cp = &fieldbuf[0] + strlen(fieldbuf);
1253 * XXX: We also add RPCBPROC_GETADDRLIST queries to
1254 * RPCB_GETADDR because rpcbind includes the
1255 * RPCB_GETADDRLIST successes in RPCB_GETADDR.
1257 if (i != RPCBPROC_GETADDR)
1258 (void) sprintf(cp, "%d",
1259 inf[RPCBVERS_4_STAT].info[i]);
1260 else
1261 (void) sprintf(cp, "%d",
1262 inf[RPCBVERS_4_STAT].info[i] +
1263 inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]);
1264 flen = strlen(fieldbuf);
1265 (void) printf("%s%s", rpcb4hdr[i],
1266 spaces((int)((TABSTOP * (1 + flen / TABSTOP))
1267 - strlen(rpcb4hdr[i]))));
1268 (void) snprintf(lp, MAXLINE - (lp - linebuf), "%s%s",
1269 fieldbuf, spaces(cnt =
1270 ((TABSTOP * (1 + flen / TABSTOP)) - flen)));
1271 lp += (flen + cnt);
1273 (void) printf("\n%s\n", linebuf);
1276 if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] ||
1277 inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) {
1278 (void) printf("\n");
1279 (void) printf("RPCB_RMTCALL (version 4) call statistics\n");
1280 print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1283 if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) {
1284 (void) printf("\n");
1285 (void) printf("RPCB_GETADDR (version 4) call statistics\n");
1286 print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1288 clnt_destroy(client);
1292 * Delete registeration for this (prog, vers, netid)
1294 static void
1295 deletereg(netid, argc, argv)
1296 char *netid;
1297 int argc;
1298 char **argv;
1300 struct netconfig *nconf = NULL;
1302 if (argc != 2) {
1303 usage();
1304 exit(1);
1306 if (netid) {
1307 nconf = getnetconfigent(netid);
1308 if (nconf == NULL) {
1309 (void) fprintf(stderr,
1310 "rpcinfo: netid %s not supported\n", netid);
1311 exit(1);
1314 if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0) {
1315 (void) fprintf(stderr,
1316 "rpcinfo: Could not delete registration for prog %s version %s\n",
1317 argv[0], argv[1]);
1318 exit(1);
1323 * Create and return a handle for the given nconf.
1324 * Exit if cannot create handle.
1326 static CLIENT *
1327 clnt_addr_create(address, nconf, prog, vers)
1328 char *address;
1329 struct netconfig *nconf;
1330 ulong_t prog;
1331 ulong_t vers;
1333 CLIENT *client;
1334 static struct netbuf *nbuf;
1335 static int fd = RPC_ANYFD;
1336 struct t_info tinfo;
1338 if (fd == RPC_ANYFD) {
1339 if ((fd = t_open(nconf->nc_device, O_RDWR, &tinfo)) == -1) {
1340 rpc_createerr.cf_stat = RPC_TLIERROR;
1341 rpc_createerr.cf_error.re_terrno = t_errno;
1342 clnt_pcreateerror("rpcinfo");
1343 exit(1);
1345 /* Convert the uaddr to taddr */
1346 nbuf = uaddr2taddr(nconf, address);
1347 if (nbuf == NULL) {
1348 netdir_perror("rpcinfo");
1349 exit(1);
1352 client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0);
1353 if (client == (CLIENT *)NULL) {
1354 clnt_pcreateerror("rpcinfo");
1355 exit(1);
1357 return (client);
1361 * If the version number is given, ping that (prog, vers); else try to find
1362 * the version numbers supported for that prog and ping all the versions.
1363 * Remote rpcbind is not contacted for this service. The requests are
1364 * sent directly to the services themselves.
1366 static void
1367 addrping(address, netid, argc, argv)
1368 char *address;
1369 char *netid;
1370 int argc;
1371 char **argv;
1373 CLIENT *client;
1374 struct timeval to;
1375 enum clnt_stat rpc_stat;
1376 ulong_t prognum, versnum, minvers, maxvers;
1377 struct rpc_err rpcerr;
1378 int failure = 0;
1379 struct netconfig *nconf;
1380 int fd;
1382 if (argc < 1 || argc > 2 || (netid == NULL)) {
1383 usage();
1384 exit(1);
1386 nconf = getnetconfigent(netid);
1387 if (nconf == NULL) {
1388 (void) fprintf(stderr, "rpcinfo: Could not find %s\n", netid);
1389 exit(1);
1391 to.tv_sec = 10;
1392 to.tv_usec = 0;
1393 prognum = getprognum(argv[0]);
1394 if (argc == 1) { /* Version number not known */
1396 * A call to version 0 should fail with a program/version
1397 * mismatch, and give us the range of versions supported.
1399 versnum = MIN_VERS;
1400 } else {
1401 versnum = getvers(argv[1]);
1403 client = clnt_addr_create(address, nconf, prognum, versnum);
1404 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1405 NULL, (xdrproc_t)xdr_void,
1406 NULL, to);
1407 if (argc == 2) {
1408 /* Version number was known */
1409 if (pstatus(client, prognum, versnum) < 0)
1410 failure = 1;
1411 (void) CLNT_DESTROY(client);
1412 if (failure)
1413 exit(1);
1414 return;
1416 /* Version number not known */
1417 (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, NULL);
1418 (void) CLNT_CONTROL(client, CLGET_FD, (char *)&fd);
1419 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1420 clnt_geterr(client, &rpcerr);
1421 minvers = rpcerr.re_vers.low;
1422 maxvers = rpcerr.re_vers.high;
1423 } else if (rpc_stat == RPC_SUCCESS) {
1425 * Oh dear, it DOES support version 0.
1426 * Let's try version MAX_VERS.
1428 (void) CLNT_DESTROY(client);
1429 client = clnt_addr_create(address, nconf, prognum, MAX_VERS);
1430 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1431 NULL, (xdrproc_t)xdr_void,
1432 NULL, to);
1433 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1434 clnt_geterr(client, &rpcerr);
1435 minvers = rpcerr.re_vers.low;
1436 maxvers = rpcerr.re_vers.high;
1437 } else if (rpc_stat == RPC_SUCCESS) {
1439 * It also supports version MAX_VERS.
1440 * Looks like we have a wise guy.
1441 * OK, we give them information on all
1442 * 4 billion versions they support...
1444 minvers = 0;
1445 maxvers = MAX_VERS;
1446 } else {
1447 (void) pstatus(client, prognum, MAX_VERS);
1448 exit(1);
1450 } else {
1451 (void) pstatus(client, prognum, (ulong_t)0);
1452 exit(1);
1454 (void) CLNT_DESTROY(client);
1455 for (versnum = minvers; versnum <= maxvers; versnum++) {
1456 client = clnt_addr_create(address, nconf, prognum, versnum);
1457 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1458 NULL, (xdrproc_t)xdr_void,
1459 NULL, to);
1460 if (pstatus(client, prognum, versnum) < 0)
1461 failure = 1;
1462 (void) CLNT_DESTROY(client);
1464 (void) t_close(fd);
1465 if (failure)
1466 exit(1);
1470 * If the version number is given, ping that (prog, vers); else try to find
1471 * the version numbers supported for that prog and ping all the versions.
1472 * Remote rpcbind is *contacted* for this service. The requests are
1473 * then sent directly to the services themselves.
1475 static void
1476 progping(netid, argc, argv)
1477 char *netid;
1478 int argc;
1479 char **argv;
1481 CLIENT *client;
1482 struct timeval to;
1483 enum clnt_stat rpc_stat;
1484 ulong_t prognum, versnum, minvers, maxvers;
1485 struct rpc_err rpcerr;
1486 int failure = 0;
1487 struct netconfig *nconf;
1489 if (argc < 2 || argc > 3 || (netid == NULL)) {
1490 usage();
1491 exit(1);
1493 prognum = getprognum(argv[1]);
1494 if (argc == 2) { /* Version number not known */
1496 * A call to version 0 should fail with a program/version
1497 * mismatch, and give us the range of versions supported.
1499 versnum = MIN_VERS;
1500 } else {
1501 versnum = getvers(argv[2]);
1503 if (netid) {
1504 nconf = getnetconfigent(netid);
1505 if (nconf == NULL) {
1506 (void) fprintf(stderr,
1507 "rpcinfo: Could not find %s\n", netid);
1508 exit(1);
1510 client = clnt_tp_create(argv[0], prognum, versnum, nconf);
1511 } else {
1512 client = clnt_create(argv[0], prognum, versnum, "NETPATH");
1514 if (client == (CLIENT *)NULL) {
1515 clnt_pcreateerror("rpcinfo");
1516 exit(1);
1518 to.tv_sec = 10;
1519 to.tv_usec = 0;
1520 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1521 NULL, (xdrproc_t)xdr_void,
1522 NULL, to);
1523 if (argc == 3) {
1524 /* Version number was known */
1525 if (pstatus(client, prognum, versnum) < 0)
1526 failure = 1;
1527 (void) CLNT_DESTROY(client);
1528 if (failure)
1529 exit(1);
1530 return;
1532 /* Version number not known */
1533 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1534 clnt_geterr(client, &rpcerr);
1535 minvers = rpcerr.re_vers.low;
1536 maxvers = rpcerr.re_vers.high;
1537 } else if (rpc_stat == RPC_SUCCESS) {
1539 * Oh dear, it DOES support version 0.
1540 * Let's try version MAX_VERS.
1542 versnum = MAX_VERS;
1543 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1544 rpc_stat = CLNT_CALL(client, NULLPROC,
1545 (xdrproc_t)xdr_void, NULL,
1546 (xdrproc_t)xdr_void, NULL, to);
1547 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1548 clnt_geterr(client, &rpcerr);
1549 minvers = rpcerr.re_vers.low;
1550 maxvers = rpcerr.re_vers.high;
1551 } else if (rpc_stat == RPC_SUCCESS) {
1553 * It also supports version MAX_VERS.
1554 * Looks like we have a wise guy.
1555 * OK, we give them information on all
1556 * 4 billion versions they support...
1558 minvers = 0;
1559 maxvers = MAX_VERS;
1560 } else {
1561 (void) pstatus(client, prognum, MAX_VERS);
1562 exit(1);
1564 } else {
1565 (void) pstatus(client, prognum, (ulong_t)0);
1566 exit(1);
1568 for (versnum = minvers; versnum <= maxvers; versnum++) {
1569 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1570 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1571 NULL, (xdrproc_t)xdr_void,
1572 NULL, to);
1573 if (pstatus(client, prognum, versnum) < 0)
1574 failure = 1;
1576 (void) CLNT_DESTROY(client);
1577 if (failure)
1578 exit(1);
1581 static void
1582 usage()
1584 (void) fprintf(stderr, "Usage: rpcinfo [-T netid] [-m | -s] [host]\n");
1585 #ifdef PORTMAP
1586 (void) fprintf(stderr, " rpcinfo -p [host]\n");
1587 #endif
1588 (void) fprintf(stderr,
1589 " rpcinfo -T netid host prognum [versnum]\n");
1590 (void) fprintf(stderr,
1591 " rpcinfo -l [-T netid] host prognum versnum\n");
1592 #ifdef PORTMAP
1593 (void) fprintf(stderr,
1594 " rpcinfo [-n portnum] -u | -t host prognum [versnum]\n");
1595 #endif
1596 (void) fprintf(stderr,
1597 " rpcinfo -a serv_address -T netid prognum [versnum]\n");
1598 (void) fprintf(stderr,
1599 " rpcinfo -b [-T netid] prognum versnum\n");
1600 (void) fprintf(stderr,
1601 " rpcinfo -d [-T netid] prognum versnum\n");
1604 static ulong_t
1605 getprognum (arg)
1606 char *arg;
1608 char *strptr;
1609 register struct rpcent *rpc;
1610 register ulong_t prognum;
1611 char *tptr = arg;
1613 while (*tptr && isdigit(*tptr++));
1614 if (*tptr || isalpha(*(tptr - 1))) {
1615 rpc = getrpcbyname(arg);
1616 if (rpc == NULL) {
1617 (void) fprintf(stderr,
1618 "rpcinfo: %s is unknown service\n", arg);
1619 exit(1);
1621 prognum = rpc->r_number;
1622 } else {
1623 prognum = strtol(arg, &strptr, 10);
1624 if (strptr == arg || *strptr != '\0') {
1625 (void) fprintf(stderr,
1626 "rpcinfo: %s is illegal program number\n", arg);
1627 exit(1);
1630 return (prognum);
1633 static ulong_t
1634 getvers(arg)
1635 char *arg;
1637 char *strptr;
1638 register ulong_t vers;
1640 vers = (int)strtol(arg, &strptr, 10);
1641 if (strptr == arg || *strptr != '\0') {
1642 (void) fprintf(stderr,
1643 "rpcinfo: %s is illegal version number\n", arg);
1644 exit(1);
1646 return (vers);
1650 * This routine should take a pointer to an "rpc_err" structure, rather than
1651 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
1652 * a CLIENT structure rather than a pointer to an "rpc_err" structure.
1653 * As such, we have to keep the CLIENT structure around in order to print
1654 * a good error message.
1656 static int
1657 pstatus(client, prog, vers)
1658 register CLIENT *client;
1659 ulong_t prog;
1660 ulong_t vers;
1662 struct rpc_err rpcerr;
1664 clnt_geterr(client, &rpcerr);
1665 if (rpcerr.re_status != RPC_SUCCESS) {
1666 clnt_perror(client, "rpcinfo");
1667 (void) printf("program %lu version %lu is not available\n",
1668 prog, vers);
1669 return (-1);
1670 } else {
1671 (void) printf("program %lu version %lu ready and waiting\n",
1672 prog, vers);
1673 return (0);
1677 static CLIENT *
1678 clnt_rpcbind_create(host, rpcbversnum, targaddr)
1679 char *host;
1680 ulong_t rpcbversnum;
1681 struct netbuf **targaddr;
1683 static char *tlist[3] = {
1684 "circuit_n", "circuit_v", "datagram_v"
1686 int i;
1687 struct netconfig *nconf;
1688 CLIENT *clnt = NULL;
1689 void *handle;
1691 rpc_createerr.cf_stat = RPC_SUCCESS;
1692 for (i = 0; i < 3; i++) {
1693 if ((handle = __rpc_setconf(tlist[i])) == NULL)
1694 continue;
1695 while (clnt == (CLIENT *)NULL) {
1696 if ((nconf = __rpc_getconf(handle)) == NULL) {
1697 if (rpc_createerr.cf_stat == RPC_SUCCESS)
1698 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1699 break;
1701 clnt = getclnthandle(host, nconf, rpcbversnum,
1702 targaddr);
1704 if (clnt)
1705 break;
1706 __rpc_endconf(handle);
1708 return (clnt);
1711 static CLIENT*
1712 getclnthandle(host, nconf, rpcbversnum, targaddr)
1713 char *host;
1714 struct netconfig *nconf;
1715 ulong_t rpcbversnum;
1716 struct netbuf **targaddr;
1718 struct netbuf *addr;
1719 struct nd_addrlist *nas;
1720 struct nd_hostserv rpcbind_hs;
1721 CLIENT *client = NULL;
1723 /* Get the address of the rpcbind */
1724 rpcbind_hs.h_host = host;
1725 rpcbind_hs.h_serv = "rpcbind";
1726 if (netdir_getbyname(nconf, &rpcbind_hs, &nas)) {
1727 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
1728 return (NULL);
1730 addr = nas->n_addrs;
1731 client = clnt_tli_create(RPC_ANYFD, nconf, addr, RPCBPROG,
1732 rpcbversnum, 0, 0);
1733 if (client) {
1734 if (targaddr != NULL) {
1735 *targaddr =
1736 (struct netbuf *)malloc(sizeof (struct netbuf));
1737 if (*targaddr != NULL) {
1738 (*targaddr)->maxlen = addr->maxlen;
1739 (*targaddr)->len = addr->len;
1740 (*targaddr)->buf = (char *)malloc(addr->len);
1741 if ((*targaddr)->buf != NULL) {
1742 (void) memcpy((*targaddr)->buf,
1743 addr->buf, addr->len);
1747 } else {
1748 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1750 * Assume that the other system is dead; this is a
1751 * better error to display to the user.
1753 rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1754 rpc_createerr.cf_error.re_status = RPC_FAILED;
1757 netdir_free((char *)nas, ND_ADDRLIST);
1758 return (client);
1761 static void
1762 print_rmtcallstat(rtype, infp)
1763 int rtype;
1764 rpcb_stat *infp;
1766 register rpcbs_rmtcalllist_ptr pr;
1767 struct rpcent *rpc;
1769 if (rtype == RPCBVERS_4_STAT)
1770 (void) printf(
1771 "prog\t\tvers\tproc\tnetid\tindirect success failure\n");
1772 else
1773 (void) printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n");
1774 for (pr = infp->rmtinfo; pr; pr = pr->next) {
1775 rpc = getrpcbynumber(pr->prog);
1776 if (rpc)
1777 (void) printf("%-16s", rpc->r_name);
1778 else
1779 #if defined(_LP64) || defined(_I32LPx)
1780 (void) printf("%-16u", pr->prog);
1781 (void) printf("%u\t%u\t%-7s ",
1782 #else
1783 (void) printf("%-16lu", pr->prog);
1784 (void) printf("%lu\t%lu\t%-7s ",
1785 #endif
1786 pr->vers, pr->proc, pr->netid);
1787 if (rtype == RPCBVERS_4_STAT)
1788 (void) printf("%d\t ", pr->indirect);
1789 (void) printf("%d\t%d\n", pr->success, pr->failure);
1793 static void
1794 /* LINTED E_FUNC_ARG_UNUSED for 1st arg rtype */
1795 print_getaddrstat(rtype, infp)
1796 int rtype;
1797 rpcb_stat *infp;
1799 rpcbs_addrlist_ptr al;
1800 register struct rpcent *rpc;
1802 (void) printf("prog\t\tvers\tnetid\t success\tfailure\n");
1803 for (al = infp->addrinfo; al; al = al->next) {
1804 rpc = getrpcbynumber(al->prog);
1805 if (rpc)
1806 (void) printf("%-16s", rpc->r_name);
1807 else
1808 #if defined(_LP64) || defined(_I32LPx)
1809 (void) printf("%-16u", al->prog);
1810 (void) printf("%u\t%-9s %-12d\t%d\n",
1811 #else
1812 (void) printf("%-16lu", al->prog);
1813 (void) printf("%lu\t%-9s %-12d\t%d\n",
1814 #endif
1815 al->vers, al->netid,
1816 al->success, al->failure);
1820 static char *
1821 spaces(howmany)
1822 int howmany;
1824 static char space_array[] = /* 64 spaces */
1825 " ";
1827 if (howmany <= 0 || howmany > sizeof (space_array)) {
1828 return ("");
1830 return (&space_array[sizeof (space_array) - howmany - 1]);