summaryrefslogtreecommitdiffstats
path: root/support
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2010-09-16 09:32:52 -0400
committerSteve Dickson <steved@redhat.com>2010-09-16 14:33:51 -0400
commit29b8a7700129d9768e3e2d94c81eec9f84ba8691 (patch)
tree4245a37bc9abc6b313a7c489e17c32e2c7b785bc /support
parenta88c279992f4b63e3dcaac9930e300fd4bb03dd7 (diff)
downloadnfs-utils-29b8a7700129d9768e3e2d94c81eec9f84ba8691.tar.gz
nfs-utils-29b8a7700129d9768e3e2d94c81eec9f84ba8691.tar.xz
nfs-utils-29b8a7700129d9768e3e2d94c81eec9f84ba8691.zip
libnfs.a: Fix API for getfh() & friends
This is more of a clean-up than a behavioral change. POSIX requires that a "struct sockaddr" is the same size as a "struct sockaddr_in". Therefore, a variable or field of type "struct sockaddr" cannot contain an AF_INET6 address. However, "struct sockaddr *" is often used to reference a generic (ie non-address family specific) socket address, generating some confusion about this. The nfsctl_arg struct uses a struct sockaddr (not a pointer) to pass the client's IP address to the kernel. This means the legacy nfsctl() kernel API can never support IPv6. Fortunately for us, this legacy interface was replaced by a text-based cache interface a few years back. We don't need to support non-AF_INET addresses here. The getfh() functions in nfs-utils provide a handy C API for the kernel's nfsctl interface. The getfh() functions still take a struct sockaddr *, though, and that can imply that a non-IPv4 address can be passed via this API. To make it abundantly clear that only IPv4 addresses can be used with this interface, change the synopses of getfh() and friends to take a struct sockaddr_in * instead of a struct sockaddr * . This makes these functions conform with other places in mountd and exportfs that already grok the difference between a struct sockaddr and a struct sockaddr_in. While we're here... Introduce some nice documenting comments for the get_fh() functions, and... Since mountd will support IPv6 in the near future, assert that the family of client addresses passed to this API is indeed AF_INET, in order to prevent non-AF_INET addresses from ever being passed to the legacy nfsctl() interface. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Steve Dickson <steved@redhat.com>
Diffstat (limited to 'support')
-rw-r--r--support/include/nfslib.h9
-rw-r--r--support/nfs/getfh.c64
2 files changed, 64 insertions, 9 deletions
diff --git a/support/include/nfslib.h b/support/include/nfslib.h
index af242d3..3db5bec 100644
--- a/support/include/nfslib.h
+++ b/support/include/nfslib.h
@@ -134,9 +134,12 @@ int nfsaddclient(struct nfsctl_client *clp);
int nfsdelclient(struct nfsctl_client *clp);
int nfsexport(struct nfsctl_export *exp);
int nfsunexport(struct nfsctl_export *exp);
-struct nfs_fh_len * getfh_old(struct sockaddr *addr, dev_t dev, ino_t ino);
-struct nfs_fh_len * getfh(struct sockaddr *addr, const char *);
-struct nfs_fh_len * getfh_size(struct sockaddr *addr, const char *, int size);
+
+struct nfs_fh_len * getfh_old(const struct sockaddr_in *sin,
+ const dev_t dev, const ino_t ino);
+struct nfs_fh_len * getfh(const struct sockaddr_in *sin, const char *path);
+struct nfs_fh_len * getfh_size(const struct sockaddr_in *sin,
+ const char *path, int const size);
void qword_print(FILE *f, char *str);
void qword_printhex(FILE *f, char *str, int slen);
diff --git a/support/nfs/getfh.c b/support/nfs/getfh.c
index 81266fd..611459b 100644
--- a/support/nfs/getfh.c
+++ b/support/nfs/getfh.c
@@ -19,60 +19,112 @@
#include <errno.h>
#include "nfslib.h"
+/**
+ * getfh_old - ask the kernel for an NFSv2 file handle via nfsctl()
+ * @sin: pointer to IPv4 address of a client
+ * @dev: device number of device where requested object resides
+ * @ino: inode number of requested object
+ *
+ * Returns a pointer to an NFSv2 file handle, or NULL if some error
+ * occurred. errno is set to reflect the specifics of the error.
+ */
struct nfs_fh_len *
-getfh_old (struct sockaddr *addr, dev_t dev, ino_t ino)
+getfh_old(const struct sockaddr_in *sin, const dev_t dev, const ino_t ino)
{
union nfsctl_res res;
struct nfsctl_arg arg;
static struct nfs_fh_len rfh;
+ if (sin->sin_family != AF_INET) {
+ errno = EAFNOSUPPORT;
+ return NULL;
+ }
+
+ memset(&arg, 0, sizeof(arg));
+ memset(&res, 0, sizeof(res));
+
arg.ca_version = NFSCTL_VERSION;
arg.ca_getfh.gf_version = 2; /* obsolete */
arg.ca_getfh.gf_dev = dev;
arg.ca_getfh.gf_ino = ino;
- memcpy(&arg.ca_getfh.gf_addr, addr, sizeof(struct sockaddr_in));
+ memcpy(&arg.ca_getfh.gf_addr, sin, sizeof(*sin));
if (nfsctl(NFSCTL_GETFH, &arg, &res) < 0)
return NULL;
+ memset(&rfh, 0, sizeof(rfh));
rfh.fh_size = 32;
memcpy(rfh.fh_handle, &res.cr_getfh, 32);
return &rfh;
}
+/**
+ * getfh - ask the kernel for an NFSv2 file handle via nfsctl()
+ * @sin: pointer to IPv4 address of a client
+ * @path: pointer to a '\0'-terminated ASCII string containing an pathname
+ *
+ * Returns a pointer to an NFSv2 file handle, or NULL if some error
+ * occurred. errno is set to reflect the specifics of the error.
+ */
struct nfs_fh_len *
-getfh(struct sockaddr *addr, const char *path)
+getfh(const struct sockaddr_in *sin, const char *path)
{
static union nfsctl_res res;
struct nfsctl_arg arg;
static struct nfs_fh_len rfh;
+ if (sin->sin_family != AF_INET) {
+ errno = EAFNOSUPPORT;
+ return NULL;
+ }
+
+ memset(&arg, 0, sizeof(arg));
+ memset(&res, 0, sizeof(res));
+
arg.ca_version = NFSCTL_VERSION;
arg.ca_getfd.gd_version = 2; /* obsolete */
strncpy(arg.ca_getfd.gd_path, path,
sizeof(arg.ca_getfd.gd_path) - 1);
arg.ca_getfd.gd_path[sizeof (arg.ca_getfd.gd_path) - 1] = '\0';
- memcpy(&arg.ca_getfd.gd_addr, addr, sizeof(struct sockaddr_in));
+ memcpy(&arg.ca_getfd.gd_addr, sin, sizeof(*sin));
if (nfsctl(NFSCTL_GETFD, &arg, &res) < 0)
return NULL;
+ memset(&rfh, 0, sizeof(rfh));
rfh.fh_size = 32;
memcpy(rfh.fh_handle, &res.cr_getfh, 32);
return &rfh;
}
+/**
+ * getfh_size - ask the kernel for a file handle via nfsctl()
+ * @sin: pointer to IPv4 address of a client
+ * @path: pointer to a '\0'-terminated ASCII string containing an pathname
+ * @size: maximum size, in bytes, of the returned file handle
+ *
+ * Returns a pointer to an NFSv3 file handle, or NULL if some error
+ * occurred. errno is set to reflect the specifics of the error.
+ */
struct nfs_fh_len *
-getfh_size(struct sockaddr *addr, const char *path, int size)
+getfh_size(const struct sockaddr_in *sin, const char *path, const int size)
{
static union nfsctl_res res;
struct nfsctl_arg arg;
+ if (sin->sin_family != AF_INET) {
+ errno = EAFNOSUPPORT;
+ return NULL;
+ }
+
+ memset(&arg, 0, sizeof(arg));
+ memset(&res, 0, sizeof(res));
+
arg.ca_version = NFSCTL_VERSION;
strncpy(arg.ca_getfs.gd_path, path,
sizeof(arg.ca_getfs.gd_path) - 1);
arg.ca_getfs.gd_path[sizeof (arg.ca_getfs.gd_path) - 1] = '\0';
- memcpy(&arg.ca_getfs.gd_addr, addr, sizeof(struct sockaddr_in));
+ memcpy(&arg.ca_getfs.gd_addr, sin, sizeof(*sin));
arg.ca_getfs.gd_maxlen = size;
if (nfsctl(NFSCTL_GETFS, &arg, &res) < 0)