[asterisk-commits] mnicholson: branch mnicholson/asttest r191092 - in /team/mnicholson/asttest/a...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Apr 29 11:38:05 CDT 2009


Author: mnicholson
Date: Wed Apr 29 11:38:00 2009
New Revision: 191092

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=191092
Log:
Completed implementation of asterisk:spawn(). It should be possible to start
and stop asterisk in a sandbox now.

Added:
    team/mnicholson/asttest/asttest/self-tests/spawn_asterisk/
    team/mnicholson/asttest/asttest/self-tests/spawn_asterisk/test.lua   (with props)
Modified:
    team/mnicholson/asttest/asttest/lua/astlib.c
    team/mnicholson/asttest/asttest/lua/astlib.lua

Modified: team/mnicholson/asttest/asttest/lua/astlib.c
URL: http://svn.digium.com/svn-view/asterisk/team/mnicholson/asttest/asttest/lua/astlib.c?view=diff&rev=191092&r1=191091&r2=191092
==============================================================================
--- team/mnicholson/asttest/asttest/lua/astlib.c (original)
+++ team/mnicholson/asttest/asttest/lua/astlib.c Wed Apr 29 11:38:00 2009
@@ -24,9 +24,12 @@
 
 #include <dirent.h>
 #include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <unistd.h>
 
 /*!
@@ -117,11 +120,78 @@
 	return -1;
 }
 
-static int spawn_asterisk(lua_State *L) {
+/*!
+ * \brief Recursively unlink a path.
+ * \param L the lua state to use
+ * \param path the file or directory to unlink
+ *
+ * This function unlinks the given file or directory.  If path is a directory,
+ * all of the items in the directory will be recursively unlinked.
+ *
+ * \note On error an error message is pushed onto the given lua stack.
+ *
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int recursive_unlink(lua_State *L, const char *path) {
+	DIR *dir;
+	struct dirent *d;
+	char dir_path[PATH_MAX];
+	struct stat st;
+
+	if (stat(path, &st)) {
+		if (errno == ENOENT)
+			return 0;
+
+		lua_pushstring(L, "error with stat for '");
+		lua_pushstring(L, path);
+		lua_pushstring(L, "': ");
+		lua_pushstring(L, strerror(errno));
+		lua_concat(L, 4);
+		return -1;
+	}
+
+	if (S_ISDIR(st.st_mode)) {
+		if (!(dir = opendir(path))) {
+			lua_pushstring(L, "error opening dir '");
+			lua_pushstring(L, path);
+			lua_pushstring(L, "': ");
+			lua_pushstring(L, strerror(errno));
+			lua_concat(L, 4);
+			return -1;
+		}
+
+		while ((d = readdir(dir))) {
+			snprintf(dir_path, sizeof(dir_path), "%s/%s", path, d->d_name);
+
+			if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) {
+				continue;
+			}
+
+			if (recursive_unlink(L, dir_path)) {
+				closedir(dir);
+				return -1;
+			}
+		}
+
+		closedir(dir);
+		rmdir(path);
+	} else {
+		if (unlink(path)) {
+			lua_pushstring(L, "error unlinking path '");
+			lua_pushstring(L, path);
+			lua_pushstring(L, "': ");
+			lua_pushstring(L, strerror(errno));
+			lua_concat(L, 4);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int new_asterisk(lua_State *L) {
 	int asterisk_count;
-	const char *asterisk_path;
-	char dir_path[PATH_MAX];
-	mode_t dir_mode = S_IRWXU | S_IRGRP| S_IXGRP| S_IROTH | S_IXOTH;
 
 	/* get the index for this instance */
 	lua_getfield(L, LUA_REGISTRYINDEX, "astlib_count");
@@ -132,47 +202,262 @@
 	lua_setfield(L, LUA_REGISTRYINDEX, "astlib_count");
 	lua_pop(L, 1);
 
