From 6c40a53d97dbfa52bbdbbe86672322cb7bceb08d Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 5 Aug 2010 13:47:37 +0200 Subject: [PATCH] libmount: add support for mtab managment Signed-off-by: Karel Zak --- shlibs/mount/src/Makefile.am | 4 +- shlibs/mount/src/mountP.h | 8 - shlibs/mount/src/mtab.c | 965 +++++++++++++++++++++++++++++++++++ shlibs/mount/src/optstr.c | 2 +- 4 files changed, 968 insertions(+), 11 deletions(-) create mode 100644 shlibs/mount/src/mtab.c diff --git a/shlibs/mount/src/Makefile.am b/shlibs/mount/src/Makefile.am index 37a5177e..4576dd0c 100644 --- a/shlibs/mount/src/Makefile.am +++ b/shlibs/mount/src/Makefile.am @@ -11,7 +11,7 @@ nodist_mountinc_HEADERS = mount.h usrlib_exec_LTLIBRARIES = libmount.la libmount_la_SOURCES = mountP.h version.c utils.c test.c init.c cache.c \ optstr.c optmap.c optent.c optls.c iter.c lock.c \ - fs.c tab.c tab_parse.c \ + fs.c tab.c tab_parse.c mtab.c \ $(mountinc_HEADERS) \ $(top_srcdir)/lib/at.c \ $(top_srcdir)/include/list.h \ @@ -48,7 +48,7 @@ uninstall-hook: tests = test_version test_cache test_optstr test_optls test_lock \ - test_tab test_utils + test_tab test_utils test_mtab tests: all $(tests) test_%: %.c diff --git a/shlibs/mount/src/mountP.h b/shlibs/mount/src/mountP.h index ea6a87c5..bc584e3e 100644 --- a/shlibs/mount/src/mountP.h +++ b/shlibs/mount/src/mountP.h @@ -168,14 +168,6 @@ struct _mnt_fs { #define MNT_FS_PSEUDO (1 << 1) /* pseudo filesystem */ #define MNT_FS_NET (1 << 2) /* network filesystem */ -/* - * File format - */ -enum { - MNT_FMT_FSTAB = 1, /* /etc/{fs,m}tab */ - MNT_FMT_MOUNTINFO /* /proc/#/mountinfo */ -}; - /* * mtab/fstab/mountinfo file */ diff --git a/shlibs/mount/src/mtab.c b/shlibs/mount/src/mtab.c new file mode 100644 index 00000000..81b01f2b --- /dev/null +++ b/shlibs/mount/src/mtab.c @@ -0,0 +1,965 @@ +/* + * Copyright (C) 2010 Karel Zak + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +/** + * SECTION: mtab + * @title: mtab managment + * @short_description: userspace mount information management + * + * The libmount library allows to use more modes for mtab management: + * + * - /etc/mtab is regular file + * + * then libmount manages the file in classical way (all mounts are + * added to the file) + * + * - /etc/mtab is symlink + * + * then libmount ignores mtab at all + * + * - /etc/mtab is symlink and /var/run/mount/ directory exists + * + * then libmount stores userspace specific mount options to the + * /var/run/mount/mountinfo file (the file format compatible to + * /proc/self/mountinfo) + * + * + * The mtab is always updated in two steps. The first step is to prepare a new + * mtab entry -- mnt_mtab_prepare_update(), this step has to be done before + * mount(2) syscall. The second step is to update the mtab file -- + * mnt_update_mtab(), this step should be done after mount(2) syscall. + * + * The mnt_update_mtab() behaviour is undefined if mnt_mtab_prepare_update() has + * not been used. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "c.h" +#include "mountP.h" +#include "mangle.h" +#include "pathnames.h" + + + +/* + * mtab update description + */ +struct _mnt_mtab { + int action; /* MNT_ACT_{MOUNT,UMOUNT} */ + int mountflags; /* MS_* flags */ + char *filename; /* usually /etc/mtab or /var/run/mount/mountinfo */ + char *old_target; /* for MS_MOVE */ + int format; /* MNT_FMT_{MTAB,MOUNTINFO} */ + int nolock; /* don't alloca private mnt_lock */ + mnt_fs *fs; /* entry */ + mnt_lock *lc; /* lock or NULL */ +}; + +/** + * mnt_new_mtab: + * @action: MNT_ACT_{MOUNT,UMOUNT} + * + * Returns: newly allocated mtab description + */ +mnt_mtab *mnt_new_mtab(int action) +{ + mnt_mtab *mt; + + mt = calloc(1, sizeof(struct _mnt_mtab)); + if (!mt) + return NULL; + + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab %p: allocate\n", mt)); + + mt->action = action; + mt->fs = mnt_new_fs(); + if (!mt->fs) + goto err; + return mt; +err: + mnt_free_fs(mt->fs); + free(mt); + + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab: failed to allocate handler\n")); + + return NULL; +} + +/** + * mnt_free_mtab: + * @mt: mtab + * + * Deallocates mnt_mtab handler. + */ +void mnt_free_mtab(mnt_mtab *mt) +{ + if (!mt) + return; + + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab %p: deallacate\n", mt)); + + mnt_free_lock(mt->lc); + free(mt->filename); + free(mt); +} + +/** + * mnt_mtab_set_filename: + * @mt: mtab + * @filename: path to mtab (default is /etc/mtab or /var/run/mount/mountinfo) + * + * Returns: 0 on success, -1 in case of error. + */ +int mnt_mtab_set_filename(mnt_mtab *mt, const char *filename) +{ + char *p = NULL; + assert(mt); + + if (!mt) + return -1; + if (filename) { + p = strdup(filename); + if (!p) + return -1; + } + free(mt->filename); + mt->filename = p; + return 0; +} + +/** + * mnt_mtab_set_action: + * @mt: mtab + * @action: MNT_ACT_{MOUNT,UMOUNT} + * + * Overwrites the previously defined action by mnt_new_mtab(). + * + * Returns: 0 on success, -1 in case of error. + */ +int mnt_mtab_set_action(mnt_mtab *mt, int action) +{ + assert(mt); + if (!mt) + return -1; + mt->action = action; + return 0; +} + +/** + * mnt_mtab_set_format: + * @mt: mtab + * @format: MNT_FMT_{MTAB,MOUNTINFO} + * + * Sets mtab file format, default is MNT_FMT_MTAB for paths that end with + * "mtab" and MNT_FMT_MOUNTINFO for paths that end with "mountinfo". + * + * Returns: 0 on success, -1 in case of error. + */ +int mnt_mtab_set_format(mnt_mtab *mt, int format) +{ + assert(mt); + if (!mt) + return -1; + mt->format = format; + return 0; +} + +/** + * mnt_mtab_set_optstr: + * @mt: mtab + * @optstr: mount options that will be used for mount(2) + * + * Note that mnt_mtab_prepare_update() will remove options that does not belong + * to mtab. + * + * Returns: 0 on success, -1 in case of error. + */ +int mnt_mtab_set_optstr(mnt_mtab *mt, const char *optstr) +{ + if (!mt) + return -1; + return mnt_fs_set_optstr(mt->fs, optstr); +} + +/** + * mnt_mtab_set_mountflags: + * @mt: mtab + * @flags: MS_{REMOUNT,MOVE} + * + * Sets mount flags for mount/umount action. The flags are also + * extracted from mount options by mnt_mtab_prepare_update(). + * + * Returns: 0 on success, -1 in case of error. + */ +int mnt_mtab_set_mountflags(mnt_mtab *mt, int flags) +{ + assert(mt); + if (!mt) + return -1; + mt->mountflags = flags; + return 0; +} + +/** + * mnt_mtab_get_lock: + * @mt: mtab + * + * This function should not be called before mnt_mtab_prepare_update(). The lock + * is initialized when mtab update is required only. + * + * Note that after mnt_mtab_disable_lock(mt, TRUE) or after mnt_free_mtab() + * the lock will be automaticaly deallocated. + * + * Returns: libmount lock handler or NULL if locking is disabled. + */ +mnt_lock *mnt_mtab_get_lock(mnt_mtab *mt) +{ + return mt ? mt->lc : NULL; +} + +/** + * mnt_mtab_disable_lock: + * @mt: mtab + * @disable: TRUE/FALSE + * + * Enable or disable mtab locking, the locking is enabled by default. + * + * Returns: 0 on success, -1 in case of error. + */ +int mnt_mtab_disable_lock(mnt_mtab *mt, int disable) +{ + if (!mt) + return -1; + if (disable) { + mnt_free_lock(mt->lc); + mt->lc = NULL; + } + mt->nolock = disable; + return 0; +} + +/** + * mnt_mtab_set_source: + * @mt: mtab + * @source: device or directory name + * + * Returns: 0 on success, -1 in case of error. + */ +int mnt_mtab_set_source(mnt_mtab *mt, const char *source) +{ + return mt ? mnt_fs_set_source(mt->fs, source) : -1; +} + +/** + * mnt_mtab_set_target: + * @mt: mtab + * @target: mountpoint + * + * Returns: 0 on success, -1 in case of error. + */ +int mnt_mtab_set_target(mnt_mtab *mt, const char *target) +{ + return mt ? mnt_fs_set_target(mt->fs, target) : -1; +} + +/** + * mnt_mtab_set_old_target: + * @mt: mtab + * @target: old mountpoint + * + * Sets the original target for the MS_MOVE operation. + * + * Returns: 0 on success, -1 in case of error. + */ +int mnt_mtab_set_old_target(mnt_mtab *mt, const char *target) +{ + if (!mt) + return -1; + mt->old_target = strdup(target); + if (!mt->old_target) + return -1; + return 0; +} + +/** + * mnt_mtab_set_fstype: + * @mt: mtab + * @fstype: filesystem type (e.g. "ext3") + * + * Returns: 0 on success, -1 in case of error. + */ +int mnt_mtab_set_fstype(mnt_mtab *mt, const char *fstype) +{ + if (!mt) + return -1; + return mnt_fs_set_fstype(mt->fs, fstype); +} + + +/* + * The format is same as /proc/self/mountinfo, but it contains userspace + * mount options and some unncessary fields are ignored. + */ +static int fprintf_mountinfo_fs(FILE *f, mnt_fs *fs) +{ + char *root = NULL, *target = NULL, *optstr = NULL, + *fstype = NULL, *source = NULL; + int rc = -1; + dev_t devno; + + assert(fs); + assert(f); + + if (!fs || !f) + return -1; + devno = mnt_fs_get_devno(fs); + source = mangle(mnt_fs_get_source(fs)); + root = mangle(mnt_fs_get_root(fs)); + target = mangle(mnt_fs_get_target(fs)); + fstype = mangle(mnt_fs_get_fstype(fs)); + optstr = mangle(mnt_fs_get_optstr(fs)); + + if (!root || !target || !optstr) + goto done; + + rc = fprintf(f, "%i %i %u:%u %s %s %s - %s %s %s\n", + mnt_fs_get_id(fs), + mnt_fs_get_parent_id(fs), + major(devno), minor(devno), + root, + target, + optstr, + fstype ? fstype : "auto", + source ? source : "none", + "none"); + rc = 0; +done: + free(root); + free(target); + free(optstr); + free(fstype); + free(source); + return rc; +} + +static int fprintf_mtab_fs(FILE *f, mnt_fs *fs) +{ + char *m1 = NULL, *m2 = NULL, *m3 = NULL, *m4 = NULL; + int rc = -1; + + assert(fs); + assert(f); + + if (!fs || !f) + return -1; + + m1 = mangle(mnt_fs_get_source(fs)); + m2 = mangle(mnt_fs_get_target(fs)); + m3 = mangle(mnt_fs_get_fstype(fs)); + m4 = mangle(mnt_fs_get_optstr(fs)); + + if (!m1 || !m2 || !m3 || !m4) + goto done; + + rc = fprintf(f, "%s %s %s %s %d %d\n", + m1, m2, m3, m4, + mnt_fs_get_freq(fs), + mnt_fs_get_passno(fs)); + rc = 0; +done: + free(m1); + free(m2); + free(m3); + free(m4); + + return rc; +} + +static int update_file(const char *filename, int fmt, mnt_tab *tb) +{ + mnt_iter itr; + mnt_fs *fs; + FILE *f = NULL; + char tmpname[PATH_MAX]; + struct stat st; + int fd; + int (*line_fn)(FILE *, mnt_fs *); + + assert(tb); + if (!tb) + goto error; + + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab %s: update from tab %p\n", filename, tb)); + + if (snprintf(tmpname, sizeof(tmpname), "%s.tmp", filename) + >= sizeof(tmpname)) + goto error; + + f = fopen(tmpname, "w"); + if (!f) + goto error; + + line_fn = fmt == MNT_FMT_MTAB ? fprintf_mtab_fs : fprintf_mountinfo_fs; + + mnt_reset_iter(&itr, MNT_ITER_FORWARD); + while(mnt_tab_next_fs(tb, &itr, &fs) == 0) + line_fn(f, fs); + + fd = fileno(f); + + if (fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) + goto error; + + /* Copy uid/gid from the present file before renaming. */ + if (stat(filename, &st) == 0) { + if (fchown(fd, st.st_uid, st.st_gid) < 0) + goto error; + } + + fclose(f); + f = NULL; + + if (rename(tmpname, filename) < 0) + goto error; + + return 0; +error: + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab %s: update from tab %p failed\n", filename, tb)); + if (f) + fclose(f); + return -1; +} + +static int set_fs_root(mnt_mtab *mt, mnt_fs *fs) +{ + char *root = NULL, *mnt = NULL; + const char *fstype; + char *optstr; + mnt_tab *tb = NULL; + + if (mt->mountflags & MS_REMOUNT) + return 0; + + optstr = (char *) mnt_fs_get_optstr(fs); + fstype = mnt_fs_get_fstype(fs); + + /* + * bind-mount -- get fs-root and source device for the source filesystem + */ + if (mt->mountflags & MS_BIND) { + const char *src, *src_root; + mnt_fs *src_fs; + + src = mnt_fs_get_srcpath(fs); + if (!src) + goto err; + mnt = mnt_get_mountpoint(src); + if (!mnt) + goto err; + root = mnt_get_fs_root(src, mnt); + + tb = mnt_new_tab_from_file(_PATH_PROC_MOUNTINFO); + if (!tb) + goto dflt; + src_fs = mnt_tab_find_target(tb, mnt, MNT_ITER_BACKWARD); + if (!src_fs) + goto dflt; + + /* set device name and fs */ + src = mnt_fs_get_srcpath(src_fs); + mnt_fs_set_source(fs, src); + + mnt_fs_set_fstype(fs, mnt_fs_get_fstype(src_fs)); + + /* on btrfs the subvolume is used as fs-root in + * /proc/self/mountinfo, so we have get the original subvolume + * name from src_fs and prepend the subvolume name to the + * fs-root path + */ + src_root = mnt_fs_get_root(src_fs); + if (src_root && !startswith(root, src_root)) { + size_t sz = strlen(root) + strlen(src_root) + 1; + char *tmp = malloc(sz); + + if (!tmp) + goto err; + snprintf(tmp, sz, "%s%s", src_root, root); + free(root); + root = tmp; + } + } + + /* + * btrfs-subvolume mount -- get subvolume name and use it as a root-fs path + */ + else if (fstype && !strcmp(fstype, "btrfs")) { + char *vol = NULL, *p; + size_t sz, volsz = 0; + + if (mnt_optstr_get_option(optstr, "subvol", &vol, &volsz)) + goto dflt; + + sz = volsz; + if (*vol != '/') + sz++; + root = malloc(sz + 1); + if (!root) + goto err; + p = root; + if (*vol != '/') + *p++ = '/'; + memcpy(p, vol, volsz); + *(root + sz) = '\0'; + } + +dflt: + mnt_free_tab(tb); + if (!root) + root = strdup("/"); + if (!root) + goto err; + fs->root = root; + free(mnt); + return 0; +err: + free(root); + free(mnt); + return -1; +} + +/** + * mnt_mtab_prepare_update: + * @mt: mtab + * + * Prepares internal data for mtab update: + * - set mtab filename if mnt_mtab_set_filename() was't called + * - set mtab file format if mnt_mtab_set_format() was't called + * - (bitwise) OR mountflags from mount options + * - for /var/run/mount/mountinfo: + * * evaluate if mtab update is necessary + * * set fs root and devname for bind mount and btrfs subvolumes + * - allocate mtab_lock if necessary + * + * This function has to be always called before mount(2). The mnt_update_mtab() + * should not be called is mnt_mtab_prepare_update() returns non-zero value. + * + * Returns: 0 on success, 1 if update is unncessary, -1 in case of error + */ +int mnt_mtab_prepare_update(mnt_mtab *mt) +{ + char *u = NULL; + const char *o = NULL; + + assert(mt); + + if (!mt) + return -1; + + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab %p: prepare update (target %s, source %s, optstr %s)\n", + mt, mnt_fs_get_target(mt->fs), mnt_fs_get_source(mt->fs), + mnt_fs_get_optstr(mt->fs))); + + if (!mt->filename) { + const char *p = mnt_get_writable_mtab_path(); + if (!p) { + if (errno) + goto err; /* EACCES? */ + goto nothing; /* no mtab */ + } + mt->filename = strdup(p); + if (!mt->filename) + goto err; + } + if (!mt->format) + mt->format = endswith(mt->filename, "mountinfo") ? + MNT_FMT_MOUNTINFO : MNT_FMT_MTAB; + + + /* TODO: cannonicalize source and target paths on mnt->fs */ + + o = mnt_fs_get_optstr(mt->fs); + if (o) + mt->mountflags |= mnt_optstr_get_mountflags(o); + + /* umount */ + if (mt->action == MNT_ACT_UMOUNT) + return 0; + + /* + * A) classic /etc/mtab + */ + if (mt->format != MNT_FMT_MOUNTINFO) + return 0; + + /* + * B) /var/run/mount/mountinfo + */ + if (mt->mountflags & MS_REMOUNT) { + /* remount */ + if (mnt_split_optstr(o, &u, NULL, NULL, MNT_NOMTAB, 0)) + goto err; + if (mnt_fs_set_optstr(mt->fs, u)) + goto err; + + } else { + if (!o) + goto nothing; /* no options */ + if (mnt_split_optstr(o, &u, NULL, NULL, MNT_NOMTAB, 0)) + goto err; + if (!u) + goto nothing; /* no userpsace options */ + if (set_fs_root(mt, mt->fs)) + goto err; + mnt_fs_set_optstr(mt->fs, u); + } + + if (!mt->nolock && !mt->lc) { + mt->lc = mnt_new_lock(mt->filename, 0); + if (!mt->lc) + goto err; + } + + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab %p: prepare update: success\n", mt)); + free(u); + return 0; +err: + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab %p: prepare update: failed\n", mt)); + free(u); + return -1; +nothing: + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab %p: prepare update: unnecessary\n", mt)); + free(u); + return 1; +} + +static int add_entry(mnt_mtab *mt) +{ + FILE *f; + int rc = -1; + + assert(mt); + + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab %p: add entry\n", mt)); + if (mt->lc) + mnt_lock_file(mt->lc); + f = fopen(mt->filename, "a+"); + if (f) { + if (mt->format == MNT_FMT_MOUNTINFO) + rc = fprintf_mountinfo_fs(f, mt->fs); + else + rc = fprintf_mtab_fs(f, mt->fs); + fclose(f); + } + if (mt->lc) + mnt_unlock_file(mt->lc); + return rc; +} + +static int remove_entry(mnt_mtab *mt) +{ + const char *target; + mnt_tab *tb = NULL; + mnt_fs *fs = NULL; + int rc = -1; + + assert(mt); + assert(mt->filename); + + target = mnt_fs_get_target(mt->fs); + assert(target); + + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab %p: remove entry (target %s)\n", mt, target)); + + if (mt->lc) + mnt_lock_file(mt->lc); + tb = mnt_new_tab_from_file(mt->filename); + if (!tb) + goto done; + fs = mnt_tab_find_target(tb, target, MNT_ITER_BACKWARD); + if (!fs) { + rc = 0; /* no error if the file does not contain the target */ + goto done; + } + mnt_tab_remove_fs(tb, fs); + + if (!update_file(mt->filename, mt->format, tb)) + rc = 0; +done: + if (mt->lc) + mnt_unlock_file(mt->lc); + mnt_free_tab(tb); + mnt_free_fs(fs); + return rc; +} + +static int modify_target(mnt_mtab *mt) +{ + mnt_tab *tb = NULL; + mnt_fs *fs = NULL; + int rc = -1; + + assert(mt); + assert(mt->old_target); + assert(mt->filename); + assert(mnt_fs_get_target(mt->fs)); + + if (!mt->old_target) + return -1; + + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab %p: modify target (%s->%s)\n", mt, + mt->old_target, mnt_fs_get_target(mt->fs))); + + if (mt->lc) + mnt_lock_file(mt->lc); + tb = mnt_new_tab_from_file(mt->filename); + if (!tb) + goto done; + fs = mnt_tab_find_target(tb, mt->old_target, MNT_ITER_BACKWARD); + if (!fs) { + rc = 0; /* no error if the file does not contain the target */ + goto done; + } + + mnt_fs_set_target(fs, mnt_fs_get_target(mt->fs)); + + if (!update_file(mt->filename, mt->format, tb)) + rc = 0; +done: + if (mt->lc) + mnt_unlock_file(mt->lc); + mnt_free_tab(tb); + return rc; +} + +static int modify_options(mnt_mtab *mt) +{ + mnt_tab *tb = NULL; + mnt_fs *fs = NULL, *rem_fs = NULL; + int rc = -1; + const char *target = mnt_fs_get_target(mt->fs); + + assert(target); + assert(mt->filename); + + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab %p: modify options (target %s)\n", mt, target)); + + if (mt->lc) + mnt_lock_file(mt->lc); + tb = mnt_new_tab_from_file(mt->filename); + if (!tb) + goto done; + fs = mnt_tab_find_target(tb, target, MNT_ITER_BACKWARD); + if (!fs) { + rc = 0; /* no error if the file does not contain the target */ + goto done; + } + if (mt->format == MNT_FMT_MOUNTINFO && !mnt_fs_get_optstr(mt->fs)) { + mnt_tab_remove_fs(tb, fs); + rem_fs = fs; + } else + mnt_fs_set_optstr(fs, mnt_fs_get_optstr(mt->fs)); + + if (!update_file(mt->filename, mt->format, tb)) + rc = 0; +done: + if (mt->lc) + mnt_unlock_file(mt->lc); + mnt_free_tab(tb); + mnt_free_fs(rem_fs); + return rc; +} + +/** + * mnt_update_mtab: + * @mt: mtab + * + * Updates the mtab file. The behavior of this function is undefined if + * mnt_mtab_prepare_update() has not been called. + * + * Returns: 0 on success, -1 in case of error. + */ +int mnt_update_mtab(mnt_mtab *mt) +{ + assert(mt); + assert(mt->filename); + assert(mt->format); + + if (!mt) + return -1; + + DBG(DEBUG_MTAB, fprintf(stderr, + "libmount: mtab %p: update (target %s)\n", mt, + mnt_fs_get_target(mt->fs))); + /* + * umount + */ + if (mt->action == MNT_ACT_UMOUNT) + return remove_entry(mt); + /* + * mount + */ + if (mt->action == MNT_ACT_MOUNT) { + if (mt->mountflags & MS_REMOUNT) + return modify_options(mt); + + if (mt->mountflags & MS_MOVE) + return modify_target(mt); + + return add_entry(mt); /* mount */ + } + return -1; +} + +#ifdef TEST_PROGRAM + +#include + +mnt_lock *lock; + +static void lock_fallback(void) +{ + if (lock) + mnt_unlock_file(lock); +} + +static int update(mnt_mtab *mt) +{ + int rc; + + /* + * Note that mount(2) syscal should be called *after* + * mnt_mtab_prepare_update() and *before* mnt_update_mtab() + */ + rc = mnt_mtab_prepare_update(mt); + if (!rc) { + /* setup lock fallback */ + lock = mnt_mtab_get_lock(mt); + atexit(lock_fallback); + + return mnt_update_mtab(mt); + } + if (rc == 1) { + printf("mtab: update is not reuquired\n"); + return 0; + } + fprintf(stderr, "mtab: failed to prepare update\n"); + return -1; +} + +int test_add(struct mtest *ts, int argc, char *argv[]) +{ + mnt_mtab *mt; + int rc = -1; + + if (argc < 5) + return -1; + mt = mnt_new_mtab(MNT_ACT_MOUNT); + if (!mt) + return -1; + mnt_mtab_set_source(mt, argv[1]); + mnt_mtab_set_target(mt, argv[2]); + mnt_mtab_set_fstype(mt, argv[3]); + mnt_mtab_set_optstr(mt, argv[4]); + + rc = update(mt); + + mnt_free_mtab(mt); + return rc; +} + +int test_remove(struct mtest *ts, int argc, char *argv[]) +{ + mnt_mtab *mt; + int rc = -1; + + if (argc < 2) + return -1; + mt = mnt_new_mtab(MNT_ACT_UMOUNT); + if (!mt) + return -1; + mnt_mtab_set_target(mt, argv[1]); + + rc = update(mt); + + mnt_free_mtab(mt); + return rc; +} + +int test_move(struct mtest *ts, int argc, char *argv[]) +{ + mnt_mtab *mt; + int rc = -1; + + if (argc < 3) + return -1; + mt = mnt_new_mtab(MNT_ACT_MOUNT); + if (!mt) + return -1; + mnt_mtab_set_mountflags(mt, MS_MOVE); + mnt_mtab_set_old_target(mt, argv[1]); + mnt_mtab_set_target(mt, argv[2]); + + rc = update(mt); + + mnt_free_mtab(mt); + return rc; +} + +int test_remount(struct mtest *ts, int argc, char *argv[]) +{ + mnt_mtab *mt; + int rc = -1; + + if (argc < 3) + return -1; + mt = mnt_new_mtab(MNT_ACT_MOUNT); + if (!mt) + return -1; + mnt_mtab_set_mountflags(mt, MS_REMOUNT); + mnt_mtab_set_target(mt, argv[1]); + mnt_mtab_set_optstr(mt, argv[2]); + + rc = update(mt); + + mnt_free_mtab(mt); + return rc; +} + +int main(int argc, char *argv[]) +{ + struct mtest tss[] = { + { "--add", test_add, " add line to mtab" }, + { "--remove", test_remove, " MS_REMOUNT mtab change" }, + { "--move", test_move, " MS_MOVE mtab change" }, + { "--remount",test_remount, " MS_REMOUNT mtab change" }, + { NULL } + }; + + return mnt_run_test(tss, argc, argv); +} + +#endif /* TEST_PROGRAM */ diff --git a/shlibs/mount/src/optstr.c b/shlibs/mount/src/optstr.c index c209784d..c2581be6 100644 --- a/shlibs/mount/src/optstr.c +++ b/shlibs/mount/src/optstr.c @@ -452,7 +452,7 @@ int mnt_optstr_get_mountflags(const char *optstr) } DBG(DEBUG_OPTIONS, fprintf(stderr, - "libmount: optstr '%s': mountflags 0x%08x", optstr, flags)); + "libmount: optstr '%s': mountflags 0x%08x\n", optstr, flags)); return flags; } -- 2.39.5