From 7e0c06194f5e65eb2a9ae38515d78f4ef301c809 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 4 Nov 2013 12:45:33 +0100 Subject: [PATCH] libmount: update utab after successful extern helper mount This patch allows to maintain private utab libmount file also for external mount/umount helpers that are not linked with libmount. The libmount check if utab has been updated after successful extern helper execution (status=0). If not then the file is updated. This patch affects only 'user' fstab mount option. So, for example with suid mount.cifs you can use: //server/foo /mnt cifs username=foo,noauto,user Signed-off-by: Karel Zak --- libmount/src/context.c | 30 +++++++++++++++-------- libmount/src/mountP.h | 2 ++ libmount/src/tab_update.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 10 deletions(-) diff --git a/libmount/src/context.c b/libmount/src/context.c index 5a88bcd..2ef3d30 100644 --- a/libmount/src/context.c +++ b/libmount/src/context.c @@ -1725,10 +1725,6 @@ int mnt_context_prepare_update(struct libmnt_context *cxt) DBG(CXT, mnt_debug_h(cxt, "skip update: NOMTAB flag")); return 0; } - if (cxt->helper) { - DBG(CXT, mnt_debug_h(cxt, "skip update: external helper")); - return 0; - } if (!cxt->mtab_writable && !cxt->utab_writable) { DBG(CXT, mnt_debug_h(cxt, "skip update: no writable destination")); return 0; @@ -1777,16 +1773,30 @@ int mnt_context_update_tabs(struct libmnt_context *cxt) DBG(CXT, mnt_debug_h(cxt, "don't update: NOMTAB flag")); return 0; } - if (cxt->helper) { - DBG(CXT, mnt_debug_h(cxt, "don't update: external helper")); - return 0; - } if (!cxt->update || !mnt_update_is_ready(cxt->update)) { DBG(CXT, mnt_debug_h(cxt, "don't update: no update prepared")); return 0; } - if (cxt->syscall_status) { - DBG(CXT, mnt_debug_h(cxt, "don't update: syscall failed/not called")); + + /* check utab update when external helper executed */ + if (mnt_context_helper_executed(cxt) + && mnt_context_get_helper_status(cxt) == 0 + && cxt->utab_writable) { + + if (mnt_update_already_done(cxt->update, cxt->lock)) { + DBG(CXT, mnt_debug_h(cxt, "don't update: error evaluate or already updated")); + return 0; + } + } else if (cxt->helper) { + DBG(CXT, mnt_debug_h(cxt, "don't update: external helper")); + return 0; + } + + if (cxt->syscall_status != 0 + && !(mnt_context_helper_executed(cxt) && + mnt_context_get_helper_status(cxt) == 0)) { + + DBG(CXT, mnt_debug_h(cxt, "don't update: syscall/helper failed/not called")); return 0; } diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h index 9362c00..adc245a 100644 --- a/libmount/src/mountP.h +++ b/libmount/src/mountP.h @@ -460,5 +460,7 @@ extern int mnt_context_set_tabfilter(struct libmnt_context *cxt, /* tab_update.c */ extern int mnt_update_set_filename(struct libmnt_update *upd, const char *filename, int userspace_only); +extern int mnt_update_already_done(struct libmnt_update *upd, + struct libmnt_lock *lc); #endif /* _LIBMOUNT_PRIVATE_H */ diff --git a/libmount/src/tab_update.c b/libmount/src/tab_update.c index 13f6f6e..bbe0cb2 100644 --- a/libmount/src/tab_update.c +++ b/libmount/src/tab_update.c @@ -286,6 +286,7 @@ int mnt_update_force_rdonly(struct libmnt_update *upd, int rdonly) return rc; } + /* * Allocates an utab entry (upd->fs) for mount/remount. This function should be * called *before* mount(2) syscall. The @fs is used as a read-only template. @@ -873,6 +874,67 @@ int mnt_update_table(struct libmnt_update *upd, struct libmnt_lock *lc) return rc; } +int mnt_update_already_done(struct libmnt_update *upd, struct libmnt_lock *lc) +{ + struct libmnt_table *tb = NULL; + struct libmnt_lock *lc0 = lc; + int rc = 0; + + if (!upd || !upd->filename || (!upd->fs && !upd->target)) + return -EINVAL; + + DBG(UPDATE, mnt_debug_h(upd, "%s: checking for previous update", upd->filename)); + + if (!lc) { + lc = mnt_new_lock(upd->filename, 0); + if (lc) + mnt_lock_block_signals(lc, TRUE); + } + if (lc && upd->userspace_only) + mnt_lock_use_simplelock(lc, TRUE); /* use flock */ + if (lc) + rc = mnt_lock_file(lc); + if (rc) + goto done; + + tb = __mnt_new_table_from_file(upd->filename, + upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB); + if (lc) + mnt_unlock_file(lc); + if (!tb) + goto done; + + if (upd->fs) { + /* mount */ + const char *tgt = mnt_fs_get_target(upd->fs); + const char *src = mnt_fs_get_bindsrc(upd->fs) ? + mnt_fs_get_bindsrc(upd->fs) : + mnt_fs_get_source(upd->fs); + + if (mnt_table_find_pair(tb, src, tgt, MNT_ITER_BACKWARD)) { + DBG(UPDATE, mnt_debug_h(upd, "%s: found %s %s", + upd->filename, src, tgt)); + rc = 1; + } + } else if (upd->target) { + /* umount */ + if (!mnt_table_find_target(tb, upd->target, MNT_ITER_BACKWARD)) { + DBG(UPDATE, mnt_debug_h(upd, "%s: not-found (umounted) %s", + upd->filename, upd->target)); + rc = 1; + } + } + + mnt_unref_table(tb); +done: + if (lc && lc != lc0) + mnt_free_lock(lc); + DBG(UPDATE, mnt_debug_h(upd, "%s: previous update check done [rc=%d]", + upd->filename, rc)); + return rc; +} + + #ifdef TEST_PROGRAM static int update(const char *target, struct libmnt_fs *fs, unsigned long mountflags) -- 1.8.5.1