Implement lua scripts with support for standard and posix libraries.
authorJ. Ali Harlow <ali@juiblex.co.uk>
Thu, 5 Feb 2009 22:43:29 +0000 (22:43 +0000)
committerJ. Ali Harlow <ali@juiblex.co.uk>
Thu, 5 Feb 2009 22:43:29 +0000 (22:43 +0000)
configure.ac
librazor/Makefile.am
librazor/lua.c [new file with mode: 0644]
librazor/razor-internal.h
librazor/rpm.c
librazor/test-lua.c [new file with mode: 0644]
librazor/test.lua [new file with mode: 0644]
src/Makefile.am
test/Makefile.am
test/filesystem.spec [new file with mode: 0644]
test/lua.sh [new file with mode: 0755]

index 60879df..43160ea 100644 (file)
@@ -202,6 +202,27 @@ AS_IF([test "$with_rpm" != no],
        AC_DEFINE([HAVE_RPMLIB], [1], [Define if you have librpm])])
 AC_SUBST(RPM_LIBS)
 AM_CONDITIONAL([HAVE_RPMLIB], [test -n "$RPM_LIBS"])
+
+AC_ARG_WITH([lua],
+            [AS_HELP_STRING([--without-lua], [disable support for lua])],
+            [],
+            [with_lua=yes])
+          
+LUA_CFLAGS=
+LUA_LIBS=
+AS_IF([test "x$with_lua" != xno],
+  [PKG_CHECK_MODULES(LUA, [lua])
+   REQUIREMENTS="$REQUIREMENTS lua"
+   AC_DEFINE([HAVE_LUA], [1], [Define if you have lua])
+   AC_PATH_PROG(LUA, [lua], [no])
+   AS_IF([test "x$LUA" = xno],
+     [AC_MSG_ERROR([Can't find lua program. Please install lua-devel or use --without-lua.])])
+   AC_DEFINE_UNQUOTED([LUA_BINARY], ["$LUA"],
+     [Define to the location of the lua binary])])
+AC_SUBST(LUA_CFLAGS)
+AC_SUBST(LUA_LIBS)
+AM_CONDITIONAL([HAVE_LUA], [test "x$with_lua" != xno])
+
 AC_SUBST(REQUIREMENTS)
 
 if test "x$GCC" = "xyes"; then
index ead4f92..586684a 100644 (file)
@@ -12,6 +12,9 @@ INCLUDES = \
        -DPACKAGE_LIB_DIR=\""$(libdir)"\"
 
 lib_LTLIBRARIES = librazor.la
+if HAVE_LUA
+  check_PROGRAMS = test-lua
+endif
 
 librazorincludedir = $(includedir)/razor
 
@@ -31,7 +34,22 @@ librazor_la_SOURCES =                                        \
        merger.c                                        \
        transaction.c
 
-librazor_la_LIBADD = $(ZLIB_LIBS) ../gl/libgnu.la $(EXTRA_LIBS)
+if HAVE_LUA
+  librazor_la_SOURCES += lua.c
+endif
+
+librazor_la_LIBADD = $(ZLIB_LIBS) $(LUA_LIBS) ../gl/libgnu.la $(EXTRA_LIBS)
+
+if HAVE_LUA
+  test_lua_SOURCES = test-lua.c
+  test_lua_LDADD = lua.lo util.lo $(LUA_LIBS) ../gl/libgnu.la \
+       $(EXTRA_LIBS)
+
+  TESTS = test-lua
+endif
+
+EXTRA_DIST =                   \
+       test.lua
 
 clean-local :
        rm -f *~
diff --git a/librazor/lua.c b/librazor/lua.c
new file mode 100644 (file)
index 0000000..910a82f
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+#include "razor.h"
+#include "razor-internal.h"
+
+#define MAX_ARGS               2
+
+#define ARG_FLAG_OPT           0x1
+#define ARG_FLAG_BYPASS                0x2
+
+#define ARG(flags, swtch, index, type) \
+                               ((flags) << 26 | (swtch) << 21 | \
+                                (index) << 16 | type)
+#define ARG_FLAGS(arg)         ((unsigned)(arg) >> 26)
+#define ARG_SWTCH(arg)         ((unsigned)(arg) >> 21 & 0x1F)
+#define ARG_INDEX(arg)         ((unsigned)(arg) >> 16 & 0x1F)
+#define ARG_TYPE(arg)          ((unsigned)(arg) & 0xFFFF)
+
+#define ARG_NONE               0
+#define ARG_STRING(n)          ARG(0, 0, n, LUA_TSTRING)
+#define ARG_OPT_STRING(n)      ARG(ARG_FLAG_OPT, 0, n, LUA_TSTRING)
+#define ARG_BYP_STRING(n, s)   ARG(ARG_FLAG_BYPASS, s, n, LUA_TSTRING)
+
+struct razor_proxy {
+       char *table, *name;
+       int result;
+       unsigned args[MAX_ARGS];
+};
+
+static struct razor_proxy proxy[] = {
+       { NULL, "dofile", LUA_TNONE, { ARG_STRING(1) } },
+       { NULL, "loadfile", LUA_TNONE, { ARG_OPT_STRING(1) } },
+       { "io", "input", LUA_TNONE, { ARG_OPT_STRING(1) } },
+       { "io", "output", LUA_TNONE, { ARG_OPT_STRING(1) } },
+       { "io", "lines", LUA_TNONE, { ARG_OPT_STRING(1) } },
+       { "io", "open", LUA_TNONE, { ARG_STRING(1) } },
+       { "io", "popen", LUA_TNONE, { ARG_STRING(1) } },
+       /*
+        * Note: We do not proxy os.execute
+        * We can't do it properly (there is no way to distinguish filenames
+        * in arguments from any other strings) so it's better not to try.
+        * Scripts that attempt to be portable should use posix.exec[p]
+        */
+       { "os", "remove", LUA_TNONE, { ARG_STRING(1) } },
+       { "os", "rename", LUA_TNONE, { ARG_STRING(1), ARG_STRING(2) } },
+       /*
+        * Note: We do not proxy os.tmpname
+        * It should never be used. scripts should use io.tmpfile instead
+        * if the rather limited functionality it provides suffices. The
+        * proper solution is to implement posix.mkstemp
+        */
+       { "posix", "access", LUA_TNONE, { ARG_STRING(1) } },
+       { "posix", "chdir", LUA_TNONE, { ARG_STRING(1) } },
+       { "posix", "chmod", LUA_TNONE, { ARG_STRING(1) } },
+       { "posix", "chown", LUA_TNONE, { ARG_STRING(1) } },
+       { "posix", "dir", LUA_TNONE, { ARG_OPT_STRING(1) } },
+       { "posix", "exec", LUA_TNONE, { ARG_STRING(1) } },
+       { "posix", "execp", LUA_TNONE, { ARG_STRING(1) } },
+       { "posix", "files", LUA_TNONE, { ARG_OPT_STRING(1) } },
+       { "posix", "getcwd", LUA_TSTRING, { ARG_NONE } },
+       { "posix", "glob", LUA_TTABLE, { ARG_STRING(1) } },
+       { "posix", "link", LUA_TNONE, { ARG_BYP_STRING(1, 3), ARG_STRING(2) } },
+       { "posix", "mkdir", LUA_TNONE, { ARG_STRING(1) } },
+       { "posix", "mkfifo", LUA_TNONE, { ARG_STRING(1) } },
+       { "posix", "pathconf", LUA_TNONE, { ARG_STRING(1) } },
+       { "posix", "readlink", LUA_TNONE, { ARG_STRING(1) } },
+       { "posix", "rmdir", LUA_TNONE, { ARG_STRING(1) } },
+       { "posix", "stat", LUA_TNONE, { ARG_STRING(1) } },
+       { "posix", "unlink", LUA_TNONE, { ARG_STRING(1) } },
+       { "posix", "utime", LUA_TNONE, { ARG_STRING(1) } },
+};
+
+static lua_CFunction execp_handler;
+
+struct razor_lua {
+       const char *root;
+       lua_CFunction handler[ARRAY_SIZE(proxy)];
+};
+
+static void *alloc_lua(void *user_data, void *ptr, size_t osize, size_t nsize)
+{
+       if (!nsize) {
+               free(ptr);
+               return NULL;
+       } else
+               return realloc(ptr, nsize);
+}
+
+static int proxy_execp(lua_State *L)
+{
+       int r, n, err, got_eacces = 0;
+       char *file = strdup(luaL_checkstring(L, 1));
+       char *exe;
+       const char *s, *e, *path;
+       struct razor_lua *rl;
+
+       if (*file == '\0' || strchr(file, '/')) {
+               r = execp_handler(L);
+               free(file);
+               return r;
+       }
+
+       (void)lua_getallocf(L, (void **)&rl);
+
+       path = getenv("PATH");
+       if (!path)
+               path = ":/bin:/usr/bin";
+
+       s = path;
+       for (;;) {
+               e = strchr(s, ':');
+               if (!e)
+                       e = s + strlen(s);
+               if (*s == '/') {
+                       n = strlen(rl->root);
+                       exe = malloc(n + (e - s) + 1 + strlen(file) + 1);
+                       memcpy(exe, rl->root, n);
+                       memcpy(exe + n, s, e - s);
+                       n += e - s;
+                       exe[n++] = '/';
+                       strcpy(exe + n, file);
+               } else if (e != s) {
+                       exe = malloc((e - s) + 1 + strlen(file) + 1);
+                       memcpy(exe, s, e - s);
+                       n = e - s;
+                       exe[n++] = '/';
+                       strcpy(exe + n, file);
+               } else {
+                       /* Ensure exe contains a slash to avoid PATH search */
+                       exe = malloc(2 + strlen(file) + 1);
+                       exe[0] = '.';
+                       exe[1] = '/';
+                       strcpy(exe + 2, file);
+               }
+               lua_pushstring(L, exe);
+               lua_replace(L, 1);
+               free(exe);
+               n = lua_gettop(L);
+               r = execp_handler(L);
+
+               err = lua_tointeger(L, -1);
+               switch (err) {
+               case EACCES:
+                       got_eacces = 1;
+                       /* Fall through */
+               case ENOENT:
+               case ESTALE:
+               case ENOTDIR:
+               case ENODEV:
+               case ETIMEDOUT:
+                       lua_pop(L, lua_gettop(L) - n);
+                       break;
+               default:
+                       free(file);
+                       return r;
+               }
+
+               if (*e)
+                       s = e + 1;
+               else
+                       break;
+       }
+
+       if (got_eacces)
+               err = EACCES;
+
+       lua_pushnil(L);
+       lua_pushfstring(L, "%s: %s", file, strerror(err));
+       lua_pushinteger(L, err);
+
+       free(file);
+       return 3;
+}
+
+static int real2fake(lua_State *L, struct razor_lua *rl, int indx)
+{
+       const char *path;
+
+       if (indx < 0)
+               indx += lua_gettop(L) + 1;
+
+       if (lua_type(L, indx) == LUA_TSTRING) {
+               path = lua_tostring(L, indx);
+               if (path && !strncmp(path, rl->root, strlen(rl->root)) &&
+                  (path[strlen(rl->root)] == '/' || !path[strlen(rl->root)])) {
+                       lua_pushstring(L, path + strlen(rl->root));
+                       lua_replace(L, indx);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int proxy_handler(lua_State *L)
+{
+       int i, retval, cond;
+       unsigned arg;
+       const char *path;
+       struct razor_lua *rl;
+       int method = lua_tointeger(L, lua_upvalueindex(1));
+       struct razor_proxy *rp = proxy + method;
+
+       (void)lua_getallocf(L, (void **)&rl);
+
+       for(i = 0; i < MAX_ARGS; i++) {
+               arg = rp->args[i];
+               if (arg == ARG_NONE)
+                       continue;
+               switch (ARG_TYPE(arg)) {
+               case LUA_TSTRING:
+                       if (ARG_FLAGS(arg) & ARG_FLAG_BYPASS)
+                               cond = !lua_toboolean(L, ARG_SWTCH(arg));
+                       else
+                               cond = 1;
+                       if (ARG_FLAGS(arg) & ARG_FLAG_OPT) {
+                               if (lua_isstring(L, ARG_INDEX(arg)))
+                                       path = lua_tostring(L, ARG_INDEX(arg));
+                               else
+                                       path = NULL;
+                       } else
+                               path = luaL_checkstring(L, ARG_INDEX(arg));
+                       if (cond && path && *path == '/') {
+                               lua_pushfstring(L, "%s%s", rl->root, path);
+                               lua_replace(L, ARG_INDEX(arg));
+                       }
+                       break;
+               default:
+                       lua_pushfstring(L, "razor proxy: Unhandled type (%d)",
+                                       ARG_TYPE(arg));
+                       lua_error(L);
+               }
+       }
+
+       retval = rl->handler[method](L);
+
+       if (rp->result != LUA_TNONE && !lua_isnil(L, 1)) {
+               switch (rp->result) {
+               case LUA_TNONE:
+                       break;
+               case LUA_TSTRING:
+                       real2fake(L, rl, -1);
+                       break;
+               case LUA_TTABLE:
+                       lua_pushnil(L);
+                       while (lua_next(L, -2)) {
+                               if (real2fake(L, rl, -1)) {
+                                       i = lua_tonumber(L, -2);
+                                       lua_rawseti(L, -3, i);
+                               } else
+                                       lua_pop(L, 1);
+                       }
+                       break;
+               default:
+                       lua_pushfstring(L, "razor proxy: Unhandled type (%d)",
+                                       rp->result);
+                       lua_error(L);
+               }
+       }
+
+       return retval;
+}
+
+int run_lua_script(const char *root, const char *name, const char *body,
+                  ssize_t len)
+{
+       int i, n;
+       lua_State *L;
+       struct razor_lua rl;
+
+       if (root && strcmp(root, "/"))
+               rl.root = root;
+       else
+               rl.root = NULL;
+
+       L = lua_newstate(alloc_lua, &rl);
+       luaL_openlibs(L);
+       lua_getglobal(L, "require");
+       lua_pushstring(L, "posix");
+       if (lua_pcall(L, 1, 1, 0)) {
+               fprintf(stderr, "lua posix: %s\n", lua_tostring(L, -1));
+               lua_pop(L, 1);
+               lua_close(L);
+               return -1;
+       }
+
+       if (rl.root)
+               for(i = 0; i < ARRAY_SIZE(proxy); i++) {
+                       if (proxy[i].table) {
+                               lua_getglobal(L, proxy[i].table);
+                               n = lua_gettop(L);
+                       } else
+                               n = LUA_GLOBALSINDEX;
+                       lua_getfield(L, n, proxy[i].name);
+                       rl.handler[i] = lua_tocfunction(L, -1);
+                       lua_getfenv(L, -1);
+                       lua_remove(L, -2);
+                       if (proxy[i].table &&
+                           !strcmp(proxy[i].table, "posix") &&
+                           !strcmp(proxy[i].name, "execp")) {
+                               execp_handler = rl.handler[i];
+                               rl.handler[i] = proxy_execp;
+                       }
+                       lua_pushinteger(L, i);
+                       lua_pushcclosure(L, proxy_handler, 1);
+                       lua_pushvalue(L, -2);
+                       lua_setfenv(L, -2);
+                       lua_setfield(L, n, proxy[i].name);
+                       if (proxy[i].table)
+                               lua_pop(L, 2);
+                       else
+                               lua_pop(L, 1);
+               }
+
+       if (len < 0)
+               len = strlen(body);
+
+       if (luaL_loadbuffer(L, body, len, name)) {
+               fprintf(stderr, "failed to load lua script\n");
+               lua_close(L);
+               return -1;
+       }
+
+       if (lua_pcall(L, 0, 0, 0)) {
+               fprintf(stderr, "lua script failed: %s\n", lua_tostring(L, -1));
+               lua_pop(L, 1);
+               lua_close(L);
+               return -1;
+       }
+
+       lua_close(L);
+       return 0;
+}
index 8fe0f3b..69d7857 100644 (file)
@@ -218,6 +218,9 @@ razor_merger_add_package(struct razor_merger *merger,
 struct razor_set *
 razor_merger_finish(struct razor_merger *merger);
 
+int run_lua_script(const char *root, const char *name, const char *body,
+                  ssize_t len);
+
 /* Utility functions */
 
 void
index 80c6f61..8ca7bdd 100644 (file)
@@ -742,9 +742,12 @@ run_script(struct installer *installer,
 {
 #if HAVE_CHROOT
        int pid, status, fd[2];
-#else
-       FILE *fp;
+#if HAVE_LUA
+       int save_root, retval;
 #endif
+#else  /* HAVE_CHROOT */
+       FILE *fp;
+#endif /* HAVE_CHROOT */
        const char *script = NULL, *program = NULL;
 
        program = razor_rpm_get_indirect(installer->rpm, program_tag, NULL);
@@ -764,6 +767,50 @@ run_script(struct installer *installer,
 #else
                program = "/bin/sh";
 #endif
+       } else if (!strcmp(program, "<lua>")) {
+#if HAVE_LUA
+               const char *name;
+
+               switch(script_tag) {
+                       case RPMTAG_PREIN:
+                               name = "%pre";
+                               break;
+                       case RPMTAG_POSTIN:
+                               name = "%post";
+                               break;
+                       case RPMTAG_PREUN:
+                               name = "%preun";
+                               break;
+                       case RPMTAG_POSTUN:
+                               name = "%postun";
+                               break;
+                       default:
+                               name = "script";
+                               break;
+               }
+#if HAVE_CHROOT
+               if (geteuid() == 0) {
+                       save_root = open("/", O_RDONLY, 0);
+                       if (chroot(installer->root) < 0) {
+                               fprintf(stderr, "failed to chroot to %s: %s\n",
+                                       installer->root, strerror(errno));
+                               exit(-1);
+                       }
+                       retval = run_lua_script(NULL, name, script, -1);
+                       fchdir(save_root);
+                       close(save_root);
+                       chroot(".");
+               } else
+#endif
+               {
+                       retval = run_lua_script(installer->root, name, script,
+                                               -1);
+               }
+               return retval;
+#else  /* HAVE_LUA */
+               fprintf(stderr, "lua not available to run script\n");
+               return -1;
+#endif /* HAVE_LUA */
        }
 
 #if HAVE_CHROOT
diff --git a/librazor/test-lua.c b/librazor/test-lua.c
new file mode 100644 (file)
index 0000000..6be0308
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <math.h>
+#include "razor-internal.h"
+
+/*
+ * This kludge is to work around an apparent bug in Fedora 10's lua package
+ * (it appears to require libm but not to include a DT_NEEDED).
+ */
+
+void (*kludge)() = (void (*)())sin;
+
+static void recursive_remove(const char *directory)
+{
+       DIR *dp;
+       struct dirent *dirp;
+       char *buf;
+
+       dp = opendir(directory);
+       while((dirp = readdir(dp))) {
+               if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
+                       buf = malloc(strlen(directory) + strlen(dirp->d_name)
+                                    + 2);
+                       sprintf(buf, "%s/%s", directory, dirp->d_name);
+                       if (remove(buf) < 0)
+                               recursive_remove(buf);
+                       free(buf);
+               }
+       }
+
+       rmdir(directory);
+}
+
+int main(int argc, char *argv[])
+{
+       char root[] = "/tmp/razor.XXXXXX";
+       int r;
+       void *script;
+       size_t len;
+       char *s, *test_file;
+       FILE *fp;
+
+       if (argc > 2) {
+               fprintf(stderr, "usage: %s [TESTS-FILE]\n", argv[0]);
+               exit(1);
+       }
+       if (argc == 2)
+               test_file = argv[1];
+       else
+               test_file = "test.lua";
+
+       if (!mkdtemp(root)) {
+               perror(root);
+               exit(1);
+       }
+
+       s = malloc(strlen(root) + strlen("/testfile") + 1);
+       strcpy(s, root);
+       strcat(s, "/testfile");
+       fp = fopen(s, "w");
+       if (!fp) {
+               perror(s);
+               exit(1);
+       }
+       fprintf(fp, "#!" LUA_BINARY "\n"
+         "print('Abracadabra!')\n");
+       fchmod(fileno(fp), S_IRUSR | S_IWUSR | S_IXUSR);
+       fclose(fp);
+       free(s);
+
+       script = razor_file_get_contents(test_file, &len);
+       r = run_lua_script(root, test_file, script, len);
+       razor_file_free_contents(script, len);
+
+       recursive_remove(root);
+       exit(r ? 1 : 0);
+}
diff --git a/librazor/test.lua b/librazor/test.lua
new file mode 100644 (file)
index 0000000..4867f51
--- /dev/null
@@ -0,0 +1,60 @@
+dofile("/testfile")
+assert(loadfile("/testfile"))
+assert(io.input("/testfile"))
+assert(io.output("/file1"))
+file = assert(io.open("/file1", "w"))
+assert(io.input(file))
+assert(io.output(file))
+file:write("Hello world\n")
+file:close()
+assert(io.input())
+assert(io.output())
+for line in assert(io.lines("/file1")) do
+       assert(line == "Hello world")
+end
+file, err = io.popen("/testfile", "r")
+if file == nil then
+       assert(string.find(err, " not supported") == 1)
+else
+       assert(file:read() == "Abracadabra!")
+       file:close();
+end
+assert(os.rename("/file1","/file2"))
+assert(os.remove("/file2"))
+assert(posix.mkdir("/testdir"))
+assert(posix.stat("/testdir"))
+assert(posix.chdir("/testdir"))
+assert(posix.getcwd() == "/testdir")
+assert(posix.mkdir("dir1"))
+assert(posix.link("/testdir/dir1", "/testdir/link", true))
+assert(posix.readlink("/testdir/link") == "/testdir/dir1")
+assert(posix.unlink("/testdir/link"))
+assert(posix.link("/testfile", "/testdir/magic", false))
+assert(posix.chmod("/testfile","a+x"))
+assert(posix.access("/testfile","x"))
+pid = posix.fork()
+if pid == 0 then
+       assert(posix.exec("/testfile"))
+else
+       posix.wait(pid)
+end
+assert(posix.chdir("/"))
+posix.setenv("PATH","/bin:/usr/bin:/testdir",true)
+pid = posix.fork()
+if pid == 0 then
+       assert(posix.execp("magic"))
+else
+       posix.wait(pid)
+end
+assert(posix.utime("/testfile"))
+assert(posix.pathconf("/testdir/magic"))
+assert(posix.mkfifo("/testdir/fifo"))
+assert(posix.dir())
+assert(posix.dir("/testdir"))
+assert(posix.files())
+assert(posix.files("/testdir"))
+for _,f in pairs(posix.glob("/testdir/*")) do
+       assert(string.find(f, "/testdir/") == 1)
+end
+assert(posix.rmdir("/testdir/dir1"))
+assert(posix.chown("/testfile",-1,-1))
index fef5221..5e3b259 100644 (file)
@@ -1,6 +1,7 @@
 ## Process this file with automake to produce Makefile.in
 
 INCLUDES = \
+       $(LUA_CFLAGS) \
        $(CURL_CFLAGS) \
        $(EXPAT_CFLAGS) \
        $(RPM_CFLAGS) \
@@ -22,7 +23,7 @@ razor_SOURCES = main.c import-yum.c
 if HAVE_RPMLIB
 razor_SOURCES += import-rpmdb.c
 endif
-razor_LDADD = $(RPM_LIBS) $(EXPAT_LIBS) $(CURL_LIBS) $(top_builddir)/librazor/librazor.la $(top_builddir)/gl/libgnu.la $(EXTRA_LIBS)
+razor_LDADD = $(RPM_LIBS) $(EXPAT_LIBS) $(CURL_LIBS) $(LUA_LIBS) $(top_builddir)/librazor/librazor.la $(top_builddir)/gl/libgnu.la $(EXTRA_LIBS)
 
 rpm_SOURCES = rpm.c
 rpm_LDADD = $(top_builddir)/librazor/librazor.la $(EXTRA_LIBS)
index ffa1762..2963ff5 100644 (file)
@@ -1,16 +1,23 @@
 ## Process this file with automake to produce Makefile.in
 
 check_SCRIPTS = relocate
+if HAVE_LUA
+  check_SCRIPTS += lua
+endif
 
 relocate:      relocate.sh primary.xml.gz
        cp $(srcdir)/relocate.sh relocate
 
-primary.xml.gz:        zsh.spec zip.spec zap.spec Makefile
+lua:   lua.sh primary.xml.gz
+       cp $(srcdir)/lua.sh lua
+
+primary.xml.gz:        zsh.spec zip.spec zap.spec filesystem.spec Makefile
        rm -rf rpmbuild rpms repodata
        mkdir -p rpmbuild/BUILD rpmbuild/RPMS
        rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/zap.spec
        rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/zip.spec
        rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/zsh.spec
+       rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/filesystem.spec
        mkdir rpms
        mv rpmbuild/RPMS/noarch/*.rpm rpms
        rm -rf rpmbuild
@@ -23,6 +30,8 @@ EXTRA_DIST =                  \
        zap.spec                \
        zip.spec                \
        zsh.spec                \
+       filesystem.spec         \
+       lua.sh                  \
        relocate.sh
 
 clean-local :
diff --git a/test/filesystem.spec b/test/filesystem.spec
new file mode 100644 (file)
index 0000000..da53853
--- /dev/null
@@ -0,0 +1,38 @@
+Name:      filesystem
+Summary:   Test package
+Group:     Test
+License:   GPL
+Version:   1
+Release:   1
+BuildArch: noarch
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+
+%description
+Test package
+
+%prep
+
+%build
+
+%install
+mkdir %{buildroot}
+mkdir -p %{buildroot}%{_sysconfdir}
+mkdir -p %{buildroot}/{%{_bindir},%{_libdir},%{_includedir}}
+mkdir -p %{buildroot}/media
+
+%clean
+rm -rf %{buildroot}
+
+%post -p <lua>
+function mkdir_missing(dir)
+    if posix.stat(dir) == nil then
+        posix.mkdir(dir)
+    end
+end
+mkdir_missing("/media/cdrom")
+
+%files
+%defattr(0755,root,root)
+/etc
+%{_prefix}
+%dir /media
diff --git a/test/lua.sh b/test/lua.sh
new file mode 100755 (executable)
index 0000000..2c3a084
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+check_filesystem()
+{
+    if [ ! -e "$RAZOR_ROOT$1" ]; then 
+       echo $1: Not in filesystem >&2
+       exit 1
+    fi
+}
+check_file()
+{
+    ../src/razor list-files | grep -x "$1" > /dev/null
+    if [ $? -ne 0 ]; then
+       echo $1: Not in database >&2
+       exit 1
+    fi
+    check_filesystem "$1"
+}
+export RAZOR_ROOT=`mktemp -dt` || exit 1
+../src/razor init || exit 1
+export YUM_URL="file://localhost/`pwd`"
+../src/razor import-yum || exit 1
+../src/razor install filesystem || exit 1
+check_file /etc
+check_file /usr/bin
+check_file /usr/lib
+check_file /usr/include
+check_filesystem /media/cdrom
+rm -rf "$RAZOR_ROOT"