mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Add more raw system calls to redbean
We now have execve, setitimer, sigaction, sigsuspend, and sigprocmask.
This commit is contained in:
parent
281a0f2730
commit
fb7e8ef1e6
8 changed files with 329 additions and 73 deletions
|
@ -45,7 +45,7 @@ static textwindows inline bool HasWorkingConsole(void) {
|
|||
*/
|
||||
int raise(int sig) {
|
||||
int rc, event;
|
||||
STRACE("raise(%G) → [...]", sig);
|
||||
STRACE("raise(%G) → ...", sig);
|
||||
if (sig == SIGTRAP) {
|
||||
DebugBreak();
|
||||
rc = 0;
|
||||
|
@ -75,6 +75,6 @@ int raise(int sig) {
|
|||
rc = __sig_raise(sig, SI_USER);
|
||||
}
|
||||
}
|
||||
STRACE("[...] raise(%G) → %d% m", sig, rc);
|
||||
STRACE("...raise(%G) → %d% m", sig, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -62,8 +62,6 @@ int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
|
|||
char buf[2][41];
|
||||
int res, rc, arg1;
|
||||
const sigset_t *arg2;
|
||||
STRACE("sigprocmask(%s, %s, [...]", DescribeHow(howbuf, how),
|
||||
__strace_sigset(buf[0], sizeof(buf[0]), 0, opt_set));
|
||||
sigemptyset(&old);
|
||||
if (IsAsan() &&
|
||||
((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) {
|
||||
*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[1], sizeof(buf[1]), rc, opt_out_oldset), rc);
|
||||
return rc;
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
/**
|
||||
* 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
|
||||
* NULL is equivalent to passing an empty signal set
|
||||
* @return -1 w/ EINTR (or possibly EFAULT)
|
||||
|
@ -43,8 +46,7 @@ int sigsuspend(const sigset_t *ignore) {
|
|||
char buf[41];
|
||||
long ms, totoms;
|
||||
sigset_t save, mask, *arg;
|
||||
STRACE("sigsuspend(%s) → [...]",
|
||||
__strace_sigset(buf, sizeof(buf), 0, ignore));
|
||||
STRACE("sigsuspend(%s) → ...", __strace_sigset(buf, sizeof(buf), 0, ignore));
|
||||
if (IsAsan() && ignore && !__asan_is_valid(ignore, sizeof(*ignore))) {
|
||||
rc = efault();
|
||||
} else if (IsXnu() || IsOpenbsd()) {
|
||||
|
@ -79,7 +81,7 @@ int sigsuspend(const sigset_t *ignore) {
|
|||
ms += __SIG_POLLING_INTERVAL_MS;
|
||||
if (ms >= __SIG_LOGGING_INTERVAL_MS) {
|
||||
totoms += ms, ms = 0;
|
||||
STRACE("[...] sigsuspending for %'lums...", totoms);
|
||||
STRACE("... sigsuspending for %'lums...", totoms);
|
||||
}
|
||||
#endif
|
||||
} while (1);
|
||||
|
@ -89,6 +91,6 @@ int sigsuspend(const sigset_t *ignore) {
|
|||
// TODO(jart): sigsuspend metal support
|
||||
rc = enosys();
|
||||
}
|
||||
STRACE("[...] sigsuspend → %d% m", rc);
|
||||
STRACE("...sigsuspend → %d% m", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
18
third_party/lua/lapi.c
vendored
18
third_party/lua/lapi.c
vendored
|
@ -171,11 +171,7 @@ LUA_API lua_Number lua_version (lua_State *L) {
|
|||
|
||||
|
||||
/**
|
||||
* lua_absindex
|
||||
*
|
||||
* [-0, +0, –]
|
||||
*
|
||||
* int lua_absindex (lua_State *L, int idx);
|
||||
* lua_absindex [-0, +0, –]
|
||||
*
|
||||
* Converts the acceptable index idx into an equivalent absolute index (that
|
||||
* 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
|
||||
*
|
||||
* [-0, +0, –]
|
||||
*
|
||||
* int lua_gettop (lua_State *L);
|
||||
* lua_gettop [-0, +0, –]
|
||||
*
|
||||
* 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
|
||||
|
@ -202,11 +194,7 @@ LUA_API int lua_gettop (lua_State *L) {
|
|||
}
|
||||
|
||||
/**
|
||||
* lua_settop
|
||||
*
|
||||
* [-?, +?, e]
|
||||
*
|
||||
* void lua_settop (lua_State *L, int index);
|
||||
* lua_settop [-?, +?, e]
|
||||
*
|
||||
* 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
|
||||
|
|
|
@ -34,7 +34,8 @@ FLAGS
|
|||
-b log message bodies
|
||||
-a log resource usage
|
||||
-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
|
||||
-j enable ssl client 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
|
||||
glimpse of how these powerful APIs can be used. Here's a synopsis:
|
||||
|
||||
unix.fork() → childpid|0, errno
|
||||
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
|
||||
mode can be: R_OK, W_OK, X_OK, F_OK
|
||||
unix.mkdir(path, mode) → rc, errno
|
||||
|
@ -1335,13 +1340,17 @@ UNIX MODULE
|
|||
flags MSG_OOB, MSG_DONTROUTE, MSG_NOSIGNAL, etc.
|
||||
unix.shutdown(fd, how) → rc, errno
|
||||
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
|
||||
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.
|
||||
handler can be SIG_IGN or SIG_DFL for time being
|
||||
note: this api will be changed in the future
|
||||
unix.sigsuspend([mask]) → errno
|
||||
unix.setitimer(which[, intsec, intmicros, valsec, valmicros])
|
||||
→ intsec, intns, valsec, valns, errno
|
||||
which should be ITIMER_REAL
|
||||
unix.strerror(errno) → str
|
||||
unix.strsignal(sig) → str
|
||||
|
||||
Here's your UnixStat* object.
|
||||
|
||||
|
@ -1354,9 +1363,9 @@ UNIX MODULE
|
|||
UnixStat:rdev() → int
|
||||
UnixStat:uid() → int
|
||||
UnixStat:gid() → int
|
||||
UnixStat:atim() → secs:int, nanosint
|
||||
UnixStat:mtim() → secs:int, nanosint
|
||||
UnixStat:ctim() → secs:int, nanosint
|
||||
UnixStat:atim() → secs:int, nanos:int
|
||||
UnixStat:mtim() → secs:int, nanos:int
|
||||
UnixStat:ctim() → secs:int, nanos:int
|
||||
UnixStat:blocks() → int
|
||||
UnixStat:blksize() → int
|
||||
|
||||
|
|
22
tool/net/luacheck.h
Normal file
22
tool/net/luacheck.h
Normal 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_ */
|
294
tool/net/lunix.c
294
tool/net/lunix.c
|
@ -18,16 +18,24 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.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/itimerval.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/kerrornames.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
|
@ -37,6 +45,7 @@
|
|||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
#include "libc/sysv/consts/msg.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
|
@ -50,6 +59,7 @@
|
|||
#include "third_party/lua/lauxlib.h"
|
||||
#include "third_party/lua/lua.h"
|
||||
#include "third_party/lua/luaconf.h"
|
||||
#include "tool/net/luacheck.h"
|
||||
|
||||
/**
|
||||
* @fileoverview UNIX system calls thinly wrapped for Lua
|
||||
|
@ -66,6 +76,8 @@ struct UnixDir {
|
|||
DIR *dir;
|
||||
};
|
||||
|
||||
static lua_State *GL;
|
||||
|
||||
static void LuaSetIntField(lua_State *L, const char *k, lua_Integer v) {
|
||||
lua_pushinteger(L, v);
|
||||
lua_setfield(L, -2, k);
|
||||
|
@ -90,6 +102,32 @@ static int ReturnRc(lua_State *L, int64_t rc, int olderr) {
|
|||
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
|
||||
|
||||
|
@ -227,6 +265,58 @@ static int LuaUnixFork(lua_State *L) {
|
|||
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
|
||||
static int LuaUnixGetpid(lua_State *L) {
|
||||
lua_pushinteger(L, getpid());
|
||||
|
@ -843,21 +933,27 @@ static int LuaUnixShutdown(lua_State *L) {
|
|||
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
|
||||
static int LuaUnixSigprocmask(lua_State *L) {
|
||||
uint64_t imask;
|
||||
int how, olderr;
|
||||
sigset_t mask, oldmask;
|
||||
sigset_t mask, oldmask, *maskptr;
|
||||
olderr = errno;
|
||||
how = luaL_checkinteger(L, 1);
|
||||
imask = luaL_checkinteger(L, 2);
|
||||
bzero(&mask, sizeof(mask));
|
||||
if (how == SIG_SETMASK) {
|
||||
sigprocmask(how, 0, &mask);
|
||||
if (lua_isnoneornil(L, 2)) {
|
||||
// if mask isn't passed then we're querying
|
||||
maskptr = 0;
|
||||
} else {
|
||||
maskptr = &mask;
|
||||
imask = luaL_checkinteger(L, 2);
|
||||
bzero(&mask, sizeof(mask));
|
||||
if (how == SIG_SETMASK) {
|
||||
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]);
|
||||
return 1;
|
||||
} 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.
|
||||
// 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) {
|
||||
void *handler;
|
||||
int sig, olderr;
|
||||
struct sigaction sa;
|
||||
uint64_t flags, imask;
|
||||
int i, n, sig, olderr;
|
||||
struct sigaction sa, oldsa, *saptr;
|
||||
saptr = &sa;
|
||||
olderr = errno;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sig = luaL_checkinteger(L, 1);
|
||||
handler = (void *)luaL_checkinteger(L, 2);
|
||||
flags = luaL_optinteger(L, 3, SA_RESTART);
|
||||
imask = luaL_optinteger(L, 4, 0);
|
||||
if (handler != SIG_DFL && handler != SIG_IGN) {
|
||||
luaL_argerror(L, 2, "handler not SIG_DFL or SIG_IGN");
|
||||
if (!(1 <= sig && sig <= NSIG)) {
|
||||
luaL_argerror(L, 1, "signal number invalid");
|
||||
unreachable;
|
||||
}
|
||||
sa.sa_handler = handler;
|
||||
sa.sa_flags = flags;
|
||||
sa.sa_mask.__bits[0] = imask;
|
||||
sa.sa_mask.__bits[1] = 0;
|
||||
if (!sigaction(sig, &sa, 0)) {
|
||||
lua_pushinteger(L, 0);
|
||||
return 1;
|
||||
if (lua_isnoneornil(L, 2)) {
|
||||
// if handler/flags/mask aren't passed,
|
||||
// then we're quering the current state
|
||||
saptr = 0;
|
||||
} else if (lua_isinteger(L, 2)) {
|
||||
// bypass handling signals using lua code if possible
|
||||
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 {
|
||||
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_pushinteger(L, errno);
|
||||
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_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
|
||||
static int LuaUnixStrerror(lua_State *L) {
|
||||
lua_pushstring(L, strerror(luaL_checkinteger(L, 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
|
||||
|
||||
|
@ -1139,6 +1366,8 @@ static const luaL_Reg kLuaUnix[] = {
|
|||
{"chmod", LuaUnixChmod}, // change mode of file
|
||||
{"getcwd", LuaUnixGetcwd}, // get current directory
|
||||
{"fork", LuaUnixFork}, // make child process via mitosis
|
||||
{"execve", LuaUnixExecve}, // replace process with program
|
||||
{"commandv", LuaUnixCommandv}, // resolve program on $PATH
|
||||
{"kill", LuaUnixKill}, // signal child process
|
||||
{"raise", LuaUnixRaise}, // signal this process
|
||||
{"wait", LuaUnixWait}, // wait for child to change status
|
||||
|
@ -1179,7 +1408,10 @@ static const luaL_Reg kLuaUnix[] = {
|
|||
{"getsockname", LuaUnixGetsockname}, // get address of local end
|
||||
{"sigaction", LuaUnixSigaction}, // install signal handler
|
||||
{"sigprocmask", LuaUnixSigprocmask}, // change signal mask
|
||||
{"sigsuspend", LuaUnixSigsuspend}, // wait for signal
|
||||
{"setitimer", LuaUnixSetitimer}, // set alarm clock
|
||||
{"strerror", LuaUnixStrerror}, // turn errno into string
|
||||
{"strsignal", LuaUnixStrsignal}, // turn signal into string
|
||||
{0}, //
|
||||
};
|
||||
|
||||
|
@ -1187,9 +1419,12 @@ int LuaUnix(lua_State *L) {
|
|||
int i;
|
||||
char sigbuf[12];
|
||||
|
||||
GL = L;
|
||||
luaL_newlib(L, kLuaUnix);
|
||||
LuaUnixStatObj(L);
|
||||
LuaUnixDirObj(L);
|
||||
lua_newtable(L);
|
||||
lua_setglobal(L, "__signal_handlers");
|
||||
|
||||
// errnos
|
||||
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_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;
|
||||
}
|
||||
|
|
|
@ -132,6 +132,7 @@
|
|||
#include "third_party/zlib/zlib.h"
|
||||
#include "tool/build/lib/case.h"
|
||||
#include "tool/build/lib/psk.h"
|
||||
#include "tool/net/luacheck.h"
|
||||
|
||||
STATIC_STACK_SIZE(0x40000);
|
||||
STATIC_YOINK("zip_uri_support");
|
||||
|
@ -173,16 +174,6 @@ STATIC_YOINK("zip_uri_support");
|
|||
#define HeaderEqualCase(H, S) \
|
||||
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[] = {
|
||||
0x1F, // MAGNUM
|
||||
0x8B, // MAGNUM
|
||||
|
@ -397,7 +388,8 @@ static uint32_t clientaddrsize;
|
|||
|
||||
static size_t zsize;
|
||||
static char *outbuf;
|
||||
static lua_State *GL, *YL;
|
||||
static lua_State *GL;
|
||||
static lua_State *YL;
|
||||
static char *content;
|
||||
static uint8_t *zmap;
|
||||
static uint8_t *zbase;
|
||||
|
@ -1041,7 +1033,7 @@ static void LogLuaError(char *hook, char *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;
|
||||
int status = luaL_loadstring(L, code);
|
||||
if (status != LUA_OK || LuaCallWithTrace(L, 0, 0, NULL) != LUA_OK) {
|
||||
|
@ -1053,6 +1045,10 @@ static bool LuaRunCode(const char *code) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool LuaEvalFile(const char *path) {
|
||||
return LuaEvalCode(gc(xslurp(path, 0)));
|
||||
}
|
||||
|
||||
static bool LuaOnClientConnection(void) {
|
||||
#ifndef STATIC
|
||||
bool dropit;
|
||||
|
@ -6979,7 +6975,8 @@ static void GetOpts(int argc, char *argv[]) {
|
|||
CASE('h', PrintUsage(stdout, EXIT_SUCCESS));
|
||||
CASE('M', ProgramMaxPayloadSize(ParseInt(optarg)));
|
||||
#ifndef STATIC
|
||||
CASE('e', LuaRunCode(optarg));
|
||||
CASE('e', LuaEvalCode(optarg));
|
||||
CASE('F', LuaEvalFile(optarg));
|
||||
CASE('E', leakcrashreports = true);
|
||||
CASE('A', storeasset = true; StorePath(optarg));
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue