*/
#include "mountP.h"
+#include "fileutils.h"
#include <sys/wait.h>
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;
}
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;
}
*/
int mnt_context_reset_status(struct libmnt_context *cxt)
{
- assert(cxt);
if (!cxt)
return -EINVAL;
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);
*/
int mnt_context_set_optsmode(struct libmnt_context *cxt, int mode)
{
- assert(cxt);
if (!cxt)
return -EINVAL;
cxt->optsmode = mode;
int mnt_context_get_optsmode(struct libmnt_context *cxt)
{
- assert(cxt);
return cxt->optsmode;
}
*/
struct libmnt_fs *mnt_context_get_fs(struct libmnt_context *cxt)
{
- assert(cxt);
if (!cxt)
return NULL;
if (!cxt->fs)
*/
void *mnt_context_get_fs_userdata(struct libmnt_context *cxt)
{
- assert(cxt);
return cxt->fs ? mnt_fs_get_userdata(cxt->fs) : NULL;
}
*/
void *mnt_context_get_fstab_userdata(struct libmnt_context *cxt)
{
- assert(cxt);
return cxt->fstab ? mnt_table_get_userdata(cxt->fstab) : NULL;
}
*/
void *mnt_context_get_mtab_userdata(struct libmnt_context *cxt)
{
- assert(cxt);
return cxt->mtab ? mnt_table_get_userdata(cxt->mtab) : NULL;
}
* @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)
{
- assert(cxt);
return mnt_fs_set_source(mnt_context_get_fs(cxt), source);
}
*/
const char *mnt_context_get_source(struct libmnt_context *cxt)
{
- assert(cxt);
return mnt_fs_get_source(mnt_context_get_fs(cxt));
}
*/
int mnt_context_set_target(struct libmnt_context *cxt, const char *target)
{
- assert(cxt);
return mnt_fs_set_target(mnt_context_get_fs(cxt), target);
}
*/
const char *mnt_context_get_target(struct libmnt_context *cxt)
{
- assert(cxt);
return mnt_fs_get_target(mnt_context_get_fs(cxt));
}
*/
int mnt_context_set_fstype(struct libmnt_context *cxt, const char *fstype)
{
- assert(cxt);
return mnt_fs_set_fstype(mnt_context_get_fs(cxt), fstype);
}
*/
const char *mnt_context_get_fstype(struct libmnt_context *cxt)
{
- assert(cxt);
return mnt_fs_get_fstype(mnt_context_get_fs(cxt));
}
*/
int mnt_context_set_options(struct libmnt_context *cxt, const char *optstr)
{
- assert(cxt);
return mnt_fs_set_options(mnt_context_get_fs(cxt), optstr);
}
*/
int mnt_context_append_options(struct libmnt_context *cxt, const char *optstr)
{
- assert(cxt);
return mnt_fs_append_options(mnt_context_get_fs(cxt), optstr);
}
*/
const char *mnt_context_get_options(struct libmnt_context *cxt)
{
- assert(cxt);
return mnt_fs_get_options(mnt_context_get_fs(cxt));
}
{
char *p = NULL;
- assert(cxt);
if (!cxt)
return -EINVAL;
if (pattern) {
{
char *p = NULL;
- assert(cxt);
if (!cxt)
return -EINVAL;
if (pattern) {
*/
int mnt_context_set_fstab(struct libmnt_context *cxt, struct libmnt_table *tb)
{
- assert(cxt);
if (!cxt)
return -EINVAL;
*/
int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
{
- assert(cxt);
if (!cxt)
return -EINVAL;
if (!cxt->fstab) {
*/
int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
{
- assert(cxt);
if (!cxt)
return -EINVAL;
if (!cxt->mtab) {
int rc;
+ context_init_paths(cxt, 0);
+
cxt->mtab = mnt_new_table();
if (!cxt->mtab)
return -ENOMEM;
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 (*fltr)(struct libmnt_fs *, void *),
void *data)
{
- assert(cxt);
if (!cxt)
return -EINVAL;
{
int rc;
- assert(cxt);
- assert(tb);
if (!cxt || !tb)
return -EINVAL;
int mnt_context_set_tables_errcb(struct libmnt_context *cxt,
int (*cb)(struct libmnt_table *tb, const char *filename, int line))
{
- assert(cxt);
if (!cxt)
return -EINVAL;
*/
struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt)
{
- assert(cxt);
if (!cxt || mnt_context_is_nocanonicalize(cxt))
return NULL;
char *(*get)(struct libmnt_context *),
void (*release)(struct libmnt_context *, char *))
{
- assert(cxt);
if (!cxt)
return -EINVAL;
cxt->pwd_get_cb = get;
*/
struct libmnt_lock *mnt_context_get_lock(struct libmnt_context *cxt)
{
- assert(cxt);
/*
* DON'T call this function within libmount, it will always allocate
* the lock. The mnt_update_* functions are able to allocate the lock
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);
}
*/
int mnt_context_set_mflags(struct libmnt_context *cxt, unsigned long flags)
{
- assert(cxt);
if (!cxt)
return -EINVAL;
int rc = 0;
struct list_head *p;
- assert(cxt);
- assert(flags);
if (!cxt || !flags)
return -EINVAL;
{
int rc = 0;
- assert(cxt);
- assert(flags);
if (!cxt || !flags)
return -EINVAL;
*/
int mnt_context_set_mountdata(struct libmnt_context *cxt, void *data)
{
- assert(cxt);
if (!cxt)
return -EINVAL;
cxt->mountdata = data;
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 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 (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);
- int ambi = 0;
-
- type = mnt_get_fstype(dev, &ambi, cache);
- if (type) {
- rc = mnt_fs_set_fstype(cxt->fs, type);
- if (!cache)
- free(type); /* type is not cached */
- }
- if (ambi)
- rc = -MNT_ERR_AMBIFS;
- } else {
- DBG(CXT, ul_debugobj(cxt, "access(%s) failed [%m]", dev));
- 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, ul_debugobj(cxt, "FS type: %s [rc=%d]",
mnt_fs_get_fstype(cxt->fs), rc));
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, ul_debugobj(cxt, "skip update: NOMTAB flag"));
return 0;
}
- if (!cxt->mtab_writable && !cxt->utab_writable) {
+ if (!mnt_context_get_writable_tabpath(cxt)) {
DBG(CXT, ul_debugobj(cxt, "skip update: no writable destination"));
return 0;
}
}
if (!cxt->update) {
- const char *name = cxt->mtab_writable ? cxt->mtab_path : cxt->utab_path;
+ const char *name = mnt_context_get_writable_tabpath(cxt);
if (cxt->action == MNT_ACT_UMOUNT && is_file_empty(name)) {
DBG(CXT, ul_debugobj(cxt,
if (!cxt->update)
return -ENOMEM;
- mnt_update_set_filename(cxt->update, name, !cxt->mtab_writable);
+ mnt_update_set_filename(cxt->update, name,
+ !mnt_context_mtab_writable(cxt));
}
if (cxt->action == MNT_ACT_UMOUNT)
/* check utab update when external helper executed */
if (mnt_context_helper_executed(cxt)
&& mnt_context_get_helper_status(cxt) == 0
- && cxt->utab_writable) {
+ && 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"));
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_tab_applied(cxt)) /* already applied */
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);
return 0;
}
- DBG(CXT, ul_debugobj(cxt,
- "trying to apply fstab (src=%s, target=%s)", src, tgt));
-
/* let's initialize cxt->fs */
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, ul_debugobj(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, ul_debugobj(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;
}
*/
int mnt_context_tab_applied(struct libmnt_context *cxt)
{
- assert(cxt);
return cxt->flags & MNT_FL_TAB_APPLIED;
}
*/
int mnt_context_propagation_only(struct libmnt_context *cxt)
{
- assert(cxt);
- assert(cxt->fs);
-
if (cxt->action != MNT_ACT_MOUNT)
return 0;
*/
int mnt_context_get_status(struct libmnt_context *cxt)
{
- assert(cxt);
return !cxt->syscall_status || !cxt->helper_exec_status;
}
*/
int mnt_context_helper_executed(struct libmnt_context *cxt)
{
- assert(cxt);
return cxt->helper_exec_status != 1;
}
*/
int mnt_context_get_helper_status(struct libmnt_context *cxt)
{
- assert(cxt);
return cxt->helper_status;
}
*/
int mnt_context_syscall_called(struct libmnt_context *cxt)
{
- assert(cxt);
return cxt->syscall_status != 1;
}
*/
int mnt_context_get_syscall_errno(struct libmnt_context *cxt)
{
- assert(cxt);
if (cxt->syscall_status < 0)
return -cxt->syscall_status;
return 0;
*/
int mnt_context_set_syscall_status(struct libmnt_context *cxt, int status)
{
- assert(cxt);
if (!cxt)
return -EINVAL;
{
int rc;
- assert(cxt);
+ if (!cxt)
+ return -EINVAL;
rc = mnt_context_disable_helpers(cxt, TRUE);
if (!rc)
struct libmnt_table *mtab;
int rc;
- assert(cxt);
if (!cxt || !fs || !mounted)
return -EINVAL;
{
pid_t *pids;
- assert(cxt);
if (!cxt)
return -EINVAL;
{
int i;
- assert(cxt);
if (!cxt)
return -EINVAL;