]> err.no Git - util-linux/commitdiff
libmount: support /{proc,etc}/filesystems
authorKarel Zak <kzak@redhat.com>
Wed, 10 Nov 2010 00:25:07 +0000 (01:25 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 3 Jan 2011 11:28:46 +0000 (12:28 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
shlibs/mount/src/context.c
shlibs/mount/src/context_mount.c
shlibs/mount/src/context_umount.c
shlibs/mount/src/mount.h.in
shlibs/mount/src/mountP.h
shlibs/mount/src/tab_update.c
shlibs/mount/src/utils.c

index b4662d89e593697629f8808466b182895ae8ffce..3863629caf9e722307f2be49295e065a8175aaf8 100644 (file)
@@ -33,6 +33,9 @@ mnt_context *mnt_new_context()
        ruid = getuid();
        euid = geteuid();
 
+       cxt->syscall_status = 1;        /* not called yet */
+       cxt->helper_exec_status = 1;
+
        /* if we're really root and aren't running setuid */
        cxt->restricted = (uid_t) 0 == ruid && ruid == euid ? 0 : 1;
 
@@ -115,13 +118,15 @@ int mnt_reset_context(mnt_context *cxt)
 
        cxt->fs = NULL;
        cxt->mtab = NULL;
+       cxt->ambi = 0;
        cxt->helper = NULL;
        cxt->orig_user = NULL;
        cxt->mountflags = 0;
        cxt->user_mountflags = 0;
        cxt->mountdata = NULL;
        cxt->flags = MNT_FL_DEFAULT;
-       cxt->syscall_errno = 0;
+       cxt->syscall_status = 1;
+       cxt->helper_exec_status = 1;
        cxt->helper_status = 0;
 
        /* restore non-resetable flags */
@@ -418,6 +423,8 @@ int mnt_context_set_target(mnt_context *cxt, const char *target)
  */
 int mnt_context_set_fstype(mnt_context *cxt, const char *fstype)
 {
+       if (fstype && strchr(fstype, ','))
+               return -EINVAL;
        return mnt_fs_set_fstype(mnt_context_get_fs(cxt), fstype);
 }
 
@@ -909,6 +916,9 @@ int mnt_context_guess_fstype(mnt_context *cxt)
                goto done;
        if (cxt->flags & MS_REMOUNT)
                goto none;
+       if (cxt->fstype_pattern)
+               goto done;
+
        dev = mnt_fs_get_srcpath(cxt->fs);
        if (!dev)
                goto err;
@@ -931,7 +941,7 @@ int mnt_context_guess_fstype(mnt_context *cxt)
        if (rc)
                goto err;
 done:
-       DBG(CXT, mnt_debug_h(cxt, "detected FS type: %s",
+       DBG(CXT, mnt_debug_h(cxt, "FS type: %s",
                                mnt_fs_get_fstype(cxt->fs)));
        return 0;
 none:
@@ -1159,6 +1169,15 @@ static int apply_tab(mnt_context *cxt, mnt_tab *tb, int direction)
        return rc;
 }
 
+/**
+ * mnt_context_apply_fstab:
+ * @cxt: mount context
+ *
+ * This function is optional if mnt_context_do_mount() is used. See also
+ * mnt_context_set_optsmode().
+ *
+ * Returns: 0 on success, negative number in case of error.
+ */
 int mnt_context_apply_fstab(mnt_context *cxt)
 {
        int rc;
@@ -1209,12 +1228,22 @@ int mnt_context_apply_fstab(mnt_context *cxt)
                        goto err;
        }
        return 0;
-
 err:
        DBG(CXT, mnt_debug_h(cxt, "failed to found entry in fstab/mtab"));
        return rc;
 }
 
+/**
+ * mnt_context_get_status:
+ * @cxt: mount context
+ *
+ * Returns: 1 if mount.<type> or mount(2) syscall was successfull or 0.
+ */
+int mnt_context_get_status(mnt_context *cxt)
+{
+       return cxt && (!cxt->syscall_status || !cxt->helper_exec_status);
+}
+
 /**
  * mnt_context_strerror
  * @cxt: context
index de6557df42ee3298ca6936dd817a61f275b9c884..070d72f101eb62c21995d66d021e0aed9f203ac5 100644 (file)
@@ -257,8 +257,8 @@ static int exec_helper(mnt_context *cxt)
 
                type = mnt_fs_get_fstype(cxt->fs);
 
-               args[i++] = cxt->helper;                        /* 1 */
-               args[i++] = mnt_fs_get_srcpath(cxt->fs);        /* 2 */
+               args[i++] = cxt->helper;                /* 1 */
+               args[i++] = mnt_fs_get_srcpath(cxt->fs);/* 2 */
                args[i++] = mnt_fs_get_target(cxt->fs); /* 3 */
 
                if (cxt->flags & MNT_FL_SLOPPY)
@@ -296,12 +296,12 @@ static int exec_helper(mnt_context *cxt)
 
                DBG(CXT, mnt_debug_h(cxt, "%s executed [status=%d]",
                                        cxt->helper, cxt->helper_status));
-               rc = 0;
+               cxt->helper_exec_status = rc = 0;
                break;
        }
 
        case -1:
-               rc = -errno;
+               cxt->helper_exec_status = rc = -errno;
                DBG(CXT, mnt_debug_h(cxt, "fork() failed"));
                break;
        }
