summaryrefslogtreecommitdiffstats
path: root/shlibs/mount/src
diff options
context:
space:
mode:
authorKarel Zak2010-11-08 11:14:44 +0100
committerKarel Zak2011-01-03 12:28:46 +0100
commit1d0cd73f3f8929132e731a821ceb07fa6193c00c (patch)
tree6ef4dd8d0d801baa03a8dcf1a6830d265ef7524b /shlibs/mount/src
parentlibmount: fix Makefile and tests (diff)
downloadkernel-qcow2-util-linux-1d0cd73f3f8929132e731a821ceb07fa6193c00c.tar.gz
kernel-qcow2-util-linux-1d0cd73f3f8929132e731a821ceb07fa6193c00c.tar.xz
kernel-qcow2-util-linux-1d0cd73f3f8929132e731a821ceb07fa6193c00c.zip
libmount: rewrite update
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'shlibs/mount/src')
-rw-r--r--shlibs/mount/src/context.c111
-rw-r--r--shlibs/mount/src/context_mount.c117
-rw-r--r--shlibs/mount/src/context_umount.c110
-rw-r--r--shlibs/mount/src/lock.c2
-rw-r--r--shlibs/mount/src/mount.h.in30
-rw-r--r--shlibs/mount/src/mountP.h21
-rw-r--r--shlibs/mount/src/tab_update.c1172
-rw-r--r--shlibs/mount/src/utils.c140
8 files changed, 693 insertions, 1010 deletions
diff --git a/shlibs/mount/src/context.c b/shlibs/mount/src/context.c
index 21a5d8a1d..b4662d89e 100644
--- a/shlibs/mount/src/context.c
+++ b/shlibs/mount/src/context.c
@@ -39,6 +39,12 @@ mnt_context *mnt_new_context()
DBG(CXT, mnt_debug_h(cxt, "allocate %s",
cxt->restricted ? "[RESTRICTED]" : ""));
+ mnt_has_regular_mtab(&cxt->mtab_path, &cxt->mtab_writable);
+
+ if (!cxt->mtab_writable)
+ /* use /dev/.mount/utab if /etc/mtab is useless */
+ mnt_has_regular_mtab(&cxt->utab_path, &cxt->utab_writable);
+
return cxt;
}
@@ -53,22 +59,20 @@ void mnt_free_context(mnt_context *cxt)
if (!cxt)
return;
+ mnt_reset_context(cxt);
+
DBG(CXT, mnt_debug_h(cxt, "free"));
free(cxt->fstype_pattern);
free(cxt->optstr_pattern);
- free(cxt->helper);
- free(cxt->orig_user);
- if (!(cxt->flags & MNT_FL_EXTERN_FS))
- mnt_free_fs(cxt->fs);
if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
mnt_free_tab(cxt->fstab);
if (!(cxt->flags & MNT_FL_EXTERN_CACHE))
mnt_free_cache(cxt->cache);
+ mnt_free_lock(cxt->lock);
mnt_free_update(cxt->update);
- mnt_free_tab(cxt->mtab);
free(cxt);
}
@@ -101,22 +105,18 @@ int mnt_reset_context(mnt_context *cxt)
fl = cxt->flags;
- if (cxt->update)
- mnt_update_set_fs(cxt->update, NULL);
-
if (!(cxt->flags & MNT_FL_EXTERN_FS))
mnt_free_fs(cxt->fs);
mnt_free_tab(cxt->mtab);
- cxt->fs = NULL;
- cxt->mtab = NULL;
-
free(cxt->helper);
free(cxt->orig_user);
+ cxt->fs = NULL;
+ cxt->mtab = NULL;
cxt->helper = NULL;
-
+ cxt->orig_user = NULL;
cxt->mountflags = 0;
cxt->user_mountflags = 0;
cxt->mountdata = NULL;
@@ -585,7 +585,7 @@ int mnt_context_get_mtab(mnt_context *cxt, mnt_tab **tb)
cxt->mtab = mnt_new_tab();
if (!cxt->mtab)
return -ENOMEM;
- rc = mnt_tab_parse_mtab(cxt->mtab, NULL);
+ rc = mnt_tab_parse_mtab(cxt->mtab, cxt->mtab_path);
if (rc)
return rc;
}
@@ -650,9 +650,6 @@ mnt_cache *mnt_context_get_cache(mnt_context *cxt)
* mnt_context_get_lock:
* @cxt: mount context
*
- * The lock is available after mnt_context_prepare_mount() or
- * mnt_context_prepare_umount().
- *
* The application that uses libmount context does not have to care about
* mtab locking, but with a small exceptions: the application has to be able to
* remove the lock file when interrupted by signal. It means that properly written
@@ -661,16 +658,20 @@ mnt_cache *mnt_context_get_cache(mnt_context *cxt)
* See also mnt_unlock_file(), mnt_context_disable_lock() and
* mnt_context_disable_mtab().
*
- * It's not error if this function returns NULL (it usually means that the
- * context is not prepared yet, or mtab update is unnecessary).
+ * This function returns NULL if mtab file is not writable or nolock or nomtab
+ * flags is enabled.
*
- * Returns: pointer to lock struct.
+ * Returns: pointer to lock struct or NULL.
*/
mnt_lock *mnt_context_get_lock(mnt_context *cxt)
{
- if (!cxt || !cxt->update || (cxt->flags & (MNT_FL_NOMTAB | MNT_FL_NOLOCK)))
+ if (!cxt || (cxt->flags & MNT_FL_NOMTAB) || !cxt->mtab_writable)
return NULL;
- return mnt_update_get_lock(cxt->update);
+
+ if (!cxt->lock && cxt->mtab_path)
+ cxt->lock = mnt_new_lock(cxt->mtab_path, 0);
+
+ return cxt->lock;
}
/**
@@ -1025,48 +1026,63 @@ int mnt_context_merge_mountflags(mnt_context *cxt)
}
/*
- * Prepare /etc/mtab or /var/run/mount/mountinfo update
+ * Prepare /etc/mtab or /dev/.mount/utab
*/
-int mnt_context_prepare_update(mnt_context *cxt, int act)
+int mnt_context_prepare_update(mnt_context *cxt)
{
int rc;
- const char *tgt = cxt->fs ? mnt_fs_get_target(cxt->fs) : NULL;
+ const char *target;
assert(cxt);
assert(cxt->fs);
+ assert(cxt->action);
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
- if (act == MNT_ACT_UMOUNT && tgt && !strcmp(tgt, "/"))
+ 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 */
cxt->flags |= MNT_FL_NOMTAB;
if ((cxt->flags & MNT_FL_NOMTAB) || cxt->helper)
return 0;
+ if (!cxt->mtab_writable && !cxt->utab_writable)
+ return 0;
if (!cxt->update) {
- cxt->update = mnt_new_update(act, cxt->mountflags, cxt->fs);
+ cxt->update = mnt_new_update(!cxt->mtab_writable);
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);
+ rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
+ mnt_fs_get_target(cxt->fs),
+ cxt->action == MNT_ACT_UMOUNT ? NULL : cxt->fs);
- rc = mnt_prepare_update(cxt->update);
+ return rc < 0 ? rc : 0;
+}
- if (rc == 1)
- /* mtab update is unnecessary for this system */
- rc = 0;
+int mnt_context_update_tabs(mnt_context *cxt)
+{
+ const char *filename;
+ mnt_lock *lock = NULL;
- return rc;
+ assert(cxt);
+
+ if (cxt->flags & MNT_FL_NOMTAB)
+ return 0;
+ if (!cxt->update || !mnt_update_is_ready(cxt->update))
+ return 0;
+
+ if (mnt_update_is_userspace_only(cxt->update))
+ filename = cxt->utab_path;
+ else {
+ filename = cxt->mtab_path;
+ lock = mnt_context_get_lock(cxt);
+ }
+ assert(filename);
+
+ return mnt_update_tab(cxt->update, filename, lock);
}
static int is_remount(mnt_context *cxt)
@@ -1199,6 +1215,19 @@ err:
return rc;
}
+/**
+ * mnt_context_strerror
+ * @cxt: context
+ * @buf: buffer
+ * @bufsiz: size of the buffer
+ *
+ * Returns: 0 or negative number in case of error.
+ */
+int mnt_context_strerror(mnt_context *cxt, char *buf, size_t bufsiz)
+{
+ /* TODO: based on cxt->syscall_errno or cxt->helper_status */
+ return 0;
+}
#ifdef TEST_PROGRAM
diff --git a/shlibs/mount/src/context_mount.c b/shlibs/mount/src/context_mount.c
index e12e0a933..de6557df4 100644
--- a/shlibs/mount/src/context_mount.c
+++ b/shlibs/mount/src/context_mount.c
@@ -363,32 +363,30 @@ static int do_mount(mnt_context *cxt, const char *try_type)
}
/**
- * mnt_context_prepare_mount:
+ * mnt_context_do_mount:
* @cxt: mount context
*
- * This function:
- * - read information from fstab (if necessary)
- * - cleanup mount options
- * - check premissions
- * - prepare device (e.g. loop device)
- * - detect FS type (if necessary)
- * - generate mount flags and mount data (if not set yet)
- * - prepare for mtab update (if necessary)
+ * Mount filesystem by mount(2) or fork()+exec(/sbin/mount.<type>).
*
- * It's strongly recommended to use this function before mnt_context_mount_fs().
+ * See also mnt_context_disable_helpers().
*
* Returns: 0 on success, and negative number in case of error.
*/
-int mnt_context_prepare_mount(mnt_context *cxt)
+int mnt_context_do_mount(mnt_context *cxt)
{
- int rc = 0;
+ int rc = -EINVAL;
+ const char *type;
- if (!cxt)
- return -EINVAL;
+ assert(cxt);
+ assert(cxt->fs);
+ assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
- if (!cxt->fs || (!mnt_fs_get_source(cxt->fs) &&
- !mnt_fs_get_target(cxt->fs)))
+ if (!cxt || !cxt->fs || (cxt->fs->flags & MNT_FS_SWAP))
return -EINVAL;
+ if (!mnt_fs_get_source(cxt->fs) && !mnt_fs_get_target(cxt->fs))
+ return -EINVAL;
+
+ cxt->action = MNT_ACT_MOUNT;
DBG(CXT, mnt_debug_h(cxt, "mount: preparing"));
@@ -406,39 +404,13 @@ int mnt_context_prepare_mount(mnt_context *cxt)
if (!rc)
rc = mnt_context_prepare_helper(cxt, "mount", NULL);
if (!rc)
- rc = mnt_context_prepare_update(cxt, MNT_ACT_MOUNT);
+ rc = mnt_context_prepare_update(cxt);
- if (!rc) {
- DBG(CXT, mnt_debug_h(cxt, "sucessfully prepared"));
- return 0;
+ if (rc) {
+ DBG(CXT, mnt_debug_h(cxt, "mount: preparing failed"));
+ return rc;
}
- DBG(CXT, mnt_debug_h(cxt, "prepare failed"));
- return rc;
-}
-
-/**
- * mnt_context_do_mount:
- * @cxt: mount context
- *
- * Mount filesystem by mount(2) or fork()+exec(/sbin/mount.<type>).
- *
- * See also mnt_context_disable_helpers().
- *
- * Returns: 0 on success, and negative number in case of error.
- */
-int mnt_context_do_mount(mnt_context *cxt)
-{
- int rc = -EINVAL;
- const char *type;
-
- assert(cxt);
- assert(cxt->fs);
- assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
-
- if (!cxt || !cxt->fs || (cxt->fs->flags & MNT_FS_SWAP))
- return -EINVAL;
-
DBG(CXT, mnt_debug_h(cxt, "mount: do mount"));
if (!(cxt->flags & MNT_FL_MOUNTDATA))
@@ -456,55 +428,10 @@ int mnt_context_do_mount(mnt_context *cxt)
/* TODO: try all filesystems from /proc/filesystems and /etc/filesystems */
- return rc;
-}
-
-/**
- * mnt_context_post_mount:
- * @cxt: mount context
- *
- * Updates mtab, etc. This function should be always called after
- * mnt_context_do_mount().
- *
- * Returns: 0 on success, and negative number in case of error.
- */
-int mnt_context_post_mount(mnt_context *cxt)
-{
- int rc = 0;
-
- assert(cxt);
- assert(cxt->fs);
- assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
-
- if (!cxt)
- return -EINVAL;
- /*
- * Update /etc/mtab or /var/run/mount/mountinfo
+ /* 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.
*/
- if (!cxt->syscall_errno && !cxt->helper &&
- !(cxt->flags & MNT_FL_NOMTAB) &&
- cxt->update && !mnt_update_is_pointless(cxt->update)) {
-
- /* 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.
- */
- rc = mnt_update_file(cxt->update);
- }
-
- return rc;
-}
-
-/**
- * mnt_context_mount_strerror
- * @cxt: mount context
- * @buf: buffer
- * @bufsiz: size of the buffer
- *
- * Returns: 0 or negative number in case of error.
- */
-int mnt_context_mount_strerror(mnt_context *cxt, char *buf, size_t bufsiz)
-{
- /* TODO: based on cxt->syscall_errno or cxt->helper_status */
- return 0;
+ return mnt_context_update_tabs(cxt);
}
diff --git a/shlibs/mount/src/context_umount.c b/shlibs/mount/src/context_umount.c
index b2590be94..476ee515c 100644
--- a/shlibs/mount/src/context_umount.c
+++ b/shlibs/mount/src/context_umount.c
@@ -413,32 +413,29 @@ static int do_umount(mnt_context *cxt)
}
/**
- * mnt_context_prepare_umount:
+ * mnt_context_do_umount:
* @cxt: mount context
*
- * This function:
- * - read information from fstab/mtab (if necessary)
- * - check premissions
- * - prepare for mtab update (if necessary)
+ * Umount filesystem by umount(2) or fork()+exec(/sbin/umount.<type>).
*
- * It's strongly recommended to use this function before mnt_context_do_umount().
+ * See also mnt_context_disable_helpers().
*
* Returns: 0 on success, and negative number in case of error.
*/
-int mnt_context_prepare_umount(mnt_context *cxt)
+int mnt_context_do_umount(mnt_context *cxt)
{
- int rc = 0;
+ int rc;
- if (!cxt)
+ if (!cxt || !cxt->fs || (cxt->fs->flags & MNT_FS_SWAP))
return -EINVAL;
-
- if (!cxt->fs || (!mnt_fs_get_source(cxt->fs) &&
- !mnt_fs_get_target(cxt->fs)))
+ if (!mnt_fs_get_source(cxt->fs) && !mnt_fs_get_target(cxt->fs))
return -EINVAL;
free(cxt->helper); /* be paranoid */
cxt->helper = NULL;
+ cxt->action = MNT_ACT_UMOUNT;
+
rc = lookup_umount_fs(cxt);
if (!rc)
rc = mnt_context_merge_mountflags(cxt);
@@ -452,51 +449,15 @@ int mnt_context_prepare_umount(mnt_context *cxt)
cxt->flags &= ~MNT_FL_LOOPDEL;
*/
if (!rc)
- rc = mnt_context_prepare_update(cxt, MNT_ACT_UMOUNT);
- if (!rc) {
- DBG(CXT, mnt_debug_h(cxt, "umount sucessfully prepared"));
- return 0;
+ rc = mnt_context_prepare_update(cxt);
+ if (rc) {
+ DBG(CXT, mnt_debug_h(cxt, "prepared umount failed"));
+ return rc;
}
- DBG(CXT, mnt_debug_h(cxt, "umount prepare failed"));
- return rc;
-}
-
-/**
- * mnt_context_do_umount:
- * @cxt: mount context
- *
- * Umount filesystem by umount(2) or fork()+exec(/sbin/umount.<type>).
- *
- * See also mnt_context_disable_helpers().
- *
- * Returns: 0 on success, and negative number in case of error.
- */
-int mnt_context_do_umount(mnt_context *cxt)
-{
- if (!cxt || !cxt->fs || (cxt->fs->flags & MNT_FS_SWAP))
- return -EINVAL;
-
- return do_umount(cxt);
-}
-
-/**
- * mnt_context_post_umount:
- * @cxt: mount context
- *
- * Updates mtab and detroy loopdev etc. This function should be always called after
- * mnt_context_do_umount().
- *
- * Returns: 0 on success, and negative number in case of error.
- */
-int mnt_context_post_umount(mnt_context *cxt)
-{
- int rc = 0;
-
- if (!cxt)
- return -EINVAL;
- if (cxt->syscall_errno || cxt->helper)
- return 0;
+ rc = do_umount(cxt);
+ if (rc)
+ return rc;
/* TODO
if (cxt->flags & MNT_FL_LOOPDEL)
rc = mnt_loopdev_clean(mnt_fs_get_source(cxt->fs));
@@ -507,34 +468,23 @@ int mnt_context_post_umount(mnt_context *cxt)
if ((cxt->flags & MNT_FL_RDONLY_UMOUNT) &&
(cxt->mountflags & (MS_RDONLY | MS_REMOUNT))) {
/*
- * refresh update to handle remount to read-only
+ * update options to handle remount to read-only
*/
- rc = mnt_context_prepare_update(cxt, MNT_ACT_MOUNT);
- if (rc)
- return rc;
- }
+ const char *o = mnt_fs_get_optstr(cxt->fs);
+ char *n = o ? strdup(o) : NULL;
- /*
- * Update /etc/mtab or /var/run/mount/mountinfo
- */
- if (cxt->update && !mnt_update_is_pointless(cxt->update)) {
- rc = mnt_update_file(cxt->update);
+ if (n)
+ mnt_optstr_remove_option(&n, "rw");
+ rc = mnt_optstr_prepend_option(&n, "ro", NULL);
if (!rc)
- return rc;
+ rc = __mnt_fs_set_optstr_ptr(cxt->fs, n, FALSE);
+
+ if (!rc && cxt->update &&
+ !mnt_update_is_userspace_only(cxt->update))
+ /* refresh options in /etc/mtab as well*/
+ rc = mnt_update_set_fs(cxt->update,
+ cxt->mountflags, NULL, cxt->fs);
}
- return rc;
-}
-/**
- * mnt_context_umount_strerror
- * @cxt: mount context
- * @buf: buffer
- * @bufsiz: size of the buffer
- *
- * Returns: 0 or negative number in case of error.
- */
-int mnt_context_umount_strerror(mnt_context *cxt, char *buf, size_t bufsiz)
-{
- /* TODO: based on cxt->syscall_errno or cxt->helper_status */
- return 0;
+ return rc ? : mnt_context_update_tabs(cxt);
}
diff --git a/shlibs/mount/src/lock.c b/shlibs/mount/src/lock.c
index d8043121d..b4fa7f7d1 100644
--- a/shlibs/mount/src/lock.c
+++ b/shlibs/mount/src/lock.c
@@ -424,7 +424,7 @@ int mnt_lock_file(mnt_lock *ml)
}
}
DBG(LOCKS, mnt_debug_h(ml,
- "LOCK: %s: (%d) successfully locked\n",
+ "%s: (%d) successfully locked\n",
lockfile, getpid()));
unlink(linkfile);
return 0;
diff --git a/shlibs/mount/src/mount.h.in b/shlibs/mount/src/mount.h.in
index 01ba5a6d6..8bb44c7b4 100644
--- a/shlibs/mount/src/mount.h.in
+++ b/shlibs/mount/src/mount.h.in
@@ -89,7 +89,7 @@ typedef struct _mnt_tab mnt_tab;
/**
* mnt_update
*
- * /etc/mtab or /var/run/mountinfo update description
+ * /etc/mtab or /dev/.mount/utab update description
*/
typedef struct _mnt_update mnt_update;
@@ -131,9 +131,12 @@ extern int mnt_fstype_is_netfs(const char *type);
extern int mnt_fstype_is_pseudofs(const char *type);
extern int mnt_match_fstype(const char *type, const char *pattern);
extern int mnt_match_options(const char *optstr, const char *pattern);
-extern const char *mnt_get_writable_mtab_path(void);
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_has_regular_mtab(const char **mtab, int *writable);
+extern int mnt_has_regular_utab(const char **utab, int *writable);
/* cache.c */
extern mnt_cache *mnt_new_cache(void);
@@ -251,6 +254,7 @@ extern int mnt_fs_print_debug(mnt_fs *ent, FILE *file);
/* tab-parse.c */
extern mnt_tab *mnt_new_tab_from_file(const char *filename);
+extern mnt_tab *mnt_new_tab_from_dir(const char *dirname);
extern int mnt_tab_parse_stream(mnt_tab *tb, FILE *f, const char *filename);
extern int mnt_tab_parse_file(mnt_tab *tb, const char *filename);
extern int mnt_tab_parse_fstab(mnt_tab *tb, const char *filename);
@@ -286,22 +290,14 @@ extern int mnt_tab_find_next_fs(mnt_tab *tb, mnt_iter *itr,
mnt_fs **fs);
/* tab_update.c */
-extern mnt_update *mnt_new_update(int action, unsigned long mountflags, const mnt_fs *fs);
+extern mnt_update *mnt_new_update(int userspace_only);
extern void mnt_free_update(mnt_update *upd);
-extern int mnt_update_set_filename(mnt_update *upd, const char *filename);
-extern const char *mnt_update_get_filename(mnt_update *upd);
-extern int mnt_update_get_format(mnt_update *upd);
-extern int mnt_update_set_action(mnt_update *upd, int action);
-extern int mnt_update_set_format(mnt_update *upd, int format);
-extern int mnt_update_set_mountflags(mnt_update *upd, unsigned long flags);
-extern mnt_lock *mnt_update_get_lock(mnt_update *upd);
-extern int mnt_update_disable_lock(mnt_update *upd, int disable);
-extern int mnt_update_set_old_target(mnt_update *upd, const char *target);
-extern int mnt_update_set_fs(mnt_update *upd, const mnt_fs *fs);
-
-extern int mnt_prepare_update(mnt_update *upd);
-extern int mnt_update_file(mnt_update *upd);
-extern int mnt_update_is_pointless(mnt_update *upd);
+extern int mnt_update_is_ready(mnt_update *upd);
+extern int mnt_update_set_fs(mnt_update *upd, int mountflags,
+ const char *target, mnt_fs *fs);
+extern int mnt_update_tab(mnt_update *upd, const char *filename, mnt_lock *lc);
+extern int mnt_update_is_userspace_only(mnt_update *upd);;
+
/* context.c */
diff --git a/shlibs/mount/src/mountP.h b/shlibs/mount/src/mountP.h
index 2a4187583..0f1395e5a 100644
--- a/shlibs/mount/src/mountP.h
+++ b/shlibs/mount/src/mountP.h
@@ -92,8 +92,7 @@ mnt_debug_h(void *handler, const char *mesg, ...)
#define MNT_MNTTABDIR_EXT ".fstab"
/* library private paths */
-#define MNT_PATH_RUNDIR "/var/run/mount"
-#define MNT_PATH_MOUNTINFO MNT_PATH_RUNDIR "/mountinfo"
+#define MNT_PATH_UTAB "/dev/.mount/utab"
#ifdef TEST_PROGRAM
struct mtest {
@@ -116,10 +115,9 @@ extern int mnt_get_uid(const char *username, uid_t *uid);
extern int mnt_get_gid(const char *groupname, gid_t *gid);
extern int mnt_in_group(gid_t gid);
-extern int mnt_has_regular_mtab(void);
-
extern char *mnt_get_mountpoint(const char *path);
extern char *mnt_get_fs_root(const char *path, const char *mountpoint);
+extern int mnt_open_uniq_filename(const char *filename, char **name, int flags);
/*
* Generic iterator
@@ -207,7 +205,6 @@ struct _mnt_tab {
struct _mnt_context
{
int action; /* MNT_ACT_{MOUNT,UMOUNT} */
-
int restricted; /* root or not? */
char *fstype_pattern; /* for mnt_match_fstype() */
@@ -224,8 +221,15 @@ struct _mnt_context
unsigned long user_mountflags; /* MNT_MS_* (loop=, user=, ...) */
- mnt_update *update; /* mtab update */
- mnt_cache *cache; /* paths cache */
+ mnt_cache *cache; /* paths cache */
+ mnt_lock *lock; /* mtab lock */
+ mnt_update *update;/* mtab/utab update */
+
+ const char *mtab_path; /* writable mtab */
+ int mtab_writable; /* ismtab writeable */
+
+ const char *utab_path; /* writable mtab */
+ int utab_writable; /* ismtab writeable */
int flags; /* private context flags */
int ambi; /* libblkid returns ambivalent result */
@@ -285,8 +289,9 @@ extern int __mnt_fs_set_optstr(mnt_fs *fs, const char *optstr, int split);
extern int mnt_context_prepare_srcpath(mnt_context *cxt);
extern int mnt_context_guess_fstype(mnt_context *cxt);
extern int mnt_context_prepare_helper(mnt_context *cxt, const char *name, const char *type);
-extern int mnt_context_prepare_update(mnt_context *cxt, int act);
+extern int mnt_context_prepare_update(mnt_context *cxt);
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);
#endif /* _LIBMOUNT_PRIVATE_H */
diff --git a/shlibs/mount/src/tab_update.c b/shlibs/mount/src/tab_update.c
index 946cdc090..09c9cdfa0 100644
--- a/shlibs/mount/src/tab_update.c
+++ b/shlibs/mount/src/tab_update.c
@@ -9,44 +9,14 @@
* SECTION: update
* @title: mtab (fstab) 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). This mode is always used for /etc/fstab updates as well.
- *
- * - /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)
- *
- * Note that mnt_update_* interface does not manage mount options. It's callers
- * responsibility set the right mount options (for example merge options from
- * mtab with command line on MS_REMOUNT).
- *
- * The small exception is the /var/run/mount/mountinfo file where are store
- * userspace mount options only. This is done by mnt_prepare_update().
- *
- * The mtab is always updated in two steps. The first step is to prepare a new
- * update entry -- mnt_prepare_update(), this step has to be done before
- * mount(2) syscall. The second step is to update the file --
- * mnt_update_file(), this step should be done after mount(2) syscall.
- *
- * The mnt_update_file() behaviour is undefined if mnt_prepare_update() has
- * not been used.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/file.h>
+#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
@@ -56,32 +26,24 @@
#include "mangle.h"
#include "pathnames.h"
-
-
-/*
- * mtab update description
- */
struct _mnt_update {
- int action; /* MNT_ACT_{MOUNT,UMOUNT} */
- unsigned long mountflags; /* MS_* flags */
- char *filename; /* usually /etc/mtab or /var/run/mount/mountinfo */
- char *old_target; /* for MS_MOVE */
- int format; /* MNT_FMT_{MTAB,FSTAB,MOUNTINFO} */
- int nolock; /* don't alloca private mnt_lock */
- mnt_fs *fs; /* entry */
- mnt_lock *lc; /* lock or NULL */
- int pointless; /* update is unnecessary */
+ char *target;
+ mnt_fs *fs;
+ unsigned long mountflags;
+ int userspace_only;
+ int ready;
};
+static int utab_new_entry(mnt_fs *fs, unsigned long mountflags, mnt_fs **ent);
+static int get_fs_root(mnt_fs *fs, unsigned long mountflags, char **result);
+
/**
* mnt_new_update:
- * @action: MNT_ACT_{MOUNT,UMOUNT}
- * @mountflags: MS_{REMOUNT,BIND,MOVE}
- * @fs: FS description
+ * @userspace_only: TRUE/FALSE -- maintain userspace mount options only
*
- * Returns: newly allocated update description
+ * Returns: newly allocated update handler
*/
-mnt_update *mnt_new_update(int action, unsigned long mountflags, const mnt_fs *fs)
+mnt_update *mnt_new_update(int userspace_only)
{
mnt_update *upd;
@@ -89,14 +51,9 @@ mnt_update *mnt_new_update(int action, unsigned long mountflags, const mnt_fs *f
if (!upd)
return NULL;
+ upd->userspace_only = userspace_only;
DBG(UPDATE, mnt_debug_h(upd, "allocate"));
- if (action)
- mnt_update_set_action(upd, action);
- if (mountflags)
- mnt_update_set_mountflags(upd, mountflags);
- if (fs)
- mnt_update_set_fs(upd, fs);
return upd;
}
@@ -113,378 +70,183 @@ void mnt_free_update(mnt_update *upd)
DBG(UPDATE, mnt_debug_h(upd, "free"));
- mnt_free_lock(upd->lc);
- free(upd->filename);
- free(upd->old_target);
+ mnt_free_fs(upd->fs);
+ free(upd->target);
free(upd);
}
/**
- * mnt_update_set_filename:
- * @upd: update
- * @filename: path to update (default is /etc/update or /var/run/mount/mountinfo)
- *
- * Returns: 0 on success, -1 in case of error.
- */
-int mnt_update_set_filename(mnt_update *upd, const char *filename)
-{
- char *p = NULL;
-
- assert(upd);
- if (!upd)
- return -EINVAL;
- if (filename) {
- p = strdup(filename);
- if (!p)
- return -ENOMEM;
- }
- free(upd->filename);
- upd->filename = p;
- return 0;
-}
-
-/**
- * mnt_update_get_filename
- * @upd: update
+ * mnt_update_is_ready:
+ * @upd: update handler
*
- * Note that function returns NULL if the filename has not been defined (see
- * mnt_update_set_filename()) or mnt_prepare_update() has not been called.
- *
- * Returns: filename or NULL.
+ * Returns: 1 if entry described by @upd is successfully prepared and will be
+ * written to mtab/utab file.
*/
-const char *mnt_update_get_filename(mnt_update *upd)
+int mnt_update_is_ready(mnt_update *upd)
{
- return upd ? upd->filename : NULL;
-}
-
-/**
- * mnt_update_set_action:
- * @upd: update
- * @action: MNT_ACT_{MOUNT,UMOUNT}
- *
- * Overwrites the previously defined (usually by mnt_new_update()) action.
- *
- * Returns: 0 on success, -1 in case of error.
- */
-int mnt_update_set_action(mnt_update *upd, int action)
-{
- assert(upd);
- if (!upd)
- return -EINVAL;
- upd->action = action;
- return 0;
+ return upd ? upd->ready : FALSE;
}
/**
- * mnt_update_set_format:
- * @upd: update
- * @format: MNT_FMT_{MTAB,FSTAB,MOUNTINFO}
- *
- * Sets update file format, default is MNT_FMT_MTAB for paths that end with
- * "update", MNT_FMT_MOUNTINFO for paths that end with "mountinfo" and
- * MNT_FMT_FSTAB for paths that end with "fstab".
+ * mnt_update_is_userspace_only:
+ * @upd: update handler
*
- * Returns: 0 on success, -1 in case of error.
+ * Returns: 1 if @upd cares about userspace mount options only (see
+ * mnt_new_update().
*/
-int mnt_update_set_format(mnt_update *upd, int format)
+int mnt_update_is_userspace_only(mnt_update *upd)
{
- assert(upd);
- if (!upd)
- return -EINVAL;
- upd->format = format;
- return 0;
+ return upd ? upd->userspace_only : FALSE;
}
-/**
- * mnt_update_get_format
- * @upd: update
- *
- * Note that function returns zero if the format has not been defined (see
- * mnt_update_set_format()) or mnt_prepare_update() has not been called.
- *
- * Returns: MNT_FMT_{MTAB,FSTAB,MOUNTINFO} or 0.
- */
-int mnt_update_get_format(mnt_update *upd)
-{
- return upd ? upd->format : 0;
-}
/**
* mnt_update_set_fs:
- * @upd: update
- * @fs: filesystem to write to file
- *
- * This function replaces the current setting related to the current FS. Note that
- * format, old target and mountflags are not reseted.
+ * @upd: update handler
+ * @mountflags: MS_* flags
+ * @target: umount target or MS_MOVE source
+ * @fs: mount or MS_REMOUNT filesystem description, or MS_MOVE target
*
- * Returns; 0 on success, -1 in case of error.
+ * Returns: -1 in case on error, 0 on success, 1 if update is unnecessary.
*/
-int mnt_update_set_fs(mnt_update *upd, const mnt_fs *fs)
+int mnt_update_set_fs(mnt_update *upd, int mountflags,
+ const char *target, mnt_fs *fs)
{
- mnt_fs *x = NULL;
-
assert(upd);
- if (!upd)
- return -EINVAL;
- if (fs) {
- x = mnt_copy_fs(fs);
- if (!x)
- return -ENOMEM;
- }
+ assert(target || fs);
- mnt_free_fs(upd->fs);
- upd->fs = x;
- upd->pointless = FALSE;
- return 0;
-}
-
-/**
- * mnt_update_set_mountflags:
- * @upd: update
- * @flags: MS_{REMOUNT,MOVE,BIND,...}
- *
- * Sets mount flags for mount/umount action. The flags are also
- * extracted from mount options by mnt_prepare_update(). The mount flags
- * are used for mtab update to differentiate between move, remount, ...
- *
- * Returns: 0 on success, -1 in case of error.
- */
-int mnt_update_set_mountflags(mnt_update *upd, unsigned long flags)
-{
- assert(upd);
if (!upd)
return -EINVAL;
- upd->mountflags = flags;
- return 0;
-}
-/**
- * mnt_update_get_lock:
- * @upd: update
- *
- * This function should not be called before mnt_prepare_update(). The lock
- * is initialized when mtab update is required only.
- *
- * Note that after mnt_update_disable_lock(mt, TRUE) or after mnt_free_update()
- * the lock will be automatically deallocated.
- *
- * Returns: libmount lock handler or NULL if locking is disabled or update is
- * not prepared yet.
- */
-mnt_lock *mnt_update_get_lock(mnt_update *upd)
-{
- return upd ? upd->lc : NULL;
-}
+ DBG(UPDATE, mnt_debug_h(upd,
+ "reseting FS [fs=0x%p, target=%s, flags=0x%08x]",
+ fs, target, mountflags));
-/**
- * mnt_update_disable_lock:
- * @upd: update
- * @disable: TRUE/FALSE
- *
- * Enable or disable update locking, the locking is enabled by default.
- *
- * Returns: 0 on success, -1 in case of error.
- */
-int mnt_update_disable_lock(mnt_update *upd, int disable)
-{
- if (!upd)
- return -1;
- if (disable) {
- mnt_free_lock(upd->lc);
- upd->lc = NULL;
- }
- upd->nolock = disable;
- return 0;
-}
+ mnt_free_fs(upd->fs);
+ free(upd->target);
+ upd->ready = FALSE;
+ upd->fs = NULL;
+ upd->target = NULL;
+ upd->mountflags = mountflags;
-/**
- * mnt_update_set_old_target:
- * @upd: update
- * @target: old mountpoint
- *
- * Sets the original target for the MS_MOVE operation.
- *
- * Returns: 0 on success, -1 in case of error.
- */
-int mnt_update_set_old_target(mnt_update *upd, const char *target)
-{
- char *p = NULL;
+ if (fs) {
+ if (upd->userspace_only && !(mountflags & MS_MOVE)) {
+ int rc = utab_new_entry(fs, mountflags, &upd->fs);
+ if (rc)
+ return rc;
+ } else {
+ upd->fs = mnt_copy_fs(fs);
+ if (!upd->fs)
+ return -ENOMEM;
+ }
+ }
- if (!upd)
- return -EINVAL;
if (target) {
- p = strdup(target);
- if (!p)
- return -1;
+ upd->target = strdup(target);
+ if (!upd->target)
+ return -ENOMEM;
}
- free(upd->old_target);
- upd->old_target = p;
+
+ DBG(UPDATE, mnt_debug_h(upd, "ready"));
+ upd->ready = TRUE;
return 0;
}
+
/*
- * The format is same as /proc/self/mountinfo, but it contains userspace
- * mount options and some unnecessary fields are ignored.
+ * Allocates (but does not write) utab entry for mount/remount. This function
+ * should be called *before* mount(2) syscall.
+ *
+ * Returns: 0 on success, negative number on error, 1 if utabs update is
+ * unnecessary.
*/
-static int fprintf_mountinfo_fs(FILE *f, mnt_fs *fs)
+static int utab_new_entry(mnt_fs *fs, unsigned long mountflags, mnt_fs **ent)
{
- 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 -EINVAL;
- 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;
-}
-
-/* mtab and fstab update */
-static int fprintf_mtab_fs(FILE *f, mnt_fs *fs)
-{
- char *m1 = NULL, *m2 = NULL, *m3 = NULL, *m4 = NULL;
- int rc = -1;
+ int rc = 0;
+ const char *o = NULL;
+ char *u = NULL;
assert(fs);
- assert(f);
-
- if (!fs || !f)
- return -EINVAL;
-
- 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;
-}
+ assert(ent);
+ assert(!(mountflags & MS_MOVE));
-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 *) = fprintf_mountinfo_fs;
-
- assert(tb);
- if (!tb)
+ if (!fs || !ent)
return -EINVAL;
+ *ent = NULL;
- DBG(UPDATE, mnt_debug("%s: update from tab %p", filename, tb));
-
- if (snprintf(tmpname, sizeof(tmpname), "%s.tmp", filename)
- >= sizeof(tmpname))
- goto error;
-
- f = fopen(tmpname, "w");
- if (!f)
- goto error;
-
-
- if (fmt == MNT_FMT_MTAB || fmt == MNT_FMT_FSTAB)
- line_fn = fprintf_mtab_fs;
+ DBG(UPDATE, mnt_debug("prepare utab entry"));
- 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;
+ o = mnt_fs_get_optstr(fs);
+ if (o) {
+ rc = mnt_split_optstr(o, &u, NULL, NULL, MNT_NOMTAB, 0);
+ if (rc)
+ return rc; /* parse error or so... */
+ }
+ /* TODO
+ if (extra_opts) {
+ rc = mnt_optstr_append_option(&u, extra_opts, NULL);
+ if (rc)
+ goto err;
+ }
+ */
+ if (!u)
+ return 1; /* don't have mount options */
+
+ /* allocate the entry */
+ *ent = mnt_copy_fs(fs);
+ if (!*ent) {
+ rc = -ENOMEM;
+ goto err;
}
- fclose(f);
- f = NULL;
+ rc = __mnt_fs_set_optstr_ptr(*ent, u, FALSE);
+ if (rc)
+ goto err;
+ u = NULL;
- if (rename(tmpname, filename) < 0)
- goto error;
+ if (!(mountflags & MS_REMOUNT)) {
+ rc = get_fs_root(fs, mountflags, &(*ent)->root);
+ if (rc)
+ goto err;
+ }
+ DBG(UPDATE, mnt_debug("utab entry OK"));
return 0;
-error:
- DBG(UPDATE, mnt_debug("%s: update from tab %p failed", filename, tb));
- if (f)
- fclose(f);
- return errno ? -errno : -1;
+err:
+ free(u);
+ mnt_free_fs(*ent);
+ return rc;
}
-static int set_fs_root(mnt_update *upd, mnt_fs *fs)
+static int get_fs_root(mnt_fs *fs, unsigned long mountflags, char **result)
{
char *root = NULL, *mnt = NULL;
- const char *fstype;
- char *optstr;
+ const char *fstype, *optstr;
mnt_tab *tb = NULL;
+ int rc = -ENOMEM;
- if (upd->mountflags & MS_REMOUNT)
- return 0;
+ assert(fs);
+ assert(result);
+
+ DBG(UPDATE, mnt_debug("setting FS root"));
- optstr = (char *) mnt_fs_get_optstr(fs);
+ optstr = mnt_fs_get_optstr(fs);
fstype = mnt_fs_get_fstype(fs);
/*
* bind-mount -- get fs-root and source device for the source filesystem
*/
- if (upd->mountflags & MS_BIND) {
+ if (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)
+ if (src)
+ mnt = mnt_get_mountpoint(src);
+ if (!mnt) {
+ rc = -EINVAL;
goto err;
+ }
root = mnt_get_fs_root(src, mnt);
tb = mnt_new_tab_from_file(_PATH_PROC_MOUNTINFO);
@@ -525,7 +287,8 @@ static int set_fs_root(mnt_update *upd, mnt_fs *fs)
char *vol = NULL, *p;
size_t sz, volsz = 0;
- if (mnt_optstr_get_option(optstr, "subvol", &vol, &volsz))
+ // TODO: remove this stupid cast...
+ if (mnt_optstr_get_option((char *) optstr, "subvol", &vol, &volsz))
goto dflt;
sz = volsz;
@@ -540,358 +303,338 @@ static int set_fs_root(mnt_update *upd, mnt_fs *fs)
memcpy(p, vol, volsz);
*(root + sz) = '\0';
}
-
dflt:
mnt_free_tab(tb);
- if (!root)
+ if (!root) {
root = strdup("/");
- if (!root)
- goto err;
- fs->root = root;
+ if (!root)
+ goto err;
+ }
+ *result = root;
free(mnt);
return 0;
err:
free(root);
free(mnt);
- return -1;
-}
-
-/**
- * mnt_update_is_pointless:
- * @upd: update
- *
- * This function returns 1 if the previous mnt_prepare_update() call returned 1
- * too.
- *
- * Returns: status of the update.
- */
-int mnt_update_is_pointless(mnt_update *upd)
-{
- return upd ? upd->pointless : 0;
+ return rc;
}
-/**
- * mnt_prepare_update:
- * @upd: update
- *
- * Prepares internal data for mtab update:
- * - set filename if mnt_update_set_filename() wasn't called
- * - set file format if mnt_update_set_format() wasn't called
- * - bitwise-OR mountflags from mount options
- * - for /var/run/mount/mountinfo:
- * * evaluate if the update is necessary
- * * set fs root and devname for bind mount and btrfs subvolumes
- * * removes unnecessary mount options
- * - allocate update_lock if necessary
- *
- * This function has to be always called before mount(2). The mnt_update_file()
- * should not be called if mnt_prepare_update() returns non-zero value.
- *
- * Returns: 0 on success, 1 if update is unnecessary, negative in case of error
- */
-int mnt_prepare_update(mnt_update *upd)
+/* mtab and fstab update */
+static int fprintf_mtab_fs(FILE *f, mnt_fs *fs)
{
- char *u = NULL;
- const char *o = NULL;
- int rc = 0;
-
- assert(upd);
- assert(upd->fs);
-
- if (!upd || !upd->fs)
- return -EINVAL;
+ char *m1, *m2, *m3, *m4;
+ int rc;
- DBG(UPDATE, mnt_debug_h(upd,
- "prepare update (target=%s, source=%s, optstr=%s)",
- mnt_fs_get_target(upd->fs),
- mnt_fs_get_source(upd->fs),
- mnt_fs_get_optstr(upd->fs)));
-
- if (!upd->filename) {
- const char *p = mnt_get_writable_mtab_path();
-
- if (!p) {
- if (errno) {
- rc = -errno;
- goto err; /* EACCES? */
- }
- goto nothing; /* no mtab */
- }
- upd->filename = strdup(p);
- if (!upd->filename) {
- rc = -ENOMEM;
- goto err;
- }
- }
+ assert(fs);
+ assert(f);
- DBG(UPDATE, mnt_debug_h(upd, "filename: %s", upd->filename));
+ 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 (!upd->format) {
- if (endswith(upd->filename, "mountinfo"))
- upd->format = MNT_FMT_MOUNTINFO;
- else if (endswith(upd->filename, "fstab"))
- upd->format = MNT_FMT_FSTAB;
- else
- upd->format = MNT_FMT_MTAB;
- }
+ if (m1 && m2 && m3 && m4)
+ rc = !fprintf(f, "%s %s %s %s %d %d\n",
+ m1, m2, m3, m4,
+ mnt_fs_get_freq(fs),
+ mnt_fs_get_passno(fs));
+ else
+ rc = -ENOMEM;
- DBG(UPDATE, mnt_debug_h(upd, "format: %s",
- upd->format == MNT_FMT_MOUNTINFO ? "mountinfo" :
- upd->format == MNT_FMT_FSTAB ? "fstab" : "mtab"));
+ free(m1);
+ free(m2);
+ free(m3);
+ free(m4);
- /* TODO: cannonicalize source and target paths on mnt->fs */
+ return rc;
+}
- if (upd->format != MNT_FMT_FSTAB) {
- unsigned long fl = 0;
+static int fprintf_utab_fs(FILE *f, mnt_fs *fs)
+{
+ char *root = NULL, *target = NULL, *optstr = NULL,
+ *fstype = NULL, *source = NULL;
+ int rc = -1;
+ dev_t devno;
- o = mnt_fs_get_optstr(upd->fs);
- if (o && !mnt_optstr_get_mountflags(o, &fl))
- upd->mountflags |= fl;
- }
+ assert(fs);
+ assert(f);
- /* umount */
- if (upd->action == MNT_ACT_UMOUNT)
- goto done;
+ if (!fs || !f)
+ return -EINVAL;
+ 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));
- /*
- * A) classic /etc/mtab or /etc/fstab update
- */
- if (upd->format != MNT_FMT_MOUNTINFO)
+ if (!root || !target || !optstr)
goto done;
- /*
- * B) /var/run/mount/mountinfo
- * - remove all non-userspace mount options
- */
- if (upd->mountflags & MS_REMOUNT) {
- rc = mnt_split_optstr(o, &u, NULL, NULL, MNT_NOMTAB, 0);
- if (rc)
- goto err;
- rc = __mnt_fs_set_optstr_ptr(upd->fs, u, FALSE);
- if (rc)
- goto err;
- u = NULL;
- } else {
- if (!o)
- goto nothing; /* no options */
- rc = mnt_split_optstr(o, &u, NULL, NULL, MNT_NOMTAB, 0);
- if (rc)
- goto err;
- if (!u)
- goto nothing; /* no userpsace options */
- rc = set_fs_root(upd, upd->fs);
- if (rc)
- goto err;
- rc = __mnt_fs_set_optstr_ptr(upd->fs, u, FALSE);
- if (rc)
- goto err;
- u = NULL;
- }
-
+ 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:
- if (!upd->nolock && !upd->lc) {
- upd->lc = mnt_new_lock(upd->filename, 0);
- if (!upd->lc) {
- rc = -ENOMEM;
- goto err;
- }
- }
-
- DBG(UPDATE, mnt_debug_h(upd, "prepare update: success"));
- return 0;
-err:
- free(u);
- DBG(UPDATE, mnt_debug_h(upd, "prepare update: failed"));
+ free(root);
+ free(target);
+ free(optstr);
+ free(fstype);
+ free(source);
return rc;
-nothing:
- upd->pointless = TRUE;
- DBG(UPDATE, mnt_debug_h(upd, "prepare update: pointless"));
- return 1;
}
-static int add_entry(mnt_update *upd)
+static int update_tab(mnt_update *upd, const char *filename, mnt_tab *tb)
{
FILE *f;
- int rc = -1;
+ int rc, fd;
+ char *uq = NULL;
- assert(upd);
+ if (!tb || !filename)
+ return -EINVAL;
- DBG(UPDATE, mnt_debug_h(upd, "add entry"));
+ DBG(UPDATE, mnt_debug_h(upd, "%s: updating", filename));
- if (upd->lc)
- mnt_lock_file(upd->lc);
- f = fopen(upd->filename, "a+");
+ fd = mnt_open_uniq_filename(filename, &uq, O_WRONLY);
+ if (fd < 0)
+ return fd; /* error */
+
+ f = fdopen(fd, "w");
if (f) {
- if (upd->format == MNT_FMT_MOUNTINFO)
- rc = fprintf_mountinfo_fs(f, upd->fs);
- else
- rc = fprintf_mtab_fs(f, upd->fs);
+ struct stat st;
+ mnt_iter itr;
+ mnt_fs *fs;
+ int fd;
+
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
+ if (upd->userspace_only)
+ fprintf_utab_fs(f, fs);
+ else
+ fprintf_mtab_fs(f, fs);
+ }
+ fd = fileno(f);
+ rc = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) ? -errno : 0;
+
+ if (!rc &&stat(filename, &st) == 0)
+ /* Copy uid/gid from the present file before renaming. */
+ rc = fchown(fd, st.st_uid, st.st_gid) ? -errno : 0;
+
fclose(f);
+ rc = rename(uq, filename) ? -errno : 0;
+ } else {
+ rc = -errno;
+ close(fd);
}
- if (upd->lc)
- mnt_unlock_file(upd->lc);
+
+ unlink(uq); /* be paranoid */
+ free(uq);
return rc;
}
-static int remove_entry(mnt_update *upd)
+static int utab_lock(const char *filename)
{
- const char *target;
- mnt_tab *tb = NULL;
- mnt_fs *fs = NULL;
- int rc = -1;
+ char *lfile;
+ int fd;
- assert(upd);
- assert(upd->filename);
+ assert(filename);
- target = mnt_fs_get_target(upd->fs);
- assert(target);
+ if (asprintf(&lfile, "%s.lock", filename) == -1)
+ return -1;
- DBG(UPDATE, mnt_debug_h(upd, "remove entry (target %s)", target));
+ DBG(UPDATE, mnt_debug("%s: locking", lfile));
- if (upd->lc)
- mnt_lock_file(upd->lc);
- tb = mnt_new_tab_from_file(upd->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;
+ fd = open(lfile, O_RDONLY|O_CREAT|O_CLOEXEC, S_IRUSR|S_IWUSR);
+ free(lfile);
+
+ if (fd < 0)
+ return -errno;
+ if (flock(fd, LOCK_EX)) {
+ int errsv = errno;
+ close(fd);
+ return -errsv;
}
- mnt_tab_remove_fs(tb, fs);
+ return fd;
+}
- if (!update_file(upd->filename, upd->format, tb))
- rc = 0;
-done:
- if (upd->lc)
- mnt_unlock_file(upd->lc);
- mnt_free_tab(tb);
- mnt_free_fs(fs);
- return rc;
+static void utab_unlock(int fd)
+{
+ if (fd >= 0) {
+ DBG(UPDATE, mnt_debug("unlocking utab"));
+ close(fd);
+ }
}
-static int modify_target(mnt_update *upd)
+static int update_add_entry(mnt_update *upd, const char *filename, mnt_lock *lc)
{
- mnt_tab *tb = NULL;
- mnt_fs *fs = NULL;
- int rc = -1;
+ FILE *f;
+ int rc = 0, u_lc = -1;
assert(upd);
- assert(upd->old_target);
- assert(upd->filename);
- assert(mnt_fs_get_target(upd->fs));
+ assert(upd->fs);
- if (!upd->old_target)
- return -1;
+ DBG(UPDATE, mnt_debug_h(upd, "%s: add entry", filename));
- DBG(UPDATE, mnt_debug_h(upd, "modify target (%s->%s)",
- upd->old_target, mnt_fs_get_target(upd->fs)));
+ if (lc)
+ mnt_lock_file(lc);
+ else if (upd->userspace_only)
+ u_lc = utab_lock(filename);
- if (upd->lc)
- mnt_lock_file(upd->lc);
- tb = mnt_new_tab_from_file(upd->filename);
- if (!tb)
- goto done;
- fs = mnt_tab_find_target(tb, upd->old_target, MNT_ITER_BACKWARD);
- if (!fs) {
- rc = 0; /* no error if the file does not contain the target */
- goto done;
+ f = fopen(filename, "a+");
+ if (f) {
+ rc = upd->userspace_only ? fprintf_utab_fs(f, upd->fs) :
+ fprintf_mtab_fs(f, upd->fs);
+ DBG(UPDATE, mnt_debug_h(upd, "%s: add [rc=%d]", filename, rc));
+ fclose(f);
+ } else {
+ DBG(UPDATE, mnt_debug_h(upd, "%s: failed: %m", filename));
+ rc = -errno;
}
+ if (lc)
+ mnt_unlock_file(lc);
+ else if (u_lc != -1)
+ utab_unlock(u_lc);
+ return rc;
+}
- mnt_fs_set_target(fs, mnt_fs_get_target(upd->fs));
+static int update_remove_entry(mnt_update *upd, const char *filename, mnt_lock *lc)
+{
+ mnt_tab *tb;
+ int rc = -EINVAL, u_lc = -1;
- if (!update_file(upd->filename, upd->format, tb))
- rc = 0;
-done:
- if (upd->lc)
- mnt_unlock_file(upd->lc);
- mnt_free_tab(tb);
+ assert(upd);
+ assert(upd->target);
+
+ DBG(UPDATE, mnt_debug_h(upd, "%s: remove entry", filename));
+
+ if (lc)
+ mnt_lock_file(lc);
+ else if (upd->userspace_only)
+ u_lc = utab_lock(filename);
+
+ tb = mnt_new_tab_from_file(filename);
+ if (tb) {
+ mnt_fs *rem = mnt_tab_find_target(tb, upd->target, MNT_ITER_BACKWARD);
+ if (rem) {
+ mnt_tab_remove_fs(tb, rem);
+ rc = update_tab(upd, filename, tb);
+ mnt_free_fs(rem);
+ }
+ mnt_free_tab(tb);
+ }
+ if (lc)
+ mnt_unlock_file(lc);
+ else if (u_lc != -1)
+ utab_unlock(u_lc);
return rc;
}
-static int modify_options(mnt_update *upd)
+static int update_modify_target(mnt_update *upd, const char *filename, mnt_lock *lc)
{
mnt_tab *tb = NULL;
- mnt_fs *fs = NULL, *rem_fs = NULL;
- int rc = -1;
- const char *target = mnt_fs_get_target(upd->fs);
+ int rc = -EINVAL, u_lc = -1;
+
+ DBG(UPDATE, mnt_debug_h(upd, "%s: modify target", filename));
+
+ if (lc)
+ mnt_lock_file(lc);
+ else if (upd->userspace_only)
+ u_lc = utab_lock(filename);
+
+ tb = mnt_new_tab_from_file(filename);
+ if (tb) {
+ mnt_fs *cur = mnt_tab_find_target(tb, upd->target, MNT_ITER_BACKWARD);
+ if (cur) {
+ rc = mnt_fs_set_target(cur, mnt_fs_get_target(upd->fs));
+ if (!rc)
+ rc = update_tab(upd, filename, tb);
+ }
+ mnt_free_tab(tb);
+ }
+ if (lc)
+ mnt_unlock_file(lc);
+ else if (u_lc != -1)
+ utab_unlock(u_lc);
+ return rc;
+}
- assert(target);
- assert(upd->filename);
+static int update_modify_options(mnt_update *upd, const char *filename, mnt_lock *lc)
+{
+ mnt_tab *tb = NULL;
+ int rc = -EINVAL, u_lc = -1;
- DBG(UPDATE, mnt_debug_h(upd, "modify options (target %s)", target));
+ assert(upd);
+ assert(upd->fs);
- if (upd->lc)
- mnt_lock_file(upd->lc);
- tb = mnt_new_tab_from_file(upd->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;
+ DBG(UPDATE, mnt_debug_h(upd, "%s: modify options", filename));
+
+ if (lc)
+ mnt_lock_file(lc);
+ else if (upd->userspace_only)
+ u_lc = utab_lock(filename);
+
+ tb = mnt_new_tab_from_file(filename);
+ if (tb) {
+ mnt_fs *cur = mnt_tab_find_target(tb,
+ mnt_fs_get_target(upd->fs),
+ MNT_ITER_BACKWARD);
+ if (cur) {
+ rc = mnt_fs_set_optstr(cur, mnt_fs_get_optstr(upd->fs));
+ if (!rc)
+ rc = update_tab(upd, filename, tb);
+ }
+ mnt_free_tab(tb);
}
- if (upd->format == MNT_FMT_MOUNTINFO && !mnt_fs_get_optstr(upd->fs)) {
- mnt_tab_remove_fs(tb, fs);
- rem_fs = fs;
- } else
- rc = __mnt_fs_set_optstr(fs, mnt_fs_get_optstr(upd->fs), FALSE);
+ if (lc)
+ mnt_unlock_file(lc);
+ else if (u_lc != -1)
+ utab_unlock(u_lc);
- if (!update_file(upd->filename, upd->format, tb))
- rc = 0;
-done:
- if (upd->lc)
- mnt_unlock_file(upd->lc);
- mnt_free_tab(tb);
- mnt_free_fs(rem_fs);
return rc;
}
/**
- * mnt_update_file:
- * @upd: update
+ * mnt_update_tab:
+ * @filename: mtab of utab filename
+ * @lc: lock
*
- * Updates the update file. The behavior of this function is undefined if
- * mnt_prepare_update() has not been called. The request to update file will
- * be ignored for pointless updates (see mnt_update_is_pointless()).
+ * High-level API to update /etc/mtab or /dev/.mount/utab.
*
- * Returns: 0 on success, -1 in case of error.
+ * Returns: 0 on success, negative number on error.
*/
-int mnt_update_file(mnt_update *upd)
+int mnt_update_tab(mnt_update *upd, const char *filename, mnt_lock *lc)
{
+ int rc = -EINVAL;
+
assert(upd);
- assert(upd->filename);
- assert(upd->format);
- assert(upd->fs);
+ assert(filename);
- if (!upd || !upd->fs)
- return -1;
+ DBG(UPDATE, mnt_debug_h(upd, "%s: update tab", filename));
- if (upd->pointless) {
- DBG(UPDATE, mnt_debug_h(upd, "ingnore update requiest (pointless)"));
+ if (!filename || !upd)
+ return -EINVAL;
+ if (!upd->ready)
return 0;
- }
-
- DBG(UPDATE, mnt_debug_h(upd, "update (target %s)",
- mnt_fs_get_target(upd->fs)));
- /*
- * umount
- */
- if (upd->action == MNT_ACT_UMOUNT)
- return remove_entry(upd);
- /*
- * mount
- */
- if (upd->action == MNT_ACT_MOUNT) {
- if (upd->mountflags & MS_REMOUNT)
- return modify_options(upd);
- if (upd->mountflags & MS_MOVE)
- return modify_target(upd);
-
- return add_entry(upd); /* mount */
- }
- return -1;
+ if (!upd->fs && upd->target)
+ rc = update_remove_entry(upd, filename, lc); /* umount */
+ else if (upd->mountflags & MS_MOVE)
+ rc = update_modify_target(upd, filename, lc); /* move */
+ else if (upd->mountflags & MS_REMOUNT)
+ rc = update_modify_options(upd, filename, lc); /* remount */
+ else if (upd->fs)
+ rc = update_add_entry(upd, filename, lc); /* mount */
+
+ upd->ready = FALSE;
+ DBG(UPDATE, mnt_debug_h(upd, "%s: update tab: done [rc=%d]", filename, rc));
+ return rc;
}
#ifdef TEST_PROGRAM
@@ -906,150 +649,102 @@ static void lock_fallback(void)
mnt_unlock_file(lock);
}
-static int update(mnt_update *upd)
+static int update(const char *target, mnt_fs *fs, unsigned long mountflags)
{
- int rc;
+ int rc, writable = 0;
+ const char *filename = NULL;
+ mnt_update *upd;
+ mnt_lock *lock = NULL;
- /*
- * Note that mount(2) syscal should be called *after*
- * mnt_prepare_update() and *before* mnt_update_file()
- */
- rc = mnt_prepare_update(upd);
- if (!rc) {
- /* setup lock fallback */
- int rc;
+ DBG(UPDATE, mnt_debug("update test"));
- lock = mnt_update_get_lock(upd);
- atexit(lock_fallback);
+ rc = mnt_has_regular_mtab(&filename, &writable);
+ if (rc && writable) {
+ upd = mnt_new_update(FALSE);
+ lock = mnt_new_lock(filename, 0);
- rc = mnt_update_file(upd);
- lock = NULL;
- return rc;
- }
- if (rc == 1)
- return 0;
- fprintf(stderr, "update: failed to prepare update\n");
- return -1;
-}
+ /* note that proper solution is to call mnt_unlock_file() from
+ * signal handler. The atexit() could be ignore if program ends
+ * by _exit(). The _exit() function is usually used in signal
+ * handlers.
+ */
+ atexit(lock_fallback);
-int test_add(struct mtest *ts, int argc, char *argv[])
-{
- mnt_fs *fs = mnt_new_fs();
- mnt_update *upd;
- int rc = -1;
+ } else {
+ filename = NULL;
+ rc = mnt_has_regular_utab(&filename, &writable);
- if (argc < 5 || !fs)
- return -1;
- mnt_fs_set_source(fs, argv[1]);
- mnt_fs_set_target(fs, argv[2]);
- mnt_fs_set_fstype(fs, argv[3]);
- mnt_fs_set_optstr(fs, argv[4]);
+ if (rc && writable)
+ upd = mnt_new_update(TRUE);
+ else
+ return -EACCES;
+ }
- upd = mnt_new_update(MNT_ACT_MOUNT, 0, fs);
- if (!upd)
- return -1;
+ rc = mnt_update_set_fs(upd, mountflags, target, fs);
+ if (rc)
+ goto done;
+ if (rc == 1) {
+ fprintf(stderr, "update is unnecessary\n");
+ rc = 0;
+ goto done;
+ }
- rc = update(upd);
+ /* [... here should be mount(2) call ...] */
- mnt_free_update(upd);
- mnt_free_fs(fs);
+ rc = mnt_update_tab(upd, filename, lock);
+done:
return rc;
}
-int test_add_fstab(struct mtest *ts, int argc, char *argv[])
+static int test_add(struct mtest *ts, int argc, char *argv[])
{
mnt_fs *fs = mnt_new_fs();
- mnt_update *upd;
- int rc = -1;
+ int rc;
- if (argc < 7 || !fs)
+ if (argc < 5 || !fs)
return -1;
mnt_fs_set_source(fs, argv[1]);
mnt_fs_set_target(fs, argv[2]);
mnt_fs_set_fstype(fs, argv[3]);
mnt_fs_set_optstr(fs, argv[4]);
- mnt_fs_set_freq(fs, atoi(argv[5]));
- mnt_fs_set_passno(fs, atoi(argv[6]));
-
- /* this is tricky -- to add to fstab use "MNT_ACT_MOUNT" */
- upd = mnt_new_update(MNT_ACT_MOUNT, 0, fs);
- if (!upd)
- return -1;
-
- mnt_update_disable_lock(upd, TRUE); /* lock is unnecessary */
-
- mnt_update_set_filename(upd, mnt_get_fstab_path());
- mnt_update_set_format(upd, MNT_FMT_FSTAB);
-
- rc = update(upd);
- mnt_free_update(upd);
+ rc = update(NULL, fs, 0);
mnt_free_fs(fs);
return rc;
}
-int test_remove(struct mtest *ts, int argc, char *argv[])
+static int test_remove(struct mtest *ts, int argc, char *argv[])
{
- mnt_fs *fs = mnt_new_fs();
- mnt_update *upd;
- int rc = -1;
-
- if (argc < 2 || !fs)
- return -1;
- mnt_fs_set_target(fs, argv[1]);
-
- upd = mnt_new_update(MNT_ACT_UMOUNT, 0, fs);
- if (!upd)
+ if (argc < 2)
return -1;
-
- rc = update(upd);
-
- mnt_free_update(upd);
- mnt_free_fs(fs);
- return rc;
+ return update(argv[1], NULL, 0);
}
-int test_move(struct mtest *ts, int argc, char *argv[])
+static int test_move(struct mtest *ts, int argc, char *argv[])
{
mnt_fs *fs = mnt_new_fs();
- mnt_update *upd;
- int rc = -1;
+ int rc;
- if (argc < 3 || !fs)
+ if (argc < 3)
return -1;
mnt_fs_set_target(fs, argv[2]);
+ rc = update(argv[1], fs, MS_MOVE);
- upd = mnt_new_update(MNT_ACT_MOUNT, MS_MOVE, fs);
- if (!upd)
- return -1;
- mnt_update_set_old_target(upd, argv[1]);
-
- rc = update(upd);
-
- mnt_free_update(upd);
mnt_free_fs(fs);
return rc;
}
-int test_remount(struct mtest *ts, int argc, char *argv[])
+static int test_remount(struct mtest *ts, int argc, char *argv[])
{
mnt_fs *fs = mnt_new_fs();
- mnt_update *upd;
- int rc = -1;
+ int rc;
- if (argc < 3 || !fs)
+ if (argc < 3)
return -1;
-
mnt_fs_set_target(fs, argv[1]);
mnt_fs_set_optstr(fs, argv[2]);
- upd = mnt_new_update(MNT_ACT_MOUNT, MS_REMOUNT, fs);
- if (!upd)
- return -1;
-
- rc = update(upd);
-
- mnt_free_update(upd);
+ rc = update(NULL, fs, MS_REMOUNT);
mnt_free_fs(fs);
return rc;
}
@@ -1061,9 +756,6 @@ int main(int argc, char *argv[])
{ "--remove", test_remove, "<target> MS_REMOUNT mtab change" },
{ "--move", test_move, "<old_target> <target> MS_MOVE mtab change" },
{ "--remount",test_remount, "<target> <options> MS_REMOUNT mtab change" },
-
- { "--add-fstab", test_add_fstab, "<src> <target> <type> <options> <freq> <passno> add line to fstab" },
-
{ NULL }
};
diff --git a/shlibs/mount/src/utils.c b/shlibs/mount/src/utils.c
index 924284965..410028fa7 100644
--- a/shlibs/mount/src/utils.c
+++ b/shlibs/mount/src/utils.c
@@ -87,6 +87,18 @@ int startswith(const char *s, const char *sx)
return !strncmp(s, sx, off);
}
+/* returns basename and keeps dirname in the @path, if @path is "/" (root)
+ * then returns empty string */
+static char *stripoff_last_component(char *path)
+{
+ char *p = path ? strrchr(path, '/') : NULL;
+
+ if (!p)
+ return NULL;
+ *p = '\0';
+ return ++p;
+}
+
/**
* mnt_mangle:
* @str: string
@@ -404,32 +416,116 @@ done:
return rc;
}
-/*
- * Returns 1 if /etc/mtab is a reqular file.
+static int try_write(const char *filename)
+{
+ int fd;
+
+ if (!filename)
+ return -EINVAL;
+
+ fd = open(filename, O_RDWR, 0644);
+ if (fd >= 0) {
+ close(fd);
+ return 0;
+ }
+ return -errno;
+}
+
+/**
+ * mnt_has_regular_mtab:
+ * @mtab: returns path to mtab
+ * @writable: returns 1 if the file is writable
+ *
+ * If the file does not exist and @writable argument is not NULL then it will
+ * try to create the file
+ *
+ * Returns: 1 if /etc/mtab is a reqular file, and 0 in case of error (check
+ * errno for more details).
*/
-int mnt_has_regular_mtab(const char **mtab, int *writeable)
+int mnt_has_regular_mtab(const char **mtab, int *writable)
{
struct stat st;
int rc;
- const char *x = mtab && *mtab ? *mtab : mnt_get_mtab_path();
+ const char *filename = mtab && *mtab ? *mtab : mnt_get_mtab_path();
if (mtab && !*mtab)
- *mtab = x;
- rc = (lstat(x, &st) == 0 && S_ISREG(st.st_mode));
+ *mtab = filename;
+
+ DBG(UTILS, mnt_debug("mtab: %s", filename));
+ rc = lstat(filename, &st);
+
+ if (rc == 0) {
+ /* file exist */
+ if (S_ISREG(st.st_mode)) {
+ if (writable)
+ *writable = !try_write(filename);
+ return 1;
+ }
+ return 0; /* it's not regular file */
+ }
+
+ /* try to create the file */
if (writable) {
- if (rc) {
- /* TODO: use utimensat() */
- int fd = open(path, O_RDWR, 0644);
- if (fd >= 0) {
- close(fd);
- *writable = 1;
- return rc;
- }
+ *writable = !try_write(filename);
+ return *writable;
+ }
+
+ return 0;
+}
+/**
+ *
+ * mnt_has_regular_utab:
+ * @utab: returns path to utab (usually /dev/.mount/utab)
+ * @writable: returns 1 if the file is writable
+ *
+ * If the file does not exist and @writable argument is not NULL then it will
+ * try to create the directory (e.g. /dev/.mount) and the file.
+ *
+ * Returns: 1 if /etc/utab is a reqular file, and 0 in case of error (check
+ * errno for more details).
+ */
+
+int mnt_has_regular_utab(const char **utab, int *writable)
+{
+ struct stat st;
+ int rc;
+ const char *filename = utab && *utab ? *utab : mnt_get_utab_path();
+
+ if (utab && !*utab)
+ *utab = filename;
+
+ DBG(UTILS, mnt_debug("utab: %s", filename));
+
+ rc = lstat(filename, &st);
+
+ if (rc == 0) {
+ /* file exist */
+ if (S_ISREG(st.st_mode)) {
+ if (writable)
+ *writable = try_write(filename);
+ return 1;
}
- *writable = 0;
+ return 0; /* it's not regular file */
}
- return rc;
+
+ if (writable) {
+ char *dirname = strdup(filename);
+
+ if (!dirname)
+ return 0;
+
+ stripoff_last_component(dirname); /* remove filename */
+
+ rc = mkdir(dirname, 755);
+ free(dirname);
+ if (rc && errno != EEXIST)
+ return 0; /* probably EACCES */
+
+ *writable = !try_write(filename);
+ return *writable;
+ }
+ return 0;
}
/**
@@ -496,18 +592,6 @@ int mnt_open_uniq_filename(const char *filename, char **name, int flags)
return fd < 0 ? -errno : fd;
}
-/* returns basename and keeps dirname in the @path, if @path is "/" (root)
- * then returns empty string */
-static char *stripoff_last_component(char *path)
-{
- char *p = strrchr(path, '/');
-
- if (!p)
- return NULL;
- *p = '\0';
- return ++p;
-}
-
char *mnt_get_mountpoint(const char *path)
{
char *mnt = strdup(path);