Index: rpcinfo.c
===================================================================
--- rpcinfo.c (nonexistent)
+++ rpcinfo.c (revision 5)
@@ -0,0 +1,1958 @@
+/*
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
+ */
+/*
+ * rpcinfo: ping a particular rpc program
+ * or dump the the registered programs on the remote machine.
+ */
+
+/*
+ * We are for now defining PORTMAP here. It doesnt even compile
+ * unless it is defined.
+ */
+#ifndef PORTMAP
+#define PORTMAP
+#endif
+
+/*
+ * If PORTMAP is defined, rpcinfo will talk to both portmapper and
+ * rpcbind programs; else it talks only to rpcbind. In the latter case
+ * all the portmapper specific options such as -u, -t, -p become void.
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <rpc/rpc.h>
+#include <stdio.h>
+#include <rpc/rpcb_prot.h>
+#include <rpc/rpcent.h>
+#include <rpc/nettype.h>
+#include <rpc/rpc_com.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+#include <ctype.h>
+
+#ifdef PORTMAP /* Support for version 2 portmapper */
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#endif
+
+#define max(a,b) ((a) > (b) ? (a) : (b))
+
+#define MIN_VERS ((u_long)0)
+#define MAX_VERS ((u_long)4294967295UL)
+#define UNKNOWN "unknown"
+
+/*
+ * Functions to be performed.
+ */
+#define NONE 0 /* no function */
+#define PMAPDUMP 1 /* dump portmapper registrations */
+#define TCPPING 2 /* ping TCP service */
+#define UDPPING 3 /* ping UDP service */
+#define BROADCAST 4 /* ping broadcast service */
+#define DELETES 5 /* delete registration for the service */
+#define ADDRPING 6 /* pings at the given address */
+#define PROGPING 7 /* pings a program on a given host */
+#define RPCBDUMP 8 /* dump rpcbind registrations */
+#define RPCBDUMP_SHORT 9 /* dump rpcbind registrations - short version */
+#define RPCBADDRLIST 10 /* dump addr list about one prog */
+#define RPCBGETSTAT 11 /* Get statistics */
+
+struct netidlist
+{
+ char *netid;
+ struct netidlist *next;
+};
+
+struct verslist
+{
+ int vers;
+ struct verslist *next;
+};
+
+struct rpcbdump_short
+{
+ u_long prog;
+ struct verslist *vlist;
+ struct netidlist *nlist;
+ struct rpcbdump_short *next;
+ char *owner;
+};
+
+
+#ifdef PORTMAP
+static void ip_ping (u_short, char *, int, char **);
+static void pmapdump (int, char **);
+static CLIENT *ip_getclient(const char *hostname, rpcprog_t prognum, rpcvers_t versnum, const char *proto);
+#endif
+
+static bool_t reply_proc (void *, struct netbuf *, struct netconfig *);
+static void brdcst (int, char **);
+static void addrping (char *, char *, int, char **);
+static void progping (char *, int, char **);
+static CLIENT *clnt_addr_create (char *, struct netconfig *, u_long, u_long);
+static CLIENT *clnt_rpcbind_create (char *, int, struct netbuf **);
+static CLIENT *getclnthandle (char *, struct netconfig *, u_long,
+ struct netbuf **);
+static int pstatus (CLIENT *, u_long, u_long);
+static void rpcbdump (int, char *, int, char **);
+static void rpcbgetstat (int, char **);
+static void rpcbaddrlist (char *, int, char **);
+static void deletereg (char *, int, char **);
+static void print_rmtcallstat (int, rpcb_stat *);
+static void print_getaddrstat (int, rpcb_stat *);
+static void usage (void);
+static u_long getprognum (char *);
+static u_long getvers (char *);
+static char *spaces (int);
+static bool_t add_version (struct rpcbdump_short *, u_long);
+static bool_t add_netid (struct rpcbdump_short *, char *);
+
+int main (int argc, char **argv);
+
+int
+main (int argc, char **argv)
+{
+ register int c;
+ int errflg;
+ int function;
+ char *netid = NULL;
+ char *address = NULL;
+#ifdef PORTMAP
+ char *strptr;
+ u_short portnum = 0;
+#endif
+
+ function = NONE;
+ errflg = 0;
+#ifdef PORTMAP
+ while ((c = getopt (argc, argv, "a:bdlmn:pstT:u")) != -1)
+#else
+ while ((c = getopt (argc, argv, "a:bdlmn:sT:")) != -1)
+#endif
+ {
+ switch (c)
+ {
+#ifdef PORTMAP
+ case 'p':
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = PMAPDUMP;
+ break;
+
+ case 't':
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = TCPPING;
+ break;
+
+ case 'u':
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = UDPPING;
+ break;
+
+ case 'n':
+ portnum = (u_short) strtol (optarg, &strptr, 10);
+ if (strptr == optarg || *strptr != '\0')
+ {
+ fprintf (stderr, "rpcinfo: %s is illegal port number\n",
+ optarg);
+ exit (1);
+ }
+ break;
+#endif
+
+ case 'a':
+ address = optarg;
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = ADDRPING;
+ break;
+
+ case 'b':
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = BROADCAST;
+ break;
+
+ case 'd':
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = DELETES;
+ break;
+
+ case 'l':
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = RPCBADDRLIST;
+ break;
+
+ case 'm':
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = RPCBGETSTAT;
+ break;
+
+ case 's':
+ if (function != NONE)
+ errflg = 1;
+ else
+ function = RPCBDUMP_SHORT;
+ break;
+
+ case 'T':
+ netid = optarg;
+ break;
+ case '?':
+ errflg = 1;
+ break;
+ }
+ }
+
+ if (errflg || ((function == ADDRPING) && !netid))
+ {
+ usage ();
+ return 1;
+ }
+
+ if (function == NONE)
+ {
+ if (argc - optind > 1)
+ function = PROGPING;
+ else
+ function = RPCBDUMP;
+ }
+
+ switch (function)
+ {
+#ifdef PORTMAP
+ case PMAPDUMP:
+ if (portnum != 0)
+ {
+ usage ();
+ return 1;
+ }
+ pmapdump (argc - optind, argv + optind);
+ break;
+
+ case UDPPING:
+ ip_ping (portnum, "udp", argc - optind, argv + optind);
+ break;
+
+ case TCPPING:
+ ip_ping (portnum, "tcp", argc - optind, argv + optind);
+ break;
+#endif
+ case BROADCAST:
+ brdcst (argc - optind, argv + optind);
+ break;
+ case DELETES:
+ deletereg (netid, argc - optind, argv + optind);
+ break;
+ case ADDRPING:
+ addrping (address, netid, argc - optind, argv + optind);
+ break;
+ case PROGPING:
+ progping (netid, argc - optind, argv + optind);
+ break;
+ case RPCBDUMP:
+ case RPCBDUMP_SHORT:
+ rpcbdump (function, netid, argc - optind, argv + optind);
+ break;
+ case RPCBGETSTAT:
+ rpcbgetstat (argc - optind, argv + optind);
+ break;
+ case RPCBADDRLIST:
+ rpcbaddrlist (netid, argc - optind, argv + optind);
+ break;
+ }
+ return (0);
+}
+
+static CLIENT *
+local_rpcb (rpcprog_t prog, rpcvers_t vers)
+{
+#if 0
+ void *localhandle;
+ struct netconfig *nconf;
+ CLIENT *clnt;
+
+ localhandle = setnetconfig();
+ while ((nconf = getnetconfig(localhandle)) != NULL) {
+ if (nconf->nc_protofmly != NULL &&
+ strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
+ break;
+ }
+ if (nconf == NULL) {
+ warnx("getnetconfig: %s", nc_sperror());
+ return (NULL);
+ }
+
+ clnt = clnt_tp_create (/* "localhost"*/ NULL, prog, vers, nconf);
+ endnetconfig(localhandle);
+ return clnt;
+#else
+ struct netbuf nbuf;
+ struct sockaddr_un sun;
+ int sock;
+
+ memset (&sun, 0, sizeof sun);
+ sock = socket (AF_LOCAL, SOCK_STREAM, 0);
+ if (sock < 0)
+ return NULL;
+
+ sun.sun_family = AF_LOCAL;
+ strcpy (sun.sun_path, _PATH_RPCBINDSOCK);
+ nbuf.len = SUN_LEN (&sun);
+ nbuf.maxlen = sizeof (struct sockaddr_un);
+ nbuf.buf = &sun;
+
+ return clnt_vc_create (sock, &nbuf, prog, vers, 0, 0);
+#endif
+}
+
+#ifdef PORTMAP
+static enum clnt_stat
+ip_ping_one(client, vers)
+ CLIENT *client;
+ u_int32_t vers;
+{
+ struct timeval to = { .tv_sec = 10, .tv_usec = 0 };
+
+ (void) CLNT_CONTROL (client, CLSET_VERS, &vers);
+ return CLNT_CALL (client, NULLPROC, (xdrproc_t) xdr_void,
+ (char *) NULL, (xdrproc_t) xdr_void, (char *) NULL,
+ to);
+}
+
+/*
+ * If portnum is 0, then go and get the address from portmapper, which happens
+ * transparently through clnt*_create(); If version number is not given, it
+ * tries to find out the version number by making a call to version 0 and if
+ * that fails, it obtains the high order and the low order version number. If
+ * version 0 calls succeeds, it tries for MAXVERS call and repeats the same.
+ */
+static void
+ip_ping (portnum, proto, argc, argv)
+ u_short portnum;
+ char *proto;
+ int argc;
+ char **argv;
+{
+ CLIENT *client;
+ enum clnt_stat rpc_stat;
+ const char *hostname;
+ u_long prognum, vers, minvers, maxvers;
+ struct rpc_err rpcerr;
+ int failure = 0;
+
+ if (argc < 2 || argc > 3)
+ {
+ usage ();
+ exit (1);
+ }
+
+ hostname = argv[0];
+ prognum = getprognum (argv[1]);
+ if (argc == 2)
+ { /* Version number not known */
+ /*
+ * A call to version 0 should fail with a program/version
+ * mismatch, and give us the range of versions supported.
+ */
+ vers = MIN_VERS;
+ }
+ else
+ {
+ vers = getvers (argv[2]);
+ }
+
+ client = ip_getclient(hostname, prognum, vers, proto);
+
+ rpc_stat = ip_ping_one(client, vers);
+ if (argc != 2)
+ {
+ /* Version number was known */
+ if (pstatus (client, prognum, vers) < 0)
+ exit (1);
+ (void) CLNT_DESTROY (client);
+ return;
+ }
+
+ /* Version number not known */
+ if (rpc_stat == RPC_PROGVERSMISMATCH)
+ {
+ clnt_geterr (client, &rpcerr);
+ minvers = rpcerr.re_vers.low;
+ maxvers = rpcerr.re_vers.high;
+ }
+ else if (rpc_stat == RPC_SUCCESS)
+ {
+ /*
+ * Oh dear, it DOES support version 0.
+ * Let's try version MAX_VERS.
+ */
+ rpc_stat = ip_ping_one(client, MAX_VERS);
+ if (rpc_stat == RPC_PROGVERSMISMATCH)
+ {
+ clnt_geterr (client, &rpcerr);
+ minvers = rpcerr.re_vers.low;
+ maxvers = rpcerr.re_vers.high;
+ }
+ else if (rpc_stat == RPC_SUCCESS)
+ {
+ /*
+ * It also supports version MAX_VERS.
+ * Looks like we have a wise guy.
+ * OK, we give them information on all
+ * 4 billion versions they support...
+ */
+ minvers = 0;
+ maxvers = MAX_VERS;
+ }
+ else
+ {
+ (void) pstatus (client, prognum, MAX_VERS);
+ exit (1);
+ }
+ }
+ else
+ {
+ (void) pstatus (client, prognum, (u_long) 0);
+ exit (1);
+ }
+ for (vers = minvers; vers <= maxvers; vers++)
+ {
+ rpc_stat = ip_ping_one(client, vers);
+ if (pstatus (client, prognum, vers) < 0)
+ failure = 1;
+ }
+ if (failure)
+ exit (1);
+ (void) CLNT_DESTROY (client);
+ return;
+}
+
+/*
+ * Dump all the portmapper registerations
+ */
+static void
+pmapdump (argc, argv)
+ int argc;
+ char **argv;
+{
+ struct pmaplist *head = NULL;
+ struct timeval minutetimeout;
+ register CLIENT *client;
+ struct rpcent *rpc;
+ enum clnt_stat clnt_st;
+ struct rpc_err err;
+ char *host = NULL;
+
+ if (argc > 1)
+ {
+ usage ();
+ exit (1);
+ }
+ if (argc == 1)
+ {
+ host = argv[0];
+
+ /* This is a little bit more complicated than it should be.
+ * ip_getclient will do an rpcb_getaddr call to identify the
+ * port of the portmapper - but it works, and it's easier than
+ * creating a copy of ip_getclient that avoids the getaddr call.
+ */
+ client = ip_getclient(host, PMAPPROG, PMAPVERS, "tcp");
+ }
+ else
+ client = local_rpcb (PMAPPROG, PMAPVERS);
+
+ if (client == NULL)
+ {
+ if (rpc_createerr.cf_stat == RPC_TLIERROR)
+ {
+ /*
+ * "Misc. TLI error" is not too helpful. Most likely
+ * the connection to the remote server timed out, so
+ * this error is at least less perplexing.
+ */
+ rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+ rpc_createerr.cf_error.re_status = RPC_FAILED;
+ }
+ clnt_pcreateerror ("rpcinfo: can't contact portmapper");
+ exit (1);
+ }
+
+ minutetimeout.tv_sec = 60;
+ minutetimeout.tv_usec = 0;
+
+ clnt_st = CLNT_CALL (client, PMAPPROC_DUMP, (xdrproc_t) xdr_void,
+ NULL, (xdrproc_t) xdr_pmaplist_ptr, (char *) &head,
+ minutetimeout);
+ if (clnt_st != RPC_SUCCESS)
+ {
+ if ((clnt_st == RPC_PROGVERSMISMATCH) || (clnt_st == RPC_PROGUNAVAIL))
+ {
+ CLNT_GETERR (client, &err);
+ if (err.re_vers.low > PMAPVERS)
+ fprintf (stderr,
+ "%s does not support portmapper. Try rpcinfo %s instead\n",
+ host, host);
+ exit (1);
+ }
+ clnt_perror (client, "rpcinfo: can't contact portmapper");
+ exit (1);
+ }
+ if (head == NULL)
+ {
+ printf ("No remote programs registered.\n");
+ }
+ else
+ {
+ printf (" program vers proto port service\n");
+ for (; head != NULL; head = head->pml_next)
+ {
+ printf ("%10ld%5ld", head->pml_map.pm_prog, head->pml_map.pm_vers);
+ if (head->pml_map.pm_prot == IPPROTO_UDP)
+ printf ("%6s", "udp");
+ else if (head->pml_map.pm_prot == IPPROTO_TCP)
+ printf ("%6s", "tcp");
+ else
+ printf ("%6ld", head->pml_map.pm_prot);
+ printf ("%7ld", head->pml_map.pm_port);
+ rpc = getrpcbynumber (head->pml_map.pm_prog);
+ if (rpc)
+ printf (" %s\n", rpc->r_name);
+ else
+ printf ("\n");
+ }
+ }
+}
+
+/*
+ * Try to obtain the address of a given host/program/version, using the
+ * specified protocol (one of udp or tcp).
+ * This loops over all netconfig entries (according to the order given by
+ * netpath and the config file), and tries to resolve the hostname, and obtain
+ * the address using rpcb_getaddr.
+ */
+CLIENT *
+ip_getclient(hostname, prognum, versnum, proto)
+ const char *hostname;
+ rpcprog_t prognum;
+ rpcvers_t versnum;
+ const char *proto;
+{
+ void *handle;
+ enum clnt_stat saved_stat = RPC_SUCCESS;
+ struct netconfig *nconf, *result = NULL;
+ struct netbuf bind_address;
+ struct sockaddr_storage __sa;
+ CLIENT *client;
+
+ memset(&bind_address, 0, sizeof(bind_address));
+ bind_address.maxlen = sizeof(__sa);
+ bind_address.buf = &__sa;
+
+ handle = setnetconfig();
+ while ((nconf = getnetconfig(handle)) != NULL)
+ {
+ if (!strcmp(nconf->nc_proto, proto)) {
+ if (rpcb_getaddr(prognum, versnum, nconf, &bind_address, hostname))
+ {
+ result = getnetconfigent(nconf->nc_netid);
+ endnetconfig(handle);
+ break;
+ }
+
+ if (rpc_createerr.cf_stat != RPC_UNKNOWNHOST)
+ {
+ clnt_pcreateerror (hostname);
+ exit (1);
+ }
+
+ saved_stat = rpc_createerr.cf_stat;
+ }
+ }
+
+ if (result == NULL)
+ {
+ if (saved_stat != RPC_SUCCESS)
+ {
+ rpc_createerr.cf_stat = saved_stat;
+ clnt_pcreateerror (hostname);
+ }
+ else
+ fprintf (stderr, "Cannot find suitable transport for protocol %s\n", proto);
+
+ exit (1);
+ }
+
+ client = clnt_tli_create(RPC_ANYFD, result, &bind_address, prognum, versnum, 0, 0);
+ if (client == NULL)
+ {
+ clnt_pcreateerror(hostname);
+ exit (1);
+ }
+
+ freenetconfigent(result);
+ return client;
+}
+#endif /* PORTMAP */
+
+static int
+sa_len(struct sockaddr *sa)
+{
+ socklen_t salen;
+
+ switch (sa->sa_family)
+ {
+ case AF_LOCAL:
+ salen = sizeof (struct sockaddr_un);
+ break;
+ case AF_INET:
+ salen = sizeof (struct sockaddr_in);
+ break;
+ case AF_INET6:
+ salen = sizeof (struct sockaddr_in6);
+ break;
+ default:
+ salen = 0;
+ break;
+ }
+ return salen;
+}
+
+/*
+ * reply_proc collects replies from the broadcast.
+ * to get a unique list of responses the output of rpcinfo should
+ * be piped through sort(1) and then uniq(1).
+ */
+
+ /*ARGSUSED*/ static bool_t
+reply_proc (res, who, nconf)
+ void *res; /* Nothing comes back */
+ struct netbuf *who; /* Who sent us the reply */
+ struct netconfig *nconf; /* On which transport the reply came */
+{
+ char *uaddr;
+ char hostbuf[NI_MAXHOST];
+ char *hostname;
+ struct sockaddr *sa = (struct sockaddr *) who->buf;
+
+ if (getnameinfo (sa, sa_len (sa), hostbuf, NI_MAXHOST, NULL, 0, 0))
+ {
+ hostname = UNKNOWN;
+ }
+ else
+ {
+ hostname = hostbuf;
+ }
+ if (!(uaddr = taddr2uaddr (nconf, who)))
+ {
+ uaddr = UNKNOWN;
+ }
+ printf ("%s\t%s\n", uaddr, hostname);
+ if (strcmp (uaddr, UNKNOWN))
+ free ((char *) uaddr);
+ return (FALSE);
+}
+
+static void
+brdcst (argc, argv)
+ int argc;
+ char **argv;
+{
+ enum clnt_stat rpc_stat;
+ u_long prognum, vers;
+
+ if (argc != 2)
+ {
+ usage ();
+ exit (1);
+ }
+ prognum = getprognum (argv[0]);
+ vers = getvers (argv[1]);
+ rpc_stat = rpc_broadcast (prognum, vers, NULLPROC,
+ (xdrproc_t) xdr_void, (char *) NULL,
+ (xdrproc_t) xdr_void, (char *) NULL,
+ (resultproc_t) reply_proc, NULL);
+ if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT))
+ {
+ fprintf (stderr, "rpcinfo: broadcast failed: %s\n",
+ clnt_sperrno (rpc_stat));
+ exit (1);
+ }
+ exit (0);
+}
+
+static bool_t
+add_version (rs, vers)
+ struct rpcbdump_short *rs;
+ u_long vers;
+{
+ struct verslist *vl;
+
+ for (vl = rs->vlist; vl; vl = vl->next)
+ if (vl->vers == vers)
+ break;
+ if (vl)
+ return (TRUE);
+ vl = (struct verslist *) malloc (sizeof (struct verslist));
+ if (vl == NULL)
+ return (FALSE);
+ vl->vers = vers;
+ vl->next = rs->vlist;
+ rs->vlist = vl;
+ return (TRUE);
+}
+
+static bool_t
+add_netid (rs, netid)
+ struct rpcbdump_short *rs;
+ char *netid;
+{
+ struct netidlist *nl;
+
+ for (nl = rs->nlist; nl; nl = nl->next)
+ if (strcmp (nl->netid, netid) == 0)
+ break;
+ if (nl)
+ return (TRUE);
+ nl = (struct netidlist *) malloc (sizeof (struct netidlist));
+ if (nl == NULL)
+ return (FALSE);
+ nl->netid = netid;
+ nl->next = rs->nlist;
+ rs->nlist = nl;
+ return (TRUE);
+}
+
+static void
+rpcbdump (dumptype, netid, argc, argv)
+ int dumptype;
+ char *netid;
+ int argc;
+ char **argv;
+{
+ rpcblist_ptr head = NULL;
+ struct timeval minutetimeout;
+ register CLIENT *client;
+ struct rpcent *rpc;
+ char *host;
+ struct netidlist *nl;
+ struct verslist *vl;
+ struct rpcbdump_short *rs, *rs_tail = NULL;
+ char buf[256];
+ enum clnt_stat clnt_st;
+ struct rpc_err err;
+ struct rpcbdump_short *rs_head = NULL;
+
+ if (argc > 1)
+ {
+ usage ();
+ exit (1);
+ }
+ if (argc == 1)
+ {
+ host = argv[0];
+ if (netid == NULL)
+ {
+ client = clnt_rpcbind_create (host, RPCBVERS, NULL);
+ }
+ else
+ {
+ struct netconfig *nconf;
+
+ nconf = getnetconfigent (netid);
+ if (nconf == NULL)
+ {
+ nc_perror ("rpcinfo: invalid transport");
+ exit (1);
+ }
+ client = getclnthandle (host, nconf, RPCBVERS, NULL);
+ if (nconf)
+ (void) freenetconfigent (nconf);
+ }
+ }
+ else
+ client = local_rpcb (PMAPPROG, RPCBVERS);
+
+ if (client == (CLIENT *) NULL)
+ {
+ clnt_pcreateerror ("rpcinfo: can't contact rpcbind");
+ exit (1);
+ }
+ minutetimeout.tv_sec = 60;
+ minutetimeout.tv_usec = 0;
+ clnt_st = CLNT_CALL (client, RPCBPROC_DUMP, (xdrproc_t) xdr_void,
+ NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
+ minutetimeout);
+ if (clnt_st != RPC_SUCCESS)
+ {
+ if ((clnt_st == RPC_PROGVERSMISMATCH) || (clnt_st == RPC_PROGUNAVAIL))
+ {
+ int vers;
+
+ CLNT_GETERR (client, &err);
+ if (err.re_vers.low == RPCBVERS4)
+ {
+ vers = RPCBVERS4;
+ clnt_control (client, CLSET_VERS, (char *) &vers);
+ clnt_st = CLNT_CALL (client, RPCBPROC_DUMP,
+ (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_rpcblist_ptr,
+ (char *) &head, minutetimeout);
+ if (clnt_st != RPC_SUCCESS)
+ goto failed;
+ }
+ else
+ {
+ if (err.re_vers.high == PMAPVERS)
+ {
+ int high, low;
+ struct pmaplist *pmaphead = NULL;
+ rpcblist_ptr list, prev = NULL;
+
+ vers = PMAPVERS;
+ clnt_control (client, CLSET_VERS, (char *) &vers);
+ clnt_st = CLNT_CALL (client, PMAPPROC_DUMP,
+ (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_pmaplist_ptr,
+ (char *) &pmaphead, minutetimeout);
+ if (clnt_st != RPC_SUCCESS)
+ goto failed;
+ /*
+ * convert to rpcblist_ptr format
+ */
+ for (head = NULL; pmaphead != NULL;
+ pmaphead = pmaphead->pml_next)
+ {
+ list = (rpcblist *) malloc (sizeof (rpcblist));
+ if (list == NULL)
+ goto error;
+ if (head == NULL)
+ head = list;
+ else
+ prev->rpcb_next = (rpcblist_ptr) list;
+
+ list->rpcb_next = NULL;
+ list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog;
+ list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers;
+ if (pmaphead->pml_map.pm_prot == IPPROTO_UDP)
+ list->rpcb_map.r_netid = "udp";
+ else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP)
+ list->rpcb_map.r_netid = "tcp";
+ else
+ {
+#define MAXLONG_AS_STRING "2147483648"
+ list->rpcb_map.r_netid =
+ malloc (strlen (MAXLONG_AS_STRING) + 1);
+ if (list->rpcb_map.r_netid == NULL)
+ goto error;
+ sprintf (list->rpcb_map.r_netid, "%6ld",
+ pmaphead->pml_map.pm_prot);
+ }
+ list->rpcb_map.r_owner = UNKNOWN;
+ low = pmaphead->pml_map.pm_port & 0xff;
+ high = (pmaphead->pml_map.pm_port >> 8) & 0xff;
+ list->rpcb_map.r_addr = strdup ("0.0.0.0.XXX.XXX");
+ sprintf (&list->rpcb_map.r_addr[8], "%d.%d", high, low);
+ prev = list;
+ }
+ }
+ }
+ }
+ else
+ { /* any other error */
+ failed:
+ clnt_perror (client, "rpcinfo: can't contact rpcbind: ");
+ exit (1);
+ }
+ }
+ if (head == NULL)
+ {
+ printf ("No remote programs registered.\n");
+ }
+ else if (dumptype == RPCBDUMP)
+ {
+ printf
+ (" program version netid address service owner\n");
+ for (; head != NULL; head = head->rpcb_next)
+ {
+ printf ("%10u%5u ",
+ head->rpcb_map.r_prog, head->rpcb_map.r_vers);
+ printf ("%-9s ", head->rpcb_map.r_netid);
+ printf ("%-22s", head->rpcb_map.r_addr);
+ rpc = getrpcbynumber (head->rpcb_map.r_prog);
+ if (rpc)
+ printf (" %-10s", rpc->r_name);
+ else
+ printf (" %-10s", "-");
+ printf (" %s\n", head->rpcb_map.r_owner);
+ }
+ }
+ else if (dumptype == RPCBDUMP_SHORT)
+ {
+ for (; head != NULL; head = head->rpcb_next)
+ {
+ for (rs = rs_head; rs; rs = rs->next)
+ if (head->rpcb_map.r_prog == rs->prog)
+ break;
+ if (rs == NULL)
+ {
+ rs = (struct rpcbdump_short *)
+ malloc (sizeof (struct rpcbdump_short));
+ if (rs == NULL)
+ goto error;
+ rs->next = NULL;
+ if (rs_head == NULL)
+ {
+ rs_head = rs;
+ rs_tail = rs;
+ }
+ else
+ {
+ rs_tail->next = rs;
+ rs_tail = rs;
+ }
+ rs->prog = head->rpcb_map.r_prog;
+ rs->owner = head->rpcb_map.r_owner;
+ rs->nlist = NULL;
+ rs->vlist = NULL;
+ }
+ if (add_version (rs, head->rpcb_map.r_vers) == FALSE)
+ goto error;
+ if (add_netid (rs, head->rpcb_map.r_netid) == FALSE)
+ goto error;
+ }
+ printf
+ (" program version(s) netid(s) service owner\n");
+ for (rs = rs_head; rs; rs = rs->next)
+ {
+ size_t netidmax = sizeof(buf) - 1;
+ char *p = buf;
+
+ printf ("%10ld ", rs->prog);
+ for (vl = rs->vlist; vl; vl = vl->next)
+ {
+ sprintf (p, "%d", vl->vers);
+ p = p + strlen (p);
+ if (vl->next)
+ sprintf (p++, ",");
+ }
+ printf ("%-10s", buf);
+ buf[0] = '\0';
+
+ for (nl = rs->nlist; nl; nl = nl->next)
+ {
+ strncat (buf, nl->netid, netidmax);
+ if (strlen (nl->netid) < netidmax)
+ netidmax -= strlen(nl->netid);
+ else
+ break;
+
+ if (nl->next && netidmax > 1)
+ {
+ strncat (buf, ",", netidmax);
+ netidmax --;
+ }
+ }
+
+ printf ("%-32s", buf);
+ rpc = getrpcbynumber (rs->prog);
+ if (rpc)
+ printf (" %-11s", rpc->r_name);
+ else
+ printf (" %-11s", "-");
+ printf (" %s\n", rs->owner);
+ }
+ }
+ clnt_destroy (client);
+ return;
+error:fprintf (stderr, "rpcinfo: no memory\n");
+ return;
+}
+
+static char nullstring[] = "\000";
+
+static void
+rpcbaddrlist (netid, argc, argv)
+ char *netid;
+ int argc;
+ char **argv;
+{
+ rpcb_entry_list_ptr head = NULL;
+ struct timeval minutetimeout;
+ register CLIENT *client;
+ struct rpcent *rpc;
+ char *host;
+ RPCB parms;
+ struct netbuf *targaddr;
+
+ if (argc != 3)
+ {
+ usage ();
+ exit (1);
+ }
+ host = argv[0];
+ if (netid == NULL)
+ {
+ client = clnt_rpcbind_create (host, RPCBVERS4, &targaddr);
+ }
+ else
+ {
+ struct netconfig *nconf;
+
+ nconf = getnetconfigent (netid);
+ if (nconf == NULL)
+ {
+ nc_perror ("rpcinfo: invalid transport");
+ exit (1);
+ }
+ client = getclnthandle (host, nconf, RPCBVERS4, &targaddr);
+ if (nconf)
+ (void) freenetconfigent (nconf);
+ }
+ if (client == (CLIENT *) NULL)
+ {
+ clnt_pcreateerror ("rpcinfo: can't contact rpcbind");
+ exit (1);
+ }
+ minutetimeout.tv_sec = 60;
+ minutetimeout.tv_usec = 0;
+
+ parms.r_prog = getprognum (argv[1]);
+ parms.r_vers = getvers (argv[2]);
+ parms.r_netid = client->cl_netid;
+ if (targaddr == NULL)
+ {
+ parms.r_addr = nullstring; /* for XDRing */
+ }
+ else
+ {
+ /*
+ * We also send the remote system the address we
+ * used to contact it in case it can help it
+ * connect back with us
+ */
+ struct netconfig *nconf;
+
+ nconf = getnetconfigent (client->cl_netid);
+ if (nconf != NULL)
+ {
+ parms.r_addr = taddr2uaddr (nconf, targaddr);
+ if (parms.r_addr == NULL)
+ parms.r_addr = nullstring;
+ freenetconfigent (nconf);
+ }
+ else
+ {
+ parms.r_addr = nullstring; /* for XDRing */
+ }
+ free (targaddr->buf);
+ free (targaddr);
+ }
+ parms.r_owner = nullstring;
+
+ if (CLNT_CALL (client, RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb,
+ (char *) &parms, (xdrproc_t) xdr_rpcb_entry_list_ptr,
+ (char *) &head, minutetimeout) != RPC_SUCCESS)
+ {
+ clnt_perror (client, "rpcinfo: can't contact rpcbind: ");
+ exit (1);
+ }
+ if (head == NULL)
+ {
+ printf ("No remote programs registered.\n");
+ }
+ else
+ {
+ printf
+ (" program vers tp_family/name/class address\t\t service\n");
+ for (; head != NULL; head = head->rpcb_entry_next)
+ {
+ rpcb_entry *re;
+ char buf[128];
+
+ re = &head->rpcb_entry_map;
+ printf ("%10u%3u ", parms.r_prog, parms.r_vers);
+ sprintf (buf, "%s/%s/%s ",
+ re->r_nc_protofmly, re->r_nc_proto,
+ re->r_nc_semantics == NC_TPI_CLTS ? "clts" :
+ re->r_nc_semantics == NC_TPI_COTS ? "cots" : "cots_ord");
+ printf ("%-24s", buf);
+ printf ("%-24s", re->r_maddr);
+ rpc = getrpcbynumber (parms.r_prog);
+ if (rpc)
+ printf (" %-13s", rpc->r_name);
+ else
+ printf (" %-13s", "-");
+ printf ("\n");
+ }
+ }
+ clnt_destroy (client);
+ return;
+}
+
+/*
+ * monitor rpcbind
+ */
+static void
+rpcbgetstat (argc, argv)
+ int argc;
+ char **argv;
+{
+ rpcb_stat_byvers inf;
+ struct timeval minutetimeout;
+ register CLIENT *client;
+ char *host;
+ int i, j;
+ rpcbs_addrlist *pa;
+ rpcbs_rmtcalllist *pr;
+ int cnt, flen;
+#define MAXFIELD 64
+ char fieldbuf[MAXFIELD];
+#define MAXLINE 256
+ char linebuf[MAXLINE];
+ char *cp, *lp;
+ char *pmaphdr[] = {
+ "NULL", "SET", "UNSET", "GETPORT",
+ "DUMP", "CALLIT"
+ };
+ char *rpcb3hdr[] = {
+ "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
+ "U2T", "T2U"
+ };
+ char *rpcb4hdr[] = {
+ "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
+ "U2T", "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT"
+ };
+
+#define TABSTOP 8
+
+ if (argc >= 1)
+ {
+ host = argv[0];
+ client = clnt_rpcbind_create (host, RPCBVERS4, NULL);
+ }
+ else
+ client = local_rpcb (PMAPPROG, RPCBVERS4);
+ if (client == (CLIENT *) NULL)
+ {
+ clnt_pcreateerror ("rpcinfo: can't contact rpcbind");
+ exit (1);
+ }
+ minutetimeout.tv_sec = 60;
+ minutetimeout.tv_usec = 0;
+ memset ((char *) &inf, 0, sizeof (rpcb_stat_byvers));
+ if (CLNT_CALL (client, RPCBPROC_GETSTAT, (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_rpcb_stat_byvers, (char *) &inf,
+ minutetimeout) != RPC_SUCCESS)
+ {
+ clnt_perror (client, "rpcinfo: can't contact rpcbind: ");
+ exit (1);
+ }
+ printf ("PORTMAP (version 2) statistics\n");
+ lp = linebuf;
+ for (i = 0; i <= rpcb_highproc_2; i++)
+ {
+ fieldbuf[0] = '\0';
+ switch (i)
+ {
+ case PMAPPROC_SET:
+ sprintf (fieldbuf, "%d/", inf[RPCBVERS_2_STAT].setinfo);
+ break;
+ case PMAPPROC_UNSET:
+ sprintf (fieldbuf, "%d/", inf[RPCBVERS_2_STAT].unsetinfo);
+ break;
+ case PMAPPROC_GETPORT:
+ cnt = 0;
+ for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa; pa = pa->next)
+ cnt += pa->success;
+ sprintf (fieldbuf, "%d/", cnt);
+ break;
+ case PMAPPROC_CALLIT:
+ cnt = 0;
+ for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr; pr = pr->next)
+ cnt += pr->success;
+ sprintf (fieldbuf, "%d/", cnt);
+ break;
+ default:
+ break; /* For the remaining ones */
+ }
+ cp = &fieldbuf[0] + strlen (fieldbuf);
+ sprintf (cp, "%d", inf[RPCBVERS_2_STAT].info[i]);
+ flen = strlen (fieldbuf);
+ printf ("%s%s", pmaphdr[i],
+ spaces ((TABSTOP * (1 + flen / TABSTOP))
+ - strlen (pmaphdr[i])));
+ sprintf (lp, "%s%s", fieldbuf,
+ spaces (cnt = ((TABSTOP * (1 + flen / TABSTOP)) - flen)));
+ lp += (flen + cnt);
+ }
+ printf ("\n%s\n\n", linebuf);
+
+ if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT])
+ {
+ printf ("PMAP_RMTCALL call statistics\n");
+ print_rmtcallstat (RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
+ printf ("\n");
+ }
+
+ if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT])
+ {
+ printf ("PMAP_GETPORT call statistics\n");
+ print_getaddrstat (RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
+ printf ("\n");
+ }
+
+ printf ("RPCBIND (version 3) statistics\n");
+ lp = linebuf;
+ for (i = 0; i <= rpcb_highproc_3; i++)
+ {
+ fieldbuf[0] = '\0';
+ switch (i)
+ {
+ case RPCBPROC_SET:
+ sprintf (fieldbuf, "%d/", inf[RPCBVERS_3_STAT].setinfo);
+ break;
+ case RPCBPROC_UNSET:
+ sprintf (fieldbuf, "%d/", inf[RPCBVERS_3_STAT].unsetinfo);
+ break;
+ case RPCBPROC_GETADDR:
+ cnt = 0;
+ for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa; pa = pa->next)
+ cnt += pa->success;
+ sprintf (fieldbuf, "%d/", cnt);
+ break;
+ case RPCBPROC_CALLIT:
+ cnt = 0;
+ for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr; pr = pr->next)
+ cnt += pr->success;
+ sprintf (fieldbuf, "%d/", cnt);
+ break;
+ default:
+ break; /* For the remaining ones */
+ }
+ cp = &fieldbuf[0] + strlen (fieldbuf);
+ sprintf (cp, "%d", inf[RPCBVERS_3_STAT].info[i]);
+ flen = strlen (fieldbuf);
+ printf ("%s%s", rpcb3hdr[i],
+ spaces ((TABSTOP * (1 + flen / TABSTOP))
+ - strlen (rpcb3hdr[i])));
+ sprintf (lp, "%s%s", fieldbuf,
+ spaces (cnt = ((TABSTOP * (1 + flen / TABSTOP)) - flen)));
+ lp += (flen + cnt);
+ }
+ printf ("\n%s\n\n", linebuf);
+
+ if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT])
+ {
+ printf ("RPCB_RMTCALL (version 3) call statistics\n");
+ print_rmtcallstat (RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
+ printf ("\n");
+ }
+
+ if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR])
+ {
+ printf ("RPCB_GETADDR (version 3) call statistics\n");
+ print_getaddrstat (RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
+ printf ("\n");
+ }
+
+ printf ("RPCBIND (version 4) statistics\n");
+
+ for (j = 0; j <= 9; j += 9)
+ { /* Just two iterations for printing */
+ lp = linebuf;
+ for (i = j; i <= max (8, rpcb_highproc_4 - 9 + j); i++)
+ {
+ fieldbuf[0] = '\0';
+ switch (i)
+ {
+ case RPCBPROC_SET:
+ sprintf (fieldbuf, "%d/", inf[RPCBVERS_4_STAT].setinfo);
+ break;
+ case RPCBPROC_UNSET:
+ sprintf (fieldbuf, "%d/", inf[RPCBVERS_4_STAT].unsetinfo);
+ break;
+ case RPCBPROC_GETADDR:
+ cnt = 0;
+ for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa; pa = pa->next)
+ cnt += pa->success;
+ sprintf (fieldbuf, "%d/", cnt);
+ break;
+ case RPCBPROC_CALLIT:
+ cnt = 0;
+ for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr; pr = pr->next)
+ cnt += pr->success;
+ sprintf (fieldbuf, "%d/", cnt);
+ break;
+ default:
+ break; /* For the remaining ones */
+ }
+ cp = &fieldbuf[0] + strlen (fieldbuf);
+ /*
+ * XXX: We also add RPCBPROC_GETADDRLIST queries to
+ * RPCB_GETADDR because rpcbind includes the
+ * RPCB_GETADDRLIST successes in RPCB_GETADDR.
+ */
+ if (i != RPCBPROC_GETADDR)
+ sprintf (cp, "%d", inf[RPCBVERS_4_STAT].info[i]);
+ else
+ sprintf (cp, "%d", inf[RPCBVERS_4_STAT].info[i] +
+ inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]);
+ flen = strlen (fieldbuf);
+ printf ("%s%s", rpcb4hdr[i],
+ spaces ((TABSTOP * (1 + flen / TABSTOP))
+ - strlen (rpcb4hdr[i])));
+ sprintf (lp, "%s%s", fieldbuf,
+ spaces (cnt = ((TABSTOP * (1 + flen / TABSTOP)) - flen)));
+ lp += (flen + cnt);
+ }
+ printf ("\n%s\n", linebuf);
+ }
+
+ if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] ||
+ inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT])
+ {
+ printf ("\n");
+ printf ("RPCB_RMTCALL (version 4) call statistics\n");
+ print_rmtcallstat (RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
+ }
+
+ if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR])
+ {
+ printf ("\n");
+ printf ("RPCB_GETADDR (version 4) call statistics\n");
+ print_getaddrstat (RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
+ }
+ clnt_destroy (client);
+}
+
+/*
+ * Delete registeration for this (prog, vers, netid)
+ */
+static void
+deletereg (netid, argc, argv)
+ char *netid;
+ int argc;
+ char **argv;
+{
+ struct netconfig *nconf = NULL;
+
+ if (argc != 2)
+ {
+ usage ();
+ exit (1);
+ }
+ if (netid)
+ {
+ nconf = getnetconfigent (netid);
+ if (nconf == NULL)
+ {
+ fprintf (stderr, "rpcinfo: netid %s not supported\n", netid);
+ exit (1);
+ }
+ }
+ if ((rpcb_unset (getprognum (argv[0]), getvers (argv[1]), nconf)) == 0)
+ {
+ fprintf (stderr,
+ "rpcinfo: Could not delete registration for prog %s version %s\n",
+ argv[0], argv[1]);
+ exit (1);
+ }
+}
+
+/*
+ * Create and return a handle for the given nconf.
+ * Exit if cannot create handle.
+ */
+static CLIENT *
+clnt_addr_create (address, nconf, prog, vers)
+ char *address;
+ struct netconfig *nconf;
+ u_long prog;
+ u_long vers;
+{
+ CLIENT *client;
+ static struct netbuf *nbuf;
+ static int fd = RPC_ANYFD;
+
+ if (fd == RPC_ANYFD)
+ {
+ if ((fd = __rpc_nconf2fd (nconf)) == -1)
+ {
+ rpc_createerr.cf_stat = RPC_TLIERROR;
+ clnt_pcreateerror ("rpcinfo");
+ exit (1);
+ }
+ /* Convert the uaddr to taddr */
+ nbuf = uaddr2taddr (nconf, address);
+ if (nbuf == NULL)
+ {
+ errx (1, "rpcinfo: no address for client handle");
+ exit (1);
+ }
+ }
+ client = clnt_tli_create (fd, nconf, nbuf, prog, vers, 0, 0);
+ if (client == (CLIENT *) NULL)
+ {
+ clnt_pcreateerror ("rpcinfo");
+ exit (1);
+ }
+ return (client);
+}
+
+/*
+ * If the version number is given, ping that (prog, vers); else try to find
+ * the version numbers supported for that prog and ping all the versions.
+ * Remote rpcbind is not contacted for this service. The requests are
+ * sent directly to the services themselves.
+ */
+static void
+addrping (address, netid, argc, argv)
+ char *address;
+ char *netid;
+ int argc;
+ char **argv;
+{
+ CLIENT *client;
+ struct timeval to;
+ enum clnt_stat rpc_stat;
+ u_int32_t prognum, versnum, minvers, maxvers;
+ struct rpc_err rpcerr;
+ int failure = 0;
+ struct netconfig *nconf;
+ int fd;
+
+ if (argc < 1 || argc > 2 || (netid == NULL))
+ {
+ usage ();
+ exit (1);
+ }
+ nconf = getnetconfigent (netid);
+ if (nconf == (struct netconfig *) NULL)
+ {
+ fprintf (stderr, "rpcinfo: Could not find %s\n", netid);
+ exit (1);
+ }
+ to.tv_sec = 10;
+ to.tv_usec = 0;
+ prognum = getprognum (argv[0]);
+ if (argc == 1)
+ { /* Version number not known */
+ /*
+ * A call to version 0 should fail with a program/version
+ * mismatch, and give us the range of versions supported.
+ */
+ versnum = MIN_VERS;
+ }
+ else
+ {
+ versnum = getvers (argv[1]);
+ }
+ client = clnt_addr_create (address, nconf, prognum, versnum);
+ rpc_stat = CLNT_CALL (client, NULLPROC, (xdrproc_t) xdr_void,
+ (char *) NULL, (xdrproc_t) xdr_void,
+ (char *) NULL, to);
+ if (argc == 2)
+ {
+ /* Version number was known */
+ if (pstatus (client, prognum, versnum) < 0)
+ failure = 1;
+ (void) CLNT_DESTROY (client);
+ if (failure)
+ exit (1);
+ return;
+ }
+ /* Version number not known */
+ (void) CLNT_CONTROL (client, CLSET_FD_NCLOSE, (char *) NULL);
+ (void) CLNT_CONTROL (client, CLGET_FD, (char *) &fd);
+ if (rpc_stat == RPC_PROGVERSMISMATCH)
+ {
+ clnt_geterr (client, &rpcerr);
+ minvers = rpcerr.re_vers.low;
+ maxvers = rpcerr.re_vers.high;
+ }
+ else if (rpc_stat == RPC_SUCCESS)
+ {
+ /*
+ * Oh dear, it DOES support version 0.
+ * Let's try version MAX_VERS.
+ */
+ (void) CLNT_DESTROY (client);
+ client = clnt_addr_create (address, nconf, prognum, MAX_VERS);
+ rpc_stat = CLNT_CALL (client, NULLPROC, (xdrproc_t) xdr_void,
+ (char *) NULL, (xdrproc_t) xdr_void,
+ (char *) NULL, to);
+ if (rpc_stat == RPC_PROGVERSMISMATCH)
+ {
+ clnt_geterr (client, &rpcerr);
+ minvers = rpcerr.re_vers.low;
+ maxvers = rpcerr.re_vers.high;
+ }
+ else if (rpc_stat == RPC_SUCCESS)
+ {
+ /*
+ * It also supports version MAX_VERS.
+ * Looks like we have a wise guy.
+ * OK, we give them information on all
+ * 4 billion versions they support...
+ */
+ minvers = 0;
+ maxvers = MAX_VERS;
+ }
+ else
+ {
+ (void) pstatus (client, prognum, MAX_VERS);
+ exit (1);
+ }
+ }
+ else
+ {
+ (void) pstatus (client, prognum, (u_long) 0);
+ exit (1);
+ }
+ (void) CLNT_DESTROY (client);
+ for (versnum = minvers; versnum <= maxvers; versnum++)
+ {
+ client = clnt_addr_create (address, nconf, prognum, versnum);
+ rpc_stat = CLNT_CALL (client, NULLPROC, (xdrproc_t) xdr_void,
+ (char *) NULL, (xdrproc_t) xdr_void,
+ (char *) NULL, to);
+ if (pstatus (client, prognum, versnum) < 0)
+ failure = 1;
+ (void) CLNT_DESTROY (client);
+ }
+ (void) close (fd);
+ if (failure)
+ exit (1);
+ return;
+}
+
+/*
+ * If the version number is given, ping that (prog, vers); else try to find
+ * the version numbers supported for that prog and ping all the versions.
+ * Remote rpcbind is *contacted* for this service. The requests are
+ * then sent directly to the services themselves.
+ */
+static void
+progping (netid, argc, argv)
+ char *netid;
+ int argc;
+ char **argv;
+{
+ CLIENT *client;
+ struct timeval to;
+ enum clnt_stat rpc_stat;
+ u_int32_t prognum, versnum, minvers, maxvers;
+ struct rpc_err rpcerr;
+ int failure = 0;
+ struct netconfig *nconf;
+
+ if (argc < 2 || argc > 3 || (netid == NULL))
+ {
+ usage ();
+ exit (1);
+ }
+ prognum = getprognum (argv[1]);
+ if (argc == 2)
+ { /* Version number not known */
+ /*
+ * A call to version 0 should fail with a program/version
+ * mismatch, and give us the range of versions supported.
+ */
+ versnum = MIN_VERS;
+ }
+ else
+ {
+ versnum = getvers (argv[2]);
+ }
+ if (netid)
+ {
+ nconf = getnetconfigent (netid);
+ if (nconf == (struct netconfig *) NULL)
+ {
+ fprintf (stderr, "rpcinfo: Could not find %s\n", netid);
+ exit (1);
+ }
+ client = clnt_tp_create (argv[0], prognum, versnum, nconf);
+ }
+ else
+ {
+ client = clnt_create (argv[0], prognum, versnum, "NETPATH");
+ }
+ if (client == (CLIENT *) NULL)
+ {
+ clnt_pcreateerror ("rpcinfo");
+ exit (1);
+ }
+ to.tv_sec = 10;
+ to.tv_usec = 0;
+ rpc_stat = CLNT_CALL (client, NULLPROC, (xdrproc_t) xdr_void,
+ (char *) NULL, (xdrproc_t) xdr_void,
+ (char *) NULL, to);
+ if (argc == 3)
+ {
+ /* Version number was known */
+ if (pstatus (client, prognum, versnum) < 0)
+ failure = 1;
+ (void) CLNT_DESTROY (client);
+ if (failure)
+ exit (1);
+ return;
+ }
+ /* Version number not known */
+ if (rpc_stat == RPC_PROGVERSMISMATCH)
+ {
+ clnt_geterr (client, &rpcerr);
+ minvers = rpcerr.re_vers.low;
+ maxvers = rpcerr.re_vers.high;
+ }
+ else if (rpc_stat == RPC_SUCCESS)
+ {
+ /*
+ * Oh dear, it DOES support version 0.
+ * Let's try version MAX_VERS.
+ */
+ versnum = MAX_VERS;
+ (void) CLNT_CONTROL (client, CLSET_VERS, (char *) &versnum);
+ rpc_stat = CLNT_CALL (client, NULLPROC,
+ (xdrproc_t) xdr_void, (char *) NULL,
+ (xdrproc_t) xdr_void, (char *) NULL, to);
+ if (rpc_stat == RPC_PROGVERSMISMATCH)
+ {
+ clnt_geterr (client, &rpcerr);
+ minvers = rpcerr.re_vers.low;
+ maxvers = rpcerr.re_vers.high;
+ }
+ else if (rpc_stat == RPC_SUCCESS)
+ {
+ /*
+ * It also supports version MAX_VERS.
+ * Looks like we have a wise guy.
+ * OK, we give them information on all
+ * 4 billion versions they support...
+ */
+ minvers = 0;
+ maxvers = MAX_VERS;
+ }
+ else
+ {
+ (void) pstatus (client, prognum, MAX_VERS);
+ exit (1);
+ }
+ }
+ else
+ {
+ (void) pstatus (client, prognum, (u_long) 0);
+ exit (1);
+ }
+ for (versnum = minvers; versnum <= maxvers; versnum++)
+ {
+ (void) CLNT_CONTROL (client, CLSET_VERS, (char *) &versnum);
+ rpc_stat = CLNT_CALL (client, NULLPROC, (xdrproc_t) xdr_void,
+ (char *) NULL, (xdrproc_t) xdr_void,
+ (char *) NULL, to);
+ if (pstatus (client, prognum, versnum) < 0)
+ failure = 1;
+ }
+ (void) CLNT_DESTROY (client);
+ if (failure)
+ exit (1);
+ return;
+}
+
+static void
+usage ()
+{
+ fprintf (stderr, "Usage: rpcinfo [-m | -s] [host]\n");
+#ifdef PORTMAP
+ fprintf (stderr, " rpcinfo -p [host]\n");
+#endif
+ fprintf (stderr, " rpcinfo -T netid host prognum [versnum]\n");
+ fprintf (stderr, " rpcinfo -l host prognum versnum\n");
+#ifdef PORTMAP
+ fprintf (stderr,
+ " rpcinfo [-n portnum] -u | -t host prognum [versnum]\n");
+#endif
+ fprintf (stderr,
+ " rpcinfo -a serv_address -T netid prognum [version]\n");
+ fprintf (stderr, " rpcinfo -b prognum versnum\n");
+ fprintf (stderr, " rpcinfo -d [-T netid] prognum versnum\n");
+}
+
+static u_long
+getprognum (arg)
+ char *arg;
+{
+ char *strptr;
+ register struct rpcent *rpc;
+ register u_long prognum;
+ char *tptr = arg;
+
+ while (*tptr && isdigit (*tptr++));
+ if (*tptr || isalpha (*(tptr - 1)))
+ {
+ rpc = getrpcbyname (arg);
+ if (rpc == NULL)
+ {
+ fprintf (stderr, "rpcinfo: %s is unknown service\n", arg);
+ exit (1);
+ }
+ prognum = rpc->r_number;
+ }
+ else
+ {
+ prognum = strtol (arg, &strptr, 10);
+ if (strptr == arg || *strptr != '\0')
+ {
+ fprintf (stderr, "rpcinfo: %s is illegal program number\n", arg);
+ exit (1);
+ }
+ }
+ return (prognum);
+}
+
+static u_long
+getvers (arg)
+ char *arg;
+{
+ char *strptr;
+ register u_long vers;
+
+ vers = (int) strtol (arg, &strptr, 10);
+ if (strptr == arg || *strptr != '\0')
+ {
+ fprintf (stderr, "rpcinfo: %s is illegal version number\n", arg);
+ exit (1);
+ }
+ return (vers);
+}
+
+/*
+ * This routine should take a pointer to an "rpc_err" structure, rather than
+ * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
+ * a CLIENT structure rather than a pointer to an "rpc_err" structure.
+ * As such, we have to keep the CLIENT structure around in order to print
+ * a good error message.
+ */
+static int
+pstatus (client, prog, vers)
+ register CLIENT *client;
+ u_long prog;
+ u_long vers;
+{
+ struct rpc_err rpcerr;
+
+ clnt_geterr (client, &rpcerr);
+ if (rpcerr.re_status != RPC_SUCCESS)
+ {
+ clnt_perror (client, "rpcinfo");
+ printf ("program %lu version %lu is not available\n", prog, vers);
+ return (-1);
+ }
+ else
+ {
+ printf ("program %lu version %lu ready and waiting\n", prog, vers);
+ return (0);
+ }
+}
+
+static CLIENT *
+clnt_rpcbind_create (host, rpcbversnum, targaddr)
+ char *host;
+ int rpcbversnum;
+ struct netbuf **targaddr;
+{
+ static char *tlist[3] = {
+ "circuit_n", "circuit_v", "datagram_v"
+ };
+ int i;
+ struct netconfig *nconf;
+ CLIENT *clnt = NULL;
+ void *handle;
+
+ rpc_createerr.cf_stat = RPC_SUCCESS;
+ for (i = 0; i < 3; i++)
+ {
+ if ((handle = __rpc_setconf (tlist[i])) == NULL)
+ continue;
+ while (clnt == (CLIENT *) NULL)
+ {
+ if ((nconf = __rpc_getconf (handle)) == NULL)
+ {
+ if (rpc_createerr.cf_stat == RPC_SUCCESS)
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ break;
+ }
+ clnt = getclnthandle (host, nconf, rpcbversnum, targaddr);
+ }
+ if (clnt)
+ break;
+ __rpc_endconf (handle);
+ }
+ return (clnt);
+}
+
+static CLIENT *
+getclnthandle (host, nconf, rpcbversnum, targaddr)
+ char *host;
+ struct netconfig *nconf;
+ u_long rpcbversnum;
+ struct netbuf **targaddr;
+{
+ struct netbuf addr;
+ struct addrinfo hints, *res;
+ CLIENT *client = NULL;
+
+ /* Get the address of the rpcbind */
+ memset (&hints, 0, sizeof hints);
+ if ((getaddrinfo (host, "rpcbind", &hints, &res) != 0) &&
+ (getaddrinfo (host, "portmapper",&hints, &res) != 0))
+ {
+ rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
+ return (NULL);
+ }
+ addr.len = addr.maxlen = res->ai_addrlen;
+ addr.buf = res->ai_addr;
+ client = clnt_tli_create (RPC_ANYFD, nconf, &addr, RPCBPROG,
+ rpcbversnum, 0, 0);
+ if (client)
+ {
+ if (targaddr != NULL)
+ {
+ *targaddr = (struct netbuf *) malloc (sizeof (struct netbuf));
+ if (*targaddr != NULL)
+ {
+ (*targaddr)->maxlen = addr.maxlen;
+ (*targaddr)->len = addr.len;
+ (*targaddr)->buf = (char *) malloc (addr.len);
+ if ((*targaddr)->buf != NULL)
+ {
+ memcpy ((*targaddr)->buf, addr.buf, addr.len);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (rpc_createerr.cf_stat == RPC_TLIERROR)
+ {
+ /*
+ * Assume that the other system is dead; this is a
+ * better error to display to the user.
+ */
+ rpc_createerr.cf_stat = RPC_RPCBFAILURE;
+ rpc_createerr.cf_error.re_status = RPC_FAILED;
+ }
+ }
+ freeaddrinfo (res);
+ return (client);
+}
+
+static void
+print_rmtcallstat (rtype, infp)
+ int rtype;
+ rpcb_stat *infp;
+{
+ register rpcbs_rmtcalllist_ptr pr;
+ struct rpcent *rpc;
+
+ if (rtype == RPCBVERS_4_STAT)
+ printf ("prog\t\tvers\tproc\tnetid\tindirect success failure\n");
+ else
+ printf ("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n");
+ for (pr = infp->rmtinfo; pr; pr = pr->next)
+ {
+ rpc = getrpcbynumber (pr->prog);
+ if (rpc)
+ printf ("%-16s", rpc->r_name);
+ else
+ printf ("%-16d", pr->prog);
+ printf ("%d\t%d\t%s\t", pr->vers, pr->proc, pr->netid);
+ if (rtype == RPCBVERS_4_STAT)
+ printf ("%d\t ", pr->indirect);
+ printf ("%d\t%d\n", pr->success, pr->failure);
+ }
+}
+
+static void
+print_getaddrstat (rtype, infp)
+ int rtype;
+ rpcb_stat *infp;
+{
+ rpcbs_addrlist_ptr al;
+ register struct rpcent *rpc;
+
+ printf ("prog\t\tvers\tnetid\t success\tfailure\n");
+ for (al = infp->addrinfo; al; al = al->next)
+ {
+ rpc = getrpcbynumber (al->prog);
+ if (rpc)
+ printf ("%-16s", rpc->r_name);
+ else
+ printf ("%-16d", al->prog);
+ printf ("%d\t%s\t %-12d\t%d\n",
+ al->vers, al->netid, al->success, al->failure);
+ }
+}
+
+static char *
+spaces (howmany)
+ int howmany;
+{
+ static char space_array[] = /* 64 spaces */
+ " ";
+
+ if (howmany <= 0 || howmany > sizeof (space_array))
+ {
+ return ("");
+ }
+ return (&space_array[sizeof (space_array) - howmany - 1]);
+}
Index: .
===================================================================
--- . (nonexistent)
+++ . (revision 5)
Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~