@@ -315,7 +315,7 @@ static int exec_helper(mnt_context *cxt)
  */
 static int do_mount(mnt_context *cxt, const char *try_type)
 {
-       int rc;
+       int rc = 0;
        const char *src, *target, *type;
        unsigned long flags;
 
@@ -323,6 +323,7 @@ static int do_mount(mnt_context *cxt, const char *try_type)
        assert(cxt->fs);
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
+
        if (try_type && !cxt->helper) {
                rc = mnt_context_prepare_helper(cxt, "mount", try_type);
                if (!rc)
@@ -331,8 +332,6 @@ static int do_mount(mnt_context *cxt, const char *try_type)
        if (cxt->helper)
                return exec_helper(cxt);
 
-       type = try_type ? : mnt_fs_get_fstype(cxt->fs);
-
        flags = cxt->mountflags;
        src = mnt_fs_get_srcpath(cxt->fs);
        target = mnt_fs_get_target(cxt->fs);
@@ -340,6 +339,8 @@ static int do_mount(mnt_context *cxt, const char *try_type)
        if (!src || !target)
                return -EINVAL;
 
+       type = try_type ? : mnt_fs_get_fstype(cxt->fs);
+
        if (!(flags & MS_MGC_MSK))
                flags |= MS_MGC_VAL;
 
@@ -352,14 +353,68 @@ static int do_mount(mnt_context *cxt, const char *try_type)
 
        if (!(cxt->flags & MNT_FL_FAKE)) {
                if (mount(src, target, type, flags, cxt->mountdata)) {
-                       cxt->syscall_errno = errno;
+                       cxt->syscall_status = -errno;
                        DBG(CXT, mnt_debug_h(cxt, "mount(2) failed [errno=%d]",
-                                                       cxt->syscall_errno));
-                       return -cxt->syscall_errno;
+                                                       -cxt->syscall_status));
+                       return cxt->syscall_status;
                }
                DBG(CXT, mnt_debug_h(cxt, "mount(2) success"));
+               cxt->syscall_status = 0;
        }
