Add more raw system calls to redbean

We now have execve, setitimer, sigaction, sigsuspend, and sigprocmask.
This commit is contained in:
Justine Tunney 2022-04-13 14:43:42 -07:00
parent 281a0f2730
commit fb7e8ef1e6
8 changed files with 329 additions and 73 deletions

View file

@ -45,7 +45,7 @@ static textwindows inline bool HasWorkingConsole(void) {
*/ */
int raise(int sig) { int raise(int sig) {
int rc, event; int rc, event;
STRACE("raise(%G) → [...]", sig); STRACE("raise(%G) → ...", sig);
if (sig == SIGTRAP) { if (sig == SIGTRAP) {
DebugBreak(); DebugBreak();
rc = 0; rc = 0;
@ -75,6 +75,6 @@ int raise(int sig) {
rc = __sig_raise(sig, SI_USER); rc = __sig_raise(sig, SI_USER);
} }
} }
STRACE("[...] raise(%G) → %d% m", sig, rc); STRACE("...raise(%G) → %d% m", sig, rc);
return rc; return rc;
} }

View file

@ -62,8 +62,6 @@ int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
char buf[2][41]; char buf[2][41];
int res, rc, arg1; int res, rc, arg1;
const sigset_t *arg2; const sigset_t *arg2;
STRACE("sigprocmask(%s, %s, [...]", DescribeHow(howbuf, how),
__strace_sigset(buf[0], sizeof(buf[0]), 0, opt_set));
sigemptyset(&old); sigemptyset(&old);
if (IsAsan() && if (IsAsan() &&
((opt_set && !__asan_is_valid(opt_set, sizeof(*opt_set))) || ((opt_set && !__asan_is_valid(opt_set, sizeof(*opt_set))) ||
@ -94,7 +92,7 @@ int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
if (rc != -1 && opt_out_oldset) { if (rc != -1 && opt_out_oldset) {
*opt_out_oldset = old; *opt_out_oldset = old;
} }
STRACE("[...] sigprocmask(%s, %s, [%s]) → %d% m", DescribeHow(howbuf, how), STRACE("sigprocmask(%s, %s, [%s]) → %d% m", DescribeHow(howbuf, how),
__strace_sigset(buf[0], sizeof(buf[0]), 0, opt_set), __strace_sigset(buf[0], sizeof(buf[0]), 0, opt_set),
__strace_sigset(buf[1], sizeof(buf[1]), rc, opt_out_oldset), rc); __strace_sigset(buf[1], sizeof(buf[1]), rc, opt_out_oldset), rc);
return rc; return rc;

View file

@ -32,6 +32,9 @@
/** /**
* Blocks until SIG MASK is delivered to process. * Blocks until SIG MASK is delivered to process.
* *
* This temporarily replaces the signal mask until a signal that it
* doesn't contain is delivered.
*
* @param ignore is a bitset of signals to block temporarily, which if * @param ignore is a bitset of signals to block temporarily, which if
* NULL is equivalent to passing an empty signal set * NULL is equivalent to passing an empty signal set
* @return -1 w/ EINTR (or possibly EFAULT) * @return -1 w/ EINTR (or possibly EFAULT)
@ -43,8 +46,7 @@ int sigsuspend(const sigset_t *ignore) {
char buf[41]; char buf[41];
long ms, totoms; long ms, totoms;
sigset_t save, mask, *arg; sigset_t save, mask, *arg;
STRACE("sigsuspend(%s) → [...]", STRACE("sigsuspend(%s) → ...", __strace_sigset(buf, sizeof(buf), 0, ignore));
__strace_sigset(buf, sizeof(buf), 0, ignore));
if (IsAsan() && ignore && !__asan_is_valid(ignore, sizeof(*ignore))) { if (IsAsan() && ignore && !__asan_is_valid(ignore, sizeof(*ignore))) {
rc = efault(); rc = efault();
} else if (IsXnu() || IsOpenbsd()) { } else if (IsXnu() || IsOpenbsd()) {
@ -79,7 +81,7 @@ int sigsuspend(const sigset_t *ignore) {
ms += __SIG_POLLING_INTERVAL_MS; ms += __SIG_POLLING_INTERVAL_MS;
if (ms >= __SIG_LOGGING_INTERVAL_MS) { if (ms >= __SIG_LOGGING_INTERVAL_MS) {
totoms += ms, ms = 0; totoms += ms, ms = 0;
STRACE("[...] sigsuspending for %'lums...", totoms); STRACE("... sigsuspending for %'lums...", totoms);
} }
#endif #endif
} while (1); } while (1);
@ -89,6 +91,6 @@ int sigsuspend(const sigset_t *ignore) {
// TODO(jart): sigsuspend metal support // TODO(jart): sigsuspend metal support
rc = enosys(); rc = enosys();
} }
STRACE("[...] sigsuspend → %d% m", rc); STRACE("...sigsuspend → %d% m", rc);
return rc; return rc;
} }

View file

@ -171,11 +171,7 @@ LUA_API lua_Number lua_version (lua_State *L) {
/** /**
* lua_absindex * lua_absindex [-0, +0, ]
*
* [-0, +0, ]
*
* int lua_absindex (lua_State *L, int idx);
* *
* Converts the acceptable index idx into an equivalent absolute index (that * Converts the acceptable index idx into an equivalent absolute index (that
* is, one that does not depend on the stack size). * is, one that does not depend on the stack size).
@ -187,11 +183,7 @@ LUA_API int lua_absindex (lua_State *L, int idx) {
} }
/** /**
* lua_gettop * lua_gettop [-0, +0, ]
*
* [-0, +0, ]
*
* int lua_gettop (lua_State *L);
* *
* Returns the index of the top element in the stack. Because indices start * Returns the index of the top element in the stack. Because indices start
* at 1, this result is equal to the number of elements in the stack; in * at 1, this result is equal to the number of elements in the stack; in
@ -202,11 +194,7 @@ LUA_API int lua_gettop (lua_State *L) {
} }
/** /**
* lua_settop * lua_settop [-?, +?, e]
*
* [-?, +?, e]
*
* void lua_settop (lua_State *L, int index);
* *
* Accepts any index, or 0, and sets the stack top to this index. If the new * Accepts any index, or 0, and sets the stack top to this index. If the new
* top is greater than the old one, then the new elements are filled with * top is greater than the old one, then the new elements are filled with

View file

@ -34,7 +34,8 @@ FLAGS
-b log message bodies -b log message bodies
-a log resource usage -a log resource usage
-g log handler latency -g log handler latency
-e run specified Lua command -e eval Lua code in arg
-F eval Lua code in file
-E show crash reports to public ips -E show crash reports to public ips
-j enable ssl client verify -j enable ssl client verify
-k disable ssl fetch verify -k disable ssl fetch verify
@ -1259,8 +1260,12 @@ UNIX MODULE
There's also a /unix.lua file in redbean-demo.com that provides a There's also a /unix.lua file in redbean-demo.com that provides a
glimpse of how these powerful APIs can be used. Here's a synopsis: glimpse of how these powerful APIs can be used. Here's a synopsis:
unix.fork() → childpid|0, errno
unix.exit([exitcode]) → ⊥ unix.exit([exitcode]) → ⊥
unix.fork() → childpid|0, errno
unix.commandv(prog) → path, errno
unix.execve(prog, argv[, envp]) → errno
prog needs to be absolute, see commandv()
envp defaults to environ
unix.access(path, mode) → rc, errno unix.access(path, mode) → rc, errno
mode can be: R_OK, W_OK, X_OK, F_OK mode can be: R_OK, W_OK, X_OK, F_OK
unix.mkdir(path, mode) → rc, errno unix.mkdir(path, mode) → rc, errno
@ -1335,13 +1340,17 @@ UNIX MODULE
flags MSG_OOB, MSG_DONTROUTE, MSG_NOSIGNAL, etc. flags MSG_OOB, MSG_DONTROUTE, MSG_NOSIGNAL, etc.
unix.shutdown(fd, how) → rc, errno unix.shutdown(fd, how) → rc, errno
how can be SHUT_RD, SHUT_WR, or SHUT_RDWR how can be SHUT_RD, SHUT_WR, or SHUT_RDWR
unix.sigprocmask(how, mask) → oldmask, errno unix.sigprocmask(how[, mask]) → oldmask, errno
how can be SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK how can be SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK
unix.sigaction(sig, handler[, flags[, mask]]) → rc, errno unix.sigaction(sig[, handler[, flags[, mask]]]) → handler, flags, mask, errno
handler can be SIG_IGN, SIG_DFL, intptr_t, or a Lua function
sig can be SIGINT, SIGQUIT, SIGTERM, SIGUSR1, etc. sig can be SIGINT, SIGQUIT, SIGTERM, SIGUSR1, etc.
handler can be SIG_IGN or SIG_DFL for time being unix.sigsuspend([mask]) → errno
note: this api will be changed in the future unix.setitimer(which[, intsec, intmicros, valsec, valmicros])
→ intsec, intns, valsec, valns, errno
which should be ITIMER_REAL
unix.strerror(errno) → str unix.strerror(errno) → str
unix.strsignal(sig) → str
Here's your UnixStat* object. Here's your UnixStat* object.
@ -1354,9 +1363,9 @@ UNIX MODULE
UnixStat:rdev() → int UnixStat:rdev() → int
UnixStat:uid() → int UnixStat:uid() → int
UnixStat:gid() → int UnixStat:gid() → int
UnixStat:atim() → secs:int, nanosint UnixStat:atim() → secs:int, nanos:int
UnixStat:mtim() → secs:int, nanosint UnixStat:mtim() → secs:int, nanos:int
UnixStat:ctim() → secs:int, nanosint UnixStat:ctim() → secs:int, nanos:int
UnixStat:blocks() → int UnixStat:blocks() → int
UnixStat:blksize() → int UnixStat:blksize() → int

22
tool/net/luacheck.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef COSMOPOLITAN_TOOL_NET_LUACHECK_H_
#define COSMOPOLITAN_TOOL_NET_LUACHECK_H_
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lua.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define AssertLuaStackIsEmpty(L) \
do { \
if (lua_gettop(L)) { \
char *s = LuaFormatStack(L); \
WARNF("lua stack should be empty!\n%s", s); \
free(s); \
lua_settop(L, 0); \
} \
} while (0)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_NET_LUACHECK_H_ */

View file

@ -18,16 +18,24 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/dirent.h" #include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/sigset.h" #include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#include "libc/calls/ucontext.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/fmt/kerrornames.internal.h" #include "libc/fmt/kerrornames.internal.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/af.h" #include "libc/sysv/consts/af.h"
@ -37,6 +45,7 @@
#include "libc/sysv/consts/f.h" #include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h" #include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/itimer.h"
#include "libc/sysv/consts/msg.h" #include "libc/sysv/consts/msg.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/ok.h" #include "libc/sysv/consts/ok.h"
@ -50,6 +59,7 @@
#include "third_party/lua/lauxlib.h" #include "third_party/lua/lauxlib.h"
#include "third_party/lua/lua.h" #include "third_party/lua/lua.h"
#include "third_party/lua/luaconf.h" #include "third_party/lua/luaconf.h"
#include "tool/net/luacheck.h"
/** /**
* @fileoverview UNIX system calls thinly wrapped for Lua * @fileoverview UNIX system calls thinly wrapped for Lua
@ -66,6 +76,8 @@ struct UnixDir {
DIR *dir; DIR *dir;
}; };
static lua_State *GL;
static void LuaSetIntField(lua_State *L, const char *k, lua_Integer v) { static void LuaSetIntField(lua_State *L, const char *k, lua_Integer v) {
lua_pushinteger(L, v); lua_pushinteger(L, v);
lua_setfield(L, -2, k); lua_setfield(L, -2, k);
@ -90,6 +102,32 @@ static int ReturnRc(lua_State *L, int64_t rc, int olderr) {
return 2; return 2;
} }
static char **ConvertLuaArrayToStringList(lua_State *L, int i) {
int j, n;
char **p;
luaL_checktype(L, i, LUA_TTABLE);
lua_len(L, i);
n = lua_tointeger(L, -1);
lua_pop(L, 1);
p = xcalloc(n + 1, sizeof(*p));
for (j = 1; j <= n; ++j) {
lua_geti(L, i, j);
p[j - 1] = strdup(lua_tostring(L, -1));
lua_pop(L, 1);
}
return p;
}
static void FreeStringList(char **p) {
int i;
if (p) {
for (i = 0; p[i]; ++i) {
free(p[i]);
}
free(p);
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// System Calls // System Calls
@ -227,6 +265,58 @@ static int LuaUnixFork(lua_State *L) {
return ReturnRc(L, rc, olderr); return ReturnRc(L, rc, olderr);
} }
// unix.execve(prog, argv[, envp]) → errno
// unix.exit(127)
//
// unix = require "unix"
// prog = unix.commandv("ls")
// unix.execve(prog, {prog, "-hal", "."})
// unix.exit(127)
//
// prog needs to be absolute, see commandv()
// envp defaults to environ
static int LuaUnixExecve(lua_State *L) {
int olderr;
const char *prog;
char **argv, **envp, **freeme;
olderr = errno;
prog = luaL_checkstring(L, 1);
argv = ConvertLuaArrayToStringList(L, 2);
if (!lua_isnoneornil(L, 3)) {
envp = ConvertLuaArrayToStringList(L, 3);
freeme = envp;
} else {
envp = environ;
freeme = 0;
}
execve(prog, argv, envp);
FreeStringList(freeme);
FreeStringList(argv);
lua_pushinteger(L, errno);
errno = olderr;
return 1;
}
// unix.commandv(prog) → path, errno
static int LuaUnixCommandv(lua_State *L) {
int olderr;
const char *prog;
char *pathbuf, *resolved;
olderr = errno;
pathbuf = xmalloc(PATH_MAX);
prog = luaL_checkstring(L, 1);
if ((resolved = commandv(prog, pathbuf))) {
lua_pushstring(L, resolved);
lua_pushnil(L);
} else {
lua_pushnil(L);
lua_pushinteger(L, errno);
errno = olderr;
}
free(pathbuf);
return 2;
}
// unix.getpid() → pid // unix.getpid() → pid
static int LuaUnixGetpid(lua_State *L) { static int LuaUnixGetpid(lua_State *L) {
lua_pushinteger(L, getpid()); lua_pushinteger(L, getpid());
@ -843,21 +933,27 @@ static int LuaUnixShutdown(lua_State *L) {
return ReturnRc(L, rc, olderr); return ReturnRc(L, rc, olderr);
} }
// unix.sigprocmask(how, mask) → oldmask, errno // unix.sigprocmask(how[, mask]) → oldmask, errno
// how can be SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK // how can be SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK
static int LuaUnixSigprocmask(lua_State *L) { static int LuaUnixSigprocmask(lua_State *L) {
uint64_t imask; uint64_t imask;
int how, olderr; int how, olderr;
sigset_t mask, oldmask; sigset_t mask, oldmask, *maskptr;
olderr = errno; olderr = errno;
how = luaL_checkinteger(L, 1); how = luaL_checkinteger(L, 1);
if (lua_isnoneornil(L, 2)) {
// if mask isn't passed then we're querying
maskptr = 0;
} else {
maskptr = &mask;
imask = luaL_checkinteger(L, 2); imask = luaL_checkinteger(L, 2);
bzero(&mask, sizeof(mask)); bzero(&mask, sizeof(mask));
if (how == SIG_SETMASK) { if (how == SIG_SETMASK) {
sigprocmask(how, 0, &mask); sigprocmask(how, 0, &mask);
} }
mask.__bits[0] = imask; mask.__bits[0] = imask;
if (!sigprocmask(how, &mask, &oldmask)) { }
if (!sigprocmask(how, maskptr, &oldmask)) {
lua_pushinteger(L, oldmask.__bits[0]); lua_pushinteger(L, oldmask.__bits[0]);
return 1; return 1;
} else { } else {
@ -868,32 +964,99 @@ static int LuaUnixSigprocmask(lua_State *L) {
} }
} }
// unix.sigaction(sig, handler[, flags[, mask]]) → rc, errno static void LuaUnixOnSignal(int sig, siginfo_t *si, ucontext_t *ctx) {
STRACE("LuaUnixOnSignal(%G)", sig);
lua_getglobal(GL, "__signal_handlers");
CHECK_EQ(LUA_TFUNCTION, lua_geti(GL, -1, sig));
lua_remove(GL, -2);
lua_pushinteger(GL, sig);
if (lua_pcall(GL, 1, 0, 0) != LUA_OK) {
ERRORF("(lua) %s failed: %s", strsignal(sig), lua_tostring(GL, -1));
lua_pop(GL, 1); // pop error
}
}
// unix.sigaction(sig[, handler[, flags[, mask]]]) → handler, flags, mask, errno
//
// unix = require "unix"
// unix.sigaction(unix.SIGUSR1, function(sig)
// print(string.format("got %s", unix.strsignal(sig)))
// end)
// unix.sigprocmask(unix.SIG_SETMASK, -1)
// unix.raise(unix.SIGUSR1)
// unix.sigsuspend()
//
// handler can be SIG_IGN, SIG_DFL, intptr_t, or a Lua function
// sig can be SIGINT, SIGQUIT, SIGTERM, SIGUSR1, etc. // sig can be SIGINT, SIGQUIT, SIGTERM, SIGUSR1, etc.
// handler can be SIG_IGN or SIG_DFL for time being
// note: this api will be changed in the future
static int LuaUnixSigaction(lua_State *L) { static int LuaUnixSigaction(lua_State *L) {
void *handler; int i, n, sig, olderr;
int sig, olderr; struct sigaction sa, oldsa, *saptr;
struct sigaction sa; saptr = &sa;
uint64_t flags, imask;
olderr = errno; olderr = errno;
sigemptyset(&sa.sa_mask);
sig = luaL_checkinteger(L, 1); sig = luaL_checkinteger(L, 1);
handler = (void *)luaL_checkinteger(L, 2); if (!(1 <= sig && sig <= NSIG)) {
flags = luaL_optinteger(L, 3, SA_RESTART); luaL_argerror(L, 1, "signal number invalid");
imask = luaL_optinteger(L, 4, 0);
if (handler != SIG_DFL && handler != SIG_IGN) {
luaL_argerror(L, 2, "handler not SIG_DFL or SIG_IGN");
unreachable; unreachable;
} }
sa.sa_handler = handler; if (lua_isnoneornil(L, 2)) {
sa.sa_flags = flags; // if handler/flags/mask aren't passed,
sa.sa_mask.__bits[0] = imask; // then we're quering the current state
sa.sa_mask.__bits[1] = 0; saptr = 0;
if (!sigaction(sig, &sa, 0)) { } else if (lua_isinteger(L, 2)) {
lua_pushinteger(L, 0); // bypass handling signals using lua code if possible
return 1; sa.sa_sigaction = (void *)luaL_checkinteger(L, 2);
} else if (lua_isfunction(L, 2)) {
sa.sa_sigaction = LuaUnixOnSignal;
// lua probably isn't async signal safe, so...
// let's mask all the lua handlers during handling
sigaddset(&sa.sa_mask, sig);
lua_getglobal(L, "__signal_handlers");
luaL_checktype(L, -1, LUA_TTABLE);
lua_len(L, -1);
n = lua_tointeger(L, -1);
lua_pop(L, 1);
for (i = 1; i <= MIN(n, NSIG); ++i) {
if (lua_geti(L, -1, i) == LUA_TFUNCTION) {
sigaddset(&sa.sa_mask, i);
}
lua_pop(L, 1);
}
lua_pop(L, 1);
} else { } else {
luaL_argerror(L, 2, "sigaction handler not integer or function");
unreachable;
}
sa.sa_flags = luaL_optinteger(L, 3, SA_RESTART);
sa.sa_mask.__bits[0] |= luaL_optinteger(L, 4, 0);
if (!sigaction(sig, saptr, &oldsa)) {
lua_getglobal(L, "__signal_handlers");
// push the old handler result to stack. if the global lua handler
// table has a real function, then we prefer to return that. if it's
// absent or a raw integer value, then we're better off returning
// what the kernel gave us in &oldsa.
if (lua_geti(L, -1, sig) != LUA_TFUNCTION) {
lua_pop(L, 1);
lua_pushinteger(L, (intptr_t)oldsa.sa_handler);
}
if (saptr) {
// update the global lua table
if (sa.sa_sigaction == LuaUnixOnSignal) {
lua_pushvalue(L, -3);
} else {
lua_pushnil(L);
}
lua_seti(L, -3, sig);
}
// remove the signal handler table from stack
lua_remove(L, -2);
// finish pushing the last 2/3 results
lua_pushinteger(L, oldsa.sa_flags);
lua_pushinteger(L, oldsa.sa_mask.__bits[0]);
return 3;
} else {
lua_pushnil(L);
lua_pushnil(L);
lua_pushnil(L); lua_pushnil(L);
lua_pushinteger(L, errno); lua_pushinteger(L, errno);
errno = olderr; errno = olderr;
@ -901,12 +1064,76 @@ static int LuaUnixSigaction(lua_State *L) {
} }
} }
// unix.sigsuspend([mask]) → errno
static int LuaUnixSigsuspend(lua_State *L) {
int olderr;
sigset_t mask;
olderr = errno;
mask.__bits[0] = luaL_optinteger(L, 1, 0);
mask.__bits[1] = 0;
sigsuspend(&mask);
lua_pushinteger(L, errno);
errno = olderr;
return 1;
}
// unix.setitimer(which[, intsec, intmicros, valsec, valmicros])
// → intsec, intns, valsec, valns, errno
//
// ticks = 0
// unix.sigaction(unix.SIGALRM, function(sig)
// print(string.format("tick no. %d", ticks))
// ticks = ticks + 1
// end)
// unix.setitimer(unix.ITIMER_REAL, 0, 400000, 0, 400000)
// while true do
// unix.sigsuspend()
// end
//
// which should be ITIMER_REAL
static int LuaUnixSetitimer(lua_State *L) {
int which, olderr;
struct itimerval it, oldit, *itptr;
olderr = errno;
which = luaL_checkinteger(L, 1);
if (!lua_isnoneornil(L, 2)) {
itptr = &it;
it.it_interval.tv_sec = luaL_optinteger(L, 2, 0);
it.it_interval.tv_usec = luaL_optinteger(L, 3, 0);
it.it_value.tv_sec = luaL_optinteger(L, 4, 0);
it.it_value.tv_usec = luaL_optinteger(L, 5, 0);
} else {
itptr = 0;
}
if (!setitimer(which, itptr, &oldit)) {
lua_pushinteger(L, oldit.it_interval.tv_sec);
lua_pushinteger(L, oldit.it_interval.tv_usec);
lua_pushinteger(L, oldit.it_value.tv_sec);
lua_pushinteger(L, oldit.it_value.tv_usec);
return 4;
} else {
lua_pushnil(L);
lua_pushnil(L);
lua_pushnil(L);
lua_pushnil(L);
lua_pushinteger(L, errno);
errno = olderr;
return 5;
}
}
// unix.strerror(errno) → str // unix.strerror(errno) → str
static int LuaUnixStrerror(lua_State *L) { static int LuaUnixStrerror(lua_State *L) {
lua_pushstring(L, strerror(luaL_checkinteger(L, 1))); lua_pushstring(L, strerror(luaL_checkinteger(L, 1)));
return 1; return 1;
} }
// unix.strsignal(sig) → str
static int LuaUnixStrsignal(lua_State *L) {
lua_pushstring(L, strsignal(luaL_checkinteger(L, 1)));
return 1;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// UnixStat* object // UnixStat* object
@ -1139,6 +1366,8 @@ static const luaL_Reg kLuaUnix[] = {
{"chmod", LuaUnixChmod}, // change mode of file {"chmod", LuaUnixChmod}, // change mode of file
{"getcwd", LuaUnixGetcwd}, // get current directory {"getcwd", LuaUnixGetcwd}, // get current directory
{"fork", LuaUnixFork}, // make child process via mitosis {"fork", LuaUnixFork}, // make child process via mitosis
{"execve", LuaUnixExecve}, // replace process with program
{"commandv", LuaUnixCommandv}, // resolve program on $PATH
{"kill", LuaUnixKill}, // signal child process {"kill", LuaUnixKill}, // signal child process
{"raise", LuaUnixRaise}, // signal this process {"raise", LuaUnixRaise}, // signal this process
{"wait", LuaUnixWait}, // wait for child to change status {"wait", LuaUnixWait}, // wait for child to change status
@ -1179,7 +1408,10 @@ static const luaL_Reg kLuaUnix[] = {
{"getsockname", LuaUnixGetsockname}, // get address of local end {"getsockname", LuaUnixGetsockname}, // get address of local end
{"sigaction", LuaUnixSigaction}, // install signal handler {"sigaction", LuaUnixSigaction}, // install signal handler
{"sigprocmask", LuaUnixSigprocmask}, // change signal mask {"sigprocmask", LuaUnixSigprocmask}, // change signal mask
{"sigsuspend", LuaUnixSigsuspend}, // wait for signal
{"setitimer", LuaUnixSetitimer}, // set alarm clock
{"strerror", LuaUnixStrerror}, // turn errno into string {"strerror", LuaUnixStrerror}, // turn errno into string
{"strsignal", LuaUnixStrsignal}, // turn signal into string
{0}, // {0}, //
}; };
@ -1187,9 +1419,12 @@ int LuaUnix(lua_State *L) {
int i; int i;
char sigbuf[12]; char sigbuf[12];
GL = L;
luaL_newlib(L, kLuaUnix); luaL_newlib(L, kLuaUnix);
LuaUnixStatObj(L); LuaUnixStatObj(L);
LuaUnixDirObj(L); LuaUnixDirObj(L);
lua_newtable(L);
lua_setglobal(L, "__signal_handlers");
// errnos // errnos
for (i = 0; kErrorNames[i].x; ++i) { for (i = 0; kErrorNames[i].x; ++i) {
@ -1322,5 +1557,10 @@ int LuaUnix(lua_State *L) {
LuaSetIntField(L, "SIG_DFL", (intptr_t)SIG_DFL); LuaSetIntField(L, "SIG_DFL", (intptr_t)SIG_DFL);
LuaSetIntField(L, "SIG_IGN", (intptr_t)SIG_IGN); LuaSetIntField(L, "SIG_IGN", (intptr_t)SIG_IGN);
// setitimer() which
LuaSetIntField(L, "ITIMER_REAL", ITIMER_REAL); // portable
LuaSetIntField(L, "ITIMER_PROF", ITIMER_PROF);
LuaSetIntField(L, "ITIMER_VIRTUAL", ITIMER_VIRTUAL);
return 1; return 1;
} }

View file

@ -132,6 +132,7 @@
#include "third_party/zlib/zlib.h" #include "third_party/zlib/zlib.h"
#include "tool/build/lib/case.h" #include "tool/build/lib/case.h"
#include "tool/build/lib/psk.h" #include "tool/build/lib/psk.h"
#include "tool/net/luacheck.h"
STATIC_STACK_SIZE(0x40000); STATIC_STACK_SIZE(0x40000);
STATIC_YOINK("zip_uri_support"); STATIC_YOINK("zip_uri_support");
@ -173,16 +174,6 @@ STATIC_YOINK("zip_uri_support");
#define HeaderEqualCase(H, S) \ #define HeaderEqualCase(H, S) \
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H)) SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
#define AssertLuaStackIsEmpty(L) \
do { \
if (lua_gettop(L)) { \
char *s = LuaFormatStack(L); \
WARNF("lua stack should be empty!\n%s", s); \
free(s); \
lua_settop(L, 0); \
} \
} while (0)
static const uint8_t kGzipHeader[] = { static const uint8_t kGzipHeader[] = {
0x1F, // MAGNUM 0x1F, // MAGNUM
0x8B, // MAGNUM 0x8B, // MAGNUM
@ -397,7 +388,8 @@ static uint32_t clientaddrsize;
static size_t zsize; static size_t zsize;
static char *outbuf; static char *outbuf;
static lua_State *GL, *YL; static lua_State *GL;
static lua_State *YL;
static char *content; static char *content;
static uint8_t *zmap; static uint8_t *zmap;
static uint8_t *zbase; static uint8_t *zbase;
@ -1041,7 +1033,7 @@ static void LogLuaError(char *hook, char *err) {
ERRORF("(lua) failed to run %s: %s", hook, err); ERRORF("(lua) failed to run %s: %s", hook, err);
} }
static bool LuaRunCode(const char *code) { static bool LuaEvalCode(const char *code) {
lua_State *L = GL; lua_State *L = GL;
int status = luaL_loadstring(L, code); int status = luaL_loadstring(L, code);
if (status != LUA_OK || LuaCallWithTrace(L, 0, 0, NULL) != LUA_OK) { if (status != LUA_OK || LuaCallWithTrace(L, 0, 0, NULL) != LUA_OK) {
@ -1053,6 +1045,10 @@ static bool LuaRunCode(const char *code) {
return true; return true;
} }
static bool LuaEvalFile(const char *path) {
return LuaEvalCode(gc(xslurp(path, 0)));
}
static bool LuaOnClientConnection(void) { static bool LuaOnClientConnection(void) {
#ifndef STATIC #ifndef STATIC
bool dropit; bool dropit;
@ -6979,7 +6975,8 @@ static void GetOpts(int argc, char *argv[]) {
CASE('h', PrintUsage(stdout, EXIT_SUCCESS)); CASE('h', PrintUsage(stdout, EXIT_SUCCESS));
CASE('M', ProgramMaxPayloadSize(ParseInt(optarg))); CASE('M', ProgramMaxPayloadSize(ParseInt(optarg)));
#ifndef STATIC #ifndef STATIC
CASE('e', LuaRunCode(optarg)); CASE('e', LuaEvalCode(optarg));
CASE('F', LuaEvalFile(optarg));
CASE('E', leakcrashreports = true); CASE('E', leakcrashreports = true);
CASE('A', storeasset = true; StorePath(optarg)); CASE('A', storeasset = true; StorePath(optarg));
#endif #endif