shrink the code a bit
[oweals/busybox.git] / util-linux / nfsmount.c
index d661a99a42c0f750590fc58b769df2c18ce036e2..e9d6dc6354309b6b84391cda61cd780ea8c04a99 100644 (file)
@@ -24,7 +24,7 @@
  *
  * 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.
  */
  * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
  */
 
-#include "busybox.h"
-#undef FALSE
-#undef TRUE
 #include <unistd.h>
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
 #include <netdb.h>
-#include <rpc/rpc.h>
-#include <rpc/pmap_prot.h>
-#include <rpc/pmap_clnt.h>
 #include <sys/socket.h>
-#include <sys/time.h>
+#include <time.h>
 #include <sys/utsname.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
-
+#include <stdlib.h>
+#include "busybox.h"
+#undef TRUE
+#undef FALSE
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
 #include "nfsmount.h"
-#include <linux/nfs.h>  /* For the kernels nfs stuff */
+
+/* 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;
@@ -93,14 +146,16 @@ static const int MS_NODIRATIME = 2048;    /* Do not update directory access time
  * so it is easiest to ignore the kernel altogether (at compile time).
  */
 
-static const int NFS_MOUNT_VERSION = 4;
+/* NOTE: Do not make this into a 'static const int' because the pre-processor
+ * needs to test this value in some #if statements. */
+#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 {
@@ -155,7 +210,7 @@ static const int NFS_MOUNT_NONLM = 0x0200;  /* 3 */
 #define HAVE_personality
 #define HAVE_tm_gmtoff
 
-static char *nfs_strerror(int stat);
+static char *nfs_strerror(int status);
 
 #define MAKE_VERSION(p,q,r)    (65536*(p) + 256*(q) + (r))
 #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
@@ -181,7 +236,8 @@ static int nfs_mount_version;
  *     nfs_mount_version: version this source and running kernel can handle
  */
 static void
