aboutsummaryrefslogtreecommitdiff
path: root/src/lua_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lua_state.c')
-rw-r--r--src/lua_state.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/lua_state.c b/src/lua_state.c
new file mode 100644
index 0000000..7e9dd18
--- /dev/null
+++ b/src/lua_state.c
@@ -0,0 +1,146 @@
+#include <lua.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "lua_state.h"
+#include "state.h"
+#include "str.h"
+
+lua_State *L = NULL;
+bool L_is_loaded = false;
+
+static void lua_path_push(const char *new_path) {
+ lua_getglobal(L, "package");
+ lua_getfield(L, -1, "path");
+
+ const char *current_path = lua_tostring(L, -1);
+ if (!current_path)
+ current_path = "";
+ lua_pop(L, 1);
+
+ lua_pushfstring(L, "%s;%s", current_path, new_path);
+ lua_setfield(L, -2, "path");
+
+ lua_pop(L, 1);
+}
+
+bool init_lua_state(void) {
+ if (L_is_loaded)
+ return true;
+
+ L = luaL_newstate();
+ luaL_openlibs(L);
+
+ str lua_path = str_format("%.*s/?.lua", str_fmt(&config.dir));
+ lua_path_push(lua_path.data);
+
+ if (luaL_loadfile(L, config.init_path.data) || lua_pcall(L, 0, 1, 0)) {
+ log_error("cannot run configuration script: %s", lua_tostring(L, -1));
+ log_pkgit("to generate a configuration file, head into the");
+ log_pkgit(
+ "root directory of the pkgit source and run `make defconfig`");
+ lua_close(L);
+ return false;
+ }
+
+ if (!lua_istable(L, -1)) {
+ log_error("top-level configuration is not a table");
+ lua_pop(L, 1);
+ lua_close(L);
+ return false;
+ }
+
+ str_free(&lua_path);
+ L_is_loaded = true;
+ return true;
+}
+
+static void setup_base_dirs(void) {
+ int uid = getuid(), euid = geteuid();
+
+ config.is_root = false;
+
+ if (uid < 0 || uid != euid) {
+ config.is_root = true;
+ config.dir = mstr("/etc/pkgit");
+ } else {
+ char *tmp = getenv("XDG_CONFIG_HOME");
+ if (tmp) {
+ config.dir = str_format("%s/pkgit", tmp);
+ } else {
+ config.dir = str_format("%s/.config/pkgit", getenv("HOME"));
+ }
+ }
+
+ config.init_path = str_concat_cstr(&config.dir, "/init.lua");
+ config.autogenerated_path =
+ str_concat_cstr(&config.dir, "/autogenerated.lua");
+}
+
+#define HANDLE_LUA_ERROR \
+ do { \
+ log_error("lua: %s", lua_tostring(L, -1)); \
+ lua_pop(L, 1); \
+ return false; \
+ } while (0)
+
+#define lua_get_field_type(name, type, file) \
+ do { \
+ lua_getfield(L, -1, name); \
+ if (!lua_is##type(L, -1)) { \
+ log_error("lua: expected type " #type " for " name " in %.*s", \
+ str_fmt(file)); \
+ lua_pop(L, 1); \
+ return false; \
+ } \
+ } while (0)
+
+static bool load_init_lua(void) {
+ if (luaL_loadfile(L, config.init_path.data))
+ HANDLE_LUA_ERROR;
+
+ lua_setglobal(L, "__PkgitUserConfig");
+
+ lua_getglobal(L, "__PkgitUserConfig");
+ lua_get_field_type("dirs", table, &config.init_path);
+
+#define X(field) \
+ do { \
+ lua_get_field_type(#field, string, &config.init_path); \
+ config.inst_dirs.field = str_adopt((char *)lua_tostring(L, -1)); \
+ lua_pop(L, -1); \
+ } while (0)
+
+ X(prefix);
+ X(bin);
+ X(include);
+ X(lib);
+ X(src);
+
+#undef X
+
+ lua_getfield(L, -1, "prefix");
+
+ return true;
+}
+
+bool init_lua_config(void) {
+ if (!init_lua_state())
+ return false;
+
+ setup_base_dirs();
+
+ if (!load_init_lua())
+ return false;
+
+ return true;
+}
+
+void free_lua_state(void) {
+ if (L != NULL) {
+ lua_close(L);
+ L = NULL;
+ }
+ L_is_loaded = false;
+}