*
* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
* - added Native Language Support
- *
+ *
* Modified by Olaf Kirch and Trond Myklebust for new NFS code,
* plus NFSv3 stuff.
*/
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
-#include <linux/nfs.h> /* For the kernels nfs stuff */
#include "nfsmount.h"
+/* This is just a warning of a common mistake. Possibly this should be a
+ * * uclibc faq entry rather than in busybox... */
+#if ENABLE_FEATURE_MOUNT_NFS && defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
+#error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
+#endif
+
+
+/*
+ * NFS stats. The good thing with these values is that NFSv3 errors are
+ * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
+ * no-one uses anyway), so we can happily mix code as long as we make sure
+ * no NFSv3 errors are returned to NFSv2 clients.
+ * Error codes that have a `--' in the v2 column are not part of the
+ * standard, but seem to be widely used nevertheless.
+ */
+enum nfs_stat {
+ NFS_OK = 0, /* v2 v3 */
+ NFSERR_PERM = 1, /* v2 v3 */
+ NFSERR_NOENT = 2, /* v2 v3 */
+ NFSERR_IO = 5, /* v2 v3 */
+ NFSERR_NXIO = 6, /* v2 v3 */
+ NFSERR_EAGAIN = 11, /* v2 v3 */
+ NFSERR_ACCES = 13, /* v2 v3 */
+ NFSERR_EXIST = 17, /* v2 v3 */
+ NFSERR_XDEV = 18, /* v3 */
+ NFSERR_NODEV = 19, /* v2 v3 */
+ NFSERR_NOTDIR = 20, /* v2 v3 */
+ NFSERR_ISDIR = 21, /* v2 v3 */
+ NFSERR_INVAL = 22, /* v2 v3 that Sun forgot */
+ NFSERR_FBIG = 27, /* v2 v3 */
+ NFSERR_NOSPC = 28, /* v2 v3 */
+ NFSERR_ROFS = 30, /* v2 v3 */
+ NFSERR_MLINK = 31, /* v3 */
+ NFSERR_OPNOTSUPP = 45, /* v2 v3 */
+ NFSERR_NAMETOOLONG = 63, /* v2 v3 */
+ NFSERR_NOTEMPTY = 66, /* v2 v3 */
+ NFSERR_DQUOT = 69, /* v2 v3 */
+ NFSERR_STALE = 70, /* v2 v3 */
+ NFSERR_REMOTE = 71, /* v2 v3 */
+ NFSERR_WFLUSH = 99, /* v2 */
+ NFSERR_BADHANDLE = 10001, /* v3 */
+ NFSERR_NOT_SYNC = 10002, /* v3 */
+ NFSERR_BAD_COOKIE = 10003, /* v3 */
+ NFSERR_NOTSUPP = 10004, /* v3 */
+ NFSERR_TOOSMALL = 10005, /* v3 */
+ NFSERR_SERVERFAULT = 10006, /* v3 */
+ NFSERR_BADTYPE = 10007, /* v3 */
+ NFSERR_JUKEBOX = 10008 /* v3 */
+};
+
+#define NFS_PROGRAM 100003
+
+
+
#ifndef NFS_FHSIZE
static const int NFS_FHSIZE = 32;
#endif
#define NFS_MOUNT_VERSION 4
struct nfs2_fh {
- char data[32];
+ char data[32];
};
struct nfs3_fh {
- unsigned short size;
- unsigned char data[64];
+ unsigned short size;
+ unsigned char data[64];
};
struct nfs_mount_data {
}
int nfsmount(const char *spec, const char *node, int *flags,
- char **extra_opts, char **mount_opts, int running_bg)
+ char **mount_opts, int running_bg)
{
static char *prev_bg_host;
char hostdir[1024];
CLIENT *mclient;
char *hostname;
- char *dirname;
+ char *pathname;
char *old_opts;
char *mounthost=NULL;
char new_opts[1024];
struct timeval total_timeout;
enum clnt_stat clnt_stat;
- static struct nfs_mount_data data;
+ struct nfs_mount_data data;
char *opt, *opteq;
int val;
struct hostent *hp;
msock = fsock = -1;
mclient = NULL;
if (strlen(spec) >= sizeof(hostdir)) {
- error_msg("excessively long host:dir argument");
+ bb_error_msg("excessively long host:dir argument");
goto fail;
}
strcpy(hostdir, spec);
if ((s = strchr(hostdir, ':'))) {
hostname = hostdir;
- dirname = s + 1;
+ pathname = s + 1;
*s = '\0';
/* Ignore all but first hostname in replicated mounts
until they can be fully supported. (mack@sgi.com) */
if ((s = strchr(hostdir, ','))) {
*s = '\0';
- error_msg("warning: multiple hostnames not supported");
+ bb_error_msg("warning: multiple hostnames not supported");
}
} else {
- error_msg("directory to mount not in host:dir format");
+ bb_error_msg("directory to mount not in host:dir format");
goto fail;
}
#endif
{
if ((hp = gethostbyname(hostname)) == NULL) {
- herror_msg("%s", hostname);
+ bb_herror_msg("%s", hostname);
goto fail;
} else {
if (hp->h_length > sizeof(struct in_addr)) {
- error_msg("got bad hp->h_length");
+ bb_error_msg("got bad hp->h_length");
hp->h_length = sizeof(struct in_addr);
}
memcpy(&server_addr.sin_addr,
/* add IP address to mtab options for use when unmounting */
s = inet_ntoa(server_addr.sin_addr);
- old_opts = *extra_opts;
+ old_opts = *mount_opts;
if (!old_opts)
old_opts = "";
if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
- error_msg("excessively long option argument");
+ bb_error_msg("excessively long option argument");
goto fail;
}
sprintf(new_opts, "%s%saddr=%s",
old_opts, *old_opts ? "," : "", s);
- *extra_opts = xstrdup(new_opts);
+ *mount_opts = bb_xstrdup(new_opts);
/* Set default options.
* rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
if ((opteq = strchr(opt, '='))) {
- val = atoi(opteq + 1);
+ val = atoi(opteq + 1);
*opteq = '\0';
if (!strcmp(opt, "rsize"))
data.rsize = val;
else if (!strcmp(opt, "mountport"))
mountport = val;
else if (!strcmp(opt, "mounthost"))
- mounthost=xstrndup(opteq+1,
+ mounthost=bb_xstrndup(opteq+1,
strcspn(opteq+1," \t\n\r,"));
else if (!strcmp(opt, "mountprog"))
mountprog = val;
val = 0;
opt += 2;
}
- if (!strcmp(opt, "bg"))
+ if (!strcmp(opt, "bg"))
bg = val;
- else if (!strcmp(opt, "fg"))
+ else if (!strcmp(opt, "fg"))
bg = !val;
else if (!strcmp(opt, "soft"))
soft = val;
data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
#endif
if (nfsvers > MAX_NFSPROT) {
- error_msg("NFSv%d not supported!", nfsvers);
+ bb_error_msg("NFSv%d not supported!", nfsvers);
return 0;
}
if (mountvers > MAX_NFSPROT) {
- error_msg("NFSv%d not supported!", nfsvers);
+ bb_error_msg("NFSv%d not supported!", nfsvers);
return 0;
}
if (nfsvers && !mountvers)
#endif
data.version = nfs_mount_version;
- *mount_opts = (char *) &data;
if (*flags & MS_REMOUNT)
- return 0;
+ goto copy_data_and_return;
/*
* If the previous mount operation on the same host was
mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
} else {
if ((hp = gethostbyname(mounthost)) == NULL) {
- herror_msg("%s", mounthost);
+ bb_herror_msg("%s", mounthost);
goto fail;
} else {
if (hp->h_length > sizeof(struct in_addr)) {
- error_msg("got bad hp->h_length?");
+ bb_error_msg("got bad hp->h_length?");
hp->h_length = sizeof(struct in_addr);
}
mount_server_addr.sin_family = AF_INET;
mountprog,
mountvers,
proto,
- mountport);
+ mountport);
/* contact the mount daemon via TCP */
mount_server_addr.sin_port = htons(pm_mnt->pm_port);
mclient = 0;
}
if (mclient) {
- /* try to mount hostname:dirname */
+ /* try to mount hostname:pathname */
mclient->cl_auth = authunix_create_default();
/* make pointers in xdr_mountres3 NULL so
if (pm_mnt->pm_vers == 3)
clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
(xdrproc_t) xdr_dirpath,
- (caddr_t) &dirname,
+ (caddr_t) &pathname,
(xdrproc_t) xdr_mountres3,
(caddr_t) &status,
total_timeout);
else
clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
(xdrproc_t) xdr_dirpath,
- (caddr_t) &dirname,
+ (caddr_t) &pathname,
(xdrproc_t) xdr_fhstatus,
(caddr_t) &status,
total_timeout);
if (!bg)
goto fail;
if (!running_bg) {
- prev_bg_host = xstrdup(hostname);
+ prev_bg_host = bb_xstrdup(hostname);
if (retry > 0)
retval = EX_BG;
goto fail;
if (nfsvers == 2) {
if (status.nfsv2.fhs_status != 0) {
- error_msg("%s:%s failed, reason given by server: %s",
- hostname, dirname,
+ bb_error_msg("%s:%s failed, reason given by server: %s",
+ hostname, pathname,
nfs_strerror(status.nfsv2.fhs_status));
goto fail;
}
#if NFS_MOUNT_VERSION >= 4
fhandle3 *my_fhandle;
if (status.nfsv3.fhs_status != 0) {
- error_msg("%s:%s failed, reason given by server: %s",
- hostname, dirname,
+ bb_error_msg("%s:%s failed, reason given by server: %s",
+ hostname, pathname,
nfs_strerror(status.nfsv3.fhs_status));
goto fail;
}
if (tcp) {
if (nfs_mount_version < 3) {
- printf(_("NFS over TCP is not supported.\n"));
+ printf(_("NFS over TCP is not supported.\n"));
goto fail;
}
fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
auth_destroy(mclient->cl_auth);
clnt_destroy(mclient);
close(msock);
+copy_data_and_return:
+ *mount_opts = xrealloc(*mount_opts, sizeof(data));
+ memcpy(*mount_opts, &data, sizeof(data));
return 0;
/* abort */
if (fsock != -1)
close(fsock);
return retval;
-}
+}
/*
* We need to translate between nfs status return values and
#define EDQUOT ENOSPC
#endif
-static struct {
+static const struct {
enum nfs_stat stat;
int errnum;
} nfs_errtbl[] = {
{
//register int32_t *buf;
- if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3))
+ if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
return FALSE;
return TRUE;
}
if (!xdr_fhandle3 (xdrs, &objp->fhandle))
return FALSE;
- if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0,
+ if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (unsigned int *) &objp->auth_flavours.auth_flavours_len, ~0,
sizeof (int), (xdrproc_t) xdr_int))
return FALSE;
return TRUE;