-find_kernel_nfs_mount_version(void) {
+find_kernel_nfs_mount_version(void)
+{
        static int kernel_version = 0;
 
        if (kernel_version)
@@ -191,15 +247,17 @@ find_kernel_nfs_mount_version(void) {
 
        kernel_version = get_kernel_revision();
        if (kernel_version) {
-            if (kernel_version < MAKE_VERSION(2,1,32))
-                 nfs_mount_version = 1;
-            else if (kernel_version < MAKE_VERSION(2,3,99))
-                 nfs_mount_version = 3;
-            else
-                 nfs_mount_version = 4; /* since 2.3.99pre4 */
+               if (kernel_version < MAKE_VERSION(2,1,32))
+                       nfs_mount_version = 1;
+               else if (kernel_version < MAKE_VERSION(2,2,18) ||
+                               (kernel_version >=   MAKE_VERSION(2,3,0) &&
+                                kernel_version < MAKE_VERSION(2,3,99)))
+                       nfs_mount_version = 3;
+               else
+                       nfs_mount_version = 4; /* since 2.3.99pre4 */
        }
        if (nfs_mount_version > NFS_MOUNT_VERSION)
-            nfs_mount_version = NFS_MOUNT_VERSION;
+               nfs_mount_version = NFS_MOUNT_VERSION;
 }
 
 static struct pmap *
@@ -251,19 +309,19 @@ return &p;
 }
 
 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;
@@ -305,22 +363,22 @@ int nfsmount(const char *spec, const char *node, int *flags,
        msock = fsock = -1;
        mclient = NULL;
        if (strlen(spec) >= sizeof(hostdir)) {
-               error_msg("excessively long host:dir argument\n");
+               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\n");
+                       bb_error_msg("warning: multiple hostnames not supported");
                }
        } else {
-               error_msg("directory to mount not in host:dir format\n");
+               bb_error_msg("directory to mount not in host:dir format");
                goto fail;
        }
 
@@ -330,11 +388,11 @@ int nfsmount(const char *spec, const char *node, int *flags,
 #endif
        {
                if ((hp = gethostbyname(hostname)) == NULL) {
-                       error_msg("can't get address for %s\n", hostname);
+                       bb_herror_msg("%s", hostname);
                        goto fail;
                } else {
                        if (hp->h_length > sizeof(struct in_addr)) {
-                               error_msg("got bad hp->h_length\n");
+                               bb_error_msg("got bad hp->h_length");
                                hp->h_length = sizeof(struct in_addr);
                        }
                        memcpy(&server_addr.sin_addr,
@@ -347,16 +405,16 @@ int nfsmount(const char *spec, const char *node, int *flags,
        /* 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\n");
+               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
@@ -393,7 +451,7 @@ int nfsmount(const char *spec, const char *node, int *flags,
 
        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;
@@ -424,7 +482,7 @@ int nfsmount(const char *spec, const char *node, int *flags,
                        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;
@@ -463,9 +521,9 @@ int nfsmount(const char *spec, const char *node, int *flags,
                                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;
@@ -511,11 +569,11 @@ int nfsmount(const char *spec, const char *node, int *flags,
                data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
 #endif
        if (nfsvers > MAX_NFSPROT) {
-               error_msg("NFSv%d not supported!\n", nfsvers);
+               bb_error_msg("NFSv%d not supported!", nfsvers);
                return 0;
        }
        if (mountvers > MAX_NFSPROT) {
-               error_msg("NFSv%d not supported!\n", nfsvers);
+               bb_error_msg("NFSv%d not supported!", nfsvers);
                return 0;
        }
        if (nfsvers && !mountvers)
@@ -550,10 +608,9 @@ int nfsmount(const char *spec, const char *node, int *flags,
 #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
@@ -575,11 +632,11 @@ int nfsmount(const char *spec, const char *node, int *flags,
            mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
          } else {
                  if ((hp = gethostbyname(mounthost)) == NULL) {
-                         error_msg("can't get address for %s\n", hostname);
+                         bb_herror_msg("%s", mounthost);
                          goto fail;
                  } else {
                          if (hp->h_length > sizeof(struct in_addr)) {
-                                 error_msg("got bad hp->h_length?\n");
+                                 bb_error_msg("got bad hp->h_length?");
                                  hp->h_length = sizeof(struct in_addr);
                          }
                          mount_server_addr.sin_family = AF_INET;
@@ -630,7 +687,7 @@ int nfsmount(const char *spec, const char *node, int *flags,
                                       mountprog,
                                       mountvers,
                                       proto,
-                                      mountport);
+                                      mountport);
 
                        /* contact the mount daemon via TCP */
                        mount_server_addr.sin_port = htons(pm_mnt->pm_port);
@@ -657,7 +714,7 @@ int nfsmount(const char *spec, const char *node, int *flags,
                        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
@@ -668,14 +725,14 @@ int nfsmount(const char *spec, const char *node, int *flags,
                        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);
@@ -701,7 +758,7 @@ int nfsmount(const char *spec, const char *node, int *flags,
                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;
@@ -714,8 +771,8 @@ int nfsmount(const char *spec, const char *node, int *flags,
 
        if (nfsvers == 2) {
                if (status.nfsv2.fhs_status != 0) {
-                       error_msg("%s:%s failed, reason given by server: %s\n",
-                               hostname, dirname,
+                       bb_error_msg("%s:%s failed, reason given by server: %s",
+                               hostname, pathname,
                                nfs_strerror(status.nfsv2.fhs_status));
                        goto fail;
                }
@@ -730,20 +787,20 @@ int nfsmount(const char *spec, const char *node, int *flags,
 #endif
        } else {
 #if NFS_MOUNT_VERSION >= 4
-               fhandle3 *fhandle;
+               fhandle3 *my_fhandle;
                if (status.nfsv3.fhs_status != 0) {
-                       error_msg("%s:%s failed, reason given by server: %s\n",
-                               hostname, dirname,
+                       bb_error_msg("%s:%s failed, reason given by server: %s",
+                               hostname, pathname,
                                nfs_strerror(status.nfsv3.fhs_status));
                        goto fail;
                }
-               fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
+               my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
                memset(data.old_root.data, 0, NFS_FHSIZE);
                memset(&data.root, 0, sizeof(data.root));
-               data.root.size = fhandle->fhandle3_len;
+               data.root.size = my_fhandle->fhandle3_len;
                memcpy(data.root.data,
-                      (char *) fhandle->fhandle3_val,
-                      fhandle->fhandle3_len);
+                      (char *) my_fhandle->fhandle3_val,
+                      my_fhandle->fhandle3_len);
 
                data.flags |= NFS_MOUNT_VER3;
 #endif
@@ -753,7 +810,7 @@ int nfsmount(const char *spec, const char *node, int *flags,
 
        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);
@@ -805,6 +862,9 @@ int nfsmount(const char *spec, const char *node, int *flags,
        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 */
@@ -820,7 +880,7 @@ fail:
        if (fsock != -1)
                close(fsock);
        return retval;
-}      
+}
 
 /*
  * We need to translate between nfs status return values and
@@ -835,7 +895,7 @@ fail:
 #define EDQUOT ENOSPC
 #endif
 
-static struct {
+static const struct {
        enum nfs_stat stat;
        int errnum;
 } nfs_errtbl[] = {
@@ -868,20 +928,20 @@ static struct {
        { -1,                   EIO             }
 };
 
-static char *nfs_strerror(int stat)
+static char *nfs_strerror(int status)
 {
        int i;
        static char buf[256];
 
        for (i = 0; nfs_errtbl[i].stat != -1; i++) {
-               if (nfs_errtbl[i].stat == stat)
+               if (nfs_errtbl[i].stat == status)
                        return strerror(nfs_errtbl[i].errnum);
        }
-       sprintf(buf, _("unknown nfs status return value: %d"), stat);
+       sprintf(buf, _("unknown nfs status return value: %d"), status);
        return buf;
 }
 
-bool_t
+static bool_t
 xdr_fhandle (XDR *xdrs, fhandle objp)
 {
        //register int32_t *buf;
@@ -924,7 +984,7 @@ xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
 {
        //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;
 }
@@ -936,7 +996,7 @@ xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
 
         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;