+	/* create a new table and set some initial values */
+	lua_newtable(L);
+
+	lua_pushliteral(L, "tmp/ast");
+	lua_pushinteger(L, asterisk_count);
+	lua_concat(L, 2);
+	lua_setfield(L, -2, "work_area");
+
+	lua_pushinteger(L, asterisk_count);
+	lua_setfield(L, -2, "index");
+
+	lua_getfield(L, LUA_REGISTRYINDEX, "astlib_path");
+	lua_pushliteral(L, "/sbin/asterisk");
+	lua_concat(L, 2);
+	lua_setfield(L, -2, "asterisk_binary");
+	return 1;
+}
+
+static int clean_work_area(lua_State *L) {
+	const char *work_area;
+	luaL_checktype(L, 1, LUA_TTABLE);
+
+	/* get the work area for this instance */
+	lua_getfield(L, 1, "work_area");
+	work_area = lua_tostring(L, -1);
+
+	if (recursive_unlink(L, work_area)) {
+		lua_pushstring(L, "\nerror cleaning work area");
+		lua_concat(L, 2);
+		return lua_error(L);
+	}
+
+	return 0;
+}
+
+static int create_work_area(lua_State *L) {
+	const char *work_area;
+	const char *asterisk_path;
+	mode_t dir_mode = S_IRWXU | S_IRGRP| S_IXGRP| S_IROTH | S_IXOTH;
+
+	luaL_checktype(L, 1, LUA_TTABLE);
+
+	/* get the work area for this instance */
+	lua_getfield(L, 1, "work_area");
+	work_area = lua_tostring(L, -1);
+
+	/* get the asterisk path */
 	lua_getfield(L, LUA_REGISTRYINDEX, "astlib_path");
 	asterisk_path = lua_tostring(L, -1);
 
-	snprintf(dir_path, sizeof(dir_path), "tmp/ast%d", asterisk_count);
 	if (mkdir("tmp", dir_mode) && errno != EEXIST) {
-		lua_pop(L, 1); /* remove the astlib_path */
-		lua_pushstring(L, "error creating tmp directory while spawning asterisk: ");
+		lua_pushstring(L, "error creating tmp directory for work area: ");
 		lua_pushstring(L, strerror(errno));
 		lua_concat(L, 2);
 		return lua_error(L);
 	}
 
-	if (mkdir(dir_path, dir_mode)) {
-		lua_pop(L, 1); /* remove the astlib_path */
-		lua_pushstring(L, "error spawning asterisk, unable to create working dir (");
-		lua_pushstring(L, dir_path);
+	if (mkdir(work_area, dir_mode)) {
+		lua_pushstring(L, "unable to create work area (");
+		lua_pushstring(L, work_area);
 		lua_pushstring(L, "): ");
 		lua_pushstring(L, strerror(errno));
 		lua_concat(L, 4);
 		return lua_error(L);
 	}
 
-	if (symlink_copy_dir(L, asterisk_path, dir_path)) {
-		lua_remove(L, -2); /* remove the astlib_path */
-		lua_pushstring(L, "\nerror initilizing working environment");
+	if (symlink_copy_dir(L, asterisk_path, work_area)) {
+		lua_pushstring(L, "\nerror initilizing work area");
 		lua_concat(L, 2);
 		return lua_error(L);
 	}
 
-	lua_pop(L, 1); /* remove the astlib_path */
-
-	/* XXX now start asterisk */
 	return 0;
 }
 
+static int spawn_asterisk(lua_State *L) {
+	const char *asterisk;
+	const char *asterisk_conf;
+	pid_t pid;
+	pid_t *p;
+
+	luaL_checktype(L, 1, LUA_TTABLE);
+
+	/* XXX maybe see if pid is set.  Right now, if pid is set, the previous
+	 * asterisk process will be killed (during gc) and a new one will
+	 * replace it. */
+
+	/* get the index for this instance */
+	lua_getfield(L, 1, "asterisk_binary");
+	asterisk = lua_tostring(L, -1);
+
+	/* get the location of the asterisk.conf file */
+	lua_getfield(L, 1, "asterisk_conf");
+	asterisk_conf = lua_tostring(L, -1);
+
+	/* start asterisk */
+	pid = fork();
+	if (pid == 0) {
+		execl(asterisk, asterisk, "-f", "-g", "-m", "-C", asterisk_conf, (char *) NULL);
+		exit(1);
+	} else if (pid == -1) {
+		lua_pushliteral(L, "error spawning asterisk (fork error): ");
+		lua_pushstring(L, strerror(errno));
+		lua_concat(L, 2);
+		return lua_error(L);
+	}
+
+	/* store the pid */
+	lua_pushliteral(L, "pid");
+	p = lua_newuserdata(L, sizeof(pid_t));
+	*p = pid;
+	luaL_getmetatable(L, "astlib_pid");
+	lua_setmetatable(L, -2);
+	lua_rawset(L, 1);
+
+	return 0;
+}
+
+static int pid_gc(lua_State *L) {
+	pid_t *p = luaL_checkudata(L, 1, "astlib_pid");
+	if (kill(*p, SIGTERM)) {
+		return 0;
+	}
+#if 0	/* XXX maybe we should also do SIGKILL here? */
+	sleep(1);
+	kill(*p, SIGKILL);
+#endif
+	waitpid(*p, NULL, 0);
+	return 0;
+}
+
+static int wait_asterisk(lua_State *L) {
+	pid_t pid;
+	int status;
+
+	luaL_checktype(L, 1, LUA_TTABLE);
+
+	/* get the pid of this process */
+	lua_getfield(L, 1, "pid");
+	if (lua_isnil(L, -1)) {
+		/* no process found */
+		lua_pushnil(L);
+		lua_pushliteral(L, "error");
+		return 2;
+	}
+	pid = *(pid_t *) lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	if (waitpid(pid, &status, 0) == -1) {
+		if (WIFEXITED(status)) {
+			lua_pushinteger(L, WEXITSTATUS(status));
+			lua_pushnil(L);
+		} else if (WIFSIGNALED(status)) {
+			lua_pushnil(L);
+			if (WCOREDUMP(status))
+				lua_pushliteral(L, "core");
+			else
+				lua_pushinteger(L, WTERMSIG(status));
+		} else {
+			lua_pushliteral(L, "unknown error running waitpid for asterisk");
+			return lua_error(L);
+		}
+	}
+
+	/* unset the pid */
+	lua_pushliteral(L, "pid");
+	lua_pushnil(L);
+	lua_rawset(L, 1);
+
+	return 2;
+}
+
+static int kill_asterisk(lua_State *L) {
+	pid_t pid;
+
+	luaL_checktype(L, 1, LUA_TTABLE);
+
+	/* get the pid of this process */
+	lua_getfield(L, 1, "pid");
+	if (lua_isnil(L, -1)) {
+		/* no process found */
+		lua_pushnil(L);
+		lua_pushliteral(L, "error");
+		return 2;
+	}
+	pid = *(pid_t *) lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	if (kill(pid, SIGKILL)) {
+		lua_pushnil(L);
+		lua_pushliteral(L, "error");
+		lua_pushstring(L, strerror(errno));
+		lua_pushinteger(L, errno);
+		return 4;
+	}
+
+	lua_pushcfunction(L, wait_asterisk);
+	lua_pushvalue(L, 1);
+	lua_call(L, 1, 2);
+	return 2;
+}
+
+static int terminate_asterisk(lua_State *L) {
+	pid_t pid;
+
+	luaL_checktype(L, 1, LUA_TTABLE);
+
+	/* get the pid of this process */
+	lua_getfield(L, 1, "pid");
+	if (lua_isnil(L, -1)) {
+		/* no process found */
+		lua_pushnil(L);
+		lua_pushliteral(L, "error");
+		return 2;
+	}
+	pid = *(pid_t *) lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	if (kill(pid, SIGTERM)) {
+		lua_pushnil(L);
+		lua_pushliteral(L, "error");
+		lua_pushstring(L, strerror(errno));
+		lua_pushinteger(L, errno);
+		return 4;
+	}
+
+	lua_pushcfunction(L, wait_asterisk);
+	lua_pushvalue(L, 1);
+	lua_call(L, 1, 2);
+	return 2;
+}
+
+static int unlink_file(lua_State *L) {
+	const char *file = luaL_checkstring(L, 1);
+	lua_pushinteger(L, unlink(file));
+	return 1;
+}
+
 static luaL_Reg astlib[] = {
+	{"unlink", unlink_file},
 	{NULL, NULL},
 };
 
+static luaL_Reg asterisk_pid[] = {
+	{"__gc", pid_gc},
+	{NULL, NULL},
+};
+
 static luaL_Reg asterisk_table[] = {
-	{"spawn", spawn_asterisk},
+	{"_new", new_asterisk},
+	{"_clean_work_area", clean_work_area},
+	{"_create_work_area", create_work_area},
+	{"_spawn", spawn_asterisk},
+	{"wait", wait_asterisk},
+	{"term", terminate_asterisk},
+	{"kill", kill_asterisk},
 	{NULL, NULL},
 };
 
@@ -193,7 +478,12 @@
 	lua_pushstring(L, asterisk_path);
 	lua_setfield(L, -2, "path");
 
-	/* set up the 'asterisk' table and add the spawn function to it */
+	/* set up the pid metatable */
+	luaL_newmetatable(L, "astlib_pid");
+	luaL_register(L, NULL, asterisk_pid);
+	lua_pop(L, 1);
+
+	/* set up the 'asterisk' table and add some functions to it */
 	lua_newtable(L);
 	luaL_register(L, NULL, asterisk_table);
 	lua_setfield(L, -2, "asterisk");

Modified: team/mnicholson/asttest/asttest/lua/astlib.lua
URL: http://svn.digium.com/svn-view/asterisk/team/mnicholson/asttest/asttest/lua/astlib.lua?view=diff&rev=191092&r1=191091&r2=191092
==============================================================================
--- team/mnicholson/asttest/asttest/lua/astlib.lua (original)
+++ team/mnicholson/asttest/asttest/lua/astlib.lua Wed Apr 29 11:38:00 2009
@@ -25,12 +25,24 @@
 --
 -- asterisk table is created in astlib.c
 function asterisk:new()
-	local a = {
-		configs = {},
-	}
+	local a = self:_new()
+	a.configs = {}
+	a.asterisk_conf = a.work_area .. "/etc/asterisk/asterisk.conf"
+
 	setmetatable(a, self)
 	self.__index = self
 	return a
+end
+
+function asterisk:spawn()
+	self:_clean_work_area()
+	self:_create_work_area()
+	self:_spawn()
+end
+
+function asterisk:spawn_and_wait()
+	self:spawn()
+	self:wait()
 end
 
 function asterisk:__newindex(conffile_name, conffile)
@@ -38,6 +50,9 @@
 		error("got " .. type(conffile) .. " expected type config")
 	end
 	self.configs[conffile_name] = conffile
+	if conffile.name == "asterisk.conf" then
+		self.asterisk_conf = conffile.filename
+	end
 end
 
 function asterisk:__index(conffile_name)
@@ -45,15 +60,16 @@
 end
 
 function asterisk:new_config(name)
-	c = config:new(name)
+	c = config:new(name, self.work_area .. "/etc/asterisk/" .. name)
 	self[name] = c
 	return c
 end
 
 config = {}
-function config:new(name)
+function config:new(name, filename)
 	local ac = {
 		name = name,
+		filename = filename or name,
 		sections = {},
 		section_index = {},
 	}
@@ -88,8 +104,11 @@
 
 function config:write(filename)
 	if not filename then
-		filename = self.name
+		filename = self.filename
 	end
+
+	-- remove any existing file or symlink
+	unlink(filename)
 
 	f, e = io.open(filename, "w")
 	if not f then

Added: team/mnicholson/asttest/asttest/self-tests/spawn_asterisk/test.lua
URL: http://svn.digium.com/svn-view/asterisk/team/mnicholson/asttest/asttest/self-tests/spawn_asterisk/test.lua?view=auto&rev=191092
==============================================================================
--- team/mnicholson/asttest/asttest/self-tests/spawn_asterisk/test.lua (added)
+++ team/mnicholson/asttest/asttest/self-tests/spawn_asterisk/test.lua Wed Apr 29 11:38:00 2009
@@ -1,0 +1,5 @@
+-- test spawning asterisk
+
+a = ast.new()
+a:spawn()
+

Propchange: team/mnicholson/asttest/asttest/self-tests/spawn_asterisk/test.lua
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/mnicholson/asttest/asttest/self-tests/spawn_asterisk/test.lua
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/mnicholson/asttest/asttest/self-tests/spawn_asterisk/test.lua
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the asterisk-commits mailing list