dovecot-2.2: lib: Added file_wait_lock_error() and file_try_lock...

dovecot at dovecot.org dovecot at dovecot.org
Thu Sep 25 10:29:03 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/87f10e2fac95
changeset: 17835:87f10e2fac95
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Sep 25 13:26:20 2014 +0300
description:
lib: Added file_wait_lock_error() and file_try_lock_error()

diffstat:

 src/lib/file-lock.c |  84 +++++++++++++++++++++++++++++++++++++++-------------
 src/lib/file-lock.h |  11 ++++++
 2 files changed, 74 insertions(+), 21 deletions(-)

diffs (193 lines):

diff -r 65963be31ceb -r 87f10e2fac95 src/lib/file-lock.c
--- a/src/lib/file-lock.c	Thu Sep 25 02:55:34 2014 +0300
+++ b/src/lib/file-lock.c	Thu Sep 25 13:26:20 2014 +0300
@@ -48,10 +48,19 @@
 	return file_wait_lock(fd, path, lock_type, lock_method, 0, lock_r);
 }
 
+int file_try_lock_error(int fd, const char *path, int lock_type,
+			enum file_lock_method lock_method,
+			struct file_lock **lock_r, const char **error_r)
+{
+	return file_wait_lock_error(fd, path, lock_type, lock_method, 0,
+				    lock_r, error_r);
+}
+
 static int file_lock_do(int fd, const char *path, int lock_type,
 			enum file_lock_method lock_method,
-			unsigned int timeout_secs)
+			unsigned int timeout_secs, const char **error_r)
 {
+	const char *lock_type_str;
 	int ret;
 
 	i_assert(fd != -1);
@@ -59,13 +68,17 @@
 	if (timeout_secs != 0)
 		alarm(timeout_secs);
 
+	lock_type_str = lock_type == F_UNLCK ? "unlock" :
+		(lock_type == F_RDLCK ? "read-lock" : "write-lock");
+
 	switch (lock_method) {
 	case FILE_LOCK_METHOD_FCNTL: {
 #ifndef HAVE_FCNTL
-		i_fatal("fcntl() locks not supported");
+		*error_r = t_strdup_printf(
+			"Can't lock file %s: fcntl() locks not supported", path);
+		return -1;
 #else
 		struct flock fl;
-		const char *errstr;
 
 		fl.l_type = lock_type;
 		fl.l_whence = SEEK_SET;
@@ -81,6 +94,9 @@
 		if (timeout_secs == 0 &&
 		    (errno == EACCES || errno == EAGAIN)) {
 			/* locked by another process */
+			*error_r = t_strdup_printf(
+				"fcntl(%s, %s, F_SETLK) locking failed: %m "
+				"(File is already locked)", path, lock_type_str);
 			return 0;
 		}
 
@@ -89,20 +105,22 @@
 			   even if not, we probably want to be killed
 			   so stop blocking. */
 			errno = EAGAIN;
+			*error_r = t_strdup_printf(
+				"fcntl(%s, %s, F_SETLKW) locking failed: "
+				"Timed out after %u seconds",
+				path, lock_type_str, timeout_secs);
 			return 0;
 		}
-		errstr = errno != EACCES ? strerror(errno) :
-			"File is locked by another process (EACCES)";
-		i_error("fcntl(%s) locking failed for file %s: %s",
-			lock_type == F_UNLCK ? "unlock" :
-			lock_type == F_RDLCK ? "read-lock" : "write-lock",
-			path, errstr);
+		*error_r = t_strdup_printf("fcntl(%s, %s, %s) locking failed: %m",
+			path, lock_type_str, timeout_secs == 0 ? "F_SETLK" : "F_SETLKW");
 		return -1;
 #endif
 	}
 	case FILE_LOCK_METHOD_FLOCK: {
 #ifndef HAVE_FLOCK
-		i_fatal("flock() locks not supported");
+		*error_r = t_strdup_printf(
+			"Can't lock file %s: flock() not supported", path);
+		return -1;
 #else
 		int operation = timeout_secs != 0 ? 0 : LOCK_NB;
 
@@ -124,16 +142,22 @@
 		if (ret == 0)
 			break;
 
-		if (errno == EWOULDBLOCK || errno == EINTR) {
-			/* a) locked by another process,
-			   b) timeouted */
-			errno = EAGAIN;
+		if (timeout_secs == 0 && errno == EWOULDBLOCK) {
+			/* locked by another process */
+			*error_r = t_strdup_printf(
+				"flock(%s, %s) failed: %m "
+				"(File is already locked)", path, lock_type_str);
 			return 0;
 		}
-		i_error("flock(%s) locking failed for file %s: %m",
-			lock_type == F_UNLCK ? "unlock" :
-			lock_type == F_RDLCK ? "read-lock" : "write-lock",
-			path);
+		if (errno == EINTR) {
+			errno = EAGAIN;
+			*error_r = t_strdup_printf("flock(%s, %s) failed: "
+				"Timed out after %u seconds",
+				path, lock_type_str, timeout_secs);
+			return 0;
+		}
+		*error_r = t_strdup_printf("flock(%s, %s) failed: %m",
+					   path, lock_type_str);
 		return -1;
 #endif
 	}
@@ -150,10 +174,25 @@
 		   unsigned int timeout_secs,
 		   struct file_lock **lock_r)
 {
+	const char *error;
+	int ret;
+
+	ret = file_wait_lock_error(fd, path, lock_type, lock_method,
+				   timeout_secs, lock_r, &error);
+	if (ret < 0)
+		i_error("%s", error);
+	return ret;
+}
+
+int file_wait_lock_error(int fd, const char *path, int lock_type,
+			 enum file_lock_method lock_method,
+			 unsigned int timeout_secs,
+			 struct file_lock **lock_r, const char **error_r)
+{
 	struct file_lock *lock;
 	int ret;
 
-	ret = file_lock_do(fd, path, lock_type, lock_method, timeout_secs);
+	ret = file_lock_do(fd, path, lock_type, lock_method, timeout_secs, error_r);
 	if (ret <= 0)
 		return ret;
 
@@ -168,18 +207,21 @@
 
 int file_lock_try_update(struct file_lock *lock, int lock_type)
 {
+	const char *error;
+
 	return file_lock_do(lock->fd, lock->path, lock_type,
-			    lock->lock_method, 0);
+			    lock->lock_method, 0, &error);
 }
 
 void file_unlock(struct file_lock **_lock)
 {
 	struct file_lock *lock = *_lock;
+	const char *error;
 
 	*_lock = NULL;
 
 	if (file_lock_do(lock->fd, lock->path, F_UNLCK,
-			 lock->lock_method, 0) == 0) {
+			 lock->lock_method, 0, &error) == 0) {
 		/* this shouldn't happen */
 		i_error("file_unlock(%s) failed: %m", lock->path);
 	}
diff -r 65963be31ceb -r 87f10e2fac95 src/lib/file-lock.h
--- a/src/lib/file-lock.h	Thu Sep 25 02:55:34 2014 +0300
+++ b/src/lib/file-lock.h	Thu Sep 25 13:26:20 2014 +0300
@@ -25,12 +25,23 @@
 int file_try_lock(int fd, const char *path, int lock_type,
 		  enum file_lock_method lock_method,
 		  struct file_lock **lock_r);
+/* Like file_try_lock(), but return the error message as a string instead
+   of logging it. Also when returning 0 an error message is returned. */
+int file_try_lock_error(int fd, const char *path, int lock_type,
+			enum file_lock_method lock_method,
+			struct file_lock **lock_r, const char **error_r);
 /* Like lock_try_lock(), but return 0 only after having tried to lock for
    timeout_secs. */
 int file_wait_lock(int fd, const char *path, int lock_type,
 		   enum file_lock_method lock_method,
 		   unsigned int timeout_secs,
 		   struct file_lock **lock_r);
+/* Like file_wait_lock(), but return the error message as a string instead
+   of logging it. Also when returning 0 an error message is returned. */
+int file_wait_lock_error(int fd, const char *path, int lock_type,
+			 enum file_lock_method lock_method,
+			 unsigned int timeout_secs,
+			 struct file_lock **lock_r, const char **error_r);
 /* Change the lock type. */
 int file_lock_try_update(struct file_lock *lock, int lock_type);
 


More information about the dovecot-cvs mailing list