-       return 0;
+
+       if (try_type && cxt->update) {
+               mnt_fs *fs = mnt_update_get_fs(cxt->update);
+               if (fs)
+                       rc = mnt_fs_set_fstype(fs, try_type);
+       }
+       return rc;
+}
+
+static int do_mount_by_pattern(mnt_context *cxt, const char *pattern)
+{
+       int neg = pattern && strncmp(pattern, "no", 2) == 0;
+       int rc = -EINVAL;
+       char **filesystems, **fp;
+
+       assert(cxt);
+
+       if (!neg && pattern) {
+               /*
+                * try all types from the list
+                */
+               char *p, *p0;
+
+               p0 = p = strdup(pattern);
+               if (!p)
+                       return -ENOMEM;
+               do {
+                       char *end = strchr(p, ',');
+                       if (end)
+                               *end = '\0';
+                       rc = do_mount(cxt, p);
+                       p = end ? end + 1 : NULL;
+               } while (!mnt_context_get_status(cxt) && p);
+
+               free(p0);
+
+               if (mnt_context_get_status(cxt))
+                       return rc;
+       }
+
+       /*
+        * try /etc/filesystems and /proc/filesystems
+        */
+       rc = mnt_get_filesystems(&filesystems, neg ? pattern : NULL);
+       if (rc)
+               return rc;
+
+       for (fp = filesystems; *fp; fp++) {
+               rc = do_mount(cxt, *fp);
+               if (mnt_context_get_status(cxt))
+                       break;
+       }
+       mnt_free_filesystems(filesystems);
+       return rc;
 }
 
 /**
@@ -370,16 +425,20 @@ static int do_mount(mnt_context *cxt, const char *try_type)
  *
  * See also mnt_context_disable_helpers().
  *
- * Returns: 0 on success, and negative number in case of error.
+ * Returns: 0 on success, and negative number in case of error. WARNING: error
+ *          does not mean that mount(2) syscall or mount.<type> helper wasn't
+ *          sucessfully called. Check mnt_context_get_status() after error!
  */
 int mnt_context_do_mount(mnt_context *cxt)
 {
-       int rc = -EINVAL;
+       int rc = -EINVAL, x;
        const char *type;
 
        assert(cxt);
        assert(cxt->fs);
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
+       assert(cxt->helper_exec_status == 1);
+       assert(cxt->syscall_status == 1);
 
        if (!cxt || !cxt->fs || (cxt->fs->flags & MNT_FS_SWAP))
                return -EINVAL;
@@ -417,21 +476,16 @@ int mnt_context_do_mount(mnt_context *cxt)
                cxt->mountdata = (char *) mnt_fs_get_fs_optstr(cxt->fs);
 
        type = mnt_fs_get_fstype(cxt->fs);
-
-       if (type && !strchr(type, ',')) {
+       if (type)
                rc = do_mount(cxt, NULL);
-               if (rc)
-                       return rc;
-       }
-
-       /* TODO: try all filesystems from comma separated list of types */
-
-       /* TODO: try all filesystems from /proc/filesystems and /etc/filesystems */
+       else
+               rc = do_mount_by_pattern(cxt, cxt->fstype_pattern);
 
        /* TODO: if mtab update is expected then check if the
         * target is really mounted read-write to avoid 'ro' in
         * mtab and 'rw' in /proc/mounts.
         */
-       return mnt_context_update_tabs(cxt);
+       x = mnt_context_update_tabs(cxt);
+       return rc ? rc : x;
 }
 
index 476ee515c23dd45231fbf6fb12e9650291485826..87a0bc8ef4371b303a291ca4fc7a814b771aaf6a 100644 (file)
@@ -275,6 +275,7 @@ static int exec_helper(mnt_context *cxt)
        assert(cxt->fs);
        assert(cxt->helper);
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
+       assert(cxt->helper_exec_status == 1);
 
        DBG_FLUSH;
 
@@ -329,12 +330,12 @@ static int exec_helper(mnt_context *cxt)
 
                DBG(CXT, mnt_debug_h(cxt, "%s executed [status=%d]",
                                        cxt->helper, cxt->helper_status));
-               rc = 0;
+               cxt->helper_exec_status = rc = 0;
                break;
        }
 
        case -1:
-               rc = -errno;
+               cxt->helper_exec_status = rc = -errno;
                DBG(CXT, mnt_debug_h(cxt, "fork() failed"));
                break;
        }
@@ -350,6 +351,7 @@ static int do_umount(mnt_context *cxt)
        assert(cxt);
        assert(cxt->fs);
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
+       assert(cxt->syscall_status == 1);
 
        if (cxt->helper)
                return exec_helper(cxt);
@@ -375,38 +377,37 @@ static int do_umount(mnt_context *cxt)
                rc = umount(target);
 
        if (rc < 0)
-               cxt->syscall_errno = errno;
-
+               cxt->syscall_status = -errno;
        /*
         * try remount read-only
         */
