[asterisk-commits] russell: trunk r81233 - in /trunk: ./ doc/tex/ include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Aug 28 11:28:27 CDT 2007


Author: russell
Date: Tue Aug 28 11:28:26 2007
New Revision: 81233

URL: http://svn.digium.com/view/asterisk?view=rev&rev=81233
Log:
(closes issue #7852)
Reported by: nic_bellamy
Patches:
      2006-10-03_svn_44249_voicemail_lockmode_v3.patch uploaded by nic_bellamy (license 213)

Add support for configurable file locking methods.  The default is "lockfile",
which is the old behavior.  There is an additional option, "flock", which is
intended for use in situations where the lockfile method will not work, such as
with SMB/CIFS mounts.

Modified:
    trunk/CHANGES
    trunk/doc/tex/asterisk-conf.tex
    trunk/include/asterisk/app.h
    trunk/main/app.c
    trunk/main/asterisk.c

Modified: trunk/CHANGES
URL: http://svn.digium.com/view/asterisk/trunk/CHANGES?view=diff&rev=81233&r1=81232&r2=81233
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Tue Aug 28 11:28:26 2007
@@ -125,6 +125,11 @@
   * Added support for storage of greetings using an IMAP server
   * Added ability to customize forward, reverse, stop, and pause keys for message playback
   * SMDI is now enabled in voicemail using the smdienable option.
+  * A "lockmode" option has been added to asterisk.conf to configure the file
+     locking method used for voicemail, and potentially other things in the
+	 future.  The default is the old behavior, lockfile.  However, there is a
+	 new method, "flock", that uses a different method for situations where the
+	 lockfile will not work, such as on SMB/CIFS mounts.
 
 Queue changes
 -------------

Modified: trunk/doc/tex/asterisk-conf.tex
URL: http://svn.digium.com/view/asterisk/trunk/doc/tex/asterisk-conf.tex?view=diff&rev=81233&r1=81232&r2=81233
==============================================================================
--- trunk/doc/tex/asterisk-conf.tex (original)
+++ trunk/doc/tex/asterisk-conf.tex Tue Aug 28 11:28:26 2007
@@ -118,6 +118,12 @@
 ; (only affects relative paths for sound files)
 languageprefix = yes | no			
 
+; Locking mode for voicemail
+;  - lockfile: default, for normal use
+;  - flock: for where the lockfile locking method doesn't work
+;           eh. on SMB/CIFS mounts
+lockmode = lockfile | flock
+  
 
 [files]
 ; Changing the following lines may compromise your security
@@ -132,4 +138,4 @@
 ;astctl = asterisk.ctl
 
 \end{verbatim}
-\end{astlisting}
+\end{astlisting}

Modified: trunk/include/asterisk/app.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/app.h?view=diff&rev=81233&r1=81232&r2=81233
==============================================================================
--- trunk/include/asterisk/app.h (original)
+++ trunk/include/asterisk/app.h Tue Aug 28 11:28:26 2007
@@ -202,6 +202,18 @@
 	AST_LOCK_FAILURE = -3,
 };
 
+/*! \brief Type of locking to use in ast_lock_path / ast_unlock_path */
+enum AST_LOCK_TYPE {
+	AST_LOCK_TYPE_LOCKFILE = 0,
+	AST_LOCK_TYPE_FLOCK = 1,
+};
+
+/*!
+ * \brief Set the type of locks used by ast_lock_path()
+ * \param type the locking type to use
+ */
+void ast_set_lock_type(enum AST_LOCK_TYPE type);
+
 /*!
  * \brief Lock a filesystem path.
  * \param path the path to be locked

Modified: trunk/main/app.c
URL: http://svn.digium.com/view/asterisk/trunk/main/app.c?view=diff&rev=81233&r1=81232&r2=81233
==============================================================================
--- trunk/main/app.c (original)
+++ trunk/main/app.c Tue Aug 28 11:28:26 2007
@@ -37,6 +37,7 @@
 #include <dirent.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/file.h>
 #include <regex.h>
 
 #include "asterisk/channel.h"
@@ -158,6 +159,8 @@
 	return res;
 }
 
+/* The lock type used by ast_lock_path() / ast_unlock_path() */
+static enum AST_LOCK_TYPE ast_lock_type = AST_LOCK_TYPE_LOCKFILE;
 
 int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
 {
@@ -1026,7 +1029,7 @@
 	return argc;
 }
 
