Implement lua scripts with support for standard and posix libraries.
authorJ. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 05 22:43:29 2009 +0000 (2009-02-05)
changeset 3524866573c6944
parent 351 48b0adfe3059
child 353 90b63682fdd7
Implement lua scripts with support for standard and posix libraries.
configure.ac
librazor/Makefile.am
librazor/lua.c
librazor/razor-internal.h
librazor/rpm.c
librazor/test-lua.c
librazor/test.lua
src/Makefile.am
test/Makefile.am
test/filesystem.spec
test/lua.sh
     1.1 --- a/configure.ac	Thu Jan 22 22:54:45 2009 +0000
     1.2 +++ b/configure.ac	Thu Feb 05 22:43:29 2009 +0000
     1.3 @@ -202,6 +202,27 @@
     1.4         AC_DEFINE([HAVE_RPMLIB], [1], [Define if you have librpm])])
     1.5  AC_SUBST(RPM_LIBS)
     1.6  AM_CONDITIONAL([HAVE_RPMLIB], [test -n "$RPM_LIBS"])
     1.7 +
     1.8 +AC_ARG_WITH([lua],
     1.9 +            [AS_HELP_STRING([--without-lua], [disable support for lua])],
    1.10 +            [],
    1.11 +            [with_lua=yes])
    1.12 +          
    1.13 +LUA_CFLAGS=
    1.14 +LUA_LIBS=
    1.15 +AS_IF([test "x$with_lua" != xno],
    1.16 +  [PKG_CHECK_MODULES(LUA, [lua])
    1.17 +   REQUIREMENTS="$REQUIREMENTS lua"
    1.18 +   AC_DEFINE([HAVE_LUA], [1], [Define if you have lua])
    1.19 +   AC_PATH_PROG(LUA, [lua], [no])
    1.20 +   AS_IF([test "x$LUA" = xno],
    1.21 +     [AC_MSG_ERROR([Can't find lua program. Please install lua-devel or use --without-lua.])])
    1.22 +   AC_DEFINE_UNQUOTED([LUA_BINARY], ["$LUA"],
    1.23 +     [Define to the location of the lua binary])])
    1.24 +AC_SUBST(LUA_CFLAGS)
    1.25 +AC_SUBST(LUA_LIBS)
    1.26 +AM_CONDITIONAL([HAVE_LUA], [test "x$with_lua" != xno])
    1.27 +
    1.28  AC_SUBST(REQUIREMENTS)
    1.29  
    1.30  if test "x$GCC" = "xyes"; then
     2.1 --- a/librazor/Makefile.am	Thu Jan 22 22:54:45 2009 +0000
     2.2 +++ b/librazor/Makefile.am	Thu Feb 05 22:43:29 2009 +0000
     2.3 @@ -12,6 +12,9 @@
     2.4  	-DPACKAGE_LIB_DIR=\""$(libdir)"\"
     2.5  
     2.6  lib_LTLIBRARIES = librazor.la
     2.7 +if HAVE_LUA
     2.8 +  check_PROGRAMS = test-lua
     2.9 +endif
    2.10  
    2.11  librazorincludedir = $(includedir)/razor
    2.12  
    2.13 @@ -31,7 +34,22 @@
    2.14  	merger.c					\
    2.15  	transaction.c
    2.16  
    2.17 -librazor_la_LIBADD = $(ZLIB_LIBS) ../gl/libgnu.la $(EXTRA_LIBS)
    2.18 +if HAVE_LUA
    2.19 +  librazor_la_SOURCES += lua.c
    2.20 +endif
    2.21 +
    2.22 +librazor_la_LIBADD = $(ZLIB_LIBS) $(LUA_LIBS) ../gl/libgnu.la $(EXTRA_LIBS)
    2.23 +
    2.24 +if HAVE_LUA
    2.25 +  test_lua_SOURCES = test-lua.c
    2.26 +  test_lua_LDADD = lua.lo util.lo $(LUA_LIBS) ../gl/libgnu.la \
    2.27 +	$(EXTRA_LIBS)
    2.28 +
    2.29 +  TESTS = test-lua
    2.30 +endif
    2.31 +
    2.32 +EXTRA_DIST = 			\
    2.33 +	test.lua
    2.34  
    2.35  clean-local :
    2.36  	rm -f *~
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/librazor/lua.c	Thu Feb 05 22:43:29 2009 +0000
     3.3 @@ -0,0 +1,361 @@
     3.4 +/*
     3.5 + * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
     3.6 + *
     3.7 + * This program is free software; you can redistribute it and/or modify
     3.8 + * it under the terms of the GNU General Public License as published by
     3.9 + * the Free Software Foundation; either version 2 of the License, or
    3.10 + * (at your option) any later version.
    3.11 + *
    3.12 + * This program is distributed in the hope that it will be useful,
    3.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.15 + * GNU General Public License for more details.
    3.16 + *
    3.17 + * You should have received a copy of the GNU General Public License along
    3.18 + * with this program; if not, write to the Free Software Foundation, Inc.,
    3.19 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    3.20 + */
    3.21 +
    3.22 +#include "config.h"
    3.23 +
    3.24 +#include <stdlib.h>
    3.25 +#include <string.h>
    3.26 +#include <stdio.h>
    3.27 +#include <errno.h>
    3.28 +#include <sys/stat.h>
    3.29 +#include <sys/types.h>
    3.30 +#include <lua.h>
    3.31 +#include <lualib.h>
    3.32 +#include <lauxlib.h>
    3.33 +
    3.34 +#include "razor.h"
    3.35 +#include "razor-internal.h"
    3.36 +
    3.37 +#define MAX_ARGS		2
    3.38 +
    3.39 +#define ARG_FLAG_OPT		0x1
    3.40 +#define ARG_FLAG_BYPASS		0x2
    3.41 +
    3.42 +#define ARG(flags, swtch, index, type) \
    3.43 +				((flags) << 26 | (swtch) << 21 | \
    3.44 +				 (index) << 16 | type)
    3.45 +#define ARG_FLAGS(arg)		((unsigned)(arg) >> 26)
    3.46 +#define ARG_SWTCH(arg)		((unsigned)(arg) >> 21 & 0x1F)
    3.47 +#define ARG_INDEX(arg)		((unsigned)(arg) >> 16 & 0x1F)
    3.48 +#define ARG_TYPE(arg)		((unsigned)(arg) & 0xFFFF)
    3.49 +
    3.50 +#define ARG_NONE		0
    3.51 +#define ARG_STRING(n)		ARG(0, 0, n, LUA_TSTRING)
    3.52 +#define ARG_OPT_STRING(n)	ARG(ARG_FLAG_OPT, 0, n, LUA_TSTRING)
    3.53 +#define ARG_BYP_STRING(n, s)	ARG(ARG_FLAG_BYPASS, s, n, LUA_TSTRING)
    3.54 +
    3.55 +struct razor_proxy {
    3.56 +	char *table, *name;
    3.57 +	int result;
    3.58 +	unsigned args[MAX_ARGS];
    3.59 +};
    3.60 +
    3.61 +static struct razor_proxy proxy[] = {
    3.62 +	{ NULL, "dofile", LUA_TNONE, { ARG_STRING(1) } },
    3.63 +	{ NULL, "loadfile", LUA_TNONE, { ARG_OPT_STRING(1) } },
    3.64 +	{ "io", "input", LUA_TNONE, { ARG_OPT_STRING(1) } },
    3.65 +	{ "io", "output", LUA_TNONE, { ARG_OPT_STRING(1) } },
    3.66 +	{ "io", "lines", LUA_TNONE, { ARG_OPT_STRING(1) } },
    3.67 +	{ "io", "open", LUA_TNONE, { ARG_STRING(1) } },
    3.68 +	{ "io", "popen", LUA_TNONE, { ARG_STRING(1) } },
    3.69 +	/*
    3.70 +	 * Note: We do not proxy os.execute
    3.71 +	 * We can't do it properly (there is no way to distinguish filenames
    3.72 +	 * in arguments from any other strings) so it's better not to try.
    3.73 +	 * Scripts that attempt to be portable should use posix.exec[p]
    3.74 +	 */
    3.75 +	{ "os", "remove", LUA_TNONE, { ARG_STRING(1) } },
    3.76 +	{ "os", "rename", LUA_TNONE, { ARG_STRING(1), ARG_STRING(2) } },
    3.77 +	/*
    3.78 +	 * Note: We do not proxy os.tmpname
    3.79 +	 * It should never be used. scripts should use io.tmpfile instead
    3.80 +	 * if the rather limited functionality it provides suffices. The
    3.81 +	 * proper solution is to implement posix.mkstemp
    3.82 +	 */
    3.83 +	{ "posix", "access", LUA_TNONE, { ARG_STRING(1) } },
    3.84 +	{ "posix", "chdir", LUA_TNONE, { ARG_STRING(1) } },
    3.85 +	{ "posix", "chmod", LUA_TNONE, { ARG_STRING(1) } },
    3.86 +	{ "posix", "chown", LUA_TNONE, { ARG_STRING(1) } },
    3.87 +	{ "posix", "dir", LUA_TNONE, { ARG_OPT_STRING(1) } },
    3.88 +	{ "posix", "exec", LUA_TNONE, { ARG_STRING(1) } },
    3.89 +	{ "posix", "execp", LUA_TNONE, { ARG_STRING(1) } },
    3.90 +	{ "posix", "files", LUA_TNONE, { ARG_OPT_STRING(1) } },
    3.91 +	{ "posix", "getcwd", LUA_TSTRING, { ARG_NONE } },
    3.92 +	{ "posix", "glob", LUA_TTABLE, { ARG_STRING(1) } },
    3.93 +	{ "posix", "link", LUA_TNONE, { ARG_BYP_STRING(1, 3), ARG_STRING(2) } },
    3.94 +	{ "posix", "mkdir", LUA_TNONE, { ARG_STRING(1) } },
    3.95 +	{ "posix", "mkfifo", LUA_TNONE, { ARG_STRING(1) } },
    3.96 +	{ "posix", "pathconf", LUA_TNONE, { ARG_STRING(1) } },
    3.97 +	{ "posix", "readlink", LUA_TNONE, { ARG_STRING(1) } },
    3.98 +	{ "posix", "rmdir", LUA_TNONE, { ARG_STRING(1) } },
    3.99 +	{ "posix", "stat", LUA_TNONE, { ARG_STRING(1) } },
   3.100 +	{ "posix", "unlink", LUA_TNONE, { ARG_STRING(1) } },
   3.101 +	{ "posix", "utime", LUA_TNONE, { ARG_STRING(1) } },
   3.102 +};
   3.103 +
   3.104 +static lua_CFunction execp_handler;
   3.105 +
   3.106 +struct razor_lua {
   3.107 +	const char *root;
   3.108 +	lua_CFunction handler[ARRAY_SIZE(proxy)];
   3.109 +};
   3.110 +
   3.111 +static void *alloc_lua(void *user_data, void *ptr, size_t osize, size_t nsize)
   3.112 +{
   3.113 +	if (!nsize) {
   3.114 +		free(ptr);
   3.115 +		return NULL;
   3.116 +	} else
   3.117 +		return realloc(ptr, nsize);
   3.118 +}
   3.119 +
   3.120 +static int proxy_execp(lua_State *L)
   3.121 +{
   3.122 +	int r, n, err, got_eacces = 0;
   3.123 +	char *file = strdup(luaL_checkstring(L, 1));
   3.124 +	char *exe;
   3.125 +	const char *s, *e, *path;
   3.126 +	struct razor_lua *rl;
   3.127 +
   3.128 +	if (*file == '\0' || strchr(file, '/')) {
   3.129 +		r = execp_handler(L);
   3.130 +		free(file);
   3.131 +		return r;
   3.132 +	}
   3.133 +
   3.134 +	(void)lua_getallocf(L, (void **)&rl);
   3.135 +
   3.136 +	path = getenv("PATH");
   3.137 +	if (!path)
   3.138 +		path = ":/bin:/usr/bin";
   3.139 +
   3.140 +	s = path;
   3.141 +	for (;;) {
   3.142 +		e = strchr(s, ':');
   3.143 +		if (!e)
   3.144 +			e = s + strlen(s);
   3.145 +		if (*s == '/') {
   3.146 +			n = strlen(rl->root);
   3.147 +			exe = malloc(n + (e - s) + 1 + strlen(file) + 1);
   3.148 +			memcpy(exe, rl->root, n);
   3.149 +			memcpy(exe + n, s, e - s);
   3.150 +			n += e - s;
   3.151 +			exe[n++] = '/';
   3.152 +			strcpy(exe + n, file);
   3.153 +		} else if (e != s) {
   3.154 +			exe = malloc((e - s) + 1 + strlen(file) + 1);
   3.155 +			memcpy(exe, s, e - s);
   3.156 +			n = e - s;
   3.157 +			exe[n++] = '/';
   3.158 +			strcpy(exe + n, file);
   3.159 +		} else {
   3.160 +			/* Ensure exe contains a slash to avoid PATH search */
   3.161 +			exe = malloc(2 + strlen(file) + 1);
   3.162 +			exe[0] = '.';
   3.163 +			exe[1] = '/';
   3.164 +			strcpy(exe + 2, file);
   3.165 +		}
   3.166 +		lua_pushstring(L, exe);
   3.167 +		lua_replace(L, 1);
   3.168 +		free(exe);
   3.169 +		n = lua_gettop(L);
   3.170 +		r = execp_handler(L);
   3.171 +
   3.172 +		err = lua_tointeger(L, -1);
   3.173 +		switch (err) {
   3.174 +		case EACCES:
   3.175 +			got_eacces = 1;
   3.176 +			/* Fall through */
   3.177 +		case ENOENT:
   3.178 +		case ESTALE:
   3.179 +		case ENOTDIR:
   3.180 +		case ENODEV:
   3.181 +		case ETIMEDOUT:
   3.182 +			lua_pop(L, lua_gettop(L) - n);
   3.183 +			break;
   3.184 +		default:
   3.185 +			free(file);
   3.186 +			return r;
   3.187 +		}
   3.188 +
   3.189 +		if (*e)
   3.190 +			s = e + 1;
   3.191 +		else
   3.192 +			break;
   3.193 +	}
   3.194 +
   3.195 +	if (got_eacces)
   3.196 +		err = EACCES;
   3.197 +
   3.198 +	lua_pushnil(L);
   3.199 +	lua_pushfstring(L, "%s: %s", file, strerror(err));
   3.200 +	lua_pushinteger(L, err);
   3.201 +
   3.202 +	free(file);
   3.203 +	return 3;
   3.204 +}
   3.205 +
   3.206 +static int real2fake(lua_State *L, struct razor_lua *rl, int indx)
   3.207 +{
   3.208 +	const char *path;
   3.209 +
   3.210 +	if (indx < 0)
   3.211 +		indx += lua_gettop(L) + 1;
   3.212 +
   3.213 +	if (lua_type(L, indx) == LUA_TSTRING) {
   3.214 +		path = lua_tostring(L, indx);
   3.215 +		if (path && !strncmp(path, rl->root, strlen(rl->root)) &&
   3.216 +		   (path[strlen(rl->root)] == '/' || !path[strlen(rl->root)])) {
   3.217 +			lua_pushstring(L, path + strlen(rl->root));
   3.218 +			lua_replace(L, indx);
   3.219 +			return 1;
   3.220 +		}
   3.221 +	}
   3.222 +
   3.223 +	return 0;
   3.224 +}
   3.225 +
   3.226 +static int proxy_handler(lua_State *L)
   3.227 +{
   3.228 +	int i, retval, cond;
   3.229 +	unsigned arg;
   3.230 +	const char *path;
   3.231 +	struct razor_lua *rl;
   3.232 +	int method = lua_tointeger(L, lua_upvalueindex(1));
   3.233 +	struct razor_proxy *rp = proxy + method;
   3.234 +
   3.235 +	(void)lua_getallocf(L, (void **)&rl);
   3.236 +
   3.237 +	for(i = 0; i < MAX_ARGS; i++) {
   3.238 +		arg = rp->args[i];
   3.239 +		if (arg == ARG_NONE)
   3.240 +			continue;
   3.241 +		switch (ARG_TYPE(arg)) {
   3.242 +		case LUA_TSTRING:
   3.243 +			if (ARG_FLAGS(arg) & ARG_FLAG_BYPASS)
   3.244 +				cond = !lua_toboolean(L, ARG_SWTCH(arg));
   3.245 +			else
   3.246 +				cond = 1;
   3.247 +			if (ARG_FLAGS(arg) & ARG_FLAG_OPT) {
   3.248 +				if (lua_isstring(L, ARG_INDEX(arg)))
   3.249 +					path = lua_tostring(L, ARG_INDEX(arg));
   3.250 +				else
   3.251 +					path = NULL;
   3.252 +			} else
   3.253 +				path = luaL_checkstring(L, ARG_INDEX(arg));
   3.254 +			if (cond && path && *path == '/') {
   3.255 +				lua_pushfstring(L, "%s%s", rl->root, path);
   3.256 +				lua_replace(L, ARG_INDEX(arg));
   3.257 +			}
   3.258 +			break;
   3.259 +		default:
   3.260 +			lua_pushfstring(L, "razor proxy: Unhandled type (%d)",
   3.261 +					ARG_TYPE(arg));
   3.262 +			lua_error(L);
   3.263 +		}
   3.264 +	}
   3.265 +
   3.266 +	retval = rl->handler[method](L);
   3.267 +
   3.268 +	if (rp->result != LUA_TNONE && !lua_isnil(L, 1)) {
   3.269 +		switch (rp->result) {
   3.270 +		case LUA_TNONE:
   3.271 +			break;
   3.272 +		case LUA_TSTRING:
   3.273 +			real2fake(L, rl, -1);
   3.274 +			break;
   3.275 +		case LUA_TTABLE:
   3.276 +			lua_pushnil(L);
   3.277 +			while (lua_next(L, -2)) {
   3.278 +				if (real2fake(L, rl, -1)) {
   3.279 +					i = lua_tonumber(L, -2);
   3.280 +					lua_rawseti(L, -3, i);
   3.281 +				} else
   3.282 +					lua_pop(L, 1);
   3.283 +			}
   3.284 +			break;
   3.285 +		default:
   3.286 +			lua_pushfstring(L, "razor proxy: Unhandled type (%d)",
   3.287 +					rp->result);
   3.288 +			lua_error(L);
   3.289 +		}
   3.290 +	}
   3.291 +
   3.292 +	return retval;
   3.293 +}
   3.294 +
   3.295 +int run_lua_script(const char *root, const char *name, const char *body,
   3.296 +		   ssize_t len)
   3.297 +{
   3.298 +	int i, n;
   3.299 +	lua_State *L;
   3.300 +	struct razor_lua rl;
   3.301 +
   3.302 +	if (root && strcmp(root, "/"))
   3.303 +		rl.root = root;
   3.304 +	else
   3.305 +		rl.root = NULL;
   3.306 +
   3.307 +	L = lua_newstate(alloc_lua, &rl);
   3.308 +	luaL_openlibs(L);
   3.309 +	lua_getglobal(L, "require");
   3.310 +	lua_pushstring(L, "posix");
   3.311 +	if (lua_pcall(L, 1, 1, 0)) {
   3.312 +		fprintf(stderr, "lua posix: %s\n", lua_tostring(L, -1));
   3.313 +		lua_pop(L, 1);
   3.314 +		lua_close(L);
   3.315 +		return -1;
   3.316 +	}
   3.317 +
   3.318 +	if (rl.root)
   3.319 +		for(i = 0; i < ARRAY_SIZE(proxy); i++) {
   3.320 +			if (proxy[i].table) {
   3.321 +				lua_getglobal(L, proxy[i].table);
   3.322 +				n = lua_gettop(L);
   3.323 +			} else
   3.324 +				n = LUA_GLOBALSINDEX;
   3.325 +			lua_getfield(L, n, proxy[i].name);
   3.326 +			rl.handler[i] = lua_tocfunction(L, -1);
   3.327 +			lua_getfenv(L, -1);
   3.328 +			lua_remove(L, -2);
   3.329 +			if (proxy[i].table &&
   3.330 +			    !strcmp(proxy[i].table, "posix") &&
   3.331 +			    !strcmp(proxy[i].name, "execp")) {
   3.332 +				execp_handler = rl.handler[i];
   3.333 +				rl.handler[i] = proxy_execp;
   3.334 +			}
   3.335 +			lua_pushinteger(L, i);
   3.336 +			lua_pushcclosure(L, proxy_handler, 1);
   3.337 +			lua_pushvalue(L, -2);
   3.338 +			lua_setfenv(L, -2);
   3.339 +			lua_setfield(L, n, proxy[i].name);
   3.340 +			if (proxy[i].table)
   3.341 +				lua_pop(L, 2);
   3.342 +			else
   3.343 +				lua_pop(L, 1);
   3.344 +		}
   3.345 +
   3.346 +	if (len < 0)
   3.347 +		len = strlen(body);
   3.348 +
   3.349 +	if (luaL_loadbuffer(L, body, len, name)) {
   3.350 +		fprintf(stderr, "failed to load lua script\n");
   3.351 +		lua_close(L);
   3.352 +		return -1;
   3.353 +	}
   3.354 +
   3.355 +	if (lua_pcall(L, 0, 0, 0)) {
   3.356 +		fprintf(stderr, "lua script failed: %s\n", lua_tostring(L, -1));
   3.357 +		lua_pop(L, 1);
   3.358 +		lua_close(L);
   3.359 +		return -1;
   3.360 +	}
   3.361 +
   3.362 +	lua_close(L);
   3.363 +	return 0;
   3.364 +}
     4.1 --- a/librazor/razor-internal.h	Thu Jan 22 22:54:45 2009 +0000
     4.2 +++ b/librazor/razor-internal.h	Thu Feb 05 22:43:29 2009 +0000
     4.3 @@ -218,6 +218,9 @@
     4.4  struct razor_set *
     4.5  razor_merger_finish(struct razor_merger *merger);
     4.6  
     4.7 +int run_lua_script(const char *root, const char *name, const char *body,
     4.8 +		   ssize_t len);
     4.9 +
    4.10  /* Utility functions */
    4.11  
    4.12  void
     5.1 --- a/librazor/rpm.c	Thu Jan 22 22:54:45 2009 +0000
     5.2 +++ b/librazor/rpm.c	Thu Feb 05 22:43:29 2009 +0000
     5.3 @@ -742,9 +742,12 @@
     5.4  {
     5.5  #if HAVE_CHROOT
     5.6  	int pid, status, fd[2];
     5.7 -#else
     5.8 +#if HAVE_LUA
     5.9 +	int save_root, retval;
    5.10 +#endif
    5.11 +#else	/* HAVE_CHROOT */
    5.12  	FILE *fp;
    5.13 -#endif
    5.14 +#endif	/* HAVE_CHROOT */
    5.15  	const char *script = NULL, *program = NULL;
    5.16  
    5.17  	program = razor_rpm_get_indirect(installer->rpm, program_tag, NULL);
    5.18 @@ -764,6 +767,50 @@
    5.19  #else
    5.20  		program = "/bin/sh";
    5.21  #endif
    5.22 +	} else if (!strcmp(program, "<lua>")) {
    5.23 +#if HAVE_LUA
    5.24 +		const char *name;
    5.25 +
    5.26 +		switch(script_tag) {
    5.27 +			case RPMTAG_PREIN:
    5.28 +				name = "%pre";
    5.29 +				break;
    5.30 +			case RPMTAG_POSTIN:
    5.31 +				name = "%post";
    5.32 +				break;
    5.33 +			case RPMTAG_PREUN:
    5.34 +				name = "%preun";
    5.35 +				break;
    5.36 +			case RPMTAG_POSTUN:
    5.37 +				name = "%postun";
    5.38 +				break;
    5.39 +			default:
    5.40 +				name = "script";
    5.41 +				break;
    5.42 +		}
    5.43 +#if HAVE_CHROOT
    5.44 +		if (geteuid() == 0) {
    5.45 +			save_root = open("/", O_RDONLY, 0);
    5.46 +			if (chroot(installer->root) < 0) {
    5.47 +				fprintf(stderr, "failed to chroot to %s: %s\n",
    5.48 +					installer->root, strerror(errno));
    5.49 +				exit(-1);
    5.50 +			}
    5.51 +			retval = run_lua_script(NULL, name, script, -1);
    5.52 +			fchdir(save_root);
    5.53 +			close(save_root);
    5.54 +			chroot(".");
    5.55 +		} else
    5.56 +#endif
    5.57 +		{
    5.58 +			retval = run_lua_script(installer->root, name, script,
    5.59 +						-1);
    5.60 +		}
    5.61 +		return retval;
    5.62 +#else	/* HAVE_LUA */
    5.63 +		fprintf(stderr, "lua not available to run script\n");
    5.64 +		return -1;
    5.65 +#endif	/* HAVE_LUA */
    5.66  	}
    5.67  
    5.68  #if HAVE_CHROOT
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/librazor/test-lua.c	Thu Feb 05 22:43:29 2009 +0000
     6.3 @@ -0,0 +1,102 @@
     6.4 +/*
     6.5 + * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
     6.6 + *
     6.7 + * This program is free software; you can redistribute it and/or modify
     6.8 + * it under the terms of the GNU General Public License as published by
     6.9 + * the Free Software Foundation; either version 2 of the License, or
    6.10 + * (at your option) any later version.
    6.11 + *
    6.12 + * This program is distributed in the hope that it will be useful,
    6.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    6.15 + * GNU General Public License for more details.
    6.16 + *
    6.17 + * You should have received a copy of the GNU General Public License along
    6.18 + * with this program; if not, write to the Free Software Foundation, Inc.,
    6.19 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    6.20 + */
    6.21 +
    6.22 +#include "config.h"
    6.23 +
    6.24 +#include <stdlib.h>
    6.25 +#include <stdio.h>
    6.26 +#include <string.h>
    6.27 +#include <sys/types.h>
    6.28 +#include <sys/stat.h>
    6.29 +#include <dirent.h>
    6.30 +#include <unistd.h>
    6.31 +#include <math.h>
    6.32 +#include "razor-internal.h"
    6.33 +
    6.34 +/*
    6.35 + * This kludge is to work around an apparent bug in Fedora 10's lua package
    6.36 + * (it appears to require libm but not to include a DT_NEEDED).
    6.37 + */
    6.38 +
    6.39 +void (*kludge)() = (void (*)())sin;
    6.40 +
    6.41 +static void recursive_remove(const char *directory)
    6.42 +{
    6.43 +	DIR *dp;
    6.44 +	struct dirent *dirp;
    6.45 +	char *buf;
    6.46 +
    6.47 +	dp = opendir(directory);
    6.48 +	while((dirp = readdir(dp))) {
    6.49 +		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
    6.50 +			buf = malloc(strlen(directory) + strlen(dirp->d_name)
    6.51 +				     + 2);
    6.52 +			sprintf(buf, "%s/%s", directory, dirp->d_name);
    6.53 +			if (remove(buf) < 0)
    6.54 +				recursive_remove(buf);
    6.55 +			free(buf);
    6.56 +		}
    6.57 +	}
    6.58 +
    6.59 +	rmdir(directory);
    6.60 +}
    6.61 +
    6.62 +int main(int argc, char *argv[])
    6.63 +{
    6.64 +	char root[] = "/tmp/razor.XXXXXX";
    6.65 +	int r;
    6.66 +	void *script;
    6.67 +	size_t len;
    6.68 +	char *s, *test_file;
    6.69 +	FILE *fp;
    6.70 +
    6.71 +	if (argc > 2) {
    6.72 +		fprintf(stderr, "usage: %s [TESTS-FILE]\n", argv[0]);
    6.73 +		exit(1);
    6.74 +	}
    6.75 +	if (argc == 2)
    6.76 +		test_file = argv[1];
    6.77 +	else
    6.78 +		test_file = "test.lua";
    6.79 +
    6.80 +	if (!mkdtemp(root)) {
    6.81 +		perror(root);
    6.82 +		exit(1);
    6.83 +	}
    6.84 +
    6.85 +	s = malloc(strlen(root) + strlen("/testfile") + 1);
    6.86 +	strcpy(s, root);
    6.87 +	strcat(s, "/testfile");
    6.88 +	fp = fopen(s, "w");
    6.89 +	if (!fp) {
    6.90 +		perror(s);
    6.91 +		exit(1);
    6.92 +	}
    6.93 +	fprintf(fp, "#!" LUA_BINARY "\n"
    6.94 +	  "print('Abracadabra!')\n");
    6.95 +	fchmod(fileno(fp), S_IRUSR | S_IWUSR | S_IXUSR);
    6.96 +	fclose(fp);
    6.97 +	free(s);
    6.98 +
    6.99 +	script = razor_file_get_contents(test_file, &len);
   6.100 +	r = run_lua_script(root, test_file, script, len);
   6.101 +	razor_file_free_contents(script, len);
   6.102 +
   6.103 +	recursive_remove(root);
   6.104 +	exit(r ? 1 : 0);
   6.105 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/librazor/test.lua	Thu Feb 05 22:43:29 2009 +0000
     7.3 @@ -0,0 +1,60 @@
     7.4 +dofile("/testfile")
     7.5 +assert(loadfile("/testfile"))
     7.6 +assert(io.input("/testfile"))
     7.7 +assert(io.output("/file1"))
     7.8 +file = assert(io.open("/file1", "w"))
     7.9 +assert(io.input(file))
    7.10 +assert(io.output(file))
    7.11 +file:write("Hello world\n")
    7.12 +file:close()
    7.13 +assert(io.input())
    7.14 +assert(io.output())
    7.15 +for line in assert(io.lines("/file1")) do
    7.16 +	assert(line == "Hello world")
    7.17 +end
    7.18 +file, err = io.popen("/testfile", "r")
    7.19 +if file == nil then
    7.20 +	assert(string.find(err, " not supported") == 1)
    7.21 +else
    7.22 +	assert(file:read() == "Abracadabra!")
    7.23 +	file:close();
    7.24 +end
    7.25 +assert(os.rename("/file1","/file2"))
    7.26 +assert(os.remove("/file2"))
    7.27 +assert(posix.mkdir("/testdir"))
    7.28 +assert(posix.stat("/testdir"))
    7.29 +assert(posix.chdir("/testdir"))
    7.30 +assert(posix.getcwd() == "/testdir")
    7.31 +assert(posix.mkdir("dir1"))
    7.32 +assert(posix.link("/testdir/dir1", "/testdir/link", true))
    7.33 +assert(posix.readlink("/testdir/link") == "/testdir/dir1")
    7.34 +assert(posix.unlink("/testdir/link"))
    7.35 +assert(posix.link("/testfile", "/testdir/magic", false))
    7.36 +assert(posix.chmod("/testfile","a+x"))
    7.37 +assert(posix.access("/testfile","x"))
    7.38 +pid = posix.fork()
    7.39 +if pid == 0 then
    7.40 +	assert(posix.exec("/testfile"))
    7.41 +else
    7.42 +	posix.wait(pid)
    7.43 +end
    7.44 +assert(posix.chdir("/"))
    7.45 +posix.setenv("PATH","/bin:/usr/bin:/testdir",true)
    7.46 +pid = posix.fork()
    7.47 +if pid == 0 then
    7.48 +	assert(posix.execp("magic"))
    7.49 +else
    7.50 +	posix.wait(pid)
    7.51 +end
    7.52 +assert(posix.utime("/testfile"))
    7.53 +assert(posix.pathconf("/testdir/magic"))
    7.54 +assert(posix.mkfifo("/testdir/fifo"))
    7.55 +assert(posix.dir())
    7.56 +assert(posix.dir("/testdir"))
    7.57 +assert(posix.files())
    7.58 +assert(posix.files("/testdir"))
    7.59 +for _,f in pairs(posix.glob("/testdir/*")) do
    7.60 +	assert(string.find(f, "/testdir/") == 1)
    7.61 +end
    7.62 +assert(posix.rmdir("/testdir/dir1"))
    7.63 +assert(posix.chown("/testfile",-1,-1))
     8.1 --- a/src/Makefile.am	Thu Jan 22 22:54:45 2009 +0000
     8.2 +++ b/src/Makefile.am	Thu Feb 05 22:43:29 2009 +0000
     8.3 @@ -1,6 +1,7 @@
     8.4  ## Process this file with automake to produce Makefile.in
     8.5  
     8.6  INCLUDES = \
     8.7 +	$(LUA_CFLAGS) \
     8.8  	$(CURL_CFLAGS) \
     8.9  	$(EXPAT_CFLAGS) \
    8.10  	$(RPM_CFLAGS) \
    8.11 @@ -22,7 +23,7 @@
    8.12  if HAVE_RPMLIB
    8.13  razor_SOURCES += import-rpmdb.c
    8.14  endif
    8.15 -razor_LDADD = $(RPM_LIBS) $(EXPAT_LIBS) $(CURL_LIBS) $(top_builddir)/librazor/librazor.la $(top_builddir)/gl/libgnu.la $(EXTRA_LIBS)
    8.16 +razor_LDADD = $(RPM_LIBS) $(EXPAT_LIBS) $(CURL_LIBS) $(LUA_LIBS) $(top_builddir)/librazor/librazor.la $(top_builddir)/gl/libgnu.la $(EXTRA_LIBS)
    8.17  
    8.18  rpm_SOURCES = rpm.c
    8.19  rpm_LDADD = $(top_builddir)/librazor/librazor.la $(EXTRA_LIBS)
     9.1 --- a/test/Makefile.am	Thu Jan 22 22:54:45 2009 +0000
     9.2 +++ b/test/Makefile.am	Thu Feb 05 22:43:29 2009 +0000
     9.3 @@ -1,16 +1,23 @@
     9.4  ## Process this file with automake to produce Makefile.in
     9.5  
     9.6  check_SCRIPTS = relocate
     9.7 +if HAVE_LUA
     9.8 +  check_SCRIPTS += lua
     9.9 +endif
    9.10  
    9.11  relocate:	relocate.sh primary.xml.gz
    9.12  	cp $(srcdir)/relocate.sh relocate
    9.13  
    9.14 -primary.xml.gz:	zsh.spec zip.spec zap.spec Makefile
    9.15 +lua:	lua.sh primary.xml.gz
    9.16 +	cp $(srcdir)/lua.sh lua
    9.17 +
    9.18 +primary.xml.gz:	zsh.spec zip.spec zap.spec filesystem.spec Makefile
    9.19  	rm -rf rpmbuild rpms repodata
    9.20  	mkdir -p rpmbuild/BUILD rpmbuild/RPMS
    9.21  	rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/zap.spec
    9.22  	rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/zip.spec
    9.23  	rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/zsh.spec
    9.24 +	rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/filesystem.spec
    9.25  	mkdir rpms
    9.26  	mv rpmbuild/RPMS/noarch/*.rpm rpms
    9.27  	rm -rf rpmbuild
    9.28 @@ -23,6 +30,8 @@
    9.29  	zap.spec		\
    9.30  	zip.spec		\
    9.31  	zsh.spec		\
    9.32 +	filesystem.spec		\
    9.33 +	lua.sh			\
    9.34  	relocate.sh
    9.35  
    9.36  clean-local :
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/test/filesystem.spec	Thu Feb 05 22:43:29 2009 +0000
    10.3 @@ -0,0 +1,38 @@
    10.4 +Name:      filesystem
    10.5 +Summary:   Test package
    10.6 +Group:     Test
    10.7 +License:   GPL
    10.8 +Version:   1
    10.9 +Release:   1
   10.10 +BuildArch: noarch
   10.11 +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
   10.12 +
   10.13 +%description
   10.14 +Test package
   10.15 +
   10.16 +%prep
   10.17 +
   10.18 +%build
   10.19 +
   10.20 +%install
   10.21 +mkdir %{buildroot}
   10.22 +mkdir -p %{buildroot}%{_sysconfdir}
   10.23 +mkdir -p %{buildroot}/{%{_bindir},%{_libdir},%{_includedir}}
   10.24 +mkdir -p %{buildroot}/media
   10.25 +
   10.26 +%clean
   10.27 +rm -rf %{buildroot}
   10.28 +
   10.29 +%post -p <lua>
   10.30 +function mkdir_missing(dir)
   10.31 +    if posix.stat(dir) == nil then
   10.32 +        posix.mkdir(dir)
   10.33 +    end
   10.34 +end
   10.35 +mkdir_missing("/media/cdrom")
   10.36 +
   10.37 +%files
   10.38 +%defattr(0755,root,root)
   10.39 +/etc
   10.40 +%{_prefix}
   10.41 +%dir /media
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/test/lua.sh	Thu Feb 05 22:43:29 2009 +0000
    11.3 @@ -0,0 +1,28 @@
    11.4 +#!/bin/sh
    11.5 +check_filesystem()
    11.6 +{
    11.7 +    if [ ! -e "$RAZOR_ROOT$1" ]; then 
    11.8 +	echo $1: Not in filesystem >&2
    11.9 +	exit 1
   11.10 +    fi
   11.11 +}
   11.12 +check_file()
   11.13 +{
   11.14 +    ../src/razor list-files | grep -x "$1" > /dev/null
   11.15 +    if [ $? -ne 0 ]; then
   11.16 +	echo $1: Not in database >&2
   11.17 +	exit 1
   11.18 +    fi
   11.19 +    check_filesystem "$1"
   11.20 +}
   11.21 +export RAZOR_ROOT=`mktemp -dt` || exit 1
   11.22 +../src/razor init || exit 1
   11.23 +export YUM_URL="file://localhost/`pwd`"
   11.24 +../src/razor import-yum || exit 1
   11.25 +../src/razor install filesystem || exit 1
   11.26 +check_file /etc
   11.27 +check_file /usr/bin
   11.28 +check_file /usr/lib
   11.29 +check_file /usr/include
   11.30 +check_filesystem /media/cdrom
   11.31 +rm -rf "$RAZOR_ROOT"