Commit d6ccca99 authored by Michal 'vorner' Vaner's avatar Michal 'vorner' Vaner

lua: Wrapper for mkdtemp

We'll need several temporary directories during the installation.
parent 11077b6a
......@@ -29,6 +29,7 @@
#include <stdbool.h>
#include <stdarg.h>
#include <inttypes.h>
#include <errno.h>
// The name used in lua registry to store stuff
#define REGISTRY_NAME "libupdater"
......@@ -285,6 +286,25 @@ static int lua_events_wait(lua_State *L) {
return 0;
}
static int lua_mkdtemp(lua_State *L) {
int param_count = lua_gettop(L);
if (param_count > 1)
return luaL_error(L, "Too many parameters to mkdtemp: %d", param_count);
const char *base_dir = "/tmp";
if (param_count)
base_dir = luaL_checkstring(L, 1);
char *template = aprintf("%s/updater-XXXXXX", base_dir);
char *result = mkdtemp(template);
if (result) {
lua_pushstring(L, result);
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, strerror(errno));
return 2;
}
}
struct injected_func {
int (*func)(lua_State *);
const char *name;
......@@ -292,9 +312,9 @@ struct injected_func {
static const struct injected_func injected_funcs[] = {
{ lua_log, "log" },
// TODO: Document that thing
{ lua_run_command, "run_command" },
{ lua_events_wait, "events_wait" }
{ lua_events_wait, "events_wait" },
{ lua_mkdtemp, "mkdtemp" }
/*
* Note: watch_cancel is not provided, because it would be hell to
* manage the dynamically allocated memory correctly and there doesn't
......
......@@ -75,3 +75,12 @@ the command.
Currently, there's no way to cancel running command from lua, since
that would make the wrapper code needlessly complex (while there seems
to be no need to cancel them currently).
Filesystem manipulation
-----------------------
mkdtemp([directory])::
It creates a temporary directory. If directory is provided, it is
created as a subdirectory of the given directory, otherwise it is
created inside `/tmp`. It returns path to the new directory, or
`nil` and an error message.
......@@ -56,3 +56,19 @@ enum log_level log_level_get(const char *level) {
}
return LL_UNKNOWN;
}
size_t printf_len(const char *msg, ...) {
va_list args;
va_start(args, msg);
size_t result = vsnprintf(NULL, 0, msg, args);
va_end(args);
return result + 1;
}
char *printf_into(char *dst, const char *msg, ...) {
va_list args;
va_start(args, msg);
vsprintf(dst, msg, args);
va_end(args);
return dst;
}
......@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <stdbool.h>
#include <alloca.h>
enum log_level {
LL_DIE,
......@@ -45,4 +46,11 @@ enum log_level log_level_get(const char *str) __attribute__((nonnull));
extern bool updater_logging_enabled;
// Compute the size needed (including \0) to format given message
size_t printf_len(const char *msg, ...) __attribute__((format(printf, 1, 2)));
// Like sprintf, but returs the string. Expects there's enough space.
char *printf_into(char *dst, const char *msg, ...) __attribute__((format(printf, 2, 3)));
// Like printf, but allocates the data on the stack with alloca and returns. It uses the arguments multiple times, so beware of side effects.
#define aprintf(...) printf_into(alloca(printf_len(__VA_ARGS__)), __VA_ARGS__)
#endif
......@@ -22,6 +22,10 @@
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
struct loading_case {
// Just a name of the test
......@@ -195,6 +199,41 @@ START_INTERPRETER_TEST(call_echo)
ck_assert_str_eq(s, "hello");
END_INTERPRETER_TEST
static void check_mkdtemp(struct interpreter *interpreter, const char *error, size_t results) {
ck_assert_msg(!error, "Failed to run the mkdtemp function: %s", error);
ck_assert_uint_eq(1, results);
char *dname;
ck_assert_int_eq(-1, interpreter_collect_results(interpreter, "s", &dname));
DIR *d = opendir(dname);
ck_assert_msg(d, "Failed to open the temp directory: %s", strerror(errno));
closedir(d);
ck_assert_int_eq(rmdir(dname), 0);
const char *prefix = "/tmp/updater-";
ck_assert(strncmp("/tmp/updater-", dname, strlen(prefix)) == 0);
}
START_INTERPRETER_TEST(test_mkdtemp) {
/*
* Test the mkdtemp function acts sane in lua.
*/
size_t results;
// Try it with default directory
const char *error = interpreter_call(interpreter, "mkdtemp", &results, "");
check_mkdtemp(interpreter, error, results);
mark_point();
// Try explicitly specifying the /tmp directory and see it doesn't vomit
error = interpreter_call(interpreter, "mkdtemp", &results, "s", "/tmp");
check_mkdtemp(interpreter, error, results);
mark_point();
// This should fail, but softly
error = interpreter_call(interpreter, "mkdtemp", &results, "s", "/dir/does/not/exist");
ck_assert_msg(!error, "Failed to run the mkdtemp function: %s", error);
ck_assert_uint_eq(2, results);
char *e;
ck_assert_int_eq(-1, interpreter_collect_results(interpreter, "ns", &e));
}
END_INTERPRETER_TEST
Suite *gen_test_suite(void) {
Suite *result = suite_create("Lua interpreter");
TCase *interpreter = tcase_create("loading");
......@@ -204,6 +243,7 @@ Suite *gen_test_suite(void) {
tcase_add_test(interpreter, call_noparams);
tcase_add_test(interpreter, call_method);
tcase_add_test(interpreter, call_echo);
tcase_add_test(interpreter, test_mkdtemp);
suite_add_tcase(result, interpreter);
return result;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment