]> err.no Git - util-linux/commitdiff
libmount: split context.c
authorKarel Zak <kzak@redhat.com>
Mon, 4 Oct 2010 11:37:33 +0000 (13:37 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 3 Jan 2011 11:28:44 +0000 (12:28 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
shlibs/mount/src/Makefile.am
shlibs/mount/src/context.c
shlibs/mount/src/context_mount.c [new file with mode: 0644]
shlibs/mount/src/mount.h.in
shlibs/mount/src/mountP.h

index 298a8754d842b7636009ab4cbab92a6e6d5890b7..f1db1ad1b7a35d792d8c34ad7ceb3ca8a1d542e3 100644 (file)
@@ -11,7 +11,8 @@ nodist_mountinc_HEADERS = mount.h
 usrlib_exec_LTLIBRARIES = libmount.la
 libmount_la_SOURCES =  mountP.h version.c utils.c test.c init.c cache.c \
                        optstr.c optmap.c iter.c lock.c \
-                       fs.c tab.c tab_parse.c tab_update.c context.c \
+                       fs.c tab.c tab_parse.c tab_update.c \
+                       context.c context_mount.c \
                        $(mountinc_HEADERS) \
                        $(top_srcdir)/lib/at.c \
                        $(top_srcdir)/include/list.h \
index 2102be539c0eb999243b0610668e3933b7ffa088..07a72c2d35ff2a3351b4a9048917baa0cec70e47 100644 (file)
 #include <string.h>
 #include <errno.h>
 
-#include <sys/wait.h>
-#include <sys/mount.h>
-
-#ifdef HAVE_LIBSELINUX
-#include <selinux/selinux.h>
-#include <selinux/context.h>
-#endif
-
 #include "c.h"
 #include "mountP.h"
 
-/*
- * Mount context -- high-level API
- */
-struct _mnt_context
-{
-       int     action;         /* MNT_ACT_{MOUNT,UMOUNT} */
-
-       int     restricted;     /* root or not? */
-
-       char    *fstype_pattern;        /* for mnt_match_fstype() */
-       char    *optstr_pattern;        /* for mnt_match_options() */
-
-       char    *spec;          /* unresolved source OR target */
-       mnt_fs  *fs;            /* filesystem description (type, mountpopint, device, ...) */
-
-       mnt_tab *fstab;         /* fstab (or mtab for some remounts) entires */
-       mnt_tab *mtab;          /* mtab entries */
-       int     optsmode;       /* fstab optstr mode MNT_OPTSMODE_{AUTO,FORCE,IGNORE} */
-
-       unsigned long   mountflags;     /* final mount(2) flags */
-       const void      *mountdata;     /* final mount(2) data, string or binary data */
-
-       unsigned long   user_mountflags;        /* MNT_MS_* (loop=, user=, ...) */
-
-       mnt_update      *update;        /* mtab update */
-       mnt_cache       *cache;         /* paths cache */
-
-       int     flags;          /* private context flags */
-       int     ambi;           /* libblkid returns ambivalent result */
-
-       char    *helper;        /* name of the used /sbin/[u]mount.<type> helper */
-       int     helper_status;  /* helper wait(2) status */
-
-       char    *orig_user;     /* original (non-fixed) user= option */
-
-       int     syscall_errno;  /* mount(2) or umount(2) error */
-};
-
-/* flags */
-#define MNT_FL_NOMTAB          (1 << 1)
-#define MNT_FL_FAKE            (1 << 2)
-#define MNT_FL_SLOPPY          (1 << 3)
-#define MNT_FL_VERBOSE         (1 << 4)
-#define MNT_FL_NOHELPERS       (1 << 5)
-#define MNT_FL_LOOPDEL         (1 << 6)
-#define MNT_FL_LAZY            (1 << 7)
-#define MNT_FL_FORCE           (1 << 8)
-#define MNT_FL_NOCANONICALIZE  (1 << 9)
-#define MNT_FL_NOLOCK          (1 << 10)       /* don't lock mtab file */
-
-#define MNT_FL_EXTERN_FS       (1 << 15)       /* cxt->fs is not private */
-#define MNT_FL_EXTERN_FSTAB    (1 << 16)       /* cxt->fstab is not private */
-#define MNT_FL_EXTERN_CACHE    (1 << 17)       /* cxt->cache is not private */
-
-#define MNT_FL_MOUNTDATA       (1 << 20)
-#define MNT_FL_FSTAB_APPLIED   (1 << 21)
-#define MNT_FL_MOUNTFLAGS_MERGED (1 << 22)     /* MS_* flags was read from optstr */
-#define MNT_FL_SAVED_USER      (1 << 23)
-
-/* default flags */
-#define MNT_FL_DEFAULT         0
-
-/* mode for mount options from fstab */
-enum {
-       MNT_OPTSMODE_AUTO = 0,          /* use options if source or target are not defined */
-       MNT_OPTSMODE_IGNORE,            /* never use mount options from fstab */
-       MNT_OPTSMODE_FORCE,             /* always use mount options from fstab */
-       MNT_OPTSMODE_MTABFORCE,         /* for MS_REMOUNT use always options mountinfo/mtab */
-};
-
 /**
  * mnt_new_context:
  *
@@ -212,7 +134,7 @@ int mnt_reset_context(mnt_context *cxt)
        return 0;
 }
 
-static int mnt_context_set_flag(mnt_context *cxt, int flag, int enable)
+static int set_flag(mnt_context *cxt, int flag, int enable)
 {
        if (!cxt)
                return -EINVAL;
@@ -223,17 +145,6 @@ static int mnt_context_set_flag(mnt_context *cxt, int flag, int enable)
        return 0;
 }
 
-static mnt_fs *mnt_context_get_fs(mnt_context *cxt)
-{
-       if (!cxt)
-               return NULL;
-       if (!cxt->fs) {
-               cxt->fs = mnt_new_fs();
-               cxt->flags &= ~MNT_FL_EXTERN_FS;
-       }
-       return cxt->fs;
-}
-
 /**
  * mnt_context_is_restricted:
  * @cxt: mount context
@@ -292,7 +203,7 @@ int mnt_context_set_optsmode(mnt_context *cxt, int mode)
  */
 int mnt_context_disable_canonicalize(mnt_context *cxt, int disable)
 {
-       return mnt_context_set_flag(cxt, MNT_FL_NOCANONICALIZE, disable);
+       return set_flag(cxt, MNT_FL_NOCANONICALIZE, disable);
 }
 
 /**
@@ -306,7 +217,7 @@ int mnt_context_disable_canonicalize(mnt_context *cxt, int disable)
  */
 int mnt_context_enable_lazy(mnt_context *cxt, int enable)
 {
-       return mnt_context_set_flag(cxt, MNT_FL_LAZY, enable);
+       return set_flag(cxt, MNT_FL_LAZY, enable);
 }
 
 /**
@@ -320,7 +231,7 @@ int mnt_context_enable_lazy(mnt_context *cxt, int enable)
  */
 int mnt_context_disable_helpers(mnt_context *cxt, int disable)
 {
-       return mnt_context_set_flag(cxt, MNT_FL_NOHELPERS, disable);
+       return set_flag(cxt, MNT_FL_NOHELPERS, disable);
 }
 
 /**
@@ -334,7 +245,7 @@ int mnt_context_disable_helpers(mnt_context *cxt, int disable)
  */
 int mnt_context_enable_sloppy(mnt_context *cxt, int enable)
 {
-       return mnt_context_set_flag(cxt, MNT_FL_SLOPPY, enable);
+       return set_flag(cxt, MNT_FL_SLOPPY, enable);
 }
 
 /**
@@ -348,7 +259,7 @@ int mnt_context_enable_sloppy(mnt_context *cxt, int enable)
  */
 int mnt_context_enable_fake(mnt_context *cxt, int enable)
 {
-       return mnt_context_set_flag(cxt, MNT_FL_FAKE, enable);
+       return set_flag(cxt, MNT_FL_FAKE, enable);
 }
 
 /**
@@ -362,7 +273,7 @@ int mnt_context_enable_fake(mnt_context *cxt, int enable)
  */
 int mnt_context_disable_mtab(mnt_context *cxt, int disable)
 {
-       return mnt_context_set_flag(cxt, MNT_FL_NOMTAB, disable);
+       return set_flag(cxt, MNT_FL_NOMTAB, disable);
 }
 
 /**
@@ -376,7 +287,7 @@ int mnt_context_disable_mtab(mnt_context *cxt, int disable)
  */
 int mnt_context_disable_lock(mnt_context *cxt, int disable)
 {
-       return mnt_context_set_flag(cxt, MNT_FL_NOLOCK, disable);
+       return set_flag(cxt, MNT_FL_NOLOCK, disable);
 }
 
 /**
@@ -390,7 +301,7 @@ int mnt_context_disable_lock(mnt_context *cxt, int disable)
  */
 int mnt_context_enable_force(mnt_context *cxt, int enable)
 {
-       return mnt_context_set_flag(cxt, MNT_FL_FORCE, enable);
+       return set_flag(cxt, MNT_FL_FORCE, enable);
 }
 
 /**
@@ -398,13 +309,13 @@ int mnt_context_enable_force(mnt_context *cxt, int enable)
  * @cxt: mount context
  * @enable: TRUE or FALSE
  *
- * Enable/disable verbose output.
+ * Enable/disable verbose output (see also mnt_context_mount_strerror()).
  *
  * Returns: 0 on success, negative number in case of error.
  */
 int mnt_context_enable_verbose(mnt_context *cxt, int enable)
 {
-       return mnt_context_set_flag(cxt, MNT_FL_VERBOSE, enable);
+       return set_flag(cxt, MNT_FL_VERBOSE, enable);
 }
 
 /**
@@ -418,7 +329,7 @@ int mnt_context_enable_verbose(mnt_context *cxt, int enable)
  */
 int mnt_context_enable_loopdel(mnt_context *cxt, int enable)
 {
-       return mnt_context_set_flag(cxt, MNT_FL_LOOPDEL, enable);
+       return set_flag(cxt, MNT_FL_LOOPDEL, enable);
 }
 
 /**
@@ -464,11 +375,22 @@ int mnt_context_set_fs(mnt_context *cxt, mnt_fs *fs)
        if (!(cxt->flags & MNT_FL_EXTERN_FS))
                mnt_free_fs(cxt->fs);
 
-       mnt_context_set_flag(cxt, MNT_FL_EXTERN_FS, fs != NULL);
+       set_flag(cxt, MNT_FL_EXTERN_FS, fs != NULL);
        cxt->fs = fs;
        return 0;
 }
 
+mnt_fs *mnt_context_get_fs(mnt_context *cxt)
+{
+       if (!cxt)
+               return NULL;
+       if (!cxt->fs) {
+               cxt->fs = mnt_new_fs();
+               cxt->flags &= ~MNT_FL_EXTERN_FS;
+       }
+       return cxt->fs;
+}
+
 /**
  * mnt_context_set_source:
  * @cxt: mount context
@@ -606,7 +528,7 @@ int mnt_context_set_fstab(mnt_context *cxt, mnt_tab *tb)
        if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
                mnt_free_tab(cxt->fstab);
 
-       mnt_context_set_flag(cxt, MNT_FL_EXTERN_FSTAB, tb != NULL);
+       set_flag(cxt, MNT_FL_EXTERN_FSTAB, tb != NULL);
        cxt->fstab = tb;
        return 0;
 }
@@ -632,12 +554,20 @@ int mnt_context_set_cache(mnt_context *cxt, mnt_cache *cache)
        if (!(cxt->flags & MNT_FL_EXTERN_CACHE))
                mnt_free_cache(cxt->cache);
 
-       mnt_context_set_flag(cxt, MNT_FL_EXTERN_CACHE, cache != NULL);
+       set_flag(cxt, MNT_FL_EXTERN_CACHE, cache != NULL);
        cxt->cache = cache;
        return 0;
 }
 
-static mnt_cache *mnt_context_get_cache(mnt_context *cxt)
+/**
+ * mnt_context_get_cache
+ * @cxt: mount context
+ *
+ * See also mnt_context_set_cache().
+ *
+ * Returns: pointer to cache or NULL if canonicalization is disabled.
+ */
+mnt_cache *mnt_context_get_cache(mnt_context *cxt)
 {
        if (!cxt || (cxt->flags & MNT_FL_NOCANONICALIZE))
                return NULL;
@@ -651,6 +581,33 @@ static mnt_cache *mnt_context_get_cache(mnt_context *cxt)
        return cxt->cache;
 }
 
+/**
+ * mnt_context_get_lock:
+ * @cxt: mount context
+ *
+ * The lock is available after mnt_context_prepare_mount() or
+ * mnt_context_prepare_umount().
+ *
+ * The application that uses libmount context does not have to care about
+ * mtab locking, but with a small exceptions: the application has to be able to
+ * remove the lock file when interrupted by signal. It means that properly written
+ * mount(8)-like application has to call mnt_unlock_file() from a signal handler.
+ *
+ * See also mnt_unlock_file(), mnt_context_disable_lock() and
+ * mnt_context_disable_mtab().
+ *
+ * It's not error if this function returns NULL (it usually means that the
+ * context is not prepared yet, or mtab update is unnecessary).
+ *
+ * Returns: pointer to lock struct.
+ */
+mnt_lock *mnt_context_get_lock(mnt_context *cxt)
+{
+       if (!cxt || !cxt->update || (cxt->flags & (MNT_FL_NOMTAB | MNT_FL_NOLOCK)))
+               return NULL;
+       return mnt_update_get_lock(cxt->update);
+}
+
 /**
  * mnt_context_set_mountflags:
  * @cxt: mount context
@@ -704,17 +661,6 @@ int mnt_context_get_mountflags(mnt_context *cxt, unsigned long *flags)
        return rc;
 }
 
-static int mnt_context_is_remount(mnt_context *cxt)
-{
-       unsigned long fl = 0;
-
-       if (cxt->mountflags & MS_REMOUNT)
-               return 1;
-       if (!mnt_context_get_mountflags(cxt, &fl) && (fl & MS_REMOUNT))
-               return 1;
-       return 0;
-}
-
 /**
  * mnt_context_set_userspace_mountflags:
  * @cxt: mount context
@@ -759,7 +705,7 @@ int mnt_context_get_userspace_mountflags(mnt_context *cxt, unsigned long *flags)
        return rc;
 }
 
-static int mnt_context_is_loop(mnt_context *cxt)
+static int is_loop(mnt_context *cxt)
 {
        unsigned long fl = 0;
 
@@ -774,7 +720,6 @@ static int mnt_context_is_loop(mnt_context *cxt)
        return 0;
 }
 
-
 /**
  * mnt_context_set_mountdata:
  * @cxt: mount context
@@ -798,322 +743,10 @@ int mnt_context_set_mountdata(mnt_context *cxt, void *data)
        return 0;
 }
 
-static int mnt_context_apply_tab(mnt_context *cxt, mnt_tab *tb)
-{
-       mnt_fs *fs = NULL;
-       const char *src = NULL, *tgt = NULL;
-       int rc;
-
-       if (!cxt->fs)
-               return -EINVAL;
-
-       src = mnt_fs_get_source(cxt->fs);
-       tgt = mnt_fs_get_target(cxt->fs);
-
-       if (tgt && src)
-               ;       /* TODO: search pair for MNT_OPTSMODE_FORCE */
-       else if (src)
-               fs = mnt_tab_find_source(tb, src, MNT_ITER_FORWARD);
-       else if (tgt)
-               fs = mnt_tab_find_target(tb, tgt, MNT_ITER_FORWARD);
-       else if (cxt->spec) {
-               fs = mnt_tab_find_source(tb, cxt->spec, MNT_ITER_FORWARD);
-
-               if (!fs && (strncmp(cxt->spec, "LABEL=", 6) ||
-                           strncmp(cxt->spec, "UUID=", 5)))
-                       fs = mnt_tab_find_target(tb, cxt->spec, MNT_ITER_FORWARD);
-       }
-
-       if (!fs)
-               return -EINVAL;
-
-       DBG(CXT, mnt_debug_h(cxt, "apply entry:"));
-       DBG(CXT, mnt_fs_print_debug(fs, stderr));
-
-       /* copy from fstab to our FS description
-        */
-       rc = mnt_fs_set_source(cxt->fs, mnt_fs_get_source(fs));
-       if (!rc)
-               rc = mnt_fs_set_target(cxt->fs, mnt_fs_get_target(fs));
-
-       if (!rc && !mnt_fs_get_fstype(cxt->fs))
-               rc = mnt_fs_set_fstype(cxt->fs, mnt_fs_get_fstype(fs));
-
-       if (!rc && cxt->optsmode != MNT_OPTSMODE_IGNORE)
-               rc = mnt_fs_prepend_optstr(cxt->fs, mnt_fs_get_optstr(fs));
-
-       if (!rc)
-               cxt->flags |= MNT_FL_FSTAB_APPLIED;
-
-       return rc;
-}
-
-int mnt_context_apply_fstab(mnt_context *cxt)
-{
-       int rc;
-       mnt_cache *cache;
-       const char *src = NULL, *tgt = NULL;
-
-       if (!cxt || (!cxt->spec && !cxt->fs))
-               return -EINVAL;
-
-       if (cxt->flags & MNT_FL_FSTAB_APPLIED)
-               return 0;
-
-       if (cxt->fs) {
-               src = mnt_fs_get_source(cxt->fs);
-               tgt = mnt_fs_get_target(cxt->fs);
-       }
-
-       /* fstab is not required if source and target are specified */
-       if (src && tgt && !(cxt->optsmode == MNT_OPTSMODE_FORCE ||
-                           cxt->optsmode == MNT_OPTSMODE_MTABFORCE))
-               return 0;
-
-       DBG(CXT, mnt_debug_h(cxt,
-               "trying to apply fstab (src=%s, target=%s, spec=%s)",
-               src, tgt, cxt->spec));
-
-       /* initialize fstab */
-       if (!cxt->fstab) {
-               cxt->fstab = mnt_new_tab();
-               if (!cxt->fstab)
-                       goto errnomem;
-               cxt->flags &= ~MNT_FL_EXTERN_FSTAB;
-               rc = mnt_tab_parse_fstab(cxt->fstab);
-               if (rc)
-                       goto err;
-       }
-
-       cache = mnt_context_get_cache(cxt);     /* NULL if MNT_FL_NOCANONICALIZE is enabled */
-
-       /*  never touch an external fstab */
-       if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
-               mnt_tab_set_cache(cxt->fstab, cache);
-
-       /* let's initialize cxt->fs */
-       mnt_context_get_fs(cxt);
-
-       /* try fstab */
-       rc = mnt_context_apply_tab(cxt, cxt->fstab);
-
-       /* try mtab */
-       if (rc || (cxt->optsmode == MNT_OPTSMODE_MTABFORCE &&
-                  mnt_context_is_remount(cxt))) {
-
-               cxt->mtab = mnt_new_tab();
-               if (!cxt->mtab)
-                       goto errnomem;
-               rc = mnt_tab_parse_mtab(cxt->mtab);
-               if (rc)
-                       goto err;
-
-               mnt_tab_set_cache(cxt->mtab, cache);
-               rc = mnt_context_apply_tab(cxt, cxt->mtab);
-               if (rc)
-                       goto err;
-       }
-       return 0;
-
-errnomem:
-       rc = ENOMEM;
-err:
-       DBG(CXT, mnt_debug_h(cxt, "failed to found entry in fstab/mtab"));
-       return rc;
-}
-
-/*
- * this has to be called after mnt_context_evaluate_permissions()
- */
-static int mnt_context_fix_optstr(mnt_context *cxt)
-{
-       int rc = 0, rem_se = 0;
-       char *next, **optstr;
-       char *name, *val;
-       size_t namesz, valsz;
-
-       if (!cxt)
-               return -EINVAL;
-       if (!cxt->fs)
-               return 0;
-
-       assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
-
-       /*
-        * we directly work with optstr pointer here
-        */
-       optstr = &cxt->fs->optstr;
-       if (!optstr)
-               return 0;
-
-       /* The propagation flags should not be used together with any other flags */
-       if (cxt->mountflags & MS_PROPAGATION)
-               cxt->mountflags &= MS_PROPAGATION;
-
-       if (!mnt_optstr_get_option(*optstr, "user", &val, &valsz)) {
-               if (val) {
-                       cxt->orig_user = strndup(val, valsz);
-                       if (!cxt->orig_user) {
-                               rc = -ENOMEM;
-                               goto done;
-                       }
-               }
-               cxt->flags |= MNT_FL_SAVED_USER;
-       }
-
-       /*
-        * Sync mount options with mount flags
-        */
-       rc = mnt_optstr_apply_flags(optstr, cxt->mountflags,
-                               mnt_get_builtin_optmap(MNT_LINUX_MAP));
-       if (rc)
-               goto done;
-
-       rc = mnt_optstr_apply_flags(optstr, cxt->user_mountflags,
-                               mnt_get_builtin_optmap(MNT_USERSPACE_MAP));
-       if (rc)
-               goto done;
-
-       next = *optstr;
-
-#ifdef HAVE_LIBSELINUX
-       rem_se = (cxt->mountflags & MS_REMOUNT) || !is_selinux_enabled();
-#endif
-       DBG(CXT, mnt_debug_h(cxt, "fixing mount options: '%s'", *optstr));
-
-       while (!mnt_optstr_next_option(&next, &name, &namesz, &val, &valsz)) {
-
-               if (namesz == 3 && !strncmp(name, "uid", 3))
-                       rc = mnt_optstr_fix_uid(optstr, val, valsz, &next);
-               else if (namesz == 3 && !strncmp(name, "gid", 3))
-                       rc = mnt_optstr_fix_gid(optstr, val, valsz, &next);
-#ifdef HAVE_LIBSELINUX
-               else if (namesz >= 7 && (!strncmp(name, "context", 7) ||
-                                        !strncmp(name, "fscontext", 9) ||
-                                        !strncmp(name, "defcontext", 10) ||
-                                        !strncmp(name, "rootcontext", 11))) {
-                       if (rem_se) {
-                               /* remove context= option */
-                               next = name;
-                               rc = mnt_optstr_remove_option_at(optstr,
-                                                       name, val + valsz);
-                       } else
-                               rc = mnt_optstr_fix_secontext(optstr,
-                                                       val, valsz, &next);
-               }
-#endif
-               else if (namesz == 4 && (cxt->user_mountflags && MNT_MS_USER) &&
-                        !strncmp(name, "user", 4)) {
-
-                       rc = mnt_optstr_fix_user(optstr,
-                                                val ? val : name + namesz,
-                                                valsz, &next);
-               }
-               if (rc)
-                       goto done;
-       }
-
-done:
-       __mnt_fs_set_optstr_ptr(cxt->fs, *optstr, TRUE);
-       DBG(CXT, mnt_debug_h(cxt, "fixed options [rc=%d]: '%s'", rc, *optstr));
-       return rc;
-}
-
-/*
- * Converts already evalulated and fixed options to the form that is comaptible
- * with /sbin/mount.<type> helpers.
- *
- * Retursn newly allocated string.
- */
-static int mnt_context_get_helper_optstr(mnt_context *cxt, char **optstr)
-{
-       const char *o;
-       int rc = 0;
-
-       assert(cxt);
-       assert(cxt->fs);
-       assert(optstr);
-
-       *optstr = NULL;
-       o = mnt_fs_get_optstr(cxt->fs);
-
-       if (o)
-               rc = mnt_optstr_append_option(optstr, o, NULL);
-       if (!rc && (cxt->flags & MNT_FL_SAVED_USER))
-               rc = mnt_optstr_set_option(optstr, "user", cxt->orig_user);
-       if (rc) {
-               free(*optstr);
-               *optstr = NULL;
-       }
-       return rc;
-}
-
-
 /*
- * this has to be called before mnt_context_fix_optstr()
+ * Translates LABEL/UUID/path to mountable path
  */
-static int mnt_context_evaluate_permissions(mnt_context *cxt)
-{
-       unsigned long u_flags;
-       const char *srcpath;
-
-       if (!cxt)
-               return -EINVAL;
-       if (!cxt->fs)
-               return 0;
-
-       mnt_context_get_userspace_mountflags(cxt, &u_flags);
-
-       if (!mnt_context_is_restricted(cxt)) {
-               /*
-                * superuser mount
-                */
-               cxt->user_mountflags &= ~MNT_MS_OWNER;
-               cxt->user_mountflags &= ~MNT_MS_GROUP;
-               cxt->user_mountflags &= ~MNT_MS_USER;
-               cxt->user_mountflags &= ~MNT_MS_USERS;
-       } else {
-               /*
-                * user mount
-                */
-               if (u_flags & (MNT_MS_OWNER | MNT_MS_GROUP))
-                       cxt->mountflags |= MS_OWNERSECURE;
-
-               if (u_flags & (MNT_MS_USER | MNT_MS_USERS))
-                       cxt->mountflags |= MS_SECURE;
-
-               srcpath = mnt_fs_get_srcpath(cxt->fs);
-               if (!srcpath)
-                       return -EINVAL;
-
-               /*
-                * MS_OWNER: Allow owners to mount when fstab contains the
-                * owner option.  Note that this should never be used in a high
-                * security environment, but may be useful to give people at
-                * the console the possibility of mounting a floppy.  MS_GROUP:
-                * Allow members of device group to mount. (Martin Dickopp)
-                */
-               if (u_flags & (MNT_MS_OWNER | MNT_MS_GROUP)) {
-                       struct stat sb;
-
-                       if (strncmp(srcpath, "/dev/", 5) == 0 &&
-                           stat(srcpath, &sb) == 0 &&
-                           (((u_flags & MNT_MS_OWNER) && getuid() == sb.st_uid) ||
-                            ((u_flags & MNT_MS_GROUP) && mnt_in_group(sb.st_gid))))
-
-                               cxt->user_mountflags |= MNT_MS_USER;
-               }
-
-               if (!(cxt->user_mountflags & (MNT_MS_USER | MNT_MS_USERS))) {
-                       DBG(CXT, mnt_debug_h(cxt, "permissions evaluation ends with -EPERMS"));
-                       return -EPERM;
-               }
-       }
-
-       return 0;
-}
-
-static int mnt_context_prepare_srcpath(mnt_context *cxt)
+int mnt_context_prepare_srcpath(mnt_context *cxt)
 {
        const char *path = NULL, *type;
        mnt_cache *cache;
@@ -1168,7 +801,7 @@ static int mnt_context_prepare_srcpath(mnt_context *cxt)
        /*
         * Initialize loop device
         */
-       if (mnt_context_is_loop(cxt) &&
+       if (is_loop(cxt) &&
            !(cxt->mountflags & (MS_BIND | MS_MOVE |
                                 MS_PROPAGATION | MS_REMOUNT))) {
                ; /* TODO */
@@ -1178,7 +811,7 @@ static int mnt_context_prepare_srcpath(mnt_context *cxt)
        return 0;
 }
 
-static int mnt_context_guess_fstype(mnt_context *cxt)
+int mnt_context_guess_fstype(mnt_context *cxt)
 {
        char *type;
        const char *dev;
@@ -1232,26 +865,6 @@ err:
        return rc;
 }
 
-static int mnt_context_merge_mountflags(mnt_context *cxt)
-{
-       unsigned long fl = 0;
-       int rc;
-
-       rc = mnt_context_get_mountflags(cxt, &fl);
-       if (rc)
-               return rc;
-       cxt->mountflags = fl;
-
-       fl = 0;
-       rc = mnt_context_get_userspace_mountflags(cxt, &fl);
-       if (rc)
-               return rc;
-       cxt->user_mountflags = fl;
-
-       cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED;
-       return 0;
-}
-
 /*
  * The default is to use fstype from cxt->fs, this could be overwritten by
  * @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
@@ -1259,17 +872,15 @@ static int mnt_context_merge_mountflags(mnt_context *cxt)
  * Returns: 0 on success or negative number in case of error. Note that success
  * does not mean that there is any usable helper, you have to check cxt->helper.
  */
-static int mnt_context_prepare_helper(mnt_context *cxt, int act, const char *type)
+int mnt_context_prepare_helper(mnt_context *cxt, const char *name,
+                               const char *type)
 {
        char search_path[] = FS_SEARCH_PATH;            /* from config.h */
        char *p = NULL, *path;
-       const char *name;
 
        assert(cxt);
        assert(cxt->fs);
 
-       name = MNT_ACT_MOUNT ? "mount" : "umount";
-
        if (!type)
                type = mnt_fs_get_fstype(cxt->fs);
 
@@ -1313,7 +924,10 @@ static int mnt_context_prepare_helper(mnt_context *cxt, int act, const char *typ
        return 0;
 }
 
-static int mnt_context_prepare_update(mnt_context *cxt, int act)
+/*
+ * Prepare /etc/mtab or /var/run/mount/mountinfo update
+ */
+int mnt_context_prepare_update(mnt_context *cxt, int act)
 {
        int rc;
 
@@ -1346,377 +960,3 @@ static int mnt_context_prepare_update(mnt_context *cxt, int act)
        return rc;
 }
 
-/**
- * mnt_context_get_lock:
- * @cxt: mount context
- *
- * The lock is available after mnt_context_prepare_mount() or
- * mnt_context_prepare_umount().
- *
- * The application that uses libmount context does not have to care about
- * mtab locking, but with a small exceptions: the application has to be able to
- * remove the lock file when interrupted by signal. It means that properly written
- * mount(8)-like application has to call mnt_unlock_file() from a signal handler.
- *
- * See also mnt_unlock_file(), mnt_context_disable_lock() and
- * mnt_context_disable_mtab().
- *
- * It's not error if this function returns NULL (it usually means that the
- * context is not prepared yet, or mtab update is unnecessary).
- *
- * Returns: pointer to lock struct.
- */
-mnt_lock *mnt_context_get_lock(mnt_context *cxt)
-{
-       if (!cxt || !cxt->update || (cxt->flags & (MNT_FL_NOMTAB | MNT_FL_NOLOCK)))
-               return NULL;
-       return mnt_update_get_lock(cxt->update);
-}
-
-/**
- * mnt_context_prepare_mount:
- * @cxt: mount context
- *
- * This function:
- *     - read information from fstab (if necessary)
- *     - cleanup mount options
- *     - check premissions
- *     - prepare device (e.g. loop device)
- *     - detect FS type (if necessary)
- *     - generate mount flags and mount data (if not set yet)
- *     - prepare for mtab update (if necessary)
- *
- * It's strongly recommended to use this function before mnt_context_mount_fs().
- *
- * Returns: 0 on success, and negative number in case of error.
- */
-int mnt_context_prepare_mount(mnt_context *cxt)
-{
-       int rc = 0;
-
-       if (!cxt)
-               return -EINVAL;
-
-       if (!cxt->spec && !(cxt->fs && (mnt_fs_get_source(cxt->fs) ||
-                                       mnt_fs_get_target(cxt->fs))))
-               return -EINVAL;
-
-       rc = mnt_context_apply_fstab(cxt);
-       if (!rc)
-               rc = mnt_context_merge_mountflags(cxt);
-       if (!rc)
-               rc = mnt_context_evaluate_permissions(cxt);
-       if (!rc)
-               rc = mnt_context_fix_optstr(cxt);
-       if (!rc)
-               rc = mnt_context_prepare_srcpath(cxt);
-       if (!rc)
-               rc = mnt_context_guess_fstype(cxt);
-       if (!rc)
-               rc = mnt_context_prepare_helper(cxt, MNT_ACT_MOUNT, NULL);
-       if (!rc)
-               rc = mnt_context_prepare_update(cxt, MNT_ACT_MOUNT);
-
-       if (!rc) {
-               DBG(CXT, mnt_debug_h(cxt, "sucessfully prepared"));
-               return 0;
-       }
-
-       DBG(CXT, mnt_debug_h(cxt, "prepare failed"));
-       return rc;
-}
-
-static int exec_mount_helper(mnt_context *cxt)
-{
-       char *o = NULL;
-       int rc;
-
-       assert(cxt);
-       assert(cxt->fs);
-       assert(cxt->helper);
-
-       rc = mnt_context_get_helper_optstr(cxt, &o);
-       if (rc)
-               goto done;
-
-       DBG_FLUSH;
-
-       switch (fork()) {
-       case 0:
-       {
-               const char *args[12], *type;
-               int i = 0;
-
-               if (setgid(getgid()) < 0)
-                       exit(EXIT_FAILURE);
-
-               if (setuid(getuid()) < 0)
-                       exit(EXIT_FAILURE);
-
-               type = mnt_fs_get_fstype(cxt->fs);
-
-               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)
-                       args[i++] = "-s";               /* 4 */
-               if (cxt->flags & MNT_FL_FAKE)
-                       args[i++] = "-f";               /* 5 */
-               if (cxt->flags & MNT_FL_NOMTAB)
-                       args[i++] = "-n";               /* 6 */
-               if (cxt->flags & MNT_FL_VERBOSE)
-                       args[i++] = "-v";               /* 7 */
-               if (o) {
-                       args[i++] = "-o";               /* 8 */
-                       args[i++] = o;                  /* 9 */
-               }
-               if (type && !endswith(cxt->helper, type)) {
-                       args[i++] = "-t";               /* 10 */
-                       args[i++] = type;               /* 11 */
-               }
-               args[i] = NULL;                         /* 12 */
-#ifdef CONFIG_LIBMOUNT_DEBUG
-               i = 0;
-               for (i = 0; args[i]; i++)
-                       DBG(CXT, mnt_debug_h(cxt, "argv[%d] = \"%s\"",
-                                                       i, args[i]));
-#endif
-               DBG_FLUSH;
-               execv(cxt->helper, (char * const *) args);
-               exit(EXIT_FAILURE);
-       }
-       default:
-       {
-               int st;
-               wait(&st);
-               cxt->helper_status = WIFEXITED(st) ? WEXITSTATUS(st) : -1;
-
-               DBG(CXT, mnt_debug_h(cxt, "%s executed [status=%d]",
-                                       cxt->helper, cxt->helper_status));
-               rc = 0;
-               break;
-       }
-
-       case -1:
-               rc = -errno;
-               DBG(CXT, mnt_debug_h(cxt, "fork() failed"));
-               break;
-       }
-
-done:
-       free(o);
-       return rc;
-}
-
-/*
- * The default is to use fstype from cxt->fs, this could be overwritten by
- * @try_type argument.
- */
-static int mnt_context_do_mount(mnt_context *cxt, const char *try_type)
-{
-       int rc;
-       const char *src, *target, *type;
-       unsigned long flags;
-
-       assert(cxt);
-       assert(cxt->fs);
-
-       if (try_type && !cxt->helper) {
-               rc = mnt_context_prepare_helper(cxt, MNT_ACT_MOUNT, try_type);
-               if (!rc)
-                       return rc;
-       }
-       if (cxt->helper)
-               return exec_mount_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);
-
-       if (!src || !target)
-               return -EINVAL;
-
-       if (!(flags & MS_MGC_MSK))
-               flags |= MS_MGC_VAL;
-
-       DBG(CXT, mnt_debug_h(cxt, "calling mount(2) "
-                       "[source=%s, target=%s, type=%s, "
-                       " mountflags=%08lx, mountdata=%s]",
-                       src, target, type,
-                       flags, cxt->mountdata ? "yes" : "<none>"));
-
-       if (mount(src, target, type, flags, cxt->mountdata)) {
-               cxt->syscall_errno = errno;
-               DBG(CXT, mnt_debug_h(cxt, "mount(2) failed [errno=%d]",
-                                               cxt->syscall_errno));
-               return -cxt->syscall_errno;
-       }
-
-       DBG(CXT, mnt_debug_h(cxt, "mount(2) success"));
-       return 0;
-}
-
-/**
- * mnt_context_mount_fs:
- * @cxt: mount context
- *
- * Mount filesystem by mount(2) or fork()+exec(/sbin/mount.<type>).
- *
- * See also mnt_context_disable_helpers().
- *
- * Returns: 0 on success, and negative number in case of error.
- */
-int mnt_context_mount_fs(mnt_context *cxt)
-{
-       int rc = -EINVAL;
-       const char *type;
-
-       if (!cxt || !cxt->fs || (cxt->fs->flags & MNT_FS_SWAP))
-               return -EINVAL;
-
-       if (!(cxt->flags & MNT_FL_MOUNTDATA))
-               cxt->mountdata = (char *) mnt_fs_get_fs_optstr(cxt->fs);
-
-       type = mnt_fs_get_fstype(cxt->fs);
-
-       if (type && !strchr(type, ',')) {
-               rc = mnt_context_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 */
-
-       return rc;
-}
-
-/**
- * mnt_context_post_mount:
- * @cxt: mount context
- *
- * Updates mtab, etc. This function should be always called after
- * mnt_context_do_mount().
- *
- * Returns: 0 on success, and negative number in case of error.
- */
-int mnt_context_post_mount(mnt_context *cxt)
-{
-       int rc = 0;
-
-       if (!cxt)
-               return -EINVAL;
-       /*
-        * Update /etc/mtab or /var/run/mount/mountinfo
-        */
-       if (!cxt->syscall_errno && !cxt->helper &&
-           !(cxt->flags & MNT_FL_NOMTAB) &&
-           cxt->update && !mnt_update_is_pointless(cxt->update)) {
-
-               /* TODO: if mtab update is expected then checkif the target is really
-                *       mounted read-write to avoid 'ro' in mtab and 'rw' in /proc/mounts.
-                */
-               rc = mnt_update_file(cxt->update);
-       }
-
-       return rc;
-}
-
-/**
- * mnt_context_get_mount_error:
- * @cxt: mount context
- * @buf: buffer for error message
- * @bufsiz: size of buffer
- *
- * Generates human readable error message for failed mnt_context_mount_fs().
- *
- * Returns: 0 on success, and negative number in case of error.
- */
-int mnt_context_get_mount_error(mnt_context *cxt, char *buf, size_t bufsiz)
-{
-       /* TODO: based on cxt->syscall_errno or cxt->helper_status */
-       return 0;
-}
-
-#ifdef TEST_PROGRAM
-
-mnt_lock *lock;
-
-static void lock_fallback(void)
-{
-       if (lock) {
-               mnt_unlock_file(lock);
-               mnt_free_lock(lock);
-       }
-}
-
-int test_mount(struct mtest *ts, int argc, char *argv[])
-{
-       int idx = 1, rc = 0;
-       mnt_context *cxt;
-
-       if (argc < 2)
-               return -EINVAL;
-
-       cxt = mnt_new_context();
-       if (!cxt)
-               return -ENOMEM;
-
-       if (!strcmp(argv[idx], "-o")) {
-               mnt_context_set_optstr(cxt, argv[idx + 1]);
-               idx += 2;
-       }
-       if (!strcmp(argv[idx], "-t")) {
-               /* TODO: use mnt_context_set_fstype_pattern() */
-               mnt_context_set_fstype(cxt, argv[idx + 1]);
-               idx += 2;
-       }
-
-       if (argc == idx + 1)
-               /* mount <spec> */
-               mnt_context_set_spec(cxt, argv[idx++]);
-
-       else if (argc == idx + 2) {
-               /* mount <device> <mountpoint> */
-               mnt_context_set_source(cxt, argv[idx++]);
-               mnt_context_set_target(cxt, argv[idx++]);
-       }
-
-       rc = mnt_context_prepare_mount(cxt);
-       if (rc)
-               printf("failed to prepare mount\n");
-       else {
-               lock = mnt_context_get_lock(cxt);
-               if (lock)
-                       atexit(lock_fallback);
-
-               rc = mnt_context_mount_fs(cxt);
-               if (rc)
-                       printf("failed to mount\n");
-               else {
-                       printf("successfully mounted");
-                       rc = mnt_context_post_mount(cxt);
-                       if (rc)
-                               printf("mtab update failed\n");
-               }
-       }
-
-       mnt_free_context(cxt);
-       return rc;
-}
-
-int main(int argc, char *argv[])
-{
-       struct mtest tss[] = {
-       { "--mount",    test_mount,        "[-o <opts>] [-t <type>] <spec> | <src> <target>" },
-       { NULL }
-       };
-
-       return mnt_run_test(tss, argc, argv);
-}
-
-#endif /* TEST_PROGRAM */
diff --git a/shlibs/mount/src/context_mount.c b/shlibs/mount/src/context_mount.c
new file mode 100644 (file)
index 0000000..d5f361a
--- /dev/null
@@ -0,0 +1,716 @@
+/*
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#endif
+
+#include <sys/wait.h>
+#include <sys/mount.h>
+
+#include "c.h"
+#include "mountP.h"
+
+static int is_remount(mnt_context *cxt)
+{
+       unsigned long fl = 0;
+
+       if (cxt->mountflags & MS_REMOUNT)
+               return 1;
+       if (!mnt_context_get_mountflags(cxt, &fl) && (fl & MS_REMOUNT))
+               return 1;
+       return 0;
+}
+
+static int apply_tab(mnt_context *cxt, mnt_tab *tb)
+{
+       mnt_fs *fs = NULL;
+       const char *src = NULL, *tgt = NULL;
+       int rc;
+
+       if (!cxt->fs)
+               return -EINVAL;
+
+       src = mnt_fs_get_source(cxt->fs);
+       tgt = mnt_fs_get_target(cxt->fs);
+
+       if (tgt && src)
+               ;       /* TODO: search pair for MNT_OPTSMODE_FORCE */
+       else if (src)
+               fs = mnt_tab_find_source(tb, src, MNT_ITER_FORWARD);
+       else if (tgt)
+               fs = mnt_tab_find_target(tb, tgt, MNT_ITER_FORWARD);
+       else if (cxt->spec) {
+               fs = mnt_tab_find_source(tb, cxt->spec, MNT_ITER_FORWARD);
+
+               if (!fs && (strncmp(cxt->spec, "LABEL=", 6) ||
+                           strncmp(cxt->spec, "UUID=", 5)))
+                       fs = mnt_tab_find_target(tb, cxt->spec, MNT_ITER_FORWARD);
+       }
+
+       if (!fs)
+               return -EINVAL;
+
+       DBG(CXT, mnt_debug_h(cxt, "apply entry:"));
+       DBG(CXT, mnt_fs_print_debug(fs, stderr));
+
+       /* copy from fstab to our FS description
+        */
+       rc = mnt_fs_set_source(cxt->fs, mnt_fs_get_source(fs));
+       if (!rc)
+               rc = mnt_fs_set_target(cxt->fs, mnt_fs_get_target(fs));
+
+       if (!rc && !mnt_fs_get_fstype(cxt->fs))
+               rc = mnt_fs_set_fstype(cxt->fs, mnt_fs_get_fstype(fs));
+
+       if (!rc && cxt->optsmode != MNT_OPTSMODE_IGNORE)
+               rc = mnt_fs_prepend_optstr(cxt->fs, mnt_fs_get_optstr(fs));
+
+       if (!rc)
+               cxt->flags |= MNT_FL_FSTAB_APPLIED;
+
+       return rc;
+}
+
+static int apply_fstab(mnt_context *cxt)
+{
+       int rc;
+       mnt_cache *cache;
+       const char *src = NULL, *tgt = NULL;
+
+       if (!cxt || (!cxt->spec && !cxt->fs))
+               return -EINVAL;
+
+       if (cxt->flags & MNT_FL_FSTAB_APPLIED)
+               return 0;
+
+       if (cxt->fs) {
+               src = mnt_fs_get_source(cxt->fs);
+               tgt = mnt_fs_get_target(cxt->fs);
+       }
+
+       /* fstab is not required if source and target are specified */
+       if (src && tgt && !(cxt->optsmode == MNT_OPTSMODE_FORCE ||
+                           cxt->optsmode == MNT_OPTSMODE_MTABFORCE))
+               return 0;
+
+       DBG(CXT, mnt_debug_h(cxt,
+               "trying to apply fstab (src=%s, target=%s, spec=%s)",
+               src, tgt, cxt->spec));
+
+       /* initialize fstab */
+       if (!cxt->fstab) {
+               cxt->fstab = mnt_new_tab();
+               if (!cxt->fstab)
+                       goto errnomem;
+               cxt->flags &= ~MNT_FL_EXTERN_FSTAB;
+               rc = mnt_tab_parse_fstab(cxt->fstab);
+               if (rc)
+                       goto err;
+       }
+
+       cache = mnt_context_get_cache(cxt);     /* NULL if MNT_FL_NOCANONICALIZE is enabled */
+
+       /*  never touch an external fstab */
+       if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
+               mnt_tab_set_cache(cxt->fstab, cache);
+
+       /* let's initialize cxt->fs */
+       mnt_context_get_fs(cxt);
+
+       /* try fstab */
+       rc = apply_tab(cxt, cxt->fstab);
+
+       /* try mtab */
+       if (rc || (cxt->optsmode == MNT_OPTSMODE_MTABFORCE && is_remount(cxt))) {
+
+               cxt->mtab = mnt_new_tab();
+               if (!cxt->mtab)
+                       goto errnomem;
+               rc = mnt_tab_parse_mtab(cxt->mtab);
+               if (rc)
+                       goto err;
+
+               mnt_tab_set_cache(cxt->mtab, cache);
+               rc = apply_tab(cxt, cxt->mtab);
+               if (rc)
+                       goto err;
+       }
+       return 0;
+
+errnomem:
+       rc = ENOMEM;
+err:
+       DBG(CXT, mnt_debug_h(cxt, "failed to found entry in fstab/mtab"));
+       return rc;
+}
+
+/*
+ * this has to be called after mnt_context_evaluate_permissions()
+ */
+static int fix_optstr(mnt_context *cxt)
+{
+       int rc = 0, rem_se = 0;
+       char *next, **optstr;
+       char *name, *val;
+       size_t namesz, valsz;
+
+       if (!cxt)
+               return -EINVAL;
+       if (!cxt->fs)
+               return 0;
+
+       assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
+
+       /*
+        * we directly work with optstr pointer here
+        */
+       optstr = &cxt->fs->optstr;
+       if (!optstr)
+               return 0;
+
+       /* The propagation flags should not be used together with any other flags */
+       if (cxt->mountflags & MS_PROPAGATION)
+               cxt->mountflags &= MS_PROPAGATION;
+
+       if (!mnt_optstr_get_option(*optstr, "user", &val, &valsz)) {
+               if (val) {
+                       cxt->orig_user = strndup(val, valsz);
+                       if (!cxt->orig_user) {
+                               rc = -ENOMEM;
+                               goto done;
+                       }
+               }
+               cxt->flags |= MNT_FL_SAVED_USER;
+       }
+
+       /*
+        * Sync mount options with mount flags
+        */
+       rc = mnt_optstr_apply_flags(optstr, cxt->mountflags,
+                               mnt_get_builtin_optmap(MNT_LINUX_MAP));
+       if (rc)
+               goto done;
+
+       rc = mnt_optstr_apply_flags(optstr, cxt->user_mountflags,
+                               mnt_get_builtin_optmap(MNT_USERSPACE_MAP));
+       if (rc)
+               goto done;
+
+       next = *optstr;
+
+#ifdef HAVE_LIBSELINUX
+       rem_se = (cxt->mountflags & MS_REMOUNT) || !is_selinux_enabled();
+#endif
+       DBG(CXT, mnt_debug_h(cxt, "fixing mount options: '%s'", *optstr));
+
+       while (!mnt_optstr_next_option(&next, &name, &namesz, &val, &valsz)) {
+
+               if (namesz == 3 && !strncmp(name, "uid", 3))
+                       rc = mnt_optstr_fix_uid(optstr, val, valsz, &next);
+               else if (namesz == 3 && !strncmp(name, "gid", 3))
+                       rc = mnt_optstr_fix_gid(optstr, val, valsz, &next);
+#ifdef HAVE_LIBSELINUX
+               else if (namesz >= 7 && (!strncmp(name, "context", 7) ||
+                                        !strncmp(name, "fscontext", 9) ||
+                                        !strncmp(name, "defcontext", 10) ||
+                                        !strncmp(name, "rootcontext", 11))) {
+                       if (rem_se) {
+                               /* remove context= option */
+                               next = name;
+                               rc = mnt_optstr_remove_option_at(optstr,
+                                                       name, val + valsz);
+                       } else
+                               rc = mnt_optstr_fix_secontext(optstr,
+                                                       val, valsz, &next);
+               }
+#endif
+               else if (namesz == 4 && (cxt->user_mountflags && MNT_MS_USER) &&
+                        !strncmp(name, "user", 4)) {
+
+                       rc = mnt_optstr_fix_user(optstr,
+                                                val ? val : name + namesz,
+                                                valsz, &next);
+               }
+               if (rc)
+                       goto done;
+       }
+
+done:
+       __mnt_fs_set_optstr_ptr(cxt->fs, *optstr, TRUE);
+       DBG(CXT, mnt_debug_h(cxt, "fixed options [rc=%d]: '%s'", rc, *optstr));
+       return rc;
+}
+
+/*
+ * Converts already evalulated and fixed options to the form that is comaptible
+ * with /sbin/mount.<type> helpers.
+ *
+ * Retursn newly allocated string.
+ */
+static int generate_helper_optstr(mnt_context *cxt, char **optstr)
+{
+       const char *o;
+       int rc = 0;
+
+       assert(cxt);
+       assert(cxt->fs);
+       assert(optstr);
+
+       *optstr = NULL;
+       o = mnt_fs_get_optstr(cxt->fs);
+
+       if (o)
+               rc = mnt_optstr_append_option(optstr, o, NULL);
+       if (!rc && (cxt->flags & MNT_FL_SAVED_USER))
+               rc = mnt_optstr_set_option(optstr, "user", cxt->orig_user);
+       if (rc) {
+               free(*optstr);
+               *optstr = NULL;
+       }
+       return rc;
+}
+
+
+/*
+ * this has to be called before mnt_context_fix_optstr()
+ */
+static int evaluate_permissions(mnt_context *cxt)
+{
+       unsigned long u_flags;
+       const char *srcpath;
+
+       if (!cxt)
+               return -EINVAL;
+       if (!cxt->fs)
+               return 0;
+
+       mnt_context_get_userspace_mountflags(cxt, &u_flags);
+
+       if (!mnt_context_is_restricted(cxt)) {
+               /*
+                * superuser mount
+                */
+               cxt->user_mountflags &= ~MNT_MS_OWNER;
+               cxt->user_mountflags &= ~MNT_MS_GROUP;
+               cxt->user_mountflags &= ~MNT_MS_USER;
+               cxt->user_mountflags &= ~MNT_MS_USERS;
+       } else {
+               /*
+                * user mount
+                */
+               if (u_flags & (MNT_MS_OWNER | MNT_MS_GROUP))
+                       cxt->mountflags |= MS_OWNERSECURE;
+
+               if (u_flags & (MNT_MS_USER | MNT_MS_USERS))
+                       cxt->mountflags |= MS_SECURE;
+
+               srcpath = mnt_fs_get_srcpath(cxt->fs);
+               if (!srcpath)
+                       return -EINVAL;
+
+               /*
+                * MS_OWNER: Allow owners to mount when fstab contains the
+                * owner option.  Note that this should never be used in a high
+                * security environment, but may be useful to give people at
+                * the console the possibility of mounting a floppy.  MS_GROUP:
+                * Allow members of device group to mount. (Martin Dickopp)
+                */
+               if (u_flags & (MNT_MS_OWNER | MNT_MS_GROUP)) {
+                       struct stat sb;
+
+                       if (strncmp(srcpath, "/dev/", 5) == 0 &&
+                           stat(srcpath, &sb) == 0 &&
+                           (((u_flags & MNT_MS_OWNER) && getuid() == sb.st_uid) ||
+                            ((u_flags & MNT_MS_GROUP) && mnt_in_group(sb.st_gid))))
+
+                               cxt->user_mountflags |= MNT_MS_USER;
+               }
+
+               if (!(cxt->user_mountflags & (MNT_MS_USER | MNT_MS_USERS))) {
+                       DBG(CXT, mnt_debug_h(cxt, "permissions evaluation ends with -EPERMS"));
+                       return -EPERM;
+               }
+       }
+
+       return 0;
+}
+
+static int merge_mountflags(mnt_context *cxt)
+{
+       unsigned long fl = 0;
+       int rc;
+
+       rc = mnt_context_get_mountflags(cxt, &fl);
+       if (rc)
+               return rc;
+       cxt->mountflags = fl;
+
+       fl = 0;
+       rc = mnt_context_get_userspace_mountflags(cxt, &fl);
+       if (rc)
+               return rc;
+       cxt->user_mountflags = fl;
+
+       cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED;
+       return 0;
+}
+
+static int exec_helper(mnt_context *cxt)
+{
+       char *o = NULL;
+       int rc;
+
+       assert(cxt);
+       assert(cxt->fs);
+       assert(cxt->helper);
+
+       rc = generate_helper_optstr(cxt, &o);
+       if (rc)
+               goto done;
+
+       DBG_FLUSH;
+
+       switch (fork()) {
+       case 0:
+       {
+               const char *args[12], *type;
+               int i = 0;
+
+               if (setgid(getgid()) < 0)
+                       exit(EXIT_FAILURE);
+
+               if (setuid(getuid()) < 0)
+                       exit(EXIT_FAILURE);
+
+               type = mnt_fs_get_fstype(cxt->fs);
+
+               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)
+                       args[i++] = "-s";               /* 4 */
+               if (cxt->flags & MNT_FL_FAKE)
+                       args[i++] = "-f";               /* 5 */
+               if (cxt->flags & MNT_FL_NOMTAB)
+                       args[i++] = "-n";               /* 6 */
+               if (cxt->flags & MNT_FL_VERBOSE)
+                       args[i++] = "-v";               /* 7 */
+               if (o) {
+                       args[i++] = "-o";               /* 8 */
+                       args[i++] = o;                  /* 9 */
+               }
+               if (type && !endswith(cxt->helper, type)) {
+                       args[i++] = "-t";               /* 10 */
+                       args[i++] = type;               /* 11 */
+               }
+               args[i] = NULL;                         /* 12 */
+#ifdef CONFIG_LIBMOUNT_DEBUG
+               i = 0;
+               for (i = 0; args[i]; i++)
+                       DBG(CXT, mnt_debug_h(cxt, "argv[%d] = \"%s\"",
+                                                       i, args[i]));
+#endif
+               DBG_FLUSH;
+               execv(cxt->helper, (char * const *) args);
+               exit(EXIT_FAILURE);
+       }
+       default:
+       {
+               int st;
+               wait(&st);
+               cxt->helper_status = WIFEXITED(st) ? WEXITSTATUS(st) : -1;
+
+               DBG(CXT, mnt_debug_h(cxt, "%s executed [status=%d]",
+                                       cxt->helper, cxt->helper_status));
+               rc = 0;
+               break;
+       }
+
+       case -1:
+               rc = -errno;
+               DBG(CXT, mnt_debug_h(cxt, "fork() failed"));
+               break;
+       }
+
+done:
+       free(o);
+       return rc;
+}
+
+/*
+ * The default is to use fstype from cxt->fs, this could be overwritten by
+ * @try_type argument.
+ */
+static int do_mount(mnt_context *cxt, const char *try_type)
+{
+       int rc;
+       const char *src, *target, *type;
+       unsigned long flags;
+
+       assert(cxt);
+       assert(cxt->fs);
+
+       if (try_type && !cxt->helper) {
+               rc = mnt_context_prepare_helper(cxt, "mount", try_type);
+               if (!rc)
+                       return rc;
+       }
+       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);
+
+       if (!src || !target)
+               return -EINVAL;
+
+       if (!(flags & MS_MGC_MSK))
+               flags |= MS_MGC_VAL;
+
+       DBG(CXT, mnt_debug_h(cxt, "calling mount(2) "
+                       "[source=%s, target=%s, type=%s, "
+                       " mountflags=%08lx, mountdata=%s]",
+                       src, target, type,
+                       flags, cxt->mountdata ? "yes" : "<none>"));
+
+       if (mount(src, target, type, flags, cxt->mountdata)) {
+               cxt->syscall_errno = errno;
+               DBG(CXT, mnt_debug_h(cxt, "mount(2) failed [errno=%d]",
+                                               cxt->syscall_errno));
+               return -cxt->syscall_errno;
+       }
+
+       DBG(CXT, mnt_debug_h(cxt, "mount(2) success"));
+       return 0;
+}
+
+/**
+ * mnt_context_prepare_mount:
+ * @cxt: mount context
+ *
+ * This function:
+ *     - read information from fstab (if necessary)
+ *     - cleanup mount options
+ *     - check premissions
+ *     - prepare device (e.g. loop device)
+ *     - detect FS type (if necessary)
+ *     - generate mount flags and mount data (if not set yet)
+ *     - prepare for mtab update (if necessary)
+ *
+ * It's strongly recommended to use this function before mnt_context_mount_fs().
+ *
+ * Returns: 0 on success, and negative number in case of error.
+ */
+int mnt_context_prepare_mount(mnt_context *cxt)
+{
+       int rc = 0;
+
+       if (!cxt)
+               return -EINVAL;
+
+       if (!cxt->spec && !(cxt->fs && (mnt_fs_get_source(cxt->fs) ||
+                                       mnt_fs_get_target(cxt->fs))))
+               return -EINVAL;
+
+       rc = apply_fstab(cxt);
+       if (!rc)
+               rc = merge_mountflags(cxt);
+       if (!rc)
+               rc = evaluate_permissions(cxt);
+       if (!rc)
+               rc = fix_optstr(cxt);
+       if (!rc)
+               rc = mnt_context_prepare_srcpath(cxt);
+       if (!rc)
+               rc = mnt_context_guess_fstype(cxt);
+       if (!rc)
+               rc = mnt_context_prepare_helper(cxt, "mount", NULL);
+       if (!rc)
+               rc = mnt_context_prepare_update(cxt, MNT_ACT_MOUNT);
+
+       if (!rc) {
+               DBG(CXT, mnt_debug_h(cxt, "sucessfully prepared"));
+               return 0;
+       }
+
+       DBG(CXT, mnt_debug_h(cxt, "prepare failed"));
+       return rc;
+}
+
+/**
+ * mnt_context_do_mount:
+ * @cxt: mount context
+ *
+ * Mount filesystem by mount(2) or fork()+exec(/sbin/mount.<type>).
+ *
+ * See also mnt_context_disable_helpers().
+ *
+ * Returns: 0 on success, and negative number in case of error.
+ */
+int mnt_context_do_mount(mnt_context *cxt)
+{
+       int rc = -EINVAL;
+       const char *type;
+
+       if (!cxt || !cxt->fs || (cxt->fs->flags & MNT_FS_SWAP))
+               return -EINVAL;
+
+       if (!(cxt->flags & MNT_FL_MOUNTDATA))
+               cxt->mountdata = (char *) mnt_fs_get_fs_optstr(cxt->fs);
+
+       type = mnt_fs_get_fstype(cxt->fs);
+
+       if (type && !strchr(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 */
+
+       return rc;
+}
+
+/**
+ * mnt_context_post_mount:
+ * @cxt: mount context
+ *
+ * Updates mtab, etc. This function should be always called after
+ * mnt_context_do_mount().
+ *
+ * Returns: 0 on success, and negative number in case of error.
+ */
+int mnt_context_post_mount(mnt_context *cxt)
+{
+       int rc = 0;
+
+       if (!cxt)
+               return -EINVAL;
+       /*
+        * Update /etc/mtab or /var/run/mount/mountinfo
+        */
+       if (!cxt->syscall_errno && !cxt->helper &&
+           !(cxt->flags & MNT_FL_NOMTAB) &&
+           cxt->update && !mnt_update_is_pointless(cxt->update)) {
+
+               /* TODO: if mtab update is expected then checkif the target is really
+                *       mounted read-write to avoid 'ro' in mtab and 'rw' in /proc/mounts.
+                */
+               rc = mnt_update_file(cxt->update);
+       }
+
+       return rc;
+}
+
+/**
+ * mnt_context_mount_strerror
+ * @cxt: mount context
+ * @buf: buffer
+ * @bufsiz: size of the buffer
+ *
+ * Returns: 0 or negative number in case of error.
+ */
+int mnt_context_mount_strerror(mnt_context *cxt, char *buf, size_t bufsiz)
+{
+       /* TODO: based on cxt->syscall_errno or cxt->helper_status */
+       return 0;
+}
+
+#ifdef TEST_PROGRAM
+
+mnt_lock *lock;
+
+static void lock_fallback(void)
+{
+       if (lock) {
+               mnt_unlock_file(lock);
+               mnt_free_lock(lock);
+       }
+}
+
+int test_mount(struct mtest *ts, int argc, char *argv[])
+{
+       int idx = 1, rc = 0;
+       mnt_context *cxt;
+
+       if (argc < 2)
+               return -EINVAL;
+
+       cxt = mnt_new_context();
+       if (!cxt)
+               return -ENOMEM;
+
+       if (!strcmp(argv[idx], "-o")) {
+               mnt_context_set_optstr(cxt, argv[idx + 1]);
+               idx += 2;
+       }
+       if (!strcmp(argv[idx], "-t")) {
+               /* TODO: use mnt_context_set_fstype_pattern() */
+               mnt_context_set_fstype(cxt, argv[idx + 1]);
+               idx += 2;
+       }
+
+       if (argc == idx + 1)
+               /* mount <spec> */
+               mnt_context_set_spec(cxt, argv[idx++]);
+
+       else if (argc == idx + 2) {
+               /* mount <device> <mountpoint> */
+               mnt_context_set_source(cxt, argv[idx++]);
+               mnt_context_set_target(cxt, argv[idx++]);
+       }
+
+       rc = mnt_context_prepare_mount(cxt);
+       if (rc)
+               printf("failed to prepare mount\n");
+       else {
+               lock = mnt_context_get_lock(cxt);
+               if (lock)
+                       atexit(lock_fallback);
+
+               rc = mnt_context_do_mount(cxt);
+               if (rc)
+                       printf("failed to mount\n");
+               else {
+                       printf("successfully mounted");
+                       rc = mnt_context_post_mount(cxt);
+                       if (rc)
+                               printf("mtab update failed\n");
+               }
+       }
+
+       mnt_free_context(cxt);
+       return rc;
+}
+
+int main(int argc, char *argv[])
+{
+       struct mtest tss[] = {
+       { "--mount",    test_mount,        "[-o <opts>] [-t <type>] <spec> | <src> <target>" },
+       { NULL }
+       };
+
+       return mnt_run_test(tss, argc, argv);
+}
+
+#endif /* TEST_PROGRAM */
index 12f4b34cb332a83b9f0b765bacdba22bfd54de76..99969727410eabe18c432de9e29b157a1ed1cfd6 100644 (file)
@@ -299,6 +299,55 @@ extern int mnt_prepare_update(mnt_update *upd);
 extern int mnt_update_file(mnt_update *upd);
 extern int mnt_update_is_pointless(mnt_update *upd);
 
+/* context.c */
+
+/* mode for mount options from fstab */
+enum {
+       MNT_OPTSMODE_AUTO = 0,          /* use options if source or target are not defined */
+       MNT_OPTSMODE_IGNORE,            /* never use mount options from fstab */
+       MNT_OPTSMODE_FORCE,             /* always use mount options from fstab */
+       MNT_OPTSMODE_MTABFORCE,         /* for MS_REMOUNT use always options from mountinfo/mtab */
+};
+
+mnt_context *mnt_new_context(void);
+void mnt_free_context(mnt_context *cxt);
+int mnt_reset_context(mnt_context *cxt);
+int mnt_context_is_restricted(mnt_context *cxt);
+int mnt_context_set_optsmode(mnt_context *cxt, int mode);
+int mnt_context_disable_canonicalize(mnt_context *cxt, int disable);
+int mnt_context_enable_lazy(mnt_context *cxt, int enable);
+int mnt_context_disable_helpers(mnt_context *cxt, int disable);
+int mnt_context_enable_sloppy(mnt_context *cxt, int enable);
+int mnt_context_enable_fake(mnt_context *cxt, int enable);
+int mnt_context_disable_mtab(mnt_context *cxt, int disable);
+int mnt_context_disable_lock(mnt_context *cxt, int disable);
+int mnt_context_enable_force(mnt_context *cxt, int enable);
+int mnt_context_enable_verbose(mnt_context *cxt, int enable);
+int mnt_context_enable_loopdel(mnt_context *cxt, int enable);
+int mnt_context_set_fs(mnt_context *cxt, mnt_fs *fs);
+int mnt_context_set_source(mnt_context *cxt, const char *source);
+int mnt_context_set_target(mnt_context *cxt, const char *target);
+int mnt_context_set_fstype(mnt_context *cxt, const char *fstype);
+int mnt_context_set_optstr(mnt_context *cxt, const char *optstr);
+int mnt_context_append_optstr(mnt_context *cxt, const char *optstr);
+int mnt_context_set_fstype_pattern(mnt_context *cxt, const char *pattern);
+int mnt_context_set_optstr_pattern(mnt_context *cxt, const char *pattern);
+int mnt_context_set_fstab(mnt_context *cxt, mnt_tab *tb);
+int mnt_context_set_cache(mnt_context *cxt, mnt_cache *cache);
+mnt_cache *mnt_context_get_cache(mnt_context *cxt);
+mnt_lock *mnt_context_get_lock(mnt_context *cxt);
+int mnt_context_set_mountflags(mnt_context *cxt, unsigned long flags);
+int mnt_context_get_mountflags(mnt_context *cxt, unsigned long *flags);
+int mnt_context_set_userspace_mountflags(mnt_context *cxt, unsigned long flags);
+int mnt_context_get_userspace_mountflags(mnt_context *cxt, unsigned long *flags);
+int mnt_context_set_mountdata(mnt_context *cxt, void *data);
+
+
+
+
+
+
+
 /*
  * mount(8) userspace options masks (MNT_MAP_USERSPACE map)
  */
index 468e77a09538765171b11ada166af20e3f80756f..51230c67b170762b7ea0264cd545dc23292ea763 100644 (file)
@@ -202,6 +202,68 @@ struct _mnt_tab {
 };
 
 
+/*
+ * Mount context -- high-level API
+ */
+struct _mnt_context
+{
+       int     action;         /* MNT_ACT_{MOUNT,UMOUNT} */
+
+       int     restricted;     /* root or not? */
+
+       char    *fstype_pattern;        /* for mnt_match_fstype() */
+       char    *optstr_pattern;        /* for mnt_match_options() */
+
+       char    *spec;          /* unresolved source OR target */
+       mnt_fs  *fs;            /* filesystem description (type, mountpopint, device, ...) */
+
+       mnt_tab *fstab;         /* fstab (or mtab for some remounts) entires */
+       mnt_tab *mtab;          /* mtab entries */
+       int     optsmode;       /* fstab optstr mode MNT_OPTSMODE_{AUTO,FORCE,IGNORE} */
+
+       unsigned long   mountflags;     /* final mount(2) flags */
+       const void      *mountdata;     /* final mount(2) data, string or binary data */
+
+       unsigned long   user_mountflags;        /* MNT_MS_* (loop=, user=, ...) */
+
+       mnt_update      *update;        /* mtab update */
+       mnt_cache       *cache;         /* paths cache */
+
+       int     flags;          /* private context flags */
+       int     ambi;           /* libblkid returns ambivalent result */
+
+       char    *helper;        /* name of the used /sbin/[u]mount.<type> helper */
+       int     helper_status;  /* helper wait(2) status */
+
+       char    *orig_user;     /* original (non-fixed) user= option */
+
+       int     syscall_errno;  /* mount(2) or umount(2) error */
+};
+
+/* flags */
+#define MNT_FL_NOMTAB          (1 << 1)
+#define MNT_FL_FAKE            (1 << 2)
+#define MNT_FL_SLOPPY          (1 << 3)
+#define MNT_FL_VERBOSE         (1 << 4)
+#define MNT_FL_NOHELPERS       (1 << 5)
+#define MNT_FL_LOOPDEL         (1 << 6)
+#define MNT_FL_LAZY            (1 << 7)
+#define MNT_FL_FORCE           (1 << 8)
+#define MNT_FL_NOCANONICALIZE  (1 << 9)
+#define MNT_FL_NOLOCK          (1 << 10)       /* don't lock mtab file */
+
+#define MNT_FL_EXTERN_FS       (1 << 15)       /* cxt->fs is not private */
+#define MNT_FL_EXTERN_FSTAB    (1 << 16)       /* cxt->fstab is not private */
+#define MNT_FL_EXTERN_CACHE    (1 << 17)       /* cxt->cache is not private */
+
+#define MNT_FL_MOUNTDATA       (1 << 20)
+#define MNT_FL_FSTAB_APPLIED   (1 << 21)
+#define MNT_FL_MOUNTFLAGS_MERGED (1 << 22)     /* MS_* flags was read from optstr */
+#define MNT_FL_SAVED_USER      (1 << 23)
+
+/* default flags */
+#define MNT_FL_DEFAULT         0
+
 /* optmap.c */
 extern const struct mnt_optmap *mnt_optmap_get_entry(struct mnt_optmap const **maps,
                              int nmaps, const char *name,
@@ -220,4 +282,11 @@ extern int __mnt_fs_set_fstype_ptr(mnt_fs *fs, char *fstype);
 extern int __mnt_fs_set_optstr_ptr(mnt_fs *fs, char *optstr, int split);
 extern int __mnt_fs_set_optstr(mnt_fs *fs, const char *optstr, int split);
 
+/* context.c */
+extern int mnt_context_prepare_srcpath(mnt_context *cxt);
+extern int mnt_context_guess_fstype(mnt_context *cxt);
+extern int mnt_context_prepare_helper(mnt_context *cxt, const char *name, const char *type);
+extern int mnt_context_prepare_update(mnt_context *cxt, int act);
+extern mnt_fs *mnt_context_get_fs(mnt_context *cxt);
+
 #endif /* _LIBMOUNT_PRIVATE_H */