-enum AST_LOCK_RESULT ast_lock_path(const char *path)
+static enum AST_LOCK_RESULT ast_lock_path_lockfile(const char *path)
 {
 	char *s;
 	char *fs;
@@ -1035,10 +1038,8 @@
 	int lp = strlen(path);
 	time_t start;
 
-	if (!(s = alloca(lp + 10)) || !(fs = alloca(lp + 20))) {
-		ast_log(LOG_WARNING, "Out of memory!\n");
-		return AST_LOCK_FAILURE;
-	}
+	s = alloca(lp + 10); 
+	fs = alloca(lp + 20);
 
 	snprintf(fs, strlen(path) + 19, "%s/.lock-%08lx", path, ast_random());
 	fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, AST_FILE_MODE);
@@ -1064,15 +1065,12 @@
 	}
 }
 
-int ast_unlock_path(const char *path)
+static int ast_unlock_path_lockfile(const char *path)
 {
 	char *s;
 	int res;
 
-	if (!(s = alloca(strlen(path) + 10))) {
-		ast_log(LOG_WARNING, "Out of memory!\n");
-		return -1;
-	}
+	s = alloca(strlen(path) + 10);
 
 	snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
 
@@ -1083,6 +1081,170 @@
 	}
 
 	return res;
+}
+
+struct path_lock {
+	AST_LIST_ENTRY(path_lock) le;
+	int fd;
+	char *path;
+};
+
+static AST_LIST_HEAD_STATIC(path_lock_list, path_lock);
+
+static void path_lock_destroy(struct path_lock *obj)
+{
+	if (obj->fd >= 0)
+		close(obj->fd);
+	if (obj->path)
+		free(obj->path);
+	free(obj);
+}
+
+static enum AST_LOCK_RESULT ast_lock_path_flock(const char *path)
+{
+	char *fs;
+	int res;
+	int fd;
+	time_t start;
+	struct path_lock *pl;
+	struct stat st, ost;
+
+	fs = alloca(strlen(path) + 20);
+
+	snprintf(fs, strlen(path) + 19, "%s/lock", path);
+	if (lstat(fs, &st) == 0) {
+		if ((st.st_mode & S_IFMT) == S_IFLNK) {
+			ast_log(LOG_WARNING, "Unable to create lock file "
+					"'%s': it's already a symbolic link\n",
+					fs);
+			return AST_LOCK_FAILURE;
+		}
+		if (st.st_nlink > 1) {
+			ast_log(LOG_WARNING, "Unable to create lock file "
+					"'%s': %u hard links exist\n",
+					fs, (unsigned int) st.st_nlink);
+			return AST_LOCK_FAILURE;
+		}
+	}
+	fd = open(fs, O_WRONLY | O_CREAT, 0600);
+	if (fd < 0) {
+		ast_log(LOG_WARNING, "Unable to create lock file '%s': %s\n",
+				fs, strerror(errno));
+		return AST_LOCK_PATH_NOT_FOUND;
+	}
+	pl = ast_calloc(1, sizeof(*pl));
+	if (!pl) {
+		/* We don't unlink the lock file here, on the possibility that
+		 * someone else created it - better to leave a little mess
+		 * than create a big one by destroying someone elses lock
+		 * and causing something to be corrupted.
+		 */
+		close(fd);
+		return AST_LOCK_FAILURE;
+	}
+	pl->fd = fd;
+	pl->path = strdup(path);
+
+	time(&start);
+	while (((res = flock(pl->fd, LOCK_EX | LOCK_NB)) < 0) &&
+			(errno == EWOULDBLOCK) && (time(NULL) - start < 5))
+		usleep(1000);
+	if (res) {
+		ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n",
+				path, strerror(errno));
+		/* No unlinking of lock done, since we tried and failed to
+		 * flock() it.
+		 */
+		path_lock_destroy(pl);
+		return AST_LOCK_TIMEOUT;
+	}
+
+	/* Check for the race where the file is recreated or deleted out from
+	 * underneath us.
+	 */
+	if (lstat(fs, &st) != 0 && fstat(pl->fd, &ost) != 0 &&
+			st.st_dev != ost.st_dev &&
+			st.st_ino != ost.st_ino) {
+		ast_log(LOG_WARNING, "Unable to create lock file '%s': "
+				"file changed underneath us\n", fs);
+		path_lock_destroy(pl);
+		return AST_LOCK_FAILURE;
+	}
+
+	/* Success: file created, flocked, and is the one we started with */
+	AST_LIST_LOCK(&path_lock_list);
+	AST_LIST_INSERT_TAIL(&path_lock_list, pl, le);
+	AST_LIST_UNLOCK(&path_lock_list);
+
+	ast_debug(1, "Locked path '%s'\n", path);
+
+	return AST_LOCK_SUCCESS;
+}
+
+static int ast_unlock_path_flock(const char *path)
+{
+	char *s;
+	struct path_lock *p;
+
+	s = alloca(strlen(path) + 20);
+
+	AST_LIST_LOCK(&path_lock_list);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&path_lock_list, p, le) {
+		if (!strcmp(p->path, path)) {
+			AST_LIST_REMOVE_CURRENT(&path_lock_list, le);
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+	AST_LIST_UNLOCK(&path_lock_list);
+
+	if (p) {
+		snprintf(s, strlen(path) + 19, "%s/lock", path);
+		unlink(s);
+		path_lock_destroy(p);
+		ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
+	} else
+		ast_log(LOG_DEBUG, "Failed to unlock path '%s': "
+				"lock not found\n", path);
+
+	return 0;
+}
+
+void ast_set_lock_type(enum AST_LOCK_TYPE type)
+{
+	ast_lock_type = type;
+}
+
+enum AST_LOCK_RESULT ast_lock_path(const char *path)
+{
+	enum AST_LOCK_RESULT r = AST_LOCK_FAILURE;
+
+	switch (ast_lock_type) {
+	case AST_LOCK_TYPE_LOCKFILE:
+		r = ast_lock_path_lockfile(path);
+		break;
+	case AST_LOCK_TYPE_FLOCK:
+		r = ast_lock_path_flock(path);
+		break;
+	}
+
+	return r;
+}
+
+int ast_unlock_path(const char *path)
+{
+	int r = 0;
+
+	switch (ast_lock_type) {
+	case AST_LOCK_TYPE_LOCKFILE:
+		r = ast_unlock_path_lockfile(path);
+		break;
+	case AST_LOCK_TYPE_FLOCK:
+		r = ast_unlock_path_flock(path);
+		break;
+	}
+
+	return r;
 }
 
 int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path) 

Modified: trunk/main/asterisk.c
URL: http://svn.digium.com/view/asterisk/trunk/main/asterisk.c?view=diff&rev=81233&r1=81232&r2=81233
==============================================================================
--- trunk/main/asterisk.c (original)
+++ trunk/main/asterisk.c Tue Aug 28 11:28:26 2007
@@ -2453,6 +2453,16 @@
 			}
 		} else if (!strcasecmp(v->name, "languageprefix")) {
 			ast_language_is_prefix = ast_true(v->value);
+ 		} else if (!strcasecmp(v->name, "lockmode")) {
+ 			if (!strcasecmp(v->value, "lockfile")) {
+ 				ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
+ 			} else if (!strcasecmp(v->value, "flock")) {
+ 				ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
+ 			} else {
+				ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
+					"defaulting to 'lockfile'\n", v->value);
+ 				ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
+			}
 #if defined(HAVE_SYSINFO)
 		} else if (!strcasecmp(v->name, "minmemfree")) {
 			/* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls




More information about the asterisk-commits mailing list