From f58168ffb6facb095ec3c618513ed49d730d7488 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 29 Sep 2010 23:42:43 +0200 Subject: [PATCH] libmount: add mount(2) and /sbin/mount. support Signed-off-by: Karel Zak --- shlibs/mount/src/cache.c | 12 +- shlibs/mount/src/context.c | 305 +++++++++++++++++++++++++++++++----- shlibs/mount/src/mount.h.in | 2 +- shlibs/mount/src/mountP.h | 3 + 4 files changed, 281 insertions(+), 41 deletions(-) diff --git a/shlibs/mount/src/cache.c b/shlibs/mount/src/cache.c index fe05feba..c8fd8e77 100644 --- a/shlibs/mount/src/cache.c +++ b/shlibs/mount/src/cache.c @@ -402,16 +402,18 @@ char *mnt_cache_find_tag_value(mnt_cache *cache, /** * mnt_get_fstype: * @devname: device name + * @ambi: returns TRUE if probing result is ambivalent (optional argument) * @cache: cache for results or NULL * * Returns: fileststem type or NULL in case of error. The result has to be * deallocated by free() if @cache is NULL. */ -char *mnt_get_fstype(const char *devname, mnt_cache *cache) +char *mnt_get_fstype(const char *devname, int *ambi, mnt_cache *cache) { blkid_probe pr; const char *data; char *type = NULL; + int rc; if (cache) return mnt_cache_find_tag_value(cache, devname, "TYPE"); @@ -423,10 +425,14 @@ char *mnt_get_fstype(const char *devname, mnt_cache *cache) blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE); - if (!blkid_do_safeprobe(pr) && - !blkid_probe_lookup_value(pr, "TYPE", &data, NULL)) + rc = blkid_do_safeprobe(pr); + + if (!rc && !blkid_probe_lookup_value(pr, "TYPE", &data, NULL)) type = strdup(data); + if (ambi) + *ambi = rc == -2 ? TRUE : FALSE; + blkid_free_probe(pr); return type; } diff --git a/shlibs/mount/src/context.c b/shlibs/mount/src/context.c index 23593ac5..a6cc8688 100644 --- a/shlibs/mount/src/context.c +++ b/shlibs/mount/src/context.c @@ -13,6 +13,9 @@ #include #include +#include +#include + #ifdef HAVE_LIBSELINUX #include #include @@ -49,6 +52,12 @@ struct _mnt_context mnt_cache *cache; /* paths cache */ int flags; /* private context flags */ + int ambi; /* libblkid returns ambivalent result */ + + char *helper_name; /* name of the used /sbin/[u]mount. helper */ + int helper_status; /* helper wait(2) status */ + + int syscall_errno; /* mount(2) or umount(2) error */ }; /* flags */ @@ -124,6 +133,7 @@ void mnt_free_context(mnt_context *cxt) free(cxt->fstype_pattern); free(cxt->optstr_pattern); free(cxt->spec); + free(cxt->helper_name); if (!(cxt->flags & MNT_FL_EXTERN_FS)) mnt_free_fs(cxt->fs); @@ -178,12 +188,17 @@ int mnt_reset_context(mnt_context *cxt) cxt->mtab = NULL; free(cxt->spec); + free(cxt->helper_name); + cxt->spec = NULL; + cxt->helper_name = NULL; cxt->mountflags = 0; cxt->user_mountflags = 0; cxt->mountdata = NULL; cxt->flags = MNT_FL_DEFAULT; + cxt->syscall_errno = 0; + cxt->helper_status = 0; /* restore non-resetable flags */ cxt->flags |= (fl & MNT_FL_EXTERN_FSTAB); @@ -926,6 +941,9 @@ static int mnt_context_fix_optstr(mnt_context *cxt) 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; /* * Sync mount options with mount flags */ @@ -1103,17 +1121,17 @@ static int mnt_context_prepare_srcpath(mnt_context *cxt) return 0; } -static int mnt_context_detect_fstype(mnt_context *cxt) +static int mnt_context_guess_fstype(mnt_context *cxt) { - char *type = NULL; + char *type; + const char *dev; + mnt_cache *cache; if (!cxt || !cxt->fs) return -EINVAL; - if (cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION)) { - mnt_fs_set_fstype(cxt->fs, "none"); - return 0; - } + if (cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION)) + goto none; type = (char *) mnt_fs_get_fstype(cxt->fs); if (type && !strcmp(type, "auto")) { @@ -1121,24 +1139,30 @@ static int mnt_context_detect_fstype(mnt_context *cxt) type = NULL; } - if (!type && !(cxt->flags & MS_REMOUNT)) { - mnt_cache *cache; - const char *dev = mnt_fs_get_srcpath(cxt->fs); - - if (!dev) - return -EINVAL; - - cache = mnt_context_get_cache(cxt); - type = mnt_get_fstype(dev, cache); + if (type) + goto done; + if (cxt->flags & MS_REMOUNT) + goto none; + dev = mnt_fs_get_srcpath(cxt->fs); + if (!dev) + goto err; - if (!type) - return -EINVAL; - mnt_fs_set_fstype(cxt->fs, type); - if (!cache) - free(type); /* type is not cached */ - } + cache = mnt_context_get_cache(cxt); + type = mnt_get_fstype(dev, &cxt->ambi, cache); + if (!type) + goto err; + mnt_fs_set_fstype(cxt->fs, type); + if (!cache) + free(type); /* type is not cached */ +done: + DBG(CXT, mnt_debug_h(cxt, "detected FS type: %s", type)); return 0; +none: + return mnt_fs_set_fstype(cxt->fs, "none"); +err: + DBG(CXT, mnt_debug_h(cxt, "failed to detect FS type")); + return -EINVAL; } static int mnt_context_merge_mountflags(mnt_context *cxt) @@ -1165,17 +1189,22 @@ static int mnt_context_prepare_update(mnt_context *cxt, int act) { int rc; - if (cxt->update) { - mnt_free_update(cxt->update); - cxt->update = NULL; - } - if (cxt->flags & MNT_FL_NOMTAB) return 0; - cxt->update = mnt_new_update(act, cxt->mountflags, cxt->fs); - if (!cxt->update) - return -ENOMEM; + if (!cxt->update) { + cxt->update = mnt_new_update(act, cxt->mountflags, cxt->fs); + if (!cxt->update) + return -ENOMEM; + } else { + rc = mnt_update_set_action(cxt->update, act); + if (!rc) + rc = mnt_update_set_mountflags(cxt->update, cxt->mountflags); + if (!rc) + rc = mnt_update_set_fs(cxt->update, cxt->fs); + if (rc) + return rc; + } if (cxt->flags & MNT_FL_NOLOCK) mnt_update_disable_lock(cxt->update, TRUE); @@ -1264,7 +1293,7 @@ int mnt_context_prepare_mount(mnt_context *cxt) if (rc) goto err; - rc = mnt_context_detect_fstype(cxt); + rc = mnt_context_guess_fstype(cxt); if (rc) goto err; @@ -1272,7 +1301,6 @@ int mnt_context_prepare_mount(mnt_context *cxt) if (rc) goto err; - DBG(CXT, mnt_debug_h(cxt, "sucessfully prepared")); return 0; err: @@ -1280,15 +1308,216 @@ err: return rc; } +static int exec_mount_helper(mnt_context *cxt, const char *prog, + const char *subtype) +{ + DBG_FLUSH; + + switch (fork()) { + case 0: + { + char *o; + const char *args[12]; + int i = 0; + + if (setgid(getgid()) < 0) + exit(EXIT_FAILURE); + + if (setuid(getuid()) < 0) + exit(EXIT_FAILURE); + + o = (char *) mnt_fs_get_fs_optstr(cxt->fs); + + args[i++] = prog; /* 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 (subtype) { + args[i++] = "-t"; /* 10 */ + args[i++] = subtype; /* 11 */ + } + args[i] = NULL; /* 12 */ + + execv(prog, (char * const *) args); + exit(EXIT_FAILURE); + } + default: + { + int st; + wait(&st); + cxt->helper_status = WIFEXITED(st) ? WEXITSTATUS(st) : -1; + cxt->helper_name = strdup(prog); + + DBG(CXT, mnt_debug_h(cxt, "%s executed [status=%d]", + prog, cxt->helper_status)); + return 0; + } + + case -1: + DBG(CXT, mnt_debug_h(cxt, "fork() failed")); + return -errno; + } +} + +/* + * Returns: 0 on success, 1 if helper not found and negative number in case of + * error. + */ +static int mnt_context_call_helper(mnt_context *cxt, + const char *name, const char *type) +{ + char search_path[] = FS_SEARCH_PATH; /* from config.h */ + char *p = NULL, *path; + + assert(cxt); + + if (!(cxt->flags & MNT_FL_NOHELPERS) || + !type || !strcmp(type, "none")) + return 1; + + path = strtok_r(search_path, ":", &p); + while (path) { + char helper[PATH_MAX]; + struct stat st; + const char *subtype = NULL; + int rc; + + rc = snprintf(helper, sizeof(helper), "%s/%s.%s", + name, path, type); + path = strtok_r(NULL, ":", &p); + + if (rc >= sizeof(helper) || rc < 0) + continue; + + rc = stat(helper, &st); + if (rc == -1 && errno == ENOENT && strchr(type, '.')) { + /* If type ends with ".subtype" try without it */ + *strrchr(helper, '.') = '\0'; + subtype = type; + rc = stat(helper, &st); + } + if (rc) + continue; + + return exec_mount_helper(cxt, helper, subtype); + } + + DBG(CXT, mnt_debug_h(cxt, "%s.%s helper not found", name, type)); + return 1; +} + +static int mnt_context_do_mount(mnt_context *cxt, const char *type) +{ + int rc; + const char *src, *target; + unsigned long flags; + + assert(cxt); + assert(type); + assert(cxt->fs); + + flags = cxt->mountflags; + src = mnt_fs_get_srcpath(cxt->fs); + target = mnt_fs_get_target(cxt->fs); + + DBG(CXT, mnt_debug_h(cxt, + "mounting [fstype=%s, source=%s, target=%s, " + "fs_optstr='%s', vfs_optstr='%s', " + "mountflags=%08lx, mountdata=%s", + + type, src, target, + mnt_fs_get_fs_optstr(cxt->fs), + mnt_fs_get_vfs_optstr(cxt->fs), + flags, + cxt->mountdata ? "yes" : "")); + + rc = mnt_context_call_helper(cxt, "mount", type); + if (rc <= 0) + return rc; + + if (!src || !target) + return -EINVAL; + + if (!(flags & MS_MGC_MSK)) + flags |= MS_MGC_VAL; + + DBG(CXT, mnt_debug_h(cxt, "calling mount(2)")); + + 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.). + * + * 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) { - if (!cxt) + int rc = -EINVAL; + const char *type; + + if (!cxt || !cxt->fs || (cxt->fs->flags & MNT_FS_SWAP)) return -EINVAL; - DBG(CXT, mnt_debug_h(cxt, "mounting:")); - DBG(CXT, mnt_fs_print_debug(cxt->fs, stderr)); - DBG(CXT, mnt_debug_h(cxt, "mountflags: 0x%lx", cxt->mountflags)); + type = mnt_fs_get_fstype(cxt->fs); + + if (!(cxt->flags & MNT_FL_MOUNTDATA)) + cxt->mountdata = (char *) mnt_fs_get_fs_optstr(cxt->fs); + + if (type && !strchr(type, ',')) + rc = mnt_context_do_mount(cxt, type); + + /* TODO: try all filesystems from comma separated list of types */ + + /* TODO: try all filesystems from /proc/filesystems and /etc/filesystems */ + + /* 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. + */ + + return rc; +} + +/* TODO: mnt_context_post_mount() */ +/** + * 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; } @@ -1328,11 +1557,13 @@ int test_mount(struct mtest *ts, int argc, char *argv[]) rc = mnt_context_prepare_mount(cxt); if (rc) - fprintf(stderr, "failed to prepare mount\n"); + printf("failed to prepare mount\n"); else { rc = mnt_context_mount_fs(cxt); if (rc) - fprintf(stderr, "failed to mount\n"); + printf("failed to mount\n"); + else + printf("successfully mounted"); } mnt_free_context(cxt); diff --git a/shlibs/mount/src/mount.h.in b/shlibs/mount/src/mount.h.in index 041be62e..cf491151 100644 --- a/shlibs/mount/src/mount.h.in +++ b/shlibs/mount/src/mount.h.in @@ -149,7 +149,7 @@ extern char *mnt_cache_find_tag_value(mnt_cache *cache, extern char *mnt_resolve_path(const char *path, mnt_cache *cache); extern char *mnt_resolve_tag(const char *token, const char *value, mnt_cache *cache); extern char *mnt_resolve_spec(const char *spec, mnt_cache *cache); -extern char *mnt_get_fstype(const char *devname, mnt_cache *cache); +extern char *mnt_get_fstype(const char *devname, int *ambi, mnt_cache *cache); /* optstr.c */ extern int mnt_optstr_next_option(char **optstr, char **name, size_t *namesz, diff --git a/shlibs/mount/src/mountP.h b/shlibs/mount/src/mountP.h index 289249e5..468e77a0 100644 --- a/shlibs/mount/src/mountP.h +++ b/shlibs/mount/src/mountP.h @@ -57,6 +57,8 @@ } \ } while(0) +# define DBG_FLUSH do { fflush(stderr); } while(0) + extern int libmount_debug_mask; static inline void __attribute__ ((__format__ (__printf__, 1, 2))) @@ -83,6 +85,7 @@ mnt_debug_h(void *handler, const char *mesg, ...) #else /* !CONFIG_LIBMOUNT_DEBUG */ # define DBG(m,x) +# define DBG_FLUSH #endif /* extension for files in the /etc/fstab.d directory */ -- 2.39.5