hush: rename o_quoted to has_quoted_part; small code shrink
[oweals/busybox.git] / util-linux / mount.c
index e1372ead5b9b9ed73f8e5cc5537ab8d196fd32ec..5e85f998641c473ef5f4e66c42dc394b245adc80 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
  * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
  *
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
 // Design notes: There is no spec for mount.  Remind me to write one.
 //
 #include <sys/utsname.h>
 #undef TRUE
 #undef FALSE
-#include <rpc/rpc.h>
-#include <rpc/pmap_prot.h>
-#include <rpc/pmap_clnt.h>
+#if ENABLE_FEATURE_MOUNT_NFS
+/* This is just a warning of a common mistake.  Possibly this should be a
+ * uclibc faq entry rather than in busybox... */
+# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
+#  error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support"
+# endif
+# include <rpc/rpc.h>
+# include <rpc/pmap_prot.h>
+# include <rpc/pmap_clnt.h>
+#endif
 
 
 #if defined(__dietlibc__)
@@ -260,8 +267,7 @@ struct globals {
 #endif
        llist_t *fslist;
        char getmntent_buf[1];
-
-};
+} FIX_ALIASING;
 enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
 #define G (*(struct globals*)&bb_common_bufsiz1)
 #define nfs_mount_version (G.nfs_mount_version)
@@ -450,7 +456,7 @@ static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
                                args[rc++] = filteropts;
                        }
                        args[rc] = NULL;
-                       rc = wait4pid(spawn(args));
+                       rc = spawn_and_wait(args);
                        free(args[0]);
                        if (!rc)
                                break;
@@ -526,7 +532,7 @@ static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
  * Linux NFS mount
  * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
  *
- * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2, see file LICENSE in this source tree.
  *
  * Wed Feb  8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
  * numbers to be specified on the command line.
@@ -544,12 +550,6 @@ static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
  * plus NFSv3 stuff.
  */
 
-/* This is just a warning of a common mistake.  Possibly this should be a
- * uclibc faq entry rather than in busybox... */
-#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
-#error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
-#endif
-
 #define MOUNTPORT 635
 #define MNTPATHLEN 1024
 #define MNTNAMLEN 255
@@ -740,28 +740,35 @@ enum {
  * "after #include <errno.h> the symbol errno is reserved for any use,
  *  it cannot even be used as a struct tag or field name".
  */
-
 #ifndef EDQUOT
-#define EDQUOT ENOSPC
+# define EDQUOT ENOSPC
 #endif
-
 /* Convert each NFSERR_BLAH into EBLAH */
-static const struct {
-       short stat;
-       short errnum;
-} nfs_errtbl[] = {
-       {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},
-       {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},
-       {28,ENOSPC}, {30,EROFS}, {63,ENAMETOOLONG}, {66,ENOTEMPTY}, {69,EDQUOT},
-       {70,ESTALE}, {71,EREMOTE}, {-1,EIO}
+static const uint8_t nfs_err_stat[] = {
+        1,  2,  5,  6, 13, 17,
+       19, 20, 21, 22, 27, 28,
+       30, 63, 66, 69, 70, 71
+};
+#if ( \
+       EPERM | ENOENT      | EIO      | ENXIO | EACCES| EEXIST | \
+       ENODEV| ENOTDIR     | EISDIR   | EINVAL| EFBIG | ENOSPC | \
+       EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256
+typedef uint8_t nfs_err_type;
+#else
+typedef uint16_t nfs_err_type;
+#endif
+static const nfs_err_type nfs_err_errnum[] = {
+       EPERM , ENOENT      , EIO      , ENXIO , EACCES, EEXIST,
+       ENODEV, ENOTDIR     , EISDIR   , EINVAL, EFBIG , ENOSPC,
+       EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
 };
 static char *nfs_strerror(int status)
 {
        int i;
 
-       for (i = 0; nfs_errtbl[i].stat != -1; i++) {
-               if (nfs_errtbl[i].stat == status)
-                       return strerror(nfs_errtbl[i].errnum);
+       for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
+               if (nfs_err_stat[i] == status)
+                       return strerror(nfs_err_errnum[i]);
        }
        return xasprintf("unknown nfs status return value: %d", status);
 }
@@ -797,8 +804,12 @@ static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
 
 static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
 {
-       if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
+       if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
+                               (unsigned int *) &objp->fhandle3_len,
+                               FHSIZE3)
+       ) {
                 return FALSE;
+       }
        return TRUE;
 }
 
