]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: block signals when writing to mtab
authorKarel Zak <kzak@redhat.com>
Wed, 30 Mar 2011 07:30:05 +0000 (09:30 +0200)
committerKarel Zak <kzak@redhat.com>
Wed, 30 Mar 2011 07:30:05 +0000 (09:30 +0200)
Signed-off-by: Karel Zak <kzak@redhat.com>
shlibs/mount/src/context.c
shlibs/mount/src/libmount.h.in
shlibs/mount/src/libmount.sym
shlibs/mount/src/lock.c
shlibs/mount/src/tab_update.c

index dba49430d07d051955cb8e743d192a515f7cbb39..f24e90ebb9b6261fe1aca3a7f3c2d8e2bc42f161 100644 (file)
@@ -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;
 }
 
index c9d0ba8f4da5b00695591dc2667788f6d2bd9977..d7e7a51729a431bd79fbf4839b831b42702bdce8 100644 (file)
@@ -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);
index f8a5345b04c65c41a76a7b8009e1d74a94e1ac70..af6f7bf48a0496ffa36037e1ea369a9fd449b8c4 100644 (file)
@@ -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;
index 554915876ec5bff01bd4415db59353a674ffd141..55dcf73b2c7f6f7a5b55f63351978baf1b3eb596 100644 (file)
@@ -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.
index 9a56b67381a20d268a62066cd017bf082512f371..7cf166ba5a101f1fa56cd5c2240e66f0967cb007 100644 (file)
@@ -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;
 }