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