*/
#include "mountP.h"
+#include "fileutils.h"
#include <sys/wait.h>
if (!cxt)
return NULL;
+ INIT_LIST_HEAD(&cxt->addmounts);
+
ruid = getuid();
euid = geteuid();
/* if we're really root and aren't running setuid */
cxt->restricted = (uid_t) 0 == ruid && ruid == euid ? 0 : 1;
- DBG(CXT, mnt_debug_h(cxt, "----> allocate %s",
+ DBG(CXT, ul_debugobj(cxt, "----> allocate %s",
cxt->restricted ? "[RESTRICTED]" : ""));
- mnt_has_regular_mtab(&cxt->mtab_path, &cxt->mtab_writable);
-
- if (!cxt->mtab_writable)
- /* use /run/mount/utab if /etc/mtab is useless */
- mnt_has_regular_utab(&cxt->utab_path, &cxt->utab_writable);
return cxt;
}
free(cxt->fstype_pattern);
free(cxt->optstr_pattern);
- if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
- mnt_free_table(cxt->fstab);
- if (!(cxt->flags & MNT_FL_EXTERN_CACHE))
- mnt_free_cache(cxt->cache);
+ mnt_unref_table(cxt->fstab);
+ mnt_unref_cache(cxt->cache);
mnt_context_clear_loopdev(cxt);
mnt_free_lock(cxt->lock);
free(cxt->children);
- DBG(CXT, mnt_debug_h(cxt, "<---- free"));
+ DBG(CXT, ul_debugobj(cxt, "<---- free"));
free(cxt);
}
* mnt_reset_context:
* @cxt: mount context
*
- * Resets all information in the context that are directly related to
- * the latest mount (spec, source, target, mount options, ....)
+ * Resets all information in the context that is directly related to
+ * the latest mount (spec, source, target, mount options, ...).
*
- * The match patters, cached fstab, cached canonicalized paths and tags and
- * [e]uid are not reseted. You have to use
+ * The match patterns, cached fstab, cached canonicalized paths and tags and
+ * [e]uid are not reset. You have to use
*
* mnt_context_set_fstab(cxt, NULL);
* mnt_context_set_cache(cxt, NULL);
* mnt_context_set_options_pattern(cxt, NULL);
*
*
- * to reset these stuff.
+ * to reset this stuff.
*
* Returns: 0 on success, negative number in case of error.
*/
if (!cxt)
return -EINVAL;
- DBG(CXT, mnt_debug_h(cxt, "<---- reset [status=%d] ---->",
+ DBG(CXT, ul_debugobj(cxt, "<---- reset [status=%d] ---->",
mnt_context_get_status(cxt)));
fl = cxt->flags;
- if (!(cxt->flags & MNT_FL_EXTERN_FS))
- mnt_free_fs(cxt->fs);
-
- mnt_free_table(cxt->mtab);
+ mnt_unref_fs(cxt->fs);
+ mnt_unref_table(cxt->mtab);
+ mnt_unref_table(cxt->utab);
free(cxt->helper);
free(cxt->orig_user);
cxt->fs = NULL;
cxt->mtab = NULL;
- cxt->ambi = 0;
+ cxt->utab = NULL;
cxt->helper = NULL;
cxt->orig_user = NULL;
cxt->mountflags = 0;
cxt->mountdata = NULL;
cxt->flags = MNT_FL_DEFAULT;
+ /* free additional mounts list */
+ while (!list_empty(&cxt->addmounts)) {
+ struct libmnt_addmount *ad = list_entry(cxt->addmounts.next,
+ struct libmnt_addmount,
+ mounts);
+ mnt_free_addmount(ad);
+ }
+
mnt_context_reset_status(cxt);
- /* restore non-resetable flags */
- cxt->flags |= (fl & MNT_FL_EXTERN_FSTAB);
- cxt->flags |= (fl & MNT_FL_EXTERN_CACHE);
+ if (cxt->table_fltrcb)
+ mnt_context_set_tabfilter(cxt, NULL, NULL);
+
+ /* restore non-resettable flags */
cxt->flags |= (fl & MNT_FL_NOMTAB);
cxt->flags |= (fl & MNT_FL_FAKE);
cxt->flags |= (fl & MNT_FL_SLOPPY);
cxt->flags |= (fl & MNT_FL_FORCE);
cxt->flags |= (fl & MNT_FL_NOCANONICALIZE);
cxt->flags |= (fl & MNT_FL_RDONLY_UMOUNT);
+ cxt->flags |= (fl & MNT_FL_NOSWAPMATCH);
+ cxt->flags |= (fl & MNT_FL_TABPATHS_CHECKED);
return 0;
}
return 0;
}
+static int context_init_paths(struct libmnt_context *cxt, int writable)
+{
+ assert(cxt);
+
+ if (!cxt->mtab_path)
+ cxt->mtab_path = mnt_get_mtab_path();
+ if (!cxt->utab_path)
+ cxt->utab_path = mnt_get_utab_path();
+
+ if (!writable)
+ return 0; /* only paths wanted */
+ if (mnt_context_is_nomtab(cxt))
+ return 0; /* write mode overrided by mount -n */
+ if (cxt->flags & MNT_FL_TABPATHS_CHECKED)
+ return 0;
+
+ DBG(CXT, ul_debugobj(cxt, "checking for writable tab files"));
+
+#ifdef USE_LIBMOUNT_FORCE_MOUNTINFO
+ cxt->mtab_writable = 0;
+#else
+ mnt_has_regular_mtab(&cxt->mtab_path, &cxt->mtab_writable);
+#endif
+
+ if (!cxt->mtab_writable)
+ /* use /run/mount/utab if /etc/mtab is useless */
+ mnt_has_regular_utab(&cxt->utab_path, &cxt->utab_writable);
+
+ cxt->flags |= MNT_FL_TABPATHS_CHECKED;
+ return 0;
+}
+
+int mnt_context_mtab_writable(struct libmnt_context *cxt)
+{
+ assert(cxt);
+
+ context_init_paths(cxt, 1);
+ return cxt->mtab_writable == 1;
+}
+
+int mnt_context_utab_writable(struct libmnt_context *cxt)
+{
+ assert(cxt);
+
+ context_init_paths(cxt, 1);
+ return cxt->utab_writable == 1;
+}
+
+const char *mnt_context_get_writable_tabpath(struct libmnt_context *cxt)
+{
+ assert(cxt);
+
+ context_init_paths(cxt, 1);
+ return cxt->mtab_writable ? cxt->mtab_path : cxt->utab_path;
+}
+
+
static int set_flag(struct libmnt_context *cxt, int flag, int enable)
{
+ assert(cxt);
if (!cxt)
return -EINVAL;
if (enable) {
- DBG(CXT, mnt_debug_h(cxt, "enabling flag %04x", flag));
+ DBG(CXT, ul_debugobj(cxt, "enabling flag %04x", flag));
cxt->flags |= flag;
} else {
- DBG(CXT, mnt_debug_h(cxt, "disabling flag %04x", flag));
+ DBG(CXT, ul_debugobj(cxt, "disabling flag %04x", flag));
cxt->flags &= ~flag;
}
return 0;
* mnt_context_is_restricted:
* @cxt: mount context
*
- * Returns: 0 for unrestricted mount (user is root), or 1 for non-root mounts
+ * Returns: 0 for an unrestricted mount (user is root), or 1 for non-root mounts
*/
int mnt_context_is_restricted(struct libmnt_context *cxt)
{
- assert(cxt);
return cxt->restricted;
}
/**
* mnt_context_set_optsmode
* @cxt: mount context
- * @mode: MNT_OMASK_* flags
+ * @mode: MNT_OMODE_* flags
*
- * Controls how to use mount optionsmsource and target paths from fstab/mtab.
+ * Controls how to use mount optionssource and target paths from fstab/mtab.
*
* @MNT_OMODE_IGNORE: ignore mtab/fstab options
*
*
* @MNT_OMODE_REPLACE: replace existing options with options from mtab/fstab
*
- * @MNT_OMODE_FORCE: always read mtab/fstab (although source and target is defined)
+ * @MNT_OMODE_FORCE: always read mtab/fstab (although source and target are defined)
*
* @MNT_OMODE_FSTAB: read from fstab
*
* Notes:
*
* - MNT_OMODE_USER is always used if mount context is in restricted mode
- * - MNT_OMODE_AUTO is used if nothing other is defined
- * - the flags are eavaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
+ * - MNT_OMODE_AUTO is used if nothing else is defined
+ * - the flags are evaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
* MNT_OMODE_FSTAB, MNT_OMODE_MTAB and then the mount options from fstab/mtab
* are set according to MNT_OMODE_{IGNORE,APPEND,PREPAND,REPLACE}
*
* mnt_context_get_optsmode
* @cxt: mount context
*
- * Returns: MNT_OMASK_* mask or zero.
+ * Returns: MNT_OMODE_* mask or zero.
*/
int mnt_context_get_optsmode(struct libmnt_context *cxt)
{
- return cxt ? cxt->optsmode : 0;
+ return cxt->optsmode;
}
/**
* @disable: TRUE or FALSE
*
* Enable/disable paths canonicalization and tags evaluation. The libmount context
- * canonicalies paths when search in fstab and when prepare source and target paths
+ * canonicalizes paths when searching in fstab and when preparing source and target paths
* for mount(2) syscall.
*
- * This fuction has effect to the private (within context) fstab instance only
+ * This fuction has an effect on the private (within context) fstab instance only
* (see mnt_context_set_fstab()). If you want to use an external fstab then you
- * need manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
+ * need to manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
* NULL).
*
* Returns: 0 on success, negative number in case of error.
* mnt_context_is_nocanonicalize:
* @cxt: mount context
*
- * Returns: 1 if no-canonicalize mode enabled or 0.
+ * Returns: 1 if no-canonicalize mode is enabled or 0.
*/
int mnt_context_is_nocanonicalize(struct libmnt_context *cxt)
{
*/
int mnt_context_is_lazy(struct libmnt_context *cxt)
{
- return cxt && (cxt->flags & MNT_FL_LAZY) ? 1 : 0;
+ return cxt->flags & MNT_FL_LAZY ? 1 : 0;
}
/**
*/
int mnt_context_is_fork(struct libmnt_context *cxt)
{
- return cxt && (cxt->flags & MNT_FL_FORK) ? 1 : 0;
+ return cxt->flags & MNT_FL_FORK ? 1 : 0;
}
/**
* mnt_context_is_child:
* @cxt: mount context
*
- * Return: 1 if mount -F enabled and the current context is child, or 0
+ * Return: 1 f the current context is child, or 0
*/
int mnt_context_is_child(struct libmnt_context *cxt)
{
+ /* See mnt_fork_context(), the for fork flag is always disabled
+ * for children to avoid recursive forking.
+ */
return !mnt_context_is_fork(cxt) && cxt->pid;
}
* mnt_context_is_rdonly_umount
* @cxt: mount context
*
- * See also mnt_context_enable_rdonly_umount() and see umount(8) man page,
+ * See also mnt_context_enable_rdonly_umount() and umount(8) man page,
* option -r.
*
* Returns: 1 if read-only remount failed umount(2) is enables or 0
*/
int mnt_context_is_rdonly_umount(struct libmnt_context *cxt)
{
- return cxt && (cxt->flags & MNT_FL_RDONLY_UMOUNT) ? 1 : 0;
+ return cxt->flags & MNT_FL_RDONLY_UMOUNT ? 1 : 0;
}
/**
*/
int mnt_context_is_nohelpers(struct libmnt_context *cxt)
{
- return cxt && (cxt->flags & MNT_FL_NOHELPERS) ? 1 : 0;
+ return cxt->flags & MNT_FL_NOHELPERS ? 1 : 0;
}
*/
int mnt_context_is_sloppy(struct libmnt_context *cxt)
{
- return cxt && (cxt->flags & MNT_FL_SLOPPY) ? 1 : 0;
+ return cxt->flags & MNT_FL_SLOPPY ? 1 : 0;
}
/**
*/
int mnt_context_is_fake(struct libmnt_context *cxt)
{
- return cxt && (cxt->flags & MNT_FL_FAKE) ? 1 : 0;
+ return cxt->flags & MNT_FL_FAKE ? 1 : 0;
}
/**
}
/**
- * mnt_context_is_nomtab
+ * mnt_context_is_nomtab:
* @cxt: mount context
*
* Returns: 1 if no-mtab is enabled or 0
*/
int mnt_context_is_nomtab(struct libmnt_context *cxt)
{
- return cxt && (cxt->flags & MNT_FL_NOMTAB) ? 1 : 0;
+ return cxt->flags & MNT_FL_NOMTAB ? 1 : 0;
+}
+
+/**
+ * mnt_context_disable_swapmatch:
+ * @cxt: mount context
+ * @disable: TRUE or FALSE
+ *
+ * Disable/enable swap between source and target for mount(8) if only one path
+ * is specified.
+ *
+ * Returns: 0 on success, negative number in case of error.
+ */
+int mnt_context_disable_swapmatch(struct libmnt_context *cxt, int disable)
+{
+ return set_flag(cxt, MNT_FL_NOSWAPMATCH, disable);
+}
+
+/**
+ * mnt_context_is_swapmatch:
+ * @cxt: mount context
+ *
+ * Returns: 1 if swap between source and target is allowed (default is 1) or 0.
+ */
+int mnt_context_is_swapmatch(struct libmnt_context *cxt)
+{
+ return cxt->flags & MNT_FL_NOSWAPMATCH ? 0 : 1;
}
/**
*/
int mnt_context_is_force(struct libmnt_context *cxt)
{
- return cxt && (cxt->flags & MNT_FL_FORCE) ? 1 : 0;
+ return cxt->flags & MNT_FL_FORCE ? 1 : 0;
}
/**
*/
int mnt_context_is_verbose(struct libmnt_context *cxt)
{
- return cxt && (cxt->flags & MNT_FL_VERBOSE) ? 1 : 0;
+ return cxt->flags & MNT_FL_VERBOSE ? 1 : 0;
}
/**
* @cxt: mount context
* @enable: TRUE or FALSE
*
- * Enable/disable loop delete (destroy) after umount (see umount(8), option -d)
+ * Enable/disable the loop delete (destroy) after umount (see umount(8), option -d)
*
* Returns: 0 on success, negative number in case of error.
*/
*/
int mnt_context_is_loopdel(struct libmnt_context *cxt)
{
- return cxt && (cxt->flags & MNT_FL_LOOPDEL) ? 1 : 0;
+ return cxt->flags & MNT_FL_LOOPDEL ? 1 : 0;
}
/**
* @fs: filesystem description
*
* The mount context uses private @fs by default. This function allows to
- * overwrite the private @fs with an external instance. Note that the external
- * @fs instance is not deallocated by mnt_free_context() or mnt_reset_context().
+ * overwrite the private @fs with an external instance. This function
+ * increments @fs reference counter (and deincrement reference counter of the
+ * old fs).
*
* The @fs will be modified by mnt_context_set_{source,target,options,fstype}
- * functions, If the @fs is NULL then all current FS specific setting (source,
- * target, etc., exclude spec) is reseted.
+ * functions, If the @fs is NULL, then all current FS specific settings (source,
+ * target, etc., exclude spec) are reset.
*
* Returns: 0 on success, negative number in case of error.
*/
{
if (!cxt)
return -EINVAL;
- if (!(cxt->flags & MNT_FL_EXTERN_FS))
- mnt_free_fs(cxt->fs);
- set_flag(cxt, MNT_FL_EXTERN_FS, fs != NULL);
+ mnt_ref_fs(fs); /* new */
+ mnt_unref_fs(cxt->fs); /* old */
cxt->fs = fs;
return 0;
}
* Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
* functions.
*
- * Returns: pointer to FS description or NULL in case of calloc() errrr.
+ * Returns: pointer to FS description or NULL in case of a calloc() error.
*/
struct libmnt_fs *mnt_context_get_fs(struct libmnt_context *cxt)
{
if (!cxt)
return NULL;
- if (!cxt->fs) {
+ if (!cxt->fs)
cxt->fs = mnt_new_fs();
- cxt->flags &= ~MNT_FL_EXTERN_FS;
- }
return cxt->fs;
}
+/**
+ * mnt_context_get_fs_userdata:
+ * @cxt: mount context
+ *
+ * Returns: pointer to userdata or NULL.
+ */
+void *mnt_context_get_fs_userdata(struct libmnt_context *cxt)
+{
+ return cxt->fs ? mnt_fs_get_userdata(cxt->fs) : NULL;
+}
+
+/**
+ * mnt_context_get_fstab_userdata:
+ * @cxt: mount context
+ *
+ * Returns: pointer to userdata or NULL.
+ */
+void *mnt_context_get_fstab_userdata(struct libmnt_context *cxt)
+{
+ return cxt->fstab ? mnt_table_get_userdata(cxt->fstab) : NULL;
+}
+
+/**
+ * mnt_context_get_mtab_userdata:
+ * @cxt: mount context
+ *
+ * Returns: pointer to userdata or NULL.
+ */
+void *mnt_context_get_mtab_userdata(struct libmnt_context *cxt)
+{
+ return cxt->mtab ? mnt_table_get_userdata(cxt->mtab) : NULL;
+}
+
/**
* mnt_context_set_source:
* @cxt: mount context
* @source: mount source (device, directory, UUID, LABEL, ...)
*
+ * Note that libmount does not interpret "nofail" (MNT_MS_NOFAIL)
+ * mount option. The real return code is always returned, when
+ * the device does not exist then it's usually MNT_ERR_NOSOURCE
+ * from libmount or ENOENT, ENOTDIR, ENOTBLK, ENXIO from moun(2).
+ *
* Returns: 0 on success, negative number in case of error.
*/
int mnt_context_set_source(struct libmnt_context *cxt, const char *source)
* mnt_context_get_source:
* @cxt: mount context
*
- * Returns: returns pointer or NULL in case of error pr if not set.
+ * Returns: returns pointer or NULL in case of error or if not set.
*/
const char *mnt_context_get_source(struct libmnt_context *cxt)
{
* mnt_context_get_target:
* @cxt: mount context
*
- * Returns: returns pointer or NULL in case of error pr if not set.
+ * Returns: returns pointer or NULL in case of error or if not set.
*/
const char *mnt_context_get_target(struct libmnt_context *cxt)
{
* @cxt: mount context
* @fstype: filesystem type
*
- * Note that the @fstype has to be the real FS type. For comma-separated list of
- * filesystems or for "nofs" notation use mnt_context_set_fstype_pattern().
+ * Note that the @fstype has to be a FS type. For patterns with
+ * comma-separated list of filesystems or for the "nofs" notation, use
+ * mnt_context_set_fstype_pattern().
*
* Returns: 0 on success, negative number in case of error.
*/
int mnt_context_set_fstype(struct libmnt_context *cxt, const char *fstype)
{
- if (fstype && strchr(fstype, ','))
- return -EINVAL;
return mnt_fs_set_fstype(mnt_context_get_fs(cxt), fstype);
}
* mnt_context_get_fstype:
* @cxt: mount context
*
- * Returns: pointer or NULL in case of error pr if not set.
+ * Returns: pointer or NULL in case of error or if not set.
*/
const char *mnt_context_get_fstype(struct libmnt_context *cxt)
{
* This function returns mount options set by mnt_context_set_options() or
* mnt_context_append_options().
*
- * Note that *after* mnt_context_prepare_mount() may the mount options string
- * also includes options set by mnt_context_set_mflags() or another options
+ * Note that *after* mnt_context_prepare_mount(), the mount options string
+ * may also include options set by mnt_context_set_mflags() or other options
* generated by this library.
*
* Returns: pointer or NULL
* @cxt: mount context
* @tb: fstab
*
- * The mount context reads /etc/fstab to the the private struct libmnt_table by default.
+ * The mount context reads /etc/fstab to the private struct libmnt_table by default.
* This function allows to overwrite the private fstab with an external
- * instance. Note that the external instance is not deallocated by mnt_free_context().
+ * instance.
+ *
+ * This function modify the @tb reference counter. This function does not set
+ * the cache for the @tb. You have to explicitly call mnt_table_set_cache(tb,
+ * mnt_context_get_cache(cxt));
*
* The fstab is used read-only and is not modified, it should be possible to
- * share the fstab between more mount contexts (TODO: tests it.)
+ * share the fstab between more mount contexts (TODO: test it.)
*
- * If the @tb argument is NULL then the current private fstab instance is
- * reseted.
+ * If the @tb argument is NULL, then the current private fstab instance is
+ * reset.
*
* Returns: 0 on success, negative number in case of error.
*/
{
if (!cxt)
return -EINVAL;
- if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
- mnt_free_table(cxt->fstab);
- set_flag(cxt, MNT_FL_EXTERN_FSTAB, tb != NULL);
+ mnt_ref_table(tb); /* new */
+ mnt_unref_table(cxt->fstab); /* old */
+
cxt->fstab = tb;
return 0;
}
*/
int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
{
- struct libmnt_cache *cache;
-
if (!cxt)
return -EINVAL;
-
if (!cxt->fstab) {
int rc;
return -ENOMEM;
if (cxt->table_errcb)
mnt_table_set_parser_errcb(cxt->fstab, cxt->table_errcb);
- cxt->flags &= ~MNT_FL_EXTERN_FSTAB;
+ mnt_table_set_cache(cxt->fstab, mnt_context_get_cache(cxt));
rc = mnt_table_parse_fstab(cxt->fstab, NULL);
if (rc)
return rc;
}
- cache = mnt_context_get_cache(cxt);
-
- /* never touch an external fstab */
- if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
- mnt_table_set_cache(cxt->fstab, cache);
-
if (tb)
*tb = cxt->fstab;
return 0;
* @tb: returns mtab
*
* See also mnt_table_parse_mtab() for more details about mtab/mountinfo. The
- * result will deallocated by mnt_free_context(@cxt).
+ * result will be deallocated by mnt_free_context(@cxt).
*
* Returns: 0 on success, negative number in case of error.
*/
int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
{
- struct libmnt_cache *cache;
-
if (!cxt)
return -EINVAL;
-
if (!cxt->mtab) {
int rc;
+ context_init_paths(cxt, 0);
+
cxt->mtab = mnt_new_table();
if (!cxt->mtab)
return -ENOMEM;
if (cxt->table_errcb)
mnt_table_set_parser_errcb(cxt->mtab, cxt->table_errcb);
-
- rc = mnt_table_parse_mtab(cxt->mtab, cxt->mtab_path);
+ if (cxt->table_fltrcb)
+ mnt_table_set_parser_fltrcb(cxt->mtab,
+ cxt->table_fltrcb,
+ cxt->table_fltrcb_data);
+
+ mnt_table_set_cache(cxt->mtab, mnt_context_get_cache(cxt));
+ if (cxt->utab)
+ /* utab already parsed, don't parse it again */
+ rc = __mnt_table_parse_mtab(cxt->mtab,
+ cxt->mtab_path, cxt->utab);
+ else
+ rc = mnt_table_parse_mtab(cxt->mtab, cxt->mtab_path);
if (rc)
return rc;
}
- cache = mnt_context_get_cache(cxt);
- mnt_table_set_cache(cxt->mtab, cache);
-
if (tb)
*tb = cxt->mtab;
+
+ DBG(CXT, ul_debugobj(cxt, "mtab requested [nents=%d]",
+ mnt_table_get_nents(cxt->mtab)));
+ return 0;
+}
+
+/*
+ * Called by mtab parser to filter out entries, non-zero means that
+ * an entry has to be filtered out.
+ */
+static int mtab_filter(struct libmnt_fs *fs, void *data)
+{
+ if (!fs || !data)
+ return 0;
+ if (mnt_fs_streq_target(fs, data))
+ return 0;
+ if (mnt_fs_streq_srcpath(fs, data))
+ return 0;
+ return 1;
+}
+
+/*
+ * The same like mnt_context_get_mtab(), but does not read all mountinfo/mtab
+ * file, but only entries relevant for @tgt.
+ */
+int mnt_context_get_mtab_for_target(struct libmnt_context *cxt,
+ struct libmnt_table **mtab,
+ const char *tgt)
+{
+ struct stat st;
+ struct libmnt_cache *cache = NULL;
+ char *cn_tgt = NULL;
+ int rc;
+
+ if (stat(tgt, &st) == 0 && S_ISDIR(st.st_mode)) {
+ cache = mnt_context_get_cache(cxt);
+ cn_tgt = mnt_resolve_path(tgt, cache);
+ if (cn_tgt)
+ mnt_context_set_tabfilter(cxt, mtab_filter, cn_tgt);
+ }
+
+ rc = mnt_context_get_mtab(cxt, mtab);
+
+ if (cn_tgt) {
+ mnt_context_set_tabfilter(cxt, NULL, NULL);
+ if (!cache)
+ free(cn_tgt);
+ }
+
+ return rc;
+}
+
+/*
+ * Allows to specify a filter for tab file entries. The filter is called by
+ * the table parser. Currently used for mtab and utab only.
+ */
+int mnt_context_set_tabfilter(struct libmnt_context *cxt,
+ int (*fltr)(struct libmnt_fs *, void *),
+ void *data)
+{
+ if (!cxt)
+ return -EINVAL;
+
+ cxt->table_fltrcb = fltr;
+ cxt->table_fltrcb_data = data;
+
+ if (cxt->mtab)
+ mnt_table_set_parser_fltrcb(cxt->mtab,
+ cxt->table_fltrcb,
+ cxt->table_fltrcb_data);
+
+ DBG(CXT, ul_debugobj(cxt, "tabfilter %s", fltr ? "ENABLED!" : "disabled"));
return 0;
}
* callback and cache for tags and paths is set according to the @cxt setting.
* See also mnt_table_parse_file().
*
- * It's strongly recommended use mnt_context_get_mtab() and
+ * It's strongly recommended to use the mnt_context_get_mtab() and
* mnt_context_get_fstab() functions for mtab and fstab files. This function
* does not care about LIBMOUNT_* env.variables and does not merge userspace
* options.
int mnt_context_get_table(struct libmnt_context *cxt,
const char *filename, struct libmnt_table **tb)
{
- struct libmnt_cache *cache;
int rc;
if (!cxt || !tb)
rc = mnt_table_parse_file(*tb, filename);
if (rc) {
- mnt_free_table(*tb);
+ mnt_unref_table(*tb);
return rc;
}
- cache = mnt_context_get_cache(cxt);
- if (cache)
- mnt_table_set_cache(*tb, cache);
-
+ mnt_table_set_cache(*tb, mnt_context_get_cache(cxt));
return 0;
}
if (!cxt)
return -EINVAL;
+ if (cxt->mtab)
+ mnt_table_set_parser_errcb(cxt->mtab, cb);
+ if (cxt->fstab)
+ mnt_table_set_parser_errcb(cxt->fstab, cb);
+
cxt->table_errcb = cb;
return 0;
}
* @cxt: mount context
* @cache: cache instance or nULL
*
- * The mount context maintains a private struct libmnt_cache by default. This function
- * allows to overwrite the private cache with an external instance. Note that
- * the external instance is not deallocated by mnt_free_context().
+ * The mount context maintains a private struct libmnt_cache by default. This
+ * function allows to overwrite the private cache with an external instance.
+ * This function increments cache reference counter.
*
- * If the @cache argument is NULL then the current private cache instance is
- * reseted.
+ * If the @cache argument is NULL, then the current cache instance is reset.
+ * This function apply the cache to fstab and mtab instances (if already
+ * exists).
+ *
+ * The old cache instance reference counter is de-incremented.
*
* Returns: 0 on success, negative number in case of error.
*/
{
if (!cxt)
return -EINVAL;
- if (!(cxt->flags & MNT_FL_EXTERN_CACHE))
- mnt_free_cache(cxt->cache);
- set_flag(cxt, MNT_FL_EXTERN_CACHE, cache != NULL);
+ mnt_ref_cache(cache); /* new */
+ mnt_unref_cache(cxt->cache); /* old */
+
cxt->cache = cache;
+
+ if (cxt->mtab)
+ mnt_table_set_cache(cxt->mtab, cache);
+ if (cxt->fstab)
+ mnt_table_set_cache(cxt->fstab, cache);
+
return 0;
}
return NULL;
if (!cxt->cache) {
- cxt->cache = mnt_new_cache();
- if (!cxt->cache)
- return NULL;
- cxt->flags &= ~MNT_FL_EXTERN_CACHE;
+ struct libmnt_cache *cache = mnt_new_cache();
+ mnt_context_set_cache(cxt, cache);
+ mnt_unref_cache(cache);
}
return cxt->cache;
}
* @get: callback to get password
* @release: callback to release (delallocate) password
*
- * Sets callbacks for encryption password (e.g encrypted loopdev)
+ * Sets callbacks for encryption password (e.g encrypted loopdev). This
+ * function is deprecated (encrypted loops are no longer supported).
*
* Returns: 0 on success, negative number in case of error.
*/
{
if (!cxt)
return -EINVAL;
-
cxt->pwd_get_cb = get;
cxt->pwd_release_cb = release;
return 0;
*
* The default behavior is to ignore all signals (except SIGALRM and
* SIGTRAP for mtab udate) when the lock is locked. If this behavior
- * is unacceptable then use:
+ * is unacceptable, then use:
*
* lc = mnt_context_get_lock(cxt);
* if (lc)
return NULL;
if (!cxt->lock) {
- cxt->lock = mnt_new_lock(cxt->mtab_writable ?
- cxt->mtab_path : cxt->utab_path, 0);
+ cxt->lock = mnt_new_lock(
+ mnt_context_get_writable_tabpath(cxt), 0);
if (cxt->lock)
mnt_lock_block_signals(cxt->lock, TRUE);
}
*
* mnt_context_set_options(cxt, "noexec,nosuid");
*
- * these both calls have the same effect.
+ * both of these calls have the same effect.
*
* Returns: 0 on success, negative number in case of error.
*/
* @flags: returns MS_* mount flags
*
* Converts mount options string to MS_* flags and bitewise-OR the result with
- * already defined flags (see mnt_context_set_mflags()).
+ * the already defined flags (see mnt_context_set_mflags()).
*
* Returns: 0 on success, negative number in case of error.
*/
int mnt_context_get_mflags(struct libmnt_context *cxt, unsigned long *flags)
{
int rc = 0;
+ struct list_head *p;
+
if (!cxt || !flags)
return -EINVAL;
rc = mnt_optstr_get_flags(o, flags,
mnt_get_builtin_optmap(MNT_LINUX_MAP));
}
+
+ list_for_each(p, &cxt->addmounts) {
+ struct libmnt_addmount *ad =
+ list_entry(p, struct libmnt_addmount, mounts);
+
+ *flags |= ad->mountflags;
+ }
+
if (!rc)
*flags |= cxt->mountflags;
return rc;
*
* Sets userspace mount flags.
*
- * See also notest for mnt_context_set_mflags().
+ * See also notes for mnt_context_set_mflags().
*
* Returns: 0 on success, negative number in case of error.
*/
int mnt_context_set_user_mflags(struct libmnt_context *cxt, unsigned long flags)
{
+ assert(cxt);
if (!cxt)
return -EINVAL;
cxt->user_mountflags = flags;
* @flags: returns mount flags
*
* Converts mount options string to MNT_MS_* flags and bitewise-OR the result
- * with already defined flags (see mnt_context_set_user_mflags()).
+ * with the already defined flags (see mnt_context_set_user_mflags()).
*
* Returns: 0 on success, negative number in case of error.
*/
int mnt_context_get_user_mflags(struct libmnt_context *cxt, unsigned long *flags)
{
int rc = 0;
+
if (!cxt || !flags)
return -EINVAL;
* function allows to overwrite this behavior, and @data will be used instead
* of mount options.
*
- * The libmount does not deallocated the data by mnt_free_context(). Note that
+ * The libmount does not deallocate the data by mnt_free_context(). Note that
* NULL is also valid mount data.
*
* Returns: 0 on success, negative number in case of error.
if (!cxt || !cxt->fs)
return -EINVAL;
- DBG(CXT, mnt_debug_h(cxt, "preparing source path"));
+ DBG(CXT, ul_debugobj(cxt, "preparing source path"));
src = mnt_fs_get_source(cxt->fs);
- if (!src && (cxt->mountflags & MS_PROPAGATION))
+ if (!src && mnt_context_propagation_only(cxt))
/* mount --make-{shared,private,...} */
return mnt_fs_set_source(cxt->fs, "none");
/* ignore filesystems without source or filesystems
- * where the source is quasi-path (//foo/bar)
+ * where the source is a quasi-path (//foo/bar)
*/
if (!src || mnt_fs_is_netfs(cxt->fs))
return 0;
- DBG(CXT, mnt_debug_h(cxt, "srcpath '%s'", src));
+ DBG(CXT, ul_debugobj(cxt, "srcpath '%s'", src));
cache = mnt_context_get_cache(cxt);
}
if (rc) {
- DBG(CXT, mnt_debug_h(cxt, "failed to prepare srcpath [rc=%d]", rc));
+ DBG(CXT, ul_debugobj(cxt, "failed to prepare srcpath [rc=%d]", rc));
return rc;
}
if (!path)
path = src;
- if ((cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION)) ||
- mnt_fs_is_pseudofs(cxt->fs)) {
- DBG(CXT, mnt_debug_h(cxt, "BIND/MOVE/pseudo FS source: %s", path));
+ if ((cxt->mountflags & (MS_BIND | MS_MOVE | MS_REMOUNT))
+ || mnt_fs_is_pseudofs(cxt->fs)) {
+ DBG(CXT, ul_debugobj(cxt, "REMOUNT/BIND/MOVE/pseudo FS source: %s", path));
return rc;
}
return rc;
}
- DBG(CXT, mnt_debug_h(cxt, "final srcpath '%s'",
+ DBG(CXT, ul_debugobj(cxt, "final srcpath '%s'",
mnt_fs_get_source(cxt->fs)));
return 0;
}
+/* create a mountpoint if x-mount.mkdir[=<mode>] specified */
+static int mkdir_target(const char *tgt, struct libmnt_fs *fs)
+{
+ char *mstr = NULL;
+ size_t mstr_sz = 0;
+ mode_t mode = 0;
+ struct stat st;
+ int rc;
+
+ assert(tgt);
+ assert(fs);
+
+ if (mnt_optstr_get_option(fs->user_optstr, "x-mount.mkdir", &mstr, &mstr_sz) != 0)
+ return 0;
+ if (stat(tgt, &st) == 0)
+ return 0;
+
+ if (mstr && mstr_sz) {
+ char *end = NULL;
+
+ errno = 0;
+ mode = strtol(mstr, &end, 8);
+
+ if (errno || !end || mstr + mstr_sz != end) {
+ DBG(CXT, ul_debug("failed to parse mkdir mode '%s'", mstr));
+ return -MNT_ERR_MOUNTOPT;
+ }
+ }
+
+ if (!mode)
+ mode = S_IRWXU | /* 0755 */
+ S_IRGRP | S_IXGRP |
+ S_IROTH | S_IXOTH;
+
+ rc = mkdir_p(tgt, mode);
+ if (rc)
+ DBG(CXT, ul_debug("mkdir %s failed: %m", tgt));
+
+ return rc;
+}
+
int mnt_context_prepare_target(struct libmnt_context *cxt)
{
const char *tgt;
if (!cxt || !cxt->fs)
return -EINVAL;
- DBG(CXT, mnt_debug_h(cxt, "preparing target path"));
+ DBG(CXT, ul_debugobj(cxt, "preparing target path"));
tgt = mnt_fs_get_target(cxt->fs);
if (!tgt)
return 0;
+ /* mkdir target */
+ if (cxt->action == MNT_ACT_MOUNT
+ && !mnt_context_is_restricted(cxt)
+ && cxt->user_mountflags & MNT_MS_XCOMMENT) {
+
+ rc = mkdir_target(tgt, cxt->fs);
+ if (rc)
+ return rc; /* mkdir or parse error */
+ }
+
+ /* canonicalize the path */
cache = mnt_context_get_cache(cxt);
if (cache) {
char *path = mnt_resolve_path(tgt, cache);
}
if (rc)
- DBG(CXT, mnt_debug_h(cxt, "failed to prepare target '%s'", tgt));
+ DBG(CXT, ul_debugobj(cxt, "failed to prepare target '%s'", tgt));
else
- DBG(CXT, mnt_debug_h(cxt, "final target '%s'",
+ DBG(CXT, ul_debugobj(cxt, "final target '%s'",
mnt_fs_get_target(cxt->fs)));
return 0;
}
+/* Guess type, but not set to cxt->fs, always use free() for the result. It's
+ * no error when we're not able to guess a filesystem type. Note that error
+ * does not mean that result in @type is NULL.
+ */
+int mnt_context_guess_srcpath_fstype(struct libmnt_context *cxt, char **type)
+{
+ int rc = 0;
+ const char *dev = mnt_fs_get_srcpath(cxt->fs);
+
+ *type = NULL;
+
+ if (!dev)
+ goto done;
+
+ if (access(dev, F_OK) == 0) {
+ struct libmnt_cache *cache = mnt_context_get_cache(cxt);
+ int ambi = 0;
+
+ *type = mnt_get_fstype(dev, &ambi, cache);
+ if (cache && *type)
+ *type = strdup(*type);
+ if (ambi)
+ rc = -MNT_ERR_AMBIFS;
+ } else {
+ DBG(CXT, ul_debugobj(cxt, "access(%s) failed [%m]", dev));
+ if (strchr(dev, ':') != NULL)
+ *type = strdup("nfs");
+ else if (!strncmp(dev, "//", 2))
+ *type = strdup("cifs");
+ }
+
+done:
+ return rc;
+}
+
/*
- * It's usully no error when we're not able to detect filesystem type -- we
- * will try to use types from /{etc,proc}/filesystems.
+ * It's usually no error when we're not able to detect the filesystem type -- we
+ * will try to use the types from /{etc,proc}/filesystems.
*/
int mnt_context_guess_fstype(struct libmnt_context *cxt)
{
char *type;
- const char *dev;
int rc = 0;
assert(cxt);
assert(cxt->fs);
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
+ DBG(CXT, ul_debugobj(cxt, "preparing fstype"));
+
if (!cxt || !cxt->fs)
return -EINVAL;
- if (cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION))
+ if ((cxt->mountflags & (MS_BIND | MS_MOVE))
+ || mnt_context_propagation_only(cxt))
goto none;
type = (char *) mnt_fs_get_fstype(cxt->fs);
if (type)
goto done;
- if (cxt->flags & MS_REMOUNT)
+ if (cxt->mountflags & MS_REMOUNT)
goto none;
if (cxt->fstype_pattern)
goto done;
- dev = mnt_fs_get_srcpath(cxt->fs);
- if (!dev)
- goto done;
-
- if (access(dev, F_OK) == 0) {
- struct libmnt_cache *cache = mnt_context_get_cache(cxt);
-
- type = mnt_get_fstype(dev, &cxt->ambi, cache);
- if (type) {
- rc = mnt_fs_set_fstype(cxt->fs, type);
- if (!cache)
- free(type); /* type is not cached */
- }
- } else {
- if (strchr(dev, ':') != NULL)
- rc = mnt_fs_set_fstype(cxt->fs, "nfs");
- else if (!strncmp(dev, "//", 2))
- rc = mnt_fs_set_fstype(cxt->fs, "cifs");
- }
-
+ rc = mnt_context_guess_srcpath_fstype(cxt, &type);
+ if (rc == 0 && type)
+ __mnt_fs_set_fstype_ptr(cxt->fs, type);
+ else
+ free(type);
done:
- DBG(CXT, mnt_debug_h(cxt, "FS type: %s", mnt_fs_get_fstype(cxt->fs)));
+ DBG(CXT, ul_debugobj(cxt, "FS type: %s [rc=%d]",
+ mnt_fs_get_fstype(cxt->fs), rc));
return rc;
none:
return mnt_fs_set_fstype(cxt->fs, "none");
if (!type)
type = mnt_fs_get_fstype(cxt->fs);
+ if (type && strchr(type, ','))
+ return 0; /* type is fstype pattern */
+
if (mnt_context_is_nohelpers(cxt)
|| !type
|| !strcmp(type, "none")
+ || strstr(type, "/..") /* don't try to smuggle path */
|| mnt_fs_is_swaparea(cxt->fs))
return 0;
rc = stat(helper, &st);
}
- DBG(CXT, mnt_debug_h(cxt, "%-25s ... %s", helper,
+ DBG(CXT, ul_debugobj(cxt, "%-25s ... %s", helper,
rc ? "not found" : "found"));
if (rc)
continue;
assert(cxt);
- DBG(CXT, mnt_debug_h(cxt, "merging mount flags"));
+ DBG(CXT, ul_debugobj(cxt, "merging mount flags"));
rc = mnt_context_get_mflags(cxt, &fl);
if (rc)
return rc;
cxt->user_mountflags = fl;
- DBG(CXT, mnt_debug_h(cxt, "final flags: VFS=%08lx user=%08lx",
+ DBG(CXT, ul_debugobj(cxt, "final flags: VFS=%08lx user=%08lx",
cxt->mountflags, cxt->user_mountflags));
cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED;
assert(cxt->action);
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
- DBG(CXT, mnt_debug_h(cxt, "prepare update"));
+ DBG(CXT, ul_debugobj(cxt, "prepare update"));
- if (cxt->mountflags & MS_PROPAGATION) {
- DBG(CXT, mnt_debug_h(cxt, "skip update: MS_PROPAGATION"));
+ if (mnt_context_propagation_only(cxt)) {
+ DBG(CXT, ul_debugobj(cxt, "skip update: only MS_PROPAGATION"));
return 0;
}
target = mnt_fs_get_target(cxt->fs);
- if (cxt->action == MNT_ACT_UMOUNT && target && !strcmp(target, "/"))
- /* Don't try to touch mtab if umounting root FS */
+ if (cxt->action == MNT_ACT_UMOUNT && target && !strcmp(target, "/")) {
+ DBG(CXT, ul_debugobj(cxt, "root umount: setting NOMTAB"));
mnt_context_disable_mtab(cxt, TRUE);
-
- if (mnt_context_is_nomtab(cxt)) {
- DBG(CXT, mnt_debug_h(cxt, "skip update: NOMTAB flag"));
- return 0;
}
- if (cxt->helper) {
- DBG(CXT, mnt_debug_h(cxt, "skip update: external helper"));
+ if (mnt_context_is_nomtab(cxt)) {
+ DBG(CXT, ul_debugobj(cxt, "skip update: NOMTAB flag"));
return 0;
}
- if (!cxt->mtab_writable && !cxt->utab_writable) {
- DBG(CXT, mnt_debug_h(cxt, "skip update: no writable destination"));
+ if (!mnt_context_get_writable_tabpath(cxt)) {
+ DBG(CXT, ul_debugobj(cxt, "skip update: no writable destination"));
return 0;
}
/* 0 = success, 1 = not called yet */
if (cxt->syscall_status != 1 && cxt->syscall_status != 0) {
- DBG(CXT, mnt_debug_h(cxt,
+ DBG(CXT, ul_debugobj(cxt,
"skip update: syscall failed [status=%d]",
cxt->syscall_status));
return 0;
}
+
if (!cxt->update) {
+ const char *name = mnt_context_get_writable_tabpath(cxt);
+
+ if (cxt->action == MNT_ACT_UMOUNT && is_file_empty(name)) {
+ DBG(CXT, ul_debugobj(cxt,
+ "skip update: umount, no table"));
+ return 0;
+ }
+
cxt->update = mnt_new_update();
if (!cxt->update)
return -ENOMEM;
- mnt_update_set_filename(cxt->update,
- cxt->mtab_writable ? cxt->mtab_path : cxt->utab_path,
- !cxt->mtab_writable);
+ mnt_update_set_filename(cxt->update, name,
+ !mnt_context_mtab_writable(cxt));
}
if (cxt->action == MNT_ACT_UMOUNT)
assert(cxt);
if (mnt_context_is_nomtab(cxt)) {
- DBG(CXT, mnt_debug_h(cxt, "don't update: NOMTAB flag"));
+ DBG(CXT, ul_debugobj(cxt, "don't update: NOMTAB flag"));
return 0;
}
- if (cxt->helper) {
- DBG(CXT, mnt_debug_h(cxt, "don't update: external helper"));
+ if (!cxt->update || !mnt_update_is_ready(cxt->update)) {
+ DBG(CXT, ul_debugobj(cxt, "don't update: no update prepared"));
return 0;
}
- if (!cxt->update || !mnt_update_is_ready(cxt->update)) {
- DBG(CXT, mnt_debug_h(cxt, "don't update: no update prepared"));
+
+ /* check utab update when external helper executed */
+ if (mnt_context_helper_executed(cxt)
+ && mnt_context_get_helper_status(cxt) == 0
+ && mnt_context_utab_writable(cxt)) {
+
+ if (mnt_update_already_done(cxt->update, cxt->lock)) {
+ DBG(CXT, ul_debugobj(cxt, "don't update: error evaluate or already updated"));
+ return 0;
+ }
+ } else if (cxt->helper) {
+ DBG(CXT, ul_debugobj(cxt, "don't update: external helper"));
return 0;
}
- if (cxt->syscall_status) {
- DBG(CXT, mnt_debug_h(cxt, "don't update: syscall failed/not called"));
+
+ if (cxt->syscall_status != 0
+ && !(mnt_context_helper_executed(cxt) &&
+ mnt_context_get_helper_status(cxt) == 0)) {
+
+ DBG(CXT, ul_debugobj(cxt, "don't update: syscall/helper failed/not called"));
return 0;
}
else if (tgt)
fs = mnt_table_find_target(tb, tgt, direction);
- if (!fs) {
+ if (!fs && mnt_context_is_swapmatch(cxt)) {
/* swap source and target (if @src is not LABEL/UUID),
* for example in
*
* mount /foo/bar
*
- * the path could be a mountpoint as well as source (for
- * example bind mount, symlink to device, ...).
+ * the path could be a mountpoint as well as a source (for
+ * example bind mount, symlink to a device, ...).
*/
if (src && !mnt_fs_get_tag(cxt->fs, NULL, NULL))
fs = mnt_table_find_target(tb, src, direction);
if (!fs)
return -MNT_ERR_NOFSTAB; /* not found */
- DBG(CXT, mnt_debug_h(cxt, "apply entry:"));
+ DBG(CXT, ul_debugobj(cxt, "apply entry:"));
DBG(CXT, mnt_fs_print_debug(fs, stderr));
/* copy from tab to our FS description
if (!rc && !mnt_fs_get_fstype(cxt->fs))
rc = mnt_fs_set_fstype(cxt->fs, mnt_fs_get_fstype(fs));
+ if (!rc && !mnt_fs_get_root(cxt->fs) && mnt_fs_get_root(fs))
+ rc = mnt_fs_set_root(cxt->fs, mnt_fs_get_root(fs));
+
if (rc)
return rc;
*/
int mnt_context_apply_fstab(struct libmnt_context *cxt)
{
- int rc = -1;
+ int rc = -1, isremount = 0;
struct libmnt_table *tab = NULL;
const char *src = NULL, *tgt = NULL;
+ unsigned long mflags = 0;
- assert(cxt);
- assert(cxt->fs);
-
- if (!cxt)
+ if (!cxt || !cxt->fs)
return -EINVAL;
- if (mnt_context_fstab_applied(cxt))
+ if (mnt_context_tab_applied(cxt)) /* already applied */
return 0;
if (mnt_context_is_restricted(cxt)) {
- DBG(CXT, mnt_debug_h(cxt, "force fstab usage for non-root users!"));
+ DBG(CXT, ul_debugobj(cxt, "force fstab usage for non-root users!"));
cxt->optsmode = MNT_OMODE_USER;
} else if (cxt->optsmode == 0) {
- DBG(CXT, mnt_debug_h(cxt, "use default optmode"));
+ DBG(CXT, ul_debugobj(cxt, "use default optsmode"));
cxt->optsmode = MNT_OMODE_AUTO;
} else if (cxt->optsmode & MNT_OMODE_NOTAB) {
cxt->optsmode &= ~MNT_OMODE_FSTAB;
cxt->optsmode &= ~MNT_OMODE_FORCE;
}
+ if (mnt_context_get_mflags(cxt, &mflags) == 0 && mflags & MS_REMOUNT)
+ isremount = 1;
+
if (cxt->fs) {
src = mnt_fs_get_source(cxt->fs);
tgt = mnt_fs_get_target(cxt->fs);
}
- DBG(CXT, mnt_debug_h(cxt, "OPTSMODE: ignore=%d, append=%d, prepend=%d, "
+ DBG(CXT, ul_debugobj(cxt, "OPTSMODE: ignore=%d, append=%d, prepend=%d, "
"replace=%d, force=%d, fstab=%d, mtab=%d",
cxt->optsmode & MNT_OMODE_IGNORE ? 1 : 0,
cxt->optsmode & MNT_OMODE_APPEND ? 1 : 0,
/* fstab is not required if source and target are specified */
if (src && tgt && !(cxt->optsmode & MNT_OMODE_FORCE)) {
- DBG(CXT, mnt_debug_h(cxt, "fstab not required -- skip"));
+ DBG(CXT, ul_debugobj(cxt, "fstab not required -- skip"));
return 0;
}
if (!src && tgt
&& !(cxt->optsmode & MNT_OMODE_FSTAB)
&& !(cxt->optsmode & MNT_OMODE_MTAB)) {
- DBG(CXT, mnt_debug_h(cxt, "only target; fstab/mtab not required "
+ DBG(CXT, ul_debugobj(cxt, "only target; fstab/mtab not required "
"-- skip, probably MS_PROPAGATION"));
return 0;
}
- DBG(CXT, mnt_debug_h(cxt,
- "trying to apply fstab (src=%s, target=%s)", src, tgt));
-
/* let's initialize cxt->fs */
- mnt_context_get_fs(cxt);
+ ignore_result( mnt_context_get_fs(cxt) );
/* try fstab */
if (cxt->optsmode & MNT_OMODE_FSTAB) {
+ DBG(CXT, ul_debugobj(cxt, "trying to apply fstab (src=%s, target=%s)", src, tgt));
rc = mnt_context_get_fstab(cxt, &tab);
if (!rc)
rc = apply_table(cxt, tab, MNT_ITER_FORWARD);
}
/* try mtab */
- if (rc < 0 && (cxt->optsmode & MNT_OMODE_MTAB)) {
- DBG(CXT, mnt_debug_h(cxt, "trying to apply from mtab"));
- rc = mnt_context_get_mtab(cxt, &tab);
+ if (rc < 0 && (cxt->optsmode & MNT_OMODE_MTAB)
+ && (isremount || cxt->action == MNT_ACT_UMOUNT)) {
+ DBG(CXT, ul_debugobj(cxt, "trying to apply mtab (src=%s, target=%s)", src, tgt));
+ if (tgt)
+ rc = mnt_context_get_mtab_for_target(cxt, &tab, tgt);
+ else
+ rc = mnt_context_get_mtab(cxt, &tab);
if (!rc)
rc = apply_table(cxt, tab, MNT_ITER_BACKWARD);
}
- if (rc)
- DBG(CXT, mnt_debug_h(cxt, "failed to find entry in fstab/mtab"));
+ if (rc) {
+ if (!mnt_context_is_restricted(cxt)
+ && tgt && !src
+ && isremount) {
+ DBG(CXT, ul_debugobj(cxt, "only target; ignore missing mtab entry on remount"));
+ return 0;
+ }
+
+ DBG(CXT, ul_debugobj(cxt, "failed to find entry in fstab/mtab [rc=%d]: %m", rc));
+
+ /* force to "not found in fstab/mtab" error, the details why
+ * not found are not so important and may be misinterpreted by
+ * applications... */
+ rc = -MNT_ERR_NOFSTAB;
+ }
return rc;
}
/**
- * mnt_context_fstab_applied:
+ * mnt_context_tab_applied:
* @cxt: mount context
*
* Returns: 1 if fstab (or mtab) has been applied to the context, or 0.
*/
-int mnt_context_fstab_applied(struct libmnt_context *cxt)
+int mnt_context_tab_applied(struct libmnt_context *cxt)
{
- return cxt && (cxt->flags & MNT_FL_TAB_APPLIED);
+ return cxt->flags & MNT_FL_TAB_APPLIED;
+}
+
+/*
+ * This is not a public function!
+ *
+ * Returns 1 if *only propagation flags* change is requested.
+ */
+int mnt_context_propagation_only(struct libmnt_context *cxt)
+{
+ if (cxt->action != MNT_ACT_MOUNT)
+ return 0;
+
+ /* has to be called after context_mount.c: fix_opts() */
+ assert((cxt->flags & MNT_FL_MOUNTOPTS_FIXED));
+
+ /* all propagation mounts are in cxt->addmount */
+ return !list_empty(&cxt->addmounts)
+ && (cxt->mountflags == 0 || cxt->mountflags == MS_SILENT)
+ && cxt->fs
+ && (!cxt->fs->fstype || strcmp(cxt->fs->fstype, "none") == 0)
+ && (!cxt->fs->source || strcmp(cxt->fs->source, "none") == 0);
}
/**
* Global libmount status.
*
* The real exit code of the mount.type helper has to be tested by
- * mnt_context_get_helper_status(). The mnt_context_get_status() only inform
- * that exec() has been sucessful.
+ * mnt_context_get_helper_status(). The mnt_context_get_status() only informs
+ * that exec() has been successful.
*
* Returns: 1 if mount.type or mount(2) syscall has been successfully called.
*/
int mnt_context_get_status(struct libmnt_context *cxt)
{
- return cxt && (!cxt->syscall_status || !cxt->helper_exec_status);
+ return !cxt->syscall_status || !cxt->helper_exec_status;
}
/**
{
if (cxt->syscall_status < 0)
return -cxt->syscall_status;
-
return 0;
}
*
* The @status should be 0 on success, or negative number on error (-errno).
*
- * This function should be used only if [u]mount(2) syscall is NOT called by
+ * This function should only be used if the [u]mount(2) syscall is NOT called by
* libmount code.
*
* Returns: 0 or negative number in case of error.
if (!cxt)
return -EINVAL;
- DBG(CXT, mnt_debug_h(cxt, "syscall status set to: %d", status));
+ DBG(CXT, ul_debugobj(cxt, "syscall status set to: %d", status));
cxt->syscall_status = status;
return 0;
}
* @action: MNT_ACT_{UMOUNT,MOUNT}
* @flags: not used now
*
- * This function infors libmount that used from [u]mount.type helper.
+ * This function informs libmount that used from [u]mount.type helper.
*
* The function also calls mnt_context_disable_helpers() to avoid recursive
* mount.type helpers calling. It you really want to call another
- * mount.type helper from your helper than you have to explicitly enable this
+ * mount.type helper from your helper, then you have to explicitly enable this
* feature by:
*
* mnt_context_disable_helpers(cxt, FALSE);
int mnt_context_init_helper(struct libmnt_context *cxt, int action,
int flags __attribute__((__unused__)))
{
- int rc = mnt_context_disable_helpers(cxt, TRUE);
+ int rc;
+ if (!cxt)
+ return -EINVAL;
+
+ rc = mnt_context_disable_helpers(cxt, TRUE);
if (!rc)
rc = set_flag(cxt, MNT_FL_HELPER, 1);
if (!rc)
cxt->action = action;
- DBG(CXT, mnt_debug_h(cxt, "initialized for [u]mount.<type> helper [rc=%d]", rc));
+ DBG(CXT, ul_debugobj(cxt, "initialized for [u]mount.<type> helper [rc=%d]", rc));
return rc;
}
* @c: getopt() result
* @arg: getopt() optarg
*
- * This function applies [u]mount.type command line option (for example parsed
+ * This function applies the [u]mount.type command line option (for example parsed
* by getopt or getopt_long) to @cxt. All unknown options are ignored and
* then 1 is returned.
*
* @fs: filesystem
* @mounted: returns 1 for mounted and 0 for non-mounted filesystems
*
+ * Please, read the mnt_table_is_fs_mounted() description!
+ *
* Returns: 0 on success and negative number in case of error.
*/
int mnt_context_is_fs_mounted(struct libmnt_context *cxt,
if (!pids)
return -ENOMEM;
- DBG(CXT, mnt_debug_h(cxt, "add new child %d", pid));
+ DBG(CXT, ul_debugobj(cxt, "add new child %d", pid));
cxt->children = pids;
cxt->children[cxt->nchildren++] = pid;
int rc = 0;
pid_t pid;
+ assert(cxt);
if (!mnt_context_is_parent(cxt))
return -EINVAL;
- DBG(CXT, mnt_debug_h(cxt, "forking context"));
+ DBG(CXT, ul_debugobj(cxt, "forking context"));
DBG_FLUSH;
switch (pid) {
case -1: /* error */
- DBG(CXT, mnt_debug_h(cxt, "fork failed %m"));
+ DBG(CXT, ul_debugobj(cxt, "fork failed %m"));
return -errno;
case 0: /* child */
cxt->pid = getpid();
mnt_context_enable_fork(cxt, FALSE);
- DBG(CXT, mnt_debug_h(cxt, "child created"));
+ DBG(CXT, ul_debugobj(cxt, "child created"));
break;
default:
if (!pid)
continue;
do {
- DBG(CXT, mnt_debug_h(cxt,
+ DBG(CXT, ul_debugobj(cxt,
"waiting for child (%d/%d): %d",
i + 1, cxt->nchildren, pid));
errno = 0;
mnt_context_set_target(cxt, argv[idx++]);
}
- /* this is unnecessary! -- libmount is able to internaly
+ /* this is unnecessary! -- libmount is able to internally
* create and manage the lock
*/
lock = mnt_context_get_lock(cxt);
rc = mnt_context_mount(cxt);
if (rc)
- printf("failed to mount: %m\n");
+ warn("failed to mount");
else
printf("successfully mounted\n");
return -ENOMEM;
if (argc > 2) {
- if (!strcmp(argv[idx], "-O")) {
+ if (argv[idx] && !strcmp(argv[idx], "-O")) {
mnt_context_set_options_pattern(cxt, argv[idx + 1]);
idx += 2;
}
- if (!strcmp(argv[idx], "-t")) {
+ if (argv[idx] && !strcmp(argv[idx], "-t")) {
mnt_context_set_fstype_pattern(cxt, argv[idx + 1]);
idx += 2;
}