summaryrefslogtreecommitdiffstats
path: root/shlibs
diff options
context:
space:
mode:
authorKarel Zak2011-03-30 09:30:05 +0200
committerKarel Zak2011-03-30 09:30:05 +0200
commit5976114f628c96285c9b3f2cc55994f216afe6f2 (patch)
tree7ec6963afb34654f2f44810c31a04af1c413cc52 /shlibs
parentdocs: update TODO (diff)
downloadkernel-qcow2-util-linux-5976114f628c96285c9b3f2cc55994f216afe6f2.tar.gz
kernel-qcow2-util-linux-5976114f628c96285c9b3f2cc55994f216afe6f2.tar.xz
kernel-qcow2-util-linux-5976114f628c96285c9b3f2cc55994f216afe6f2.zip
libmount: block signals when writing to mtab
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'shlibs')
-rw-r--r--shlibs/mount/src/context.c26
-rw-r--r--shlibs/mount/src/libmount.h.in1
-rw-r--r--shlibs/mount/src/libmount.sym1
-rw-r--r--shlibs/mount/src/lock.c43
-rw-r--r--shlibs/mount/src/tab_update.c28
5 files changed, 73 insertions, 26 deletions
diff --git a/shlibs/mount/src/context.c b/shlibs/mount/src/context.c
index dba49430d..f24e90ebb 100644
--- a/shlibs/mount/src/context.c
+++ b/shlibs/mount/src/context.c
@@ -794,13 +794,21 @@ struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt)
* mnt_context_get_lock:
* @cxt: mount context
*
- * 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
- * mount(8)-like application has to call mnt_unlock_file() from a signal handler.
+ * The libmount applications don't have to care about mtab locking, but with a
+ * small exception: the application has to be able to remove the lock file when
+ * interrupted by signal or signals have to be ignored when the lock is locked.
*
- * This function returns NULL if mtab file is not writable or nolock or nomtab
- * flags is enabled.
+ * The default behavior is to ignore all signals (except SIGALRM and SIGTRAP)
+ * when the lock is locked. If this behavior is unacceptable then use:
+ *
+ * lc = mnt_context_get_lock(cxt);
+ * if (lc)
+ * mnt_lock_block_signals(lc, FALSE);
+ *
+ * and don't forget to call mnt_unlock_file(lc) before exit.
+ *
+ * This function returns NULL if the lock is unnecessary (mtab file is not writable
+ * or /etc/mtab is symlink to /proc/mounts).
*
* Returns: pointer to lock struct or NULL.
*/
@@ -809,9 +817,11 @@ struct libmnt_lock *mnt_context_get_lock(struct libmnt_context *cxt)
if (!cxt || (cxt->flags & MNT_FL_NOMTAB) || !cxt->mtab_writable)
return NULL;
- if (!cxt->lock && cxt->mtab_path)
+ if (!cxt->lock && cxt->mtab_path) {
cxt->lock = mnt_new_lock(cxt->mtab_path, 0);
-
+ if (cxt->lock)
+ mnt_lock_block_signals(cxt->lock, TRUE);
+ }
return cxt->lock;
}
diff --git a/shlibs/mount/src/libmount.h.in b/shlibs/mount/src/libmount.h.in
index c9d0ba8f4..d7e7a5172 100644
--- a/shlibs/mount/src/libmount.h.in
+++ b/shlibs/mount/src/libmount.h.in
@@ -195,6 +195,7 @@ extern struct libmnt_lock *mnt_new_lock(const char *datafile, pid_t id);
extern void mnt_free_lock(struct libmnt_lock *ml);
extern void mnt_unlock_file(struct libmnt_lock *ml);
extern int mnt_lock_file(struct libmnt_lock *ml);
+extern int mnt_lock_block_signals(struct libmnt_lock *ml, int enable);
/* fs.c */
extern struct libmnt_fs *mnt_new_fs(void);
diff --git a/shlibs/mount/src/libmount.sym b/shlibs/mount/src/libmount.sym
index f8a5345b0..af6f7bf48 100644
--- a/shlibs/mount/src/libmount.sym
+++ b/shlibs/mount/src/libmount.sym
@@ -126,6 +126,7 @@ global:
mnt_has_regular_mtab;
mnt_init_debug;
mnt_iter_get_direction;
+ mnt_lock_block_signals;
mnt_lock_file;
mnt_mangle;
mnt_match_fstype;
diff --git a/shlibs/mount/src/lock.c b/shlibs/mount/src/lock.c
index 554915876..55dcf73b2 100644
--- a/shlibs/mount/src/lock.c
+++ b/shlibs/mount/src/lock.c
@@ -40,7 +40,11 @@ struct libmnt_lock {
char *lockfile; /* path to lock file (e.g. /etc/mtab~) */
char *linkfile; /* path to link file (e.g. /etc/mtab~.<id>) */
int lockfile_fd; /* lock file descriptor */
- int locked; /* do we own the lock? */
+
+ int locked :1; /* do we own the lock? */
+ int sigblock: 1; /* block signals when locked */
+
+ sigset_t oldsigmask;
};
@@ -102,6 +106,24 @@ void mnt_free_lock(struct libmnt_lock *ml)
free(ml);
}
+/**
+ * mnt_lock_block_signals:
+ * @ml: struct libmnt_lock handler
+ * @enable: TRUE/FALSE
+ *
+ * Block/unblock signals when the lock is locked, the signals are not blocked
+ * by default.
+ *
+ * Returns: <0 on error, 0 on success.
+ */
+int mnt_lock_block_signals(struct libmnt_lock *ml, int enable)
+{
+ if (!ml)
+ return -EINVAL;
+ ml->sigblock = enable;
+ return 0;
+}
+
/*
* Returns path to lockfile.
*/
@@ -254,6 +276,11 @@ void mnt_unlock_file(struct libmnt_lock *ml)
ml->locked = 0;
ml->lockfile_fd = -1;
+
+ if (ml->sigblock)
+ sigprocmask(SIG_SETMASK, &ml->oldsigmask, NULL);
+
+ ml->sigblock = 0;
}
/**
@@ -337,6 +364,20 @@ int mnt_lock_file(struct libmnt_lock *ml)
if (!linkfile)
return -EINVAL;
+ if (ml->sigblock) {
+ /*
+ * Block all signals when locked, mnt_unlock_file() will
+ * restore the old mask.
+ */
+ sigset_t sigs;
+
+ sigemptyset(&ml->oldsigmask);
+ sigfillset(&sigs);
+ sigdelset(&sigs, SIGTRAP);
+ sigdelset(&sigs, SIGALRM);
+ sigprocmask(SIG_BLOCK, &sigs, &ml->oldsigmask);
+ }
+
i = open(linkfile, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
if (i < 0) {
/* linkfile does not exist (as a file) and we cannot create it.
diff --git a/shlibs/mount/src/tab_update.c b/shlibs/mount/src/tab_update.c
index 9a56b6738..7cf166ba5 100644
--- a/shlibs/mount/src/tab_update.c
+++ b/shlibs/mount/src/tab_update.c
@@ -778,10 +778,15 @@ static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *
/**
* mnt_update_table:
* @upd: update
- * @lc: lock
+ * @lc: lock or NULL
*
* High-level API to update /etc/mtab (or private /dev/.mount/utab file).
*
+ * The @lc lock is optional and will be created if necessary. Note that
+ * the automatically created lock blocks all signals.
+ *
+ * See also mnt_lock_block_signals() and mnt_context_get_lock().
+ *
* Returns: 0 on success, negative number on error.
*/
int mnt_update_table(struct libmnt_update *upd, struct libmnt_lock *lc)
@@ -801,8 +806,11 @@ int mnt_update_table(struct libmnt_update *upd, struct libmnt_lock *lc)
DBG(UPDATE, mnt_fs_print_debug(upd->fs, stderr));
}
- if (!lc && !upd->userspace_only)
+ if (!lc && !upd->userspace_only) {
lc = mnt_new_lock(upd->filename, 0);
+ if (lc)
+ mnt_lock_block_signals(lc, TRUE);
+ }
if (!upd->fs && upd->target)
rc = update_remove_entry(upd, lc); /* umount */
@@ -825,14 +833,6 @@ int mnt_update_table(struct libmnt_update *upd, struct libmnt_lock *lc)
#ifdef TEST_PROGRAM
-struct libmnt_lock *lock;
-
-static void lock_fallback(void)
-{
- if (lock)
- mnt_unlock_file(lock);
-}
-
static int update(const char *target, struct libmnt_fs *fs, unsigned long mountflags)
{
int rc;
@@ -858,13 +858,7 @@ static int update(const char *target, struct libmnt_fs *fs, unsigned long mountf
/* [... here should be mount(2) call ...] */
- filename = mnt_update_get_filename(upd);
- if (filename) {
- lock = mnt_new_lock(filename, 0);
- if (lock)
- atexit(lock_fallback);
- }
- rc = mnt_update_table(upd, lock);
+ rc = mnt_update_table(upd, NULL);
done:
return rc;
}