-       if (rc < 0 && cxt->syscall_errno == EBUSY &&
+       if (rc < 0 && cxt->syscall_status == -EBUSY &&
            (cxt->flags & MNT_FL_RDONLY_UMOUNT) && src) {
 
                cxt->mountflags |= MS_REMOUNT | MS_RDONLY;
                cxt->flags &= ~MNT_FL_LOOPDEL;
                DBG(CXT, mnt_debug_h(cxt, "umount(2) failed [errno=%d] -- "
                                        "tring remount read-only",
-                                       cxt->syscall_errno));
+                                       -cxt->syscall_status));
 
                rc = mount(src, target, NULL,
                            MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
                if (rc < 0) {
-                       cxt->syscall_errno = errno;
+                       cxt->syscall_status = -errno;
                        DBG(CXT, mnt_debug_h(cxt, "read-only re-mount(2) failed "
                                        "[errno=%d]",
-                                       cxt->syscall_errno));
-                       return -cxt->syscall_errno;
+                                       -cxt->syscall_status));
+                       return cxt->syscall_status;
                }
-               cxt->syscall_errno = 0;
+               cxt->syscall_status = 0;
                DBG(CXT, mnt_debug_h(cxt, "read-only re-mount(2) success"));
                return 0;
        }
 
        if (rc < 0) {
                DBG(CXT, mnt_debug_h(cxt, "umount(2) failed [errno=%d]",
-                                       cxt->syscall_errno));
-               return -cxt->syscall_errno;
+                                       -cxt->syscall_status));
+               return -cxt->syscall_status;
        }
        DBG(CXT, mnt_debug_h(cxt, "umount(2) success"));
        return 0;
index 8bb44c7b45902021722713c92a2db1884cdef516..5553921edaf3b2234070977bf6e0c4f1f2b4675c 100644 (file)
@@ -135,6 +135,9 @@ extern const char *mnt_get_fstab_path(void);
 extern const char *mnt_get_mtab_path(void);
 extern const char *mnt_get_utab_path(void);
 
+extern int mnt_get_filesystems(char ***filesystems, const char *pattern);
+extern void mnt_free_filesystems(char **filesystems);
+
 extern int mnt_has_regular_mtab(const char **mtab, int *writable);
 extern int mnt_has_regular_utab(const char **utab, int *writable);
 
@@ -345,6 +348,7 @@ extern int mnt_context_set_userspace_mountflags(mnt_context *cxt, unsigned long
 extern int mnt_context_get_userspace_mountflags(mnt_context *cxt, unsigned long *flags);
 extern int mnt_context_set_mountdata(mnt_context *cxt, void *data);
 extern int mnt_context_apply_fstab(mnt_context *cxt);
+extern int mnt_context_get_status(mnt_context *cxt);
 
 /*
  * mount(8) userspace options masks (MNT_MAP_USERSPACE map)
index 0f1395e5ac17a491fabc4b3041045519fab72de7..a277d61eb5d227192ae757559a113dd85cd0f943 100644 (file)
@@ -236,10 +236,11 @@ struct _mnt_context
 
        char    *helper;        /* name of the used /sbin/[u]mount.<type> helper */
        int     helper_status;  /* helper wait(2) status */
+       int     helper_exec_status; /* 1: not called yet, 0: success, <0: -errno */
 
        char    *orig_user;     /* original (non-fixed) user= option */
 
-       int     syscall_errno;  /* mount(2) or umount(2) error */
+       int     syscall_status; /* 1: not called yet, 0: success, <0: -errno */
 };
 
 /* flags */
@@ -294,4 +295,7 @@ extern mnt_fs *mnt_context_get_fs(mnt_context *cxt);
 extern int mnt_context_merge_mountflags(mnt_context *cxt);
 extern int mnt_context_update_tabs(mnt_context *cxt);
 
+/* tab_update.c */
+extern mnt_fs *mnt_update_get_fs(mnt_update *upd);
+
 #endif /* _LIBMOUNT_PRIVATE_H */
index 99b2a890b92b241d79a7f62cfc5d82651984f4e2..4b4f0adddce2a59afde030423488b6e2dddb49ce 100644 (file)
@@ -152,6 +152,13 @@ int mnt_update_set_fs(mnt_update *upd, int mountflags,
        return 0;
 }
 
