ruid = getuid();
euid = geteuid();
+ cxt->syscall_status = 1; /* not called yet */
+ cxt->helper_exec_status = 1;
+
/* if we're really root and aren't running setuid */
cxt->restricted = (uid_t) 0 == ruid && ruid == euid ? 0 : 1;
cxt->fs = NULL;
cxt->mtab = NULL;
+ cxt->ambi = 0;
cxt->helper = NULL;
cxt->orig_user = NULL;
cxt->mountflags = 0;
cxt->user_mountflags = 0;
cxt->mountdata = NULL;
cxt->flags = MNT_FL_DEFAULT;
- cxt->syscall_errno = 0;
+ cxt->syscall_status = 1;
+ cxt->helper_exec_status = 1;
cxt->helper_status = 0;
/* restore non-resetable flags */
*/
int mnt_context_set_fstype(mnt_context *cxt, const char *fstype)
{
+ if (fstype && strchr(fstype, ','))
+ return -EINVAL;
return mnt_fs_set_fstype(mnt_context_get_fs(cxt), fstype);
}
goto done;
if (cxt->flags & MS_REMOUNT)
goto none;
+ if (cxt->fstype_pattern)
+ goto done;
+
dev = mnt_fs_get_srcpath(cxt->fs);
if (!dev)
goto err;
if (rc)
goto err;
done:
- DBG(CXT, mnt_debug_h(cxt, "detected FS type: %s",
+ DBG(CXT, mnt_debug_h(cxt, "FS type: %s",
mnt_fs_get_fstype(cxt->fs)));
return 0;
none:
return rc;
}
+/**
+ * mnt_context_apply_fstab:
+ * @cxt: mount context
+ *
+ * This function is optional if mnt_context_do_mount() is used. See also
+ * mnt_context_set_optsmode().
+ *
+ * Returns: 0 on success, negative number in case of error.
+ */
int mnt_context_apply_fstab(mnt_context *cxt)
{
int rc;
goto err;
}
return 0;
-
err:
DBG(CXT, mnt_debug_h(cxt, "failed to found entry in fstab/mtab"));
return rc;
}
+/**
+ * mnt_context_get_status:
+ * @cxt: mount context
+ *
+ * Returns: 1 if mount.<type> or mount(2) syscall was successfull or 0.
+ */
+int mnt_context_get_status(mnt_context *cxt)
+{
+ return cxt && (!cxt->syscall_status || !cxt->helper_exec_status);
+}
+
/**
* mnt_context_strerror
* @cxt: context
type = mnt_fs_get_fstype(cxt->fs);
- args[i++] = cxt->helper; /* 1 */
- args[i++] = mnt_fs_get_srcpath(cxt->fs); /* 2 */
+ args[i++] = cxt->helper; /* 1 */
+ args[i++] = mnt_fs_get_srcpath(cxt->fs);/* 2 */
args[i++] = mnt_fs_get_target(cxt->fs); /* 3 */
if (cxt->flags & MNT_FL_SLOPPY)
DBG(CXT, mnt_debug_h(cxt, "%s executed [status=%d]",
cxt->helper, cxt->helper_status));
- rc = 0;
+ cxt->helper_exec_status = rc = 0;
break;
}
case -1:
- rc = -errno;
+ cxt->helper_exec_status = rc = -errno;
DBG(CXT, mnt_debug_h(cxt, "fork() failed"));
break;
}
*/
static int do_mount(mnt_context *cxt, const char *try_type)
{
- int rc;
+ int rc = 0;
const char *src, *target, *type;
unsigned long flags;
assert(cxt->fs);
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
+
if (try_type && !cxt->helper) {
rc = mnt_context_prepare_helper(cxt, "mount", try_type);
if (!rc)
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;
+ type = try_type ? : mnt_fs_get_fstype(cxt->fs);
+
if (!(flags & MS_MGC_MSK))
flags |= MS_MGC_VAL;
if (!(cxt->flags & MNT_FL_FAKE)) {
if (mount(src, target, type, flags, cxt->mountdata)) {
- cxt->syscall_errno = errno;
+ cxt->syscall_status = -errno;
DBG(CXT, mnt_debug_h(cxt, "mount(2) failed [errno=%d]",
- cxt->syscall_errno));
- return -cxt->syscall_errno;
+ -cxt->syscall_status));
+ return cxt->syscall_status;
}
DBG(CXT, mnt_debug_h(cxt, "mount(2) success"));
+ cxt->syscall_status = 0;
}
- return 0;
+
+ if (try_type && cxt->update) {
+ mnt_fs *fs = mnt_update_get_fs(cxt->update);
+ if (fs)
+ rc = mnt_fs_set_fstype(fs, try_type);
+ }
+ return rc;
+}
+
+static int do_mount_by_pattern(mnt_context *cxt, const char *pattern)
+{
+ int neg = pattern && strncmp(pattern, "no", 2) == 0;
+ int rc = -EINVAL;
+ char **filesystems, **fp;
+
+ assert(cxt);
+
+ if (!neg && pattern) {
+ /*
+ * try all types from the list
+ */
+ char *p, *p0;
+
+ p0 = p = strdup(pattern);
+ if (!p)
+ return -ENOMEM;
+ do {
+ char *end = strchr(p, ',');
+ if (end)
+ *end = '\0';
+ rc = do_mount(cxt, p);
+ p = end ? end + 1 : NULL;
+ } while (!mnt_context_get_status(cxt) && p);
+
+ free(p0);
+
+ if (mnt_context_get_status(cxt))
+ return rc;
+ }
+
+ /*
+ * try /etc/filesystems and /proc/filesystems
+ */
+ rc = mnt_get_filesystems(&filesystems, neg ? pattern : NULL);
+ if (rc)
+ return rc;
+
+ for (fp = filesystems; *fp; fp++) {
+ rc = do_mount(cxt, *fp);
+ if (mnt_context_get_status(cxt))
+ break;
+ }
+ mnt_free_filesystems(filesystems);
+ return rc;
}
/**
*
* See also mnt_context_disable_helpers().
*
- * Returns: 0 on success, and negative number in case of error.
+ * Returns: 0 on success, and negative number in case of error. WARNING: error
+ * does not mean that mount(2) syscall or mount.<type> helper wasn't
+ * sucessfully called. Check mnt_context_get_status() after error!
*/
int mnt_context_do_mount(mnt_context *cxt)
{
- int rc = -EINVAL;
+ int rc = -EINVAL, x;
const char *type;
assert(cxt);
assert(cxt->fs);
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
+ assert(cxt->helper_exec_status == 1);
+ assert(cxt->syscall_status == 1);
if (!cxt || !cxt->fs || (cxt->fs->flags & MNT_FS_SWAP))
return -EINVAL;
cxt->mountdata = (char *) mnt_fs_get_fs_optstr(cxt->fs);
type = mnt_fs_get_fstype(cxt->fs);
-
- if (type && !strchr(type, ',')) {
+ if (type)
rc = do_mount(cxt, NULL);
- if (rc)
- return rc;
- }
-
- /* TODO: try all filesystems from comma separated list of types */
-
- /* TODO: try all filesystems from /proc/filesystems and /etc/filesystems */
+ else
+ rc = do_mount_by_pattern(cxt, cxt->fstype_pattern);
/* TODO: if mtab update is expected then check if the
* target is really mounted read-write to avoid 'ro' in
* mtab and 'rw' in /proc/mounts.
*/
- return mnt_context_update_tabs(cxt);
+ x = mnt_context_update_tabs(cxt);
+ return rc ? rc : x;
}
assert(cxt->fs);
assert(cxt->helper);
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
+ assert(cxt->helper_exec_status == 1);
DBG_FLUSH;
DBG(CXT, mnt_debug_h(cxt, "%s executed [status=%d]",
cxt->helper, cxt->helper_status));
- rc = 0;
+ cxt->helper_exec_status = rc = 0;
break;
}
case -1:
- rc = -errno;
+ cxt->helper_exec_status = rc = -errno;
DBG(CXT, mnt_debug_h(cxt, "fork() failed"));
break;
}
assert(cxt);
assert(cxt->fs);
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
+ assert(cxt->syscall_status == 1);
if (cxt->helper)
return exec_helper(cxt);
rc = umount(target);
if (rc < 0)
- cxt->syscall_errno = errno;
-
+ cxt->syscall_status = -errno;
/*
* try remount read-only
*/
- if (rc < 0 && cxt->syscall_errno == EBUSY &&
+ if (rc < 0 && cxt->syscall_status == -EBUSY &&
(cxt->flags & MNT_FL_RDONLY_UMOUNT) && src) {
cxt->mountflags |= MS_REMOUNT | MS_RDONLY;
cxt->flags &= ~MNT_FL_LOOPDEL;
DBG(CXT, mnt_debug_h(cxt, "umount(2) failed [errno=%d] -- "
"tring remount read-only",
- cxt->syscall_errno));
+ -cxt->syscall_status));
rc = mount(src, target, NULL,
MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
if (rc < 0) {
- cxt->syscall_errno = errno;
+ cxt->syscall_status = -errno;
DBG(CXT, mnt_debug_h(cxt, "read-only re-mount(2) failed "
"[errno=%d]",
- cxt->syscall_errno));
- return -cxt->syscall_errno;
+ -cxt->syscall_status));
+ return cxt->syscall_status;
}
- cxt->syscall_errno = 0;
+ cxt->syscall_status = 0;
DBG(CXT, mnt_debug_h(cxt, "read-only re-mount(2) success"));
return 0;
}
if (rc < 0) {
DBG(CXT, mnt_debug_h(cxt, "umount(2) failed [errno=%d]",
- cxt->syscall_errno));
- return -cxt->syscall_errno;
+ -cxt->syscall_status));
+ return -cxt->syscall_status;
}
DBG(CXT, mnt_debug_h(cxt, "umount(2) success"));
return 0;
extern const char *mnt_get_mtab_path(void);
extern const char *mnt_get_utab_path(void);
+extern int mnt_get_filesystems(char ***filesystems, const char *pattern);
+extern void mnt_free_filesystems(char **filesystems);
+
extern int mnt_has_regular_mtab(const char **mtab, int *writable);
extern int mnt_has_regular_utab(const char **utab, int *writable);
extern int mnt_context_get_userspace_mountflags(mnt_context *cxt, unsigned long *flags);
extern int mnt_context_set_mountdata(mnt_context *cxt, void *data);
extern int mnt_context_apply_fstab(mnt_context *cxt);
+extern int mnt_context_get_status(mnt_context *cxt);
/*
* mount(8) userspace options masks (MNT_MAP_USERSPACE map)
char *helper; /* name of the used /sbin/[u]mount.<type> helper */
int helper_status; /* helper wait(2) status */
+ int helper_exec_status; /* 1: not called yet, 0: success, <0: -errno */
char *orig_user; /* original (non-fixed) user= option */
- int syscall_errno; /* mount(2) or umount(2) error */
+ int syscall_status; /* 1: not called yet, 0: success, <0: -errno */
};
/* flags */
extern int mnt_context_merge_mountflags(mnt_context *cxt);
extern int mnt_context_update_tabs(mnt_context *cxt);
+/* tab_update.c */
+extern mnt_fs *mnt_update_get_fs(mnt_update *upd);
+
#endif /* _LIBMOUNT_PRIVATE_H */
return 0;
}
+/*
+ * Returns update filesystem or NULL
+ */
+mnt_fs *mnt_update_get_fs(mnt_update *upd)
+{
+ return upd ? upd->fs : NULL;
+}
/*
* Allocates (but does not write) utab entry for mount/remount. This function
return 1;
}
+void mnt_free_filesystems(char **filesystems)
+{
+ char **p;
+
+ if (!filesystems)
+ return;
+ for (p = filesystems; *p; p++)
+ free(*p);
+ free(filesystems);
+}
+
+static int add_filesystem(char ***filesystems, char *name)
+{
+ int n = 0;
+
+ assert(filesystems);
+ assert(name);
+
+ if (*filesystems) {
+ char **p;
+ for (n = 0, p = *filesystems; *p; p++, n++) {
+ if (strcmp(*p, name) == 0)
+ return 0;
+ }
+ }
+
+ #define MYCHUNK 16
+
+ if (n == 0 || !((n + 1) % MYCHUNK)) {
+ size_t items = ((n + 1 + MYCHUNK) / MYCHUNK) * MYCHUNK;
+ char **x = realloc(*filesystems, items * sizeof(char *));
+
+ if (!x)
+ goto err;
+ *filesystems = x;
+ }
+ name = strdup(name);
+ if (!name)
+ goto err;
+ (*filesystems)[n] = name;
+ (*filesystems)[n + 1] = NULL;
+ return 0;
+err:
+ mnt_free_filesystems(*filesystems);
+ return -ENOMEM;
+}
+
+static int get_filesystems(const char *filename, char ***filesystems, const char *pattern)
+{
+ FILE *f;
+ char line[128];
+
+ f = fopen(filename, "r");
+ if (!f)
+ return 0;
+
+ while (fgets(line, sizeof(line), f)) {
+ char name[sizeof(line)];
+ int rc;
+
+ if (*line == '#' || strncmp(line, "nodev", 5) == 0)
+ continue;
+ if (sscanf(line, " %128[^\n ]\n", name) != 1)
+ continue;
+ if (pattern && !mnt_match_fstype(name, pattern))
+ continue;
+ rc = add_filesystem(filesystems, name);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
+int mnt_get_filesystems(char ***filesystems, const char *pattern)
+{
+ int rc;
+
+ if (!filesystems)
+ return -EINVAL;
+ *filesystems = NULL;
+
+ rc = get_filesystems(_PATH_FILESYSTEMS, filesystems, pattern);
+ if (rc)
+ return rc;
+ return get_filesystems(_PATH_PROC_FILESYSTEMS, filesystems, pattern);
+}
+
/*
* Returns allocated string with username or NULL.
*/
return 0;
}
+int test_filesystems(struct mtest *ts, int argc, char *argv[])
+{
+ char **filesystems = NULL;
+ int rc;
+
+ rc = mnt_get_filesystems(&filesystems, argc ? argv[1] : NULL);
+ if (!rc) {
+ char **p;
+ for (p = filesystems; *p; p++)
+ printf("%s\n", *p);
+ mnt_free_filesystems(filesystems);
+ }
+ return rc;
+}
+
int main(int argc, char *argv[])
{
struct mtest tss[] = {
{ "--match-fstype", test_match_fstype, "<type> <pattern> FS types matching" },
{ "--match-options", test_match_options, "<options> <pattern> options matching" },
+ { "--filesystems", test_filesystems, "[<pattern>] list /{etc,proc}/filesystems" },
{ "--starts-with", test_startswith, "<string> <prefix>" },
{ "--ends-with", test_endswith, "<string> <prefix>" },
{ "--mountpoint", test_mountpoint, "<path>" },