@@ -806,9 +817,14 @@ static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
 {
        if (!xdr_fhandle3(xdrs, &objp->fhandle))
                return FALSE;
-       if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0,
-                               sizeof(int), (xdrproc_t) xdr_int))
+       if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
+                               &(objp->auth_flavours.auth_flavours_len),
+                               ~0,
+                               sizeof(int),
+                               (xdrproc_t) xdr_int)
+       ) {
                return FALSE;
+       }
        return TRUE;
 }
 
@@ -859,11 +875,7 @@ find_kernel_nfs_mount_version(void)
 
        kernel_version = get_linux_version_code();
        if (kernel_version) {
-               if (kernel_version < KERNEL_VERSION(2,1,32))
-                       nfs_mount_version = 1;
-               else if (kernel_version < KERNEL_VERSION(2,2,18) ||
-                               (kernel_version >= KERNEL_VERSION(2,3,0) &&
-                                kernel_version < KERNEL_VERSION(2,3,99)))
+               if (kernel_version < KERNEL_VERSION(2,2,18))
                        nfs_mount_version = 3;
                /* else v4 since 2.3.99pre4 */
        }
@@ -902,10 +914,12 @@ get_mountport(struct pmap *pm_mnt,
                        goto next;
                if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
                        goto next;
-               if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
-                   (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto) ||
-                   (port && pmap->pml_map.pm_port != port))
+               if (pmap->pml_map.pm_vers > MAX_NFSPROT
+                || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
+                || (port && pmap->pml_map.pm_port != port)
+               ) {
                        goto next;
+               }
                memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
  next:
                pmap = pmap->pml_next;
@@ -1037,12 +1051,10 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
                        bb_herror_msg("%s", hostname);
                        goto fail;
                }
-               if ((size_t)hp->h_length > sizeof(struct in_addr)) {
-                       bb_error_msg("got bad hp->h_length");
-                       hp->h_length = sizeof(struct in_addr);
+               if (hp->h_length != (int)sizeof(struct in_addr)) {
+                       bb_error_msg_and_die("only IPv4 is supported");
                }
-               memcpy(&server_addr.sin_addr,
-                               hp->h_addr, hp->h_length);
+               memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
        }
 
        memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
@@ -1135,7 +1147,7 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
                                continue;
                        }
 
-                       val = xatoi_u(opteq);
+                       val = xatoi_positive(opteq);
                        switch (idx) {
                        case 0: // "rsize"
                                data.rsize = val;
@@ -1325,13 +1337,11 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
                                bb_herror_msg("%s", mounthost);
                                goto fail;
                        }
-                       if ((size_t)hp->h_length > sizeof(struct in_addr)) {
-                               bb_error_msg("got bad hp->h_length");
-                               hp->h_length = sizeof(struct in_addr);
+                       if (hp->h_length != (int)sizeof(struct in_addr)) {
+                               bb_error_msg_and_die("only IPv4 is supported");
                        }
                        mount_server_addr.sin_family = AF_INET;
-                       memcpy(&mount_server_addr.sin_addr,
-                                               hp->h_addr, hp->h_length);
+                       memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
                }
        }
 
@@ -1598,6 +1608,8 @@ static int singlemount(struct mntent *mp, int ignore_busy)
        llist_t *fl = NULL;
        struct stat st;
 
+       errno = 0;
+
        vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
 
        // Treat fstype "auto" as unspecified
@@ -1629,7 +1641,7 @@ static int singlemount(struct mntent *mp, int ignore_busy)
                }
                args[n++] = mp->mnt_dir;
                args[n] = NULL;
-               rc = wait4pid(xspawn(args));
+               rc = spawn_and_wait(args);
                goto report_error;
        }
 
