|
Packit |
8480eb |
/* ----------------------------------------------------------------------- *
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* rpc_subs.c - routines for rpc discovery
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* Copyright 2004 Ian Kent <raven@themaw.net> - All Rights Reserved
|
|
Packit |
8480eb |
* Copyright 2004 Jeff Moyer <jmoyer@redaht.com> - All Rights Reserved
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8480eb |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8480eb |
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
|
|
Packit |
8480eb |
* USA; either version 2 of the License, or (at your option) any later
|
|
Packit |
8480eb |
* version; incorporated herein by reference.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* ----------------------------------------------------------------------- */
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#ifndef _GNU_SOURCE
|
|
Packit |
8480eb |
#define _GNU_SOURCE
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#include "config.h"
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#include <rpc/types.h>
|
|
Packit |
8480eb |
#include <rpc/rpc.h>
|
|
Packit |
8480eb |
#include <rpc/pmap_prot.h>
|
|
Packit |
8480eb |
#include <sys/socket.h>
|
|
Packit |
8480eb |
#include <netdb.h>
|
|
Packit |
8480eb |
#include <net/if.h>
|
|
Packit |
8480eb |
#include <netinet/in.h>
|
|
Packit |
8480eb |
#include <arpa/inet.h>
|
|
Packit |
8480eb |
#include <errno.h>
|
|
Packit |
8480eb |
#include <sys/ioctl.h>
|
|
Packit |
8480eb |
#include <ctype.h>
|
|
Packit |
8480eb |
#include <pthread.h>
|
|
Packit |
8480eb |
#include <poll.h>
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#ifdef WITH_LIBTIRPC
|
|
Packit |
8480eb |
const rpcprog_t rpcb_prog = RPCBPROG;
|
|
Packit |
8480eb |
const rpcvers_t rpcb_version = RPCBVERS;
|
|
Packit |
8480eb |
#else
|
|
Packit |
8480eb |
const rpcprog_t rpcb_prog = PMAPPROG;
|
|
Packit |
8480eb |
const rpcvers_t rpcb_version = PMAPVERS;
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#include "mount.h"
|
|
Packit |
8480eb |
#include "rpc_subs.h"
|
|
Packit |
8480eb |
#include "replicated.h"
|
|
Packit |
8480eb |
#include "automount.h"
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* #define STANDALONE */
|
|
Packit |
8480eb |
#ifdef STANDALONE
|
|
Packit |
8480eb |
#define error(logopt, msg, args...) fprintf(stderr, msg "\n", ##args)
|
|
Packit |
8480eb |
#else
|
|
Packit |
8480eb |
#include "log.h"
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#define MAX_IFC_BUF 1024
|
|
Packit |
8480eb |
#define MAX_ERR_BUF 128
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#define MAX_NETWORK_LEN 255
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Get numeric value of the n bits starting at position p */
|
|
Packit |
8480eb |
#define getbits(x, p, n) ((x >> (p + 1 - n)) & ~(~0 << n))
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static const rpcvers_t mount_vers[] = {
|
|
Packit |
8480eb |
MOUNTVERS_NFSV3,
|
|
Packit |
8480eb |
MOUNTVERS_POSIX,
|
|
Packit |
8480eb |
MOUNTVERS,
|
|
Packit |
8480eb |
};
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int connect_nb(int, struct sockaddr *, socklen_t, struct timeval *);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Perform a non-blocking connect on the socket fd.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* The input struct timeval always has tv_nsec set to zero,
|
|
Packit |
8480eb |
* we only ever use tv_sec for timeouts.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
static int connect_nb(int fd, struct sockaddr *addr, socklen_t len, struct timeval *tout)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct pollfd pfd[1];
|
|
Packit |
8480eb |
int timeout = tout->tv_sec;
|
|
Packit |
8480eb |
int flags, ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
flags = fcntl(fd, F_GETFL, 0);
|
|
Packit |
8480eb |
if (flags < 0)
|
|
Packit |
8480eb |
return -errno;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
Packit |
8480eb |
if (ret < 0)
|
|
Packit |
8480eb |
return -errno;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* From here on subsequent sys calls could change errno so
|
|
Packit |
8480eb |
* we set ret = -errno to capture it in case we decide to
|
|
Packit |
8480eb |
* use it later.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
ret = connect(fd, addr, len);
|
|
Packit |
8480eb |
if (ret < 0 && errno != EINPROGRESS) {
|
|
Packit |
8480eb |
ret = -errno;
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (ret == 0)
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (timeout != -1) {
|
|
Packit |
8480eb |
if (timeout >= (INT_MAX - 1)/1000)
|
|
Packit |
8480eb |
timeout = INT_MAX - 1;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
timeout = timeout * 1000;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pfd[0].fd = fd;
|
|
Packit |
8480eb |
pfd[0].events = POLLOUT;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = poll(pfd, 1, timeout);
|
|
Packit |
8480eb |
if (ret <= 0) {
|
|
Packit |
8480eb |
if (ret == 0)
|
|
Packit |
8480eb |
ret = -ETIMEDOUT;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
ret = -errno;
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (pfd[0].revents) {
|
|
Packit |
8480eb |
int status;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
len = sizeof(ret);
|
|
Packit |
8480eb |
status = getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len;;
|
|
Packit |
8480eb |
if (status < 0) {
|
|
Packit |
8480eb |
char buf[MAX_ERR_BUF + 1];
|
|
Packit |
8480eb |
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* We assume getsockopt amounts to a read on the
|
|
Packit |
8480eb |
* descriptor and gives us the errno we need for
|
|
Packit |
8480eb |
* the POLLERR revent case.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
ret = -errno;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Unexpected case, log it so we know we got caught */
|
|
Packit |
8480eb |
if (pfd[0].revents & POLLNVAL)
|
|
Packit |
8480eb |
logerr("unexpected poll(2) error on connect:"
|
|
Packit |
8480eb |
" %s", estr);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Oops - something wrong with connect */
|
|
Packit |
8480eb |
if (ret)
|
|
Packit |
8480eb |
ret = -ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
done:
|
|
Packit |
8480eb |
fcntl(fd, F_SETFL, flags);
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#ifndef WITH_LIBTIRPC
|
|
Packit |
8480eb |
static int rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, int *fd, CLIENT **client)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
CLIENT *clnt = NULL;
|
|
Packit |
8480eb |
struct sockaddr_in in4_laddr;
|
|
Packit |
8480eb |
struct sockaddr_in *in4_raddr;
|
|
Packit |
8480eb |
int type, proto, ret;
|
|
Packit |
8480eb |
socklen_t slen;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
*client = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
proto = info->proto;
|
|
Packit |
8480eb |
if (proto == IPPROTO_UDP)
|
|
Packit |
8480eb |
type = SOCK_DGRAM;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
type = SOCK_STREAM;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* bind to any unused port. If we left this up to the rpc
|
|
Packit |
8480eb |
* layer, it would bind to a reserved port, which has been shown
|
|
Packit |
8480eb |
* to exhaust the reserved port range in some situations.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
in4_laddr.sin_family = AF_INET;
|
|
Packit |
8480eb |
in4_laddr.sin_port = htons(0);
|
|
Packit |
8480eb |
in4_laddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
Packit |
8480eb |
slen = sizeof(struct sockaddr_in);
|
|
Packit |
8480eb |
|
|
Packit Service |
ad2a57 |
if (!info->client && *fd == RPC_ANYSOCK) {
|
|
Packit |
8480eb |
struct sockaddr *laddr;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
*fd = open_sock(addr->sa_family, type, proto);
|
|
Packit |
8480eb |
if (*fd < 0)
|
|
Packit |
8480eb |
return -errno;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
laddr = (struct sockaddr *) &in4_laddr;
|
|
Packit |
8480eb |
if (bind(*fd, laddr, slen) < 0)
|
|
Packit |
8480eb |
return -errno;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
in4_raddr = (struct sockaddr_in *) addr;
|
|
Packit |
8480eb |
in4_raddr->sin_port = htons(info->port);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
switch (info->proto) {
|
|
Packit |
8480eb |
case IPPROTO_UDP:
|
|
Packit |
8480eb |
clnt = clntudp_bufcreate(in4_raddr,
|
|
Packit |
8480eb |
info->program, info->version,
|
|
Packit |
8480eb |
info->timeout, fd,
|
|
Packit |
8480eb |
info->send_sz, info->recv_sz);
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
case IPPROTO_TCP:
|
|
Packit |
8480eb |
ret = connect_nb(*fd, addr, slen, &info->timeout);
|
|
Packit |
8480eb |
if (ret < 0)
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
clnt = clnttcp_create(in4_raddr,
|
|
Packit |
8480eb |
info->program, info->version, fd,
|
|
Packit |
8480eb |
info->send_sz, info->recv_sz);
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
default:
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
*client = clnt;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
static int rpc_getport(struct conn_info *info,
|
|
Packit |
8480eb |
struct pmap *parms, CLIENT *client,
|
|
Packit |
8480eb |
unsigned short *port)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
enum clnt_stat status;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Check to see if server is up otherwise a getport will take
|
|
Packit |
8480eb |
* forever to timeout.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
status = clnt_call(client, PMAPPROC_NULL,
|
|
Packit |
8480eb |
(xdrproc_t) xdr_void, 0, (xdrproc_t) xdr_void, 0,
|
|
Packit |
8480eb |
info->timeout);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (status == RPC_SUCCESS) {
|
|
Packit |
8480eb |
status = clnt_call(client, PMAPPROC_GETPORT,
|
|
Packit |
8480eb |
(xdrproc_t) xdr_pmap, (caddr_t) parms,
|
|
Packit |
8480eb |
(xdrproc_t) xdr_u_short, (caddr_t) port,
|
|
Packit |
8480eb |
info->timeout);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
#else
|
|
Packit |
8480eb |
static int rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, int *fd, CLIENT **client)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
CLIENT *clnt = NULL;
|
|
Packit |
8480eb |
struct sockaddr_in in4_laddr;
|
|
Packit |
8480eb |
struct sockaddr_in6 in6_laddr;
|
|
Packit |
8480eb |
struct sockaddr *laddr = NULL;
|
|
Packit |
8480eb |
struct netbuf nb_addr;
|
|
Packit |
8480eb |
int type, proto;
|
|
Packit |
8480eb |
size_t slen;
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
*client = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
proto = info->proto;
|
|
Packit |
8480eb |
if (proto == IPPROTO_UDP)
|
|
Packit |
8480eb |
type = SOCK_DGRAM;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
type = SOCK_STREAM;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* bind to any unused port. If we left this up to the rpc
|
|
Packit |
8480eb |
* layer, it would bind to a reserved port, which has been shown
|
|
Packit |
8480eb |
* to exhaust the reserved port range in some situations.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (addr->sa_family == AF_INET) {
|
|
Packit |
8480eb |
struct sockaddr_in *in4_raddr = (struct sockaddr_in *) addr;
|
|
Packit |
8480eb |
in4_laddr.sin_family = AF_INET;
|
|
Packit |
8480eb |
in4_laddr.sin_port = htons(0);
|
|
Packit |
8480eb |
in4_laddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
Packit |
8480eb |
laddr = (struct sockaddr *) &in4_laddr;
|
|
Packit |
8480eb |
in4_raddr->sin_port = htons(info->port);
|
|
Packit |
8480eb |
slen = sizeof(struct sockaddr_in);
|
|
Packit |
8480eb |
} else if (addr->sa_family == AF_INET6) {
|
|
Packit |
8480eb |
struct sockaddr_in6 *in6_raddr = (struct sockaddr_in6 *) addr;
|
|
Packit |
8480eb |
in6_laddr.sin6_family = AF_INET6;
|
|
Packit |
8480eb |
in6_laddr.sin6_port = htons(0);
|
|
Packit |
8480eb |
in6_laddr.sin6_addr = in6addr_any;
|
|
Packit |
8480eb |
laddr = (struct sockaddr *) &in6_laddr;
|
|
Packit |
8480eb |
in6_raddr->sin6_port = htons(info->port);
|
|
Packit |
8480eb |
slen = sizeof(struct sockaddr_in6);
|
|
Packit |
8480eb |
} else
|
|
Packit |
8480eb |
return -EINVAL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* bind to any unused port. If we left this up to the rpc layer,
|
|
Packit |
8480eb |
* it would bind to a reserved port, which has been shown to
|
|
Packit |
8480eb |
* exhaust the reserved port range in some situations.
|
|
Packit |
8480eb |
*/
|
|
Packit Service |
ad2a57 |
if (!info->client && *fd == RPC_ANYSOCK) {
|
|
Packit |
8480eb |
*fd = open_sock(addr->sa_family, type, proto);
|
|
Packit |
8480eb |
if (*fd < 0) {
|
|
Packit |
8480eb |
ret = -errno;
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (bind(*fd, laddr, slen) < 0) {
|
|
Packit |
8480eb |
ret = -errno;
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
nb_addr.maxlen = nb_addr.len = slen;
|
|
Packit |
8480eb |
nb_addr.buf = addr;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (info->proto == IPPROTO_UDP)
|
|
Packit |
8480eb |
clnt = clnt_dg_create(*fd, &nb_addr,
|
|
Packit |
8480eb |
info->program, info->version,
|
|
Packit |
8480eb |
info->send_sz, info->recv_sz);
|
|
Packit |
8480eb |
else if (info->proto == IPPROTO_TCP) {
|
|
Packit |
8480eb |
ret = connect_nb(*fd, addr, slen, &info->timeout);
|
|
Packit |
8480eb |
if (ret < 0)
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
clnt = clnt_vc_create(*fd, &nb_addr,
|
|
Packit |
8480eb |
info->program, info->version,
|
|
Packit |
8480eb |
info->send_sz, info->recv_sz);
|
|
Packit |
8480eb |
} else
|
|
Packit |
8480eb |
return -EINVAL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Our timeout is in seconds */
|
|
Packit |
8480eb |
if (clnt && info->timeout.tv_sec)
|
|
Packit |
8480eb |
clnt_control(clnt, CLSET_TIMEOUT, (void *) &info->timeout);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
*client = clnt;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Thankfully nfs-utils had already dealt with this.
|
|
Packit |
8480eb |
* Thanks to Chuck Lever for his nfs-utils patch series, much of
|
|
Packit |
8480eb |
* which is used here.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
static pthread_mutex_t proto_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static enum clnt_stat rpc_get_netid(const sa_family_t family,
|
|
Packit |
8480eb |
const int protocol, char **netid)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
char *nc_protofmly, *nc_proto, *nc_netid;
|
|
Packit |
8480eb |
struct netconfig *nconf;
|
|
Packit |
8480eb |
struct protoent *proto;
|
|
Packit |
8480eb |
void *handle;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
switch (family) {
|
|
Packit |
8480eb |
case AF_LOCAL:
|
|
Packit |
8480eb |
case AF_INET:
|
|
Packit |
8480eb |
nc_protofmly = NC_INET;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
case AF_INET6:
|
|
Packit |
8480eb |
nc_protofmly = NC_INET6;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
default:
|
|
Packit |
8480eb |
return RPC_UNKNOWNPROTO;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_mutex_lock(&proto_mutex);
|
|
Packit |
8480eb |
proto = getprotobynumber(protocol);
|
|
Packit |
8480eb |
if (!proto) {
|
|
Packit |
8480eb |
pthread_mutex_unlock(&proto_mutex);
|
|
Packit |
8480eb |
return RPC_UNKNOWNPROTO;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
nc_proto = strdup(proto->p_name);
|
|
Packit |
8480eb |
pthread_mutex_unlock(&proto_mutex);
|
|
Packit |
8480eb |
if (!nc_proto)
|
|
Packit |
8480eb |
return RPC_SYSTEMERROR;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
handle = setnetconfig();
|
|
Packit |
8480eb |
while ((nconf = getnetconfig(handle)) != NULL) {
|
|
Packit |
8480eb |
if (nconf->nc_protofmly != NULL &&
|
|
Packit |
8480eb |
strcmp(nconf->nc_protofmly, nc_protofmly) != 0)
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
if (nconf->nc_proto != NULL &&
|
|
Packit |
8480eb |
strcmp(nconf->nc_proto, nc_proto) != 0)
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
nc_netid = strdup(nconf->nc_netid);
|
|
Packit |
8480eb |
if (!nc_netid) {
|
|
Packit |
8480eb |
free(nc_proto);
|
|
Packit |
8480eb |
return RPC_SYSTEMERROR;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
*netid = nc_netid;
|
|
Packit Service |
0f11ce |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
endnetconfig(handle);
|
|
Packit |
8480eb |
free(nc_proto);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return RPC_SUCCESS;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static char *rpc_sockaddr2universal(const struct sockaddr *addr)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) addr;
|
|
Packit |
8480eb |
const struct sockaddr_un *sun = (const struct sockaddr_un *) addr;
|
|
Packit |
8480eb |
const struct sockaddr_in *sin = (const struct sockaddr_in *) addr;
|
|
Packit |
8480eb |
char buf[INET6_ADDRSTRLEN + 8 /* for port information */];
|
|
Packit |
8480eb |
uint16_t port;
|
|
Packit |
8480eb |
size_t count;
|
|
Packit |
8480eb |
char *result;
|
|
Packit |
8480eb |
int len;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
switch (addr->sa_family) {
|
|
Packit |
8480eb |
case AF_LOCAL:
|
|
Packit |
8480eb |
return strndup(sun->sun_path, sizeof(sun->sun_path));
|
|
Packit |
8480eb |
case AF_INET:
|
|
Packit |
8480eb |
if (inet_ntop(AF_INET, (const void *)&sin->sin_addr.s_addr,
|
|
Packit |
8480eb |
buf, (socklen_t)sizeof(buf)) == NULL)
|
|
Packit |
8480eb |
goto out_err;
|
|
Packit |
8480eb |
port = ntohs(sin->sin_port);
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
case AF_INET6:
|
|
Packit |
8480eb |
if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
|
|
Packit |
8480eb |
buf, (socklen_t)sizeof(buf)) == NULL)
|
|
Packit |
8480eb |
goto out_err;
|
|
Packit |
8480eb |
port = ntohs(sin6->sin6_port);
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
default:
|
|
Packit |
8480eb |
goto out_err;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
count = sizeof(buf) - strlen(buf);
|
|
Packit |
8480eb |
len = snprintf(buf + strlen(buf), count, ".%u.%u",
|
|
Packit |
8480eb |
(unsigned)(port >> 8), (unsigned)(port & 0xff));
|
|
Packit |
8480eb |
/* before glibc 2.0.6, snprintf(3) could return -1 */
|
|
Packit |
8480eb |
if (len < 0 || (size_t)len > count)
|
|
Packit |
8480eb |
goto out_err;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
result = strdup(buf);
|
|
Packit |
8480eb |
return result;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
out_err:
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int rpc_universal2port(const char *uaddr)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
char *addrstr;
|
|
Packit |
8480eb |
char *p, *endptr;
|
|
Packit |
8480eb |
unsigned long portlo, porthi;
|
|
Packit |
8480eb |
int port = -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
addrstr = strdup(uaddr);
|
|
Packit |
8480eb |
if (!addrstr)
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
p = strrchr(addrstr, '.');
|
|
Packit |
8480eb |
if (!p)
|
|
Packit |
8480eb |
goto out;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
portlo = strtoul(p + 1, &endptr, 10);
|
|
Packit |
8480eb |
if (*endptr != '\0' || portlo > 255)
|
|
Packit |
8480eb |
goto out;
|
|
Packit |
8480eb |
*p = '\0';
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
p = strrchr(addrstr, '.');
|
|
Packit |
8480eb |
if (!p)
|
|
Packit |
8480eb |
goto out;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
porthi = strtoul(p + 1, &endptr, 10);
|
|
Packit |
8480eb |
if (*endptr != '\0' || porthi > 255)
|
|
Packit |
8480eb |
goto out;
|
|
Packit |
8480eb |
*p = '\0';
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
port = (porthi << 8) | portlo;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
out:
|
|
Packit |
8480eb |
free(addrstr);
|
|
Packit |
8480eb |
return port;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static enum clnt_stat rpc_rpcb_getport(CLIENT *client,
|
|
Packit |
8480eb |
struct rpcb *parms,
|
|
Packit |
8480eb |
struct timeval timeout,
|
|
Packit |
8480eb |
unsigned short *port)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
rpcvers_t rpcb_version;
|
|
Packit |
8480eb |
struct rpc_err rpcerr;
|
|
Packit |
8480eb |
int s_port = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
for (rpcb_version = RPCBVERS_4;
|
|
Packit |
8480eb |
rpcb_version >= RPCBVERS_3;
|
|
Packit |
8480eb |
rpcb_version--) {
|
|
Packit |
8480eb |
enum clnt_stat status;
|
|
Packit |
8480eb |
char *uaddr = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
CLNT_CONTROL(client, CLSET_VERS, (void *) &rpcb_version);
|
|
Packit |
8480eb |
status = CLNT_CALL(client, (rpcproc_t) RPCBPROC_GETADDR,
|
|
Packit |
8480eb |
(xdrproc_t) xdr_rpcb, (void *) parms,
|
|
Packit |
8480eb |
(xdrproc_t) xdr_wrapstring, (void *) &uaddr,
|
|
Packit |
8480eb |
timeout);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
switch (status) {
|
|
Packit |
8480eb |
case RPC_SUCCESS:
|
|
Packit |
8480eb |
if ((uaddr == NULL) || (uaddr[0] == '\0'))
|
|
Packit |
8480eb |
return RPC_PROGNOTREGISTERED;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
s_port = rpc_universal2port(uaddr);
|
|
Packit |
8480eb |
xdr_free((xdrproc_t) xdr_wrapstring, (char *) &uaddr);
|
|
Packit |
8480eb |
if (s_port == -1) {
|
|
Packit |
8480eb |
return RPC_N2AXLATEFAILURE;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
*port = s_port;
|
|
Packit |
8480eb |
return RPC_SUCCESS;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
case RPC_PROGVERSMISMATCH:
|
|
Packit |
8480eb |
clnt_geterr(client, &rpcerr);
|
|
Packit |
8480eb |
if (rpcerr.re_vers.low > RPCBVERS4)
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
case RPC_PROGUNAVAIL:
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
case RPC_PROGNOTREGISTERED:
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
default:
|
|
Packit |
8480eb |
/* Most likely RPC_TIMEDOUT or RPC_CANTRECV */
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return RPC_PROGNOTREGISTERED;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static enum clnt_stat rpc_getport(struct conn_info *info,
|
|
Packit |
8480eb |
struct pmap *parms, CLIENT *client,
|
|
Packit |
8480eb |
unsigned short *port)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
enum clnt_stat status;
|
|
Packit |
8480eb |
struct sockaddr *paddr, addr;
|
|
Packit |
8480eb |
struct rpcb rpcb_parms;
|
|
Packit |
8480eb |
char *netid, *raddr;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (info->addr)
|
|
Packit |
8480eb |
paddr = info->addr;
|
|
Packit |
8480eb |
else {
|
|
Packit |
8480eb |
if (!clnt_control(client, CLGET_SERVER_ADDR, (char *) &addr))
|
|
Packit |
8480eb |
return RPC_UNKNOWNADDR;
|
|
Packit |
8480eb |
paddr = &addr;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
netid = NULL;
|
|
Packit |
8480eb |
status = rpc_get_netid(paddr->sa_family, info->proto, &netid);
|
|
Packit |
8480eb |
if (status != RPC_SUCCESS)
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
raddr = rpc_sockaddr2universal(paddr);
|
|
Packit |
8480eb |
if (!raddr) {
|
|
Packit |
8480eb |
free(netid);
|
|
Packit |
8480eb |
return RPC_UNKNOWNADDR;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(&rpcb_parms, 0, sizeof(rpcb_parms));
|
|
Packit |
8480eb |
rpcb_parms.r_prog = parms->pm_prog;
|
|
Packit |
8480eb |
rpcb_parms.r_vers = parms->pm_vers;
|
|
Packit |
8480eb |
rpcb_parms.r_netid = netid;
|
|
Packit |
8480eb |
rpcb_parms.r_addr = raddr;
|
|
Packit |
8480eb |
rpcb_parms.r_owner = "";
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = rpc_rpcb_getport(client, &rpcb_parms, info->timeout, port);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
free(netid);
|
|
Packit |
8480eb |
free(raddr);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (status == RPC_PROGNOTREGISTERED) {
|
|
Packit |
8480eb |
/* Last chance, version 2 uses a different procedure */
|
|
Packit |
8480eb |
rpcvers_t rpcb_version = PMAPVERS;
|
|
Packit |
8480eb |
CLNT_CONTROL(client, CLSET_VERS, (void *) &rpcb_version);
|
|
Packit |
8480eb |
status = clnt_call(client, PMAPPROC_GETPORT,
|
|
Packit |
8480eb |
(xdrproc_t) xdr_pmap, (caddr_t) parms,
|
|
Packit |
8480eb |
(xdrproc_t) xdr_u_short, (caddr_t) port,
|
|
Packit |
8480eb |
info->timeout);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#if defined(HAVE_GETRPCBYNAME) || defined(HAVE_GETSERVBYNAME)
|
|
Packit |
8480eb |
static pthread_mutex_t rpcb_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static rpcprog_t rpc_getrpcbyname(const rpcprog_t program)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
#ifdef HAVE_GETRPCBYNAME
|
|
Packit |
8480eb |
static const char *rpcb_pgmtbl[] = {
|
|
Packit |
8480eb |
"rpcbind", "portmap", "portmapper", "sunrpc", NULL,
|
|
Packit |
8480eb |
};
|
|
Packit |
8480eb |
struct rpcent *entry;
|
|
Packit |
8480eb |
rpcprog_t prog_number;
|
|
Packit |
8480eb |
unsigned int i;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_mutex_lock(&rpcb_mutex);
|
|
Packit |
8480eb |
for (i = 0; rpcb_pgmtbl[i] != NULL; i++) {
|
|
Packit |
8480eb |
entry = getrpcbyname(rpcb_pgmtbl[i]);
|
|
Packit |
8480eb |
if (entry) {
|
|
Packit |
8480eb |
prog_number = entry->r_number;
|
|
Packit |
8480eb |
pthread_mutex_unlock(&rpcb_mutex);
|
|
Packit |
8480eb |
return prog_number;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
pthread_mutex_unlock(&rpcb_mutex);
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
return program;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static unsigned short rpc_getrpcbport(const int proto)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
#ifdef HAVE_GETSERVBYNAME
|
|
Packit |
8480eb |
static const char *rpcb_netnametbl[] = {
|
|
Packit |
8480eb |
"rpcbind", "portmapper", "sunrpc", NULL,
|
|
Packit |
8480eb |
};
|
|
Packit |
8480eb |
struct servent *entry;
|
|
Packit |
8480eb |
struct protoent *p_ent;
|
|
Packit |
8480eb |
unsigned short port;
|
|
Packit |
8480eb |
unsigned int i;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_mutex_lock(&rpcb_mutex);
|
|
Packit |
8480eb |
p_ent = getprotobynumber(proto);
|
|
Packit |
8480eb |
if (!p_ent)
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
for (i = 0; rpcb_netnametbl[i] != NULL; i++) {
|
|
Packit |
8480eb |
entry = getservbyname(rpcb_netnametbl[i], p_ent->p_name);
|
|
Packit |
8480eb |
if (entry) {
|
|
Packit |
8480eb |
port = entry->s_port;
|
|
Packit |
8480eb |
pthread_mutex_unlock(&rpcb_mutex);
|
|
Packit |
8480eb |
return port;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
done:
|
|
Packit |
8480eb |
pthread_mutex_unlock(&rpcb_mutex);
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
return (unsigned short) htons(PMAPPORT);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Create an RPC client
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
static int create_client(struct conn_info *info, CLIENT **client)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct addrinfo *ai, *haddr;
|
|
Packit |
8480eb |
struct addrinfo hints;
|
|
Packit |
8480eb |
int fd, ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
fd = RPC_ANYSOCK;
|
|
Packit |
8480eb |
*client = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (info->client) {
|
|
Packit |
8480eb |
if (clnt_control(info->client, CLGET_FD, (char *) &fd))
|
|
Packit |
8480eb |
clnt_control(info->client, CLSET_FD_NCLOSE, NULL);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
fd = RPC_ANYSOCK;
|
|
Packit |
8480eb |
clnt_destroy(info->client);
|
|
Packit |
8480eb |
info->client = NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (info->addr) {
|
|
Packit |
8480eb |
ret = rpc_do_create_client(info->addr, info, &fd, client);
|
|
Packit |
8480eb |
if (ret == 0)
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
if (ret == -EHOSTUNREACH)
|
|
Packit |
8480eb |
goto out_close;
|
|
Packit |
8480eb |
if (ret == -EINVAL) {
|
|
Packit |
8480eb |
char buf[MAX_ERR_BUF];
|
|
Packit |
8480eb |
char *estr = strerror_r(-ret, buf, MAX_ERR_BUF);
|
|
Packit |
8480eb |
error(LOGOPT_ANY, "connect() failed: %s", estr);
|
|
Packit |
8480eb |
goto out_close;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (fd != RPC_ANYSOCK) {
|
|
Packit |
8480eb |
close(fd);
|
|
Packit |
8480eb |
fd = RPC_ANYSOCK;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(&hints, 0, sizeof(hints));
|
|
Packit |
8480eb |
hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;
|
|
Packit |
8480eb |
hints.ai_family = AF_UNSPEC;
|
|
Packit |
8480eb |
if (info->proto == IPPROTO_UDP)
|
|
Packit |
8480eb |
hints.ai_socktype = SOCK_DGRAM;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
hints.ai_socktype = SOCK_STREAM;
|
|
Packit |
8480eb |
|
|
Packit Service |
aaaa61 |
ai = NULL;
|
|
Packit |
8480eb |
ret = getaddrinfo(info->host, NULL, &hints, &ai;;
|
|
Packit |
8480eb |
if (ret) {
|
|
Packit |
8480eb |
error(LOGOPT_ANY,
|
|
Packit Service |
986c63 |
"hostname lookup for %s failed: %s",
|
|
Packit Service |
986c63 |
info->host, gai_strerror(ret));
|
|
Packit |
8480eb |
goto out_close;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
haddr = ai;
|
|
Packit |
8480eb |
while (haddr) {
|
|
Packit |
8480eb |
if (haddr->ai_protocol != info->proto) {
|
|
Packit |
8480eb |
haddr = haddr->ai_next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = rpc_do_create_client(haddr->ai_addr, info, &fd, client);
|
|
Packit |
8480eb |
if (ret == 0)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
if (ret == -EHOSTUNREACH) {
|
|
Packit |
8480eb |
freeaddrinfo(ai);
|
|
Packit |
8480eb |
goto out_close;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (fd != RPC_ANYSOCK) {
|
|
Packit |
8480eb |
close(fd);
|
|
Packit |
8480eb |
fd = RPC_ANYSOCK;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
haddr = haddr->ai_next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
freeaddrinfo(ai);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
done:
|
|
Packit |
8480eb |
if (!*client) {
|
|
Packit |
8480eb |
ret = -ENOTCONN;
|
|
Packit |
8480eb |
goto out_close;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Close socket fd on destroy, as is default for rpcowned fds */
|
|
Packit |
8480eb |
if (!clnt_control(*client, CLSET_FD_CLOSE, NULL)) {
|
|
Packit |
8480eb |
clnt_destroy(*client);
|
|
Packit |
8480eb |
ret = -ENOTCONN;
|
|
Packit |
8480eb |
goto out_close;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
out_close:
|
|
Packit |
8480eb |
if (fd != RPC_ANYSOCK)
|
|
Packit |
8480eb |
close(fd);
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int rpc_udp_getclient(struct conn_info *info,
|
|
Packit |
8480eb |
unsigned int program, unsigned int version)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
CLIENT *client;
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!info->client) {
|
|
Packit |
8480eb |
info->proto = IPPROTO_UDP;
|
|
Packit |
8480eb |
info->timeout.tv_sec = RPC_TOUT_UDP;
|
|
Packit |
8480eb |
info->timeout.tv_usec = 0;
|
|
Packit |
8480eb |
info->send_sz = UDPMSGSIZE;
|
|
Packit |
8480eb |
info->recv_sz = UDPMSGSIZE;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
info->program = program;
|
|
Packit |
8480eb |
info->version = version;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = create_client(info, &client);
|
|
Packit |
8480eb |
if (ret < 0)
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
info->client = client;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
void rpc_destroy_udp_client(struct conn_info *info)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
if (!info->client)
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
clnt_destroy(info->client);
|
|
Packit |
8480eb |
info->client = NULL;
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int rpc_tcp_getclient(struct conn_info *info,
|
|
Packit |
8480eb |
unsigned int program, unsigned int version)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
CLIENT *client;
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!info->client) {
|
|
Packit |
8480eb |
info->proto = IPPROTO_TCP;
|
|
Packit |
8480eb |
info->timeout.tv_sec = RPC_TOUT_TCP;
|
|
Packit |
8480eb |
info->timeout.tv_usec = 0;
|
|
Packit |
8480eb |
info->send_sz = 0;
|
|
Packit |
8480eb |
info->recv_sz = 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
info->program = program;
|
|
Packit |
8480eb |
info->version = version;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = create_client(info, &client);
|
|
Packit |
8480eb |
if (ret < 0)
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
info->client = client;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
void rpc_destroy_tcp_client(struct conn_info *info)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct linger lin = { 1, 0 };
|
|
Packit |
8480eb |
socklen_t lin_len = sizeof(struct linger);
|
|
Packit |
8480eb |
int fd;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!info->client)
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!clnt_control(info->client, CLGET_FD, (char *) &fd))
|
|
Packit |
8480eb |
fd = -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
switch (info->close_option) {
|
|
Packit |
8480eb |
case RPC_CLOSE_NOLINGER:
|
|
Packit |
8480eb |
if (fd >= 0)
|
|
Packit |
8480eb |
setsockopt(fd, SOL_SOCKET, SO_LINGER, &lin, lin_len);
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
clnt_destroy(info->client);
|
|
Packit |
8480eb |
info->client = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int rpc_portmap_getclient(struct conn_info *info,
|
|
Packit |
8480eb |
const char *host, struct sockaddr *addr, size_t addr_len,
|
|
Packit |
8480eb |
int proto, unsigned int option)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
CLIENT *client;
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
info->host = host;
|
|
Packit |
8480eb |
info->addr = addr;
|
|
Packit |
8480eb |
info->addr_len = addr_len;
|
|
Packit |
8480eb |
info->program = rpc_getrpcbyname(rpcb_prog);
|
|
Packit |
8480eb |
info->port = ntohs(rpc_getrpcbport(proto));
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* When using libtirpc we might need to change the rpcbind version
|
|
Packit |
8480eb |
* to qurey AF_INET addresses. Since we might not have an address
|
|
Packit |
8480eb |
* yet set AF_INET rpcbind version in rpc_do_create_client() when
|
|
Packit |
8480eb |
* we always have an address.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
info->version = rpcb_version;
|
|
Packit |
8480eb |
info->proto = proto;
|
|
Packit |
8480eb |
info->send_sz = RPCSMALLMSGSIZE;
|
|
Packit |
8480eb |
info->recv_sz = RPCSMALLMSGSIZE;
|
|
Packit |
8480eb |
info->timeout.tv_sec = PMAP_TOUT_UDP;
|
|
Packit |
8480eb |
info->timeout.tv_usec = 0;
|
|
Packit |
8480eb |
info->close_option = option;
|
|
Packit |
8480eb |
info->client = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (info->proto == IPPROTO_TCP)
|
|
Packit |
8480eb |
info->timeout.tv_sec = PMAP_TOUT_TCP;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = create_client(info, &client);
|
|
Packit |
8480eb |
if (ret < 0)
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
info->client = client;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int rpc_portmap_getport(struct conn_info *info,
|
|
Packit |
8480eb |
struct pmap *parms, unsigned short *port)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct conn_info pmap_info;
|
|
Packit |
8480eb |
CLIENT *client;
|
|
Packit |
8480eb |
enum clnt_stat status;
|
|
Packit |
8480eb |
int proto = info->proto;
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(&pmap_info, 0, sizeof(struct conn_info));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pmap_info.proto = proto;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (proto == IPPROTO_TCP)
|
|
Packit |
8480eb |
pmap_info.timeout.tv_sec = PMAP_TOUT_TCP;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
pmap_info.timeout.tv_sec = PMAP_TOUT_UDP;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (info->client)
|
|
Packit |
8480eb |
client = info->client;
|
|
Packit |
8480eb |
else {
|
|
Packit |
8480eb |
pmap_info.host = info->host;
|
|
Packit |
8480eb |
pmap_info.addr = info->addr;
|
|
Packit |
8480eb |
pmap_info.addr_len = info->addr_len;
|
|
Packit |
8480eb |
pmap_info.port = ntohs(rpc_getrpcbport(info->proto));
|
|
Packit |
8480eb |
pmap_info.program = rpc_getrpcbyname(rpcb_prog);
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* When using libtirpc we might need to change the rpcbind
|
|
Packit |
8480eb |
* version to qurey AF_INET addresses. Since we might not
|
|
Packit |
8480eb |
* have an address yet set AF_INET rpcbind version in
|
|
Packit |
8480eb |
* rpc_do_create_client() when we always have an address.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
pmap_info.version = rpcb_version;
|
|
Packit |
8480eb |
pmap_info.proto = info->proto;
|
|
Packit |
8480eb |
pmap_info.send_sz = RPCSMALLMSGSIZE;
|
|
Packit |
8480eb |
pmap_info.recv_sz = RPCSMALLMSGSIZE;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = create_client(&pmap_info, &client);
|
|
Packit |
8480eb |
if (ret < 0)
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = rpc_getport(&pmap_info, parms, client, port);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!info->client) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Only play with the close options if we think it
|
|
Packit |
8480eb |
* completed OK
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (proto == IPPROTO_TCP && status == RPC_SUCCESS) {
|
|
Packit |
8480eb |
struct linger lin = { 1, 0 };
|
|
Packit |
8480eb |
socklen_t lin_len = sizeof(struct linger);
|
|
Packit |
8480eb |
int fd;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!clnt_control(client, CLGET_FD, (char *) &fd))
|
|
Packit |
8480eb |
fd = -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
switch (info->close_option) {
|
|
Packit |
8480eb |
case RPC_CLOSE_NOLINGER:
|
|
Packit |
8480eb |
if (fd >= 0)
|
|
Packit |
8480eb |
setsockopt(fd, SOL_SOCKET, SO_LINGER, &lin, lin_len);
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
clnt_destroy(client);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (status == RPC_TIMEDOUT)
|
|
Packit |
8480eb |
return -ETIMEDOUT;
|
|
Packit |
8480eb |
else if (status != RPC_SUCCESS)
|
|
Packit |
8480eb |
return -EIO;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int rpc_ping_proto(struct conn_info *info)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
CLIENT *client;
|
|
Packit |
8480eb |
enum clnt_stat status;
|
|
Packit |
8480eb |
int proto = info->proto;
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (info->client)
|
|
Packit |
8480eb |
client = info->client;
|
|
Packit |
8480eb |
else {
|
|
Packit |
8480eb |
if (info->proto == IPPROTO_UDP) {
|
|
Packit |
8480eb |
info->send_sz = UDPMSGSIZE;
|
|
Packit |
8480eb |
info->recv_sz = UDPMSGSIZE;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
ret = create_client(info, &client);
|
|
Packit |
8480eb |
if (ret < 0)
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
clnt_control(client, CLSET_TIMEOUT, (char *) &info->timeout);
|
|
Packit |
8480eb |
clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) &info->timeout);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = clnt_call(client, NFSPROC_NULL,
|
|
Packit |
8480eb |
(xdrproc_t) xdr_void, 0, (xdrproc_t) xdr_void, 0,
|
|
Packit |
8480eb |
info->timeout);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!info->client) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Only play with the close options if we think it
|
|
Packit |
8480eb |
* completed OK
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (proto == IPPROTO_TCP && status == RPC_SUCCESS) {
|
|
Packit |
8480eb |
struct linger lin = { 1, 0 };
|
|
Packit |
8480eb |
socklen_t lin_len = sizeof(struct linger);
|
|
Packit |
8480eb |
int fd;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!clnt_control(client, CLGET_FD, (char *) &fd))
|
|
Packit |
8480eb |
fd = -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
switch (info->close_option) {
|
|
Packit |
8480eb |
case RPC_CLOSE_NOLINGER:
|
|
Packit |
8480eb |
if (fd >= 0)
|
|
Packit |
8480eb |
setsockopt(fd, SOL_SOCKET, SO_LINGER, &lin, lin_len);
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
clnt_destroy(client);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (status == RPC_TIMEDOUT)
|
|
Packit |
8480eb |
return -ETIMEDOUT;
|
|
Packit |
8480eb |
else if (status != RPC_SUCCESS)
|
|
Packit |
8480eb |
return -EIO;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int __rpc_ping(const char *host,
|
|
Packit |
8480eb |
unsigned long version, int proto, int port,
|
|
Packit |
8480eb |
long seconds, long micros, unsigned int option)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
int status;
|
|
Packit |
8480eb |
struct conn_info info;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
info.proto = proto;
|
|
Packit |
8480eb |
info.host = host;
|
|
Packit |
8480eb |
info.addr = NULL;
|
|
Packit |
8480eb |
info.addr_len = 0;
|
|
Packit |
8480eb |
info.program = NFS_PROGRAM;
|
|
Packit |
8480eb |
info.version = version;
|
|
Packit |
8480eb |
info.send_sz = 0;
|
|
Packit |
8480eb |
info.recv_sz = 0;
|
|
Packit |
8480eb |
info.timeout.tv_sec = seconds;
|
|
Packit |
8480eb |
info.timeout.tv_usec = micros;
|
|
Packit |
8480eb |
info.close_option = option;
|
|
Packit |
8480eb |
info.client = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = RPC_PING_FAIL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (port > 0)
|
|
Packit |
8480eb |
info.port = port;
|
|
Packit |
8480eb |
else {
|
|
Packit |
8480eb |
struct pmap parms;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
parms.pm_prog = NFS_PROGRAM;
|
|
Packit |
8480eb |
parms.pm_vers = version;
|
|
Packit |
8480eb |
parms.pm_prot = info.proto;
|
|
Packit |
8480eb |
parms.pm_port = 0;
|
|
Packit |
8480eb |
status = rpc_portmap_getport(&info, &parms, &info.port);
|
|
Packit |
8480eb |
if (status < 0)
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = rpc_ping_proto(&info;;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int rpc_ping(const char *host, int port,
|
|
Packit |
8480eb |
unsigned int version, long seconds, long micros,
|
|
Packit |
8480eb |
unsigned int option)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
int status = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if ((version & NFS2_REQUESTED) && (version & TCP_REQUESTED)) {
|
|
Packit |
8480eb |
status = __rpc_ping(host, NFS2_VERSION,
|
|
Packit |
8480eb |
IPPROTO_TCP, port, seconds, micros, option);
|
|
Packit |
8480eb |
if (status > 0)
|
|
Packit |
8480eb |
return RPC_PING_V2 | RPC_PING_TCP;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if ((version & NFS2_REQUESTED) && (version & UDP_REQUESTED)) {
|
|
Packit |
8480eb |
status = __rpc_ping(host, NFS2_VERSION,
|
|
Packit |
8480eb |
IPPROTO_UDP, port, seconds, micros, option);
|
|
Packit |
8480eb |
if (status > 0)
|
|
Packit |
8480eb |
return RPC_PING_V2 | RPC_PING_UDP;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if ((version & NFS3_REQUESTED) && (version & TCP_REQUESTED)) {
|
|
Packit |
8480eb |
status = __rpc_ping(host, NFS3_VERSION,
|
|
Packit |
8480eb |
IPPROTO_TCP, port, seconds, micros, option);
|
|
Packit |
8480eb |
if (status > 0)
|
|
Packit |
8480eb |
return RPC_PING_V3 | RPC_PING_TCP;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if ((version & NFS3_REQUESTED) && (version & UDP_REQUESTED)) {
|
|
Packit |
8480eb |
status = __rpc_ping(host, NFS3_VERSION,
|
|
Packit |
8480eb |
IPPROTO_UDP, port, seconds, micros, option);
|
|
Packit |
8480eb |
if (status > 0)
|
|
Packit |
8480eb |
return RPC_PING_V3 | RPC_PING_UDP;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (version & NFS4_REQUESTED) {
|
|
Packit |
8480eb |
/* UDP isn't recommended for NFSv4, don't check it. */
|
|
Packit |
8480eb |
status = __rpc_ping(host, NFS4_VERSION,
|
|
Packit |
8480eb |
IPPROTO_TCP, port, seconds, micros, option);
|
|
Packit |
8480eb |
if (status > 0)
|
|
Packit |
8480eb |
return RPC_PING_V4 | RPC_PING_TCP;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return status;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
double monotonic_elapsed(struct timespec start, struct timespec end)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
double t1, t2;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
t1 = (double) start.tv_sec +
|
|
Packit Service |
050684 |
((double) start.tv_nsec/(1000*1000*1000));
|
|
Packit |
8480eb |
t2 = (double) end.tv_sec +
|
|
Packit Service |
050684 |
((double) end.tv_nsec/(1000*1000*1000));
|
|
Packit |
8480eb |
return t2 - t1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int rpc_get_exports_proto(struct conn_info *info, exports *exp)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
CLIENT *client;
|
|
Packit |
8480eb |
enum clnt_stat status;
|
|
Packit |
8480eb |
int proto = info->proto;
|
|
Packit |
8480eb |
unsigned int option = info->close_option;
|
|
Packit |
8480eb |
int vers_entry;
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (info->proto == IPPROTO_UDP) {
|
|
Packit |
8480eb |
info->send_sz = UDPMSGSIZE;
|
|
Packit |
8480eb |
info->recv_sz = UDPMSGSIZE;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
ret = create_client(info, &client);
|
|
Packit |
8480eb |
if (ret < 0)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
clnt_control(client, CLSET_TIMEOUT, (char *) &info->timeout);
|
|
Packit |
8480eb |
clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) &info->timeout);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
client->cl_auth = authunix_create_default();
|
|
Packit |
8480eb |
if (client->cl_auth == NULL) {
|
|
Packit |
8480eb |
error(LOGOPT_ANY, "auth create failed");
|
|
Packit |
8480eb |
clnt_destroy(client);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
vers_entry = 0;
|
|
Packit |
8480eb |
while (1) {
|
|
Packit |
8480eb |
status = clnt_call(client, MOUNTPROC_EXPORT,
|
|
Packit |
8480eb |
(xdrproc_t) xdr_void, NULL,
|
|
Packit |
8480eb |
(xdrproc_t) xdr_exports, (caddr_t) exp,
|
|
Packit |
8480eb |
info->timeout);
|
|
Packit |
8480eb |
if (status == RPC_SUCCESS)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
if (++vers_entry > 2)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
CLNT_CONTROL(client, CLSET_VERS,
|
|
Packit |
8480eb |
(void *) &mount_vers[vers_entry]);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Only play with the close options if we think it completed OK */
|
|
Packit |
8480eb |
if (proto == IPPROTO_TCP && status == RPC_SUCCESS) {
|
|
Packit |
8480eb |
struct linger lin = { 1, 0 };
|
|
Packit |
8480eb |
socklen_t lin_len = sizeof(struct linger);
|
|
Packit |
8480eb |
int fd;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!clnt_control(client, CLGET_FD, (char *) &fd))
|
|
Packit |
8480eb |
fd = -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
switch (option) {
|
|
Packit |
8480eb |
case RPC_CLOSE_NOLINGER:
|
|
Packit |
8480eb |
if (fd >= 0)
|
|
Packit |
8480eb |
setsockopt(fd, SOL_SOCKET, SO_LINGER, &lin, lin_len);
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
auth_destroy(client->cl_auth);
|
|
Packit |
8480eb |
clnt_destroy(client);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (status != RPC_SUCCESS)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void rpc_export_free(exports item)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
groups grp;
|
|
Packit |
8480eb |
groups tmp;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (item->ex_dir)
|
|
Packit |
8480eb |
free(item->ex_dir);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
grp = item->ex_groups;
|
|
Packit |
8480eb |
while (grp) {
|
|
Packit |
8480eb |
if (grp->gr_name)
|
|
Packit |
8480eb |
free(grp->gr_name);
|
|
Packit |
8480eb |
tmp = grp;
|
|
Packit |
8480eb |
grp = grp->gr_next;
|
|
Packit |
8480eb |
free(tmp);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
free(item);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
void rpc_exports_free(exports list)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
exports tmp;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
while (list) {
|
|
Packit |
8480eb |
tmp = list;
|
|
Packit |
8480eb |
list = list->ex_next;
|
|
Packit |
8480eb |
rpc_export_free(tmp);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
exports rpc_get_exports(const char *host, long seconds, long micros, unsigned int option)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct conn_info info;
|
|
Packit |
8480eb |
exports exportlist;
|
|
Packit |
8480eb |
struct pmap parms;
|
|
Packit |
8480eb |
int status;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
info.host = host;
|
|
Packit |
8480eb |
info.addr = NULL;
|
|
Packit |
8480eb |
info.addr_len = 0;
|
|
Packit |
8480eb |
info.program = MOUNTPROG;
|
|
Packit |
8480eb |
info.version = mount_vers[0];
|
|
Packit |
8480eb |
info.send_sz = 0;
|
|
Packit |
8480eb |
info.recv_sz = 0;
|
|
Packit |
8480eb |
info.timeout.tv_sec = seconds;
|
|
Packit |
8480eb |
info.timeout.tv_usec = micros;
|
|
Packit |
8480eb |
info.close_option = option;
|
|
Packit |
8480eb |
info.client = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
parms.pm_prog = info.program;
|
|
Packit |
8480eb |
parms.pm_vers = info.version;
|
|
Packit |
8480eb |
parms.pm_port = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Try UDP first */
|
|
Packit |
8480eb |
info.proto = IPPROTO_UDP;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
parms.pm_prot = info.proto;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = rpc_portmap_getport(&info, &parms, &info.port);
|
|
Packit |
8480eb |
if (status < 0)
|
|
Packit |
8480eb |
goto try_tcp;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(&exportlist, '\0', sizeof(exportlist));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = rpc_get_exports_proto(&info, &exportlist);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
return exportlist;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
try_tcp:
|
|
Packit |
8480eb |
info.proto = IPPROTO_TCP;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
parms.pm_prot = info.proto;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = rpc_portmap_getport(&info, &parms, &info.port);
|
|
Packit |
8480eb |
if (status < 0)
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(&exportlist, '\0', sizeof(exportlist));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
status = rpc_get_exports_proto(&info, &exportlist);
|
|
Packit |
8480eb |
if (!status)
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return exportlist;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
const char *get_addr_string(struct sockaddr *sa, char *name, socklen_t len)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
void *addr;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (len < INET6_ADDRSTRLEN)
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (sa->sa_family == AF_INET) {
|
|
Packit |
8480eb |
struct sockaddr_in *ipv4 = (struct sockaddr_in *) sa;
|
|
Packit |
8480eb |
addr = &(ipv4->sin_addr);
|
|
Packit |
8480eb |
} else if (sa->sa_family == AF_INET6) {
|
|
Packit |
8480eb |
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) sa;
|
|
Packit |
8480eb |
addr = &(ipv6->sin6_addr);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return inet_ntop(sa->sa_family, addr, name, len);
|
|
Packit |
8480eb |
}
|