+/*
+ * Returns update filesystem or NULL
+ */
+mnt_fs *mnt_update_get_fs(mnt_update *upd)
+{
+       return upd ? upd->fs : NULL;
+}
 
 /*
  * Allocates (but does not write) utab entry for mount/remount. This function
index 0f17edfea07dcf042e1ca8c1db53c4e1b75a203a..6af8d14f4649e58671a002625043c23b9696377a 100644 (file)
@@ -305,6 +305,93 @@ int mnt_match_options(const char *optstr, const char *pattern)
        return 1;
 }
 
+void mnt_free_filesystems(char **filesystems)
+{
+       char **p;
+
+       if (!filesystems)
+               return;
+       for (p = filesystems; *p; p++)
+               free(*p);
+       free(filesystems);
+}
+
+static int add_filesystem(char ***filesystems, char *name)
+{
+       int n = 0;
+
+       assert(filesystems);
+       assert(name);
+
+       if (*filesystems) {
+               char **p;
+               for (n = 0, p = *filesystems; *p; p++, n++) {
+                       if (strcmp(*p, name) == 0)
+                               return 0;
+               }
+       }
+
+       #define MYCHUNK 16
+
+       if (n == 0 || !((n + 1) % MYCHUNK)) {
+               size_t items = ((n + 1 + MYCHUNK) / MYCHUNK) * MYCHUNK;
+               char **x = realloc(*filesystems, items * sizeof(char *));
+
+               if (!x)
+                       goto err;
+               *filesystems = x;
+       }
+       name = strdup(name);
+       if (!name)
+               goto err;
+       (*filesystems)[n] = name;
+       (*filesystems)[n + 1] = NULL;
+       return 0;
+err:
+       mnt_free_filesystems(*filesystems);
+       return -ENOMEM;
+}
+
+static int get_filesystems(const char *filename, char ***filesystems, const char *pattern)
+{
+       FILE *f;
+       char line[128];
+
+       f = fopen(filename, "r");
+       if (!f)
+               return 0;
+
+       while (fgets(line, sizeof(line), f)) {
+               char name[sizeof(line)];
+               int rc;
+
+               if (*line == '#' || strncmp(line, "nodev", 5) == 0)
+                       continue;
+               if (sscanf(line, " %128[^\n ]\n", name) != 1)
+                       continue;
+               if (pattern && !mnt_match_fstype(name, pattern))
+                       continue;
+               rc = add_filesystem(filesystems, name);
+               if (rc)
+                       return rc;
+       }
+       return 0;
+}
+
+int mnt_get_filesystems(char ***filesystems, const char *pattern)
+{
+       int rc;
+
+       if (!filesystems)
+               return -EINVAL;
+       *filesystems = NULL;
+
+       rc = get_filesystems(_PATH_FILESYSTEMS, filesystems, pattern);
+       if (rc)
+               return rc;
+       return get_filesystems(_PATH_PROC_FILESYSTEMS, filesystems, pattern);
+}
+
 /*
  * Returns allocated string with username or NULL.
  */
@@ -721,11 +808,27 @@ int test_fsroot(struct mtest *ts, int argc, char *argv[])
        return 0;
 }
 
+int test_filesystems(struct mtest *ts, int argc, char *argv[])
+{
+       char **filesystems = NULL;
+       int rc;
+
+       rc = mnt_get_filesystems(&filesystems, argc ? argv[1] : NULL);
+       if (!rc) {
+               char **p;
+               for (p = filesystems; *p; p++)
+                       printf("%s\n", *p);
+               mnt_free_filesystems(filesystems);
+       }
+       return rc;
+}
+
 int main(int argc, char *argv[])
 {
        struct mtest tss[] = {
        { "--match-fstype",  test_match_fstype,    "<type> <pattern>     FS types matching" },
        { "--match-options", test_match_options,   "<options> <pattern>  options matching" },
+       { "--filesystems",   test_filesystems,     "[<pattern>] list /{etc,proc}/filesystems" },
        { "--starts-with",   test_startswith,      "<string> <prefix>" },
        { "--ends-with",     test_endswith,        "<string> <prefix>" },
        { "--mountpoint",    test_mountpoint,      "<path>" },