@@ -1639,52 +1651,41 @@ static int singlemount(struct mntent *mp, int ignore_busy)
         && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
         && mp->mnt_fsname[0] == mp->mnt_fsname[1]
        ) {
-#if 0 /* reported to break things */
+               int len;
+               char c;
                len_and_sockaddr *lsa;
-               char *ip, *dotted;
-               char *s;
+               char *hostname, *dotted, *ip;
 
-               // Replace '/' with '\' and verify that unc points to "//server/share".
-               for (s = mp->mnt_fsname; *s; ++s)
-                       if (*s == '/') *s = '\\';
-
-               // Get server IP
-               s = strrchr(mp->mnt_fsname, '\\');
-               if (s <= mp->mnt_fsname+1)
+               hostname = mp->mnt_fsname + 2;
+               len = strcspn(hostname, "/\\");
+               if (len == 0 || hostname[len] == '\0')
                        goto report_error;
-               *s = '\0';
-               lsa = host2sockaddr(mp->mnt_fsname+2, 0);
-               *s = '\\';
+               c = hostname[len];
+               hostname[len] = '\0';
+               lsa = host2sockaddr(hostname, 0);
+               hostname[len] = c;
                if (!lsa)
                        goto report_error;
 
-               // Insert ip=... option into string flags.
+               // Insert "ip=..." option into options
                dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
+               if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
                ip = xasprintf("ip=%s", dotted);
+               if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
                parse_mount_options(ip, &filteropts);
+               if (ENABLE_FEATURE_CLEAN_UP) free(ip);
 
-               // Compose new unc '\\server-ip\share'
-               // (s => slash after hostname)
-               mp->mnt_fsname = xasprintf("\\\\%s%s", dotted, s);
-#endif
-               // Lock is required [why?]
+               // "-o mand" is required [why?]
                vfsflags |= MS_MANDLOCK;
                mp->mnt_type = (char*)"cifs";
                rc = mount_it_now(mp, vfsflags, filteropts);
-#if 0
-               if (ENABLE_FEATURE_CLEAN_UP) {
-                       free(mp->mnt_fsname);
-                       free(ip);
-                       free(dotted);
-                       free(lsa);
-               }
-#endif
+
                goto report_error;
        }
 
        // Might this be an NFS filesystem?
        if (ENABLE_FEATURE_MOUNT_NFS
-        && (!mp->mnt_type || !strcmp(mp->mnt_type, "nfs"))
+        && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0)
         && strchr(mp->mnt_fsname, ':') != NULL
        ) {
                rc = nfsmount(mp, vfsflags, filteropts);
@@ -1702,7 +1703,7 @@ static int singlemount(struct mntent *mp, int ignore_busy)
                if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
                        loopFile = bb_simplify_path(mp->mnt_fsname);
                        mp->mnt_fsname = NULL; // will receive malloced loop dev name
-                       if (set_loop(&(mp->mnt_fsname), loopFile, 0) < 0) {
+                       if (set_loop(&mp->mnt_fsname, loopFile, 0) < 0) {
                                if (errno == EPERM || errno == EACCES)
                                        bb_error_msg(bb_msg_perm_denied_are_you_root);
                                else
@@ -1717,15 +1718,15 @@ static int singlemount(struct mntent *mp, int ignore_busy)
 
        // If we know the fstype (or don't need to), jump straight
        // to the actual mount.
-       if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
+       if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
                rc = mount_it_now(mp, vfsflags, filteropts);
-       else {
+       else {
                // Loop through filesystem types until mount succeeds
                // or we run out
 
-               // Initialize list of block backed filesystems.  This has to be
-               // done here so that during "mount -a", mounts after /proc shows up
-               // can autodetect.
+               // Initialize list of block backed filesystems.
+               // This has to be done here so that during "mount -a",
+               // mounts after /proc shows up can autodetect.
                if (!fslist) {
                        fslist = get_block_backed_filesystems();
                        if (ENABLE_FEATURE_CLEAN_UP && fslist)
@@ -1755,7 +1756,7 @@ static int singlemount(struct mntent *mp, int ignore_busy)
 
        if (errno == EBUSY && ignore_busy)
                return 0;
-       if (rc < 0)
+       if (rc != 0)
                bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
        return rc;
 }
@@ -1870,9 +1871,9 @@ int mount_main(int argc UNUSED_PARAM, char **argv)
                        {
                                // Don't show rootfs. FIXME: why??
                                // util-linux 2.12a happily shows rootfs...
-                               //if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue;
+                               //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
 
-                               if (!fstype || !strcmp(mtpair->mnt_type, fstype))
+                               if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
                                        printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
                                                        mtpair->mnt_dir, mtpair->mnt_type,
                                                        mtpair->mnt_opts);
@@ -1928,7 +1929,7 @@ int mount_main(int argc UNUSED_PARAM, char **argv)
        }
        fstab = setmntent(fstabname, "r");
        if (!fstab)
-               bb_perror_msg_and_die("can't read %s", fstabname);
+               bb_perror_msg_and_die("can't read '%s'", fstabname);
 
        // Loop through entries until we find what we're looking for
        memset(mtpair, 0, sizeof(mtpair));