Implement raw system call for redbean lua code

You can now call functions like fork() from Lua and it'll work across
all supported platforms, including Windows. This gives you a level of
control of the system that Lua traditionally hasn't been able to have
due to its focus on old portable stdio rather modern POSIX APIs. Demo
code has been added to redbean-demo.com to show how it works.

This change also modifies Lua so that integer literals with a leading
zero will be interpreted as octal. That should help avoid shooting in
the foot with POSIX APIs that frequently use octal mode bits.

This change fixes a bug in opendir(".") on New Technology.

Lastly, redbean will now serve crash reports to private network IPs.
This is consistent with other frameworks. However that isn't served
to public IPs unless the -E flag is passed to redbean at startup.
This commit is contained in:
Justine Tunney 2022-04-13 08:49:17 -07:00
parent f684e348d4
commit 281a0f2730
39 changed files with 2044 additions and 84 deletions

View file

@ -229,7 +229,7 @@ uint32_t getgid(void) nosideeffect;
uint32_t getpgrp(void) nosideeffect;
uint32_t getsid(int) nosideeffect;
uint32_t getuid(void) nosideeffect;
uint32_t umask(int32_t);
uint32_t umask(uint32_t);
void rewinddir(DIR *);
void sync(void);
int getloadavg(double *, int);

View file

@ -32,7 +32,7 @@
* @param oldfd isn't closed afterwards
* @param newfd if already assigned, is silently closed beforehand;
* unless it's equal to oldfd, in which case dup2() is a no-op
* @flags can have O_CLOEXEC
* @param flags can have O_CLOEXEC
* @see dup(), dup2()
*/
int dup3(int oldfd, int newfd, int flags) {

View file

@ -17,19 +17,23 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
/**
* Returns parent process id.
* @asyncsignalsafe
*/
int getppid(void) {
int rc;
if (!IsWindows()) {
if (!IsNetbsd()) {
return sys_getppid();
rc = sys_getppid();
} else {
return sys_getpid().dx;
rc = sys_getpid().dx;
}
} else {
return sys_getppid_nt();
rc = sys_getppid_nt();
}
STRACE("getppid() → %d% m", rc);
return rc;
}

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
/**
* Returns nice value of thing.
@ -28,9 +29,12 @@
* @see setpriority(), nice()
*/
int getpriority(int which, unsigned who) {
int rc;
if (!IsWindows()) {
return sys_getpriority(which, who) - 20;
rc = sys_getpriority(which, who) - 20;
} else {
return sys_getsetpriority_nt(which, who, 0, sys_getpriority_nt);
rc = sys_getsetpriority_nt(which, who, 0, sys_getpriority_nt);
}
STRACE("getpriority(%d, %u) → %d% m", which, who, rc);
return rc;
}

View file

@ -220,6 +220,7 @@ u32 sys_getgid(void) hidden;
u32 sys_getsid(int) hidden;
u32 sys_gettid(void) hidden;
u32 sys_getuid(void) hidden;
u32 sys_umask(u32) hidden;
void *__sys_mmap(void *, u64, u32, u32, i64, i64, i64) hidden;
void *sys_mremap(void *, u64, u64, i32, void *) hidden;
void sys_exit(int) hidden;

View file

@ -17,10 +17,14 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h"
/**
* Sets effective group ID.
*/
int setegid(unsigned gid) {
return setregid(-1, gid);
int setegid(unsigned egid) {
int rc;
rc = setregid(-1, egid);
STRACE("%s(%u) → %d% m", "setegid", egid, rc);
return rc;
}

View file

@ -17,10 +17,14 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h"
/**
* Sets effective user ID.
*/
int seteuid(unsigned euid) {
return setreuid(-1, euid);
int rc;
rc = setreuid(-1, euid);
STRACE("%s(%u) → %d% m", "seteuid", euid, rc);
return rc;
}

View file

@ -18,10 +18,15 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
/**
* Creates session and sets the process group id.
* @return new session id, or -1 w/ errno
*/
int setsid(void) {
return sys_setsid();
int rc;
rc = sys_setsid();
STRACE("setsid() → %d% m", rc);
return rc;
}

40
libc/calls/umask.c Normal file
View file

@ -0,0 +1,40 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
/**
* Sets file mode creation mask.
*
* @return previous mask
* @note always succeeds
*/
unsigned umask(unsigned newmask) {
unsigned oldmask;
if (!IsWindows()) {
oldmask = sys_umask(newmask);
} else {
// TODO(jart): what should we do with this?
oldmask = newmask;
}
STRACE("umask(%#o) → %#o", oldmask);
return oldmask;
}

View file

@ -0,0 +1,16 @@
#ifndef COSMOPOLITAN_LIBC_FMT_KERRORNAMES_INTERNAL_H_
#define COSMOPOLITAN_LIBC_FMT_KERRORNAMES_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct ErrorName {
int x, s;
};
extern const struct ErrorName kStrSignal[];
extern const struct ErrorName kErrorNames[];
extern const struct ErrorName kErrorNamesLong[];
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_FMT_KERRORNAMES_INTERNAL_H_ */

View file

@ -17,8 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
extern const struct { int x, s; } kErrorNamesLong[];
#include "libc/fmt/kerrornames.internal.h"
/**
* Converts errno value to descriptive sentence.

View file

@ -17,8 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
extern const struct { int x, s; } kErrorNames[];
#include "libc/fmt/kerrornames.internal.h"
/**
* Converts errno value to symbolic name.

View file

@ -17,6 +17,7 @@ const char *DescribeRemapFlags(int);
const char *DescribeNtPageFlags(uint32_t);
const char *DescribeNtFileMapFlags(uint32_t);
const char *DescribeNtFiletypeFlags(uint32_t);
const char *DescribeNtFileFlagsAndAttributes(uint32_t);
const char *DescribeNtFileShareFlags(uint32_t);
const char *DescribeNtFileAccessFlags(uint32_t);

View file

@ -0,0 +1,35 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/describeflags.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/filetype.h"
#include "libc/sysv/consts/mremap.h"
static const struct DescribeFlags kFiletypeFlags[] = {
{kNtFileTypeRemote, "Remote"}, //
{kNtFileTypePipe, "Pipe"}, // order matters
{kNtFileTypeDisk, "Disk"}, //
{kNtFileTypeChar, "Char"}, //
};
const char *DescribeNtFiletypeFlags(uint32_t x) {
static char filetypeflags[64];
return DescribeFlags(filetypeflags, sizeof(filetypeflags), kFiletypeFlags,
ARRAYLEN(kFiletypeFlags), "kNtFileType", x);
}

View file

@ -0,0 +1,52 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/nt/files.h"
#include "libc/nt/memory.h"
#include "libc/nt/struct/win32finddata.h"
#include "libc/nt/thunk/msabi.h"
extern typeof(FindFirstFile) *const __imp_FindFirstFileW __msabi;
/**
* Finds first file in directory.
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
*/
textwindows int64_t FindFirstFile(const char16_t *lpFileName,
struct NtWin32FindData *out_lpFindFileData) {
int64_t hFindFile;
hFindFile = __imp_FindFirstFileW(lpFileName, out_lpFindFileData);
if (hFindFile != -1) {
STRACE(
"FindFirstFile(%#hs, [{"
".cFileName=%#hs, "
".dwFileAttributes=%s, "
".dwFileType=%s"
"}]) → %ld% m",
lpFileName, out_lpFindFileData->cFileName,
DescribeNtFileFlagsAndAttributes(out_lpFindFileData->dwFileAttributes),
DescribeNtFiletypeFlags(out_lpFindFileData->dwFileType), hFindFile);
} else {
__winerr();
STRACE("FindFirstFile(%#hs, [n/a]) → %ld% m", lpFileName, hFindFile);
}
return hFindFile;
}

View file

@ -0,0 +1,52 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/nt/files.h"
#include "libc/nt/memory.h"
#include "libc/nt/struct/win32finddata.h"
#include "libc/nt/thunk/msabi.h"
extern typeof(FindNextFile) *const __imp_FindNextFileW __msabi;
/**
* Finds more files in directory.
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
*/
textwindows bool32 FindNextFile(int64_t hFindFile,
struct NtWin32FindData *out_lpFindFileData) {
bool32 ok;
ok = __imp_FindNextFileW(hFindFile, out_lpFindFileData);
if (ok) {
STRACE(
"FindNextFile(%ld, [{"
".cFileName=%#hs, "
".dwFileAttributes=%s, "
".dwFileType=%s"
"}]) → %hhhd% m",
hFindFile, out_lpFindFileData->cFileName,
DescribeNtFileFlagsAndAttributes(out_lpFindFileData->dwFileAttributes),
DescribeNtFiletypeFlags(out_lpFindFileData->dwFileType), ok);
} else {
__winerr();
STRACE("FindNextFile(%ld, [n/a]) → %hhhd% m", hFindFile, ok);
}
return ok;
}

View file

@ -70,7 +70,9 @@ o/$(MODE)/libc/intrin/createpipe.greg.o \
o/$(MODE)/libc/intrin/closehandle.greg.o \
o/$(MODE)/libc/intrin/openprocess.greg.o \
o/$(MODE)/libc/intrin/createthread.greg.o \
o/$(MODE)/libc/intrin/findnextfile.greg.o \
o/$(MODE)/libc/intrin/createprocess.greg.o \
o/$(MODE)/libc/intrin/findfirstfile.greg.o \
o/$(MODE)/libc/intrin/describeflags.greg.o \
o/$(MODE)/libc/intrin/removedirectory.greg.o \
o/$(MODE)/libc/intrin/createnamedpipe.greg.o \

View file

@ -2,11 +2,11 @@
.imp kernel32,__imp_FindFirstFileW,FindFirstFileW,0
.text.windows
FindFirstFile:
__FindFirstFile:
push %rbp
mov %rsp,%rbp
.profilable
mov __imp_FindFirstFileW(%rip),%rax
jmp __sysv2nt
.endfn FindFirstFile,globl
.endfn __FindFirstFile,globl
.previous

View file

@ -2,11 +2,11 @@
.imp kernel32,__imp_FindNextFileW,FindNextFileW,0
.text.windows
FindNextFile:
__FindNextFile:
push %rbp
mov %rsp,%rbp
.profilable
mov __imp_FindNextFileW(%rip),%rax
jmp __sysv2nt
.endfn FindNextFile,globl
.endfn __FindNextFile,globl
.previous

View file

@ -327,7 +327,6 @@ imp 'FindClose' FindClose kernel32 0 1
imp 'FindCloseChangeNotification' FindCloseChangeNotification kernel32 0
imp 'FindFirstChangeNotification' FindFirstChangeNotificationW kernel32 0
imp 'FindFirstChangeNotificationA' FindFirstChangeNotificationA kernel32 0
imp 'FindFirstFile' FindFirstFileW kernel32 0 2
imp 'FindFirstFileA' FindFirstFileA kernel32 0 2
imp 'FindFirstFileEx' FindFirstFileExW kernel32 0 6
imp 'FindFirstFileExA' FindFirstFileExA kernel32 0 6
@ -344,7 +343,6 @@ imp 'FindFirstVolumeMountPointA' FindFirstVolumeMountPointA kernel32 393
imp 'FindNLSString' FindNLSString kernel32 0
imp 'FindNLSStringEx' FindNLSStringEx kernel32 0
imp 'FindNextChangeNotification' FindNextChangeNotification kernel32 0
imp 'FindNextFile' FindNextFileW kernel32 0 2
imp 'FindNextFileA' FindNextFileA kernel32 0 2
imp 'FindNextFileName' FindNextFileNameW kernel32 0
imp 'FindNextStream' FindNextStreamW kernel32 0
@ -1359,6 +1357,8 @@ imp '__CreateProcess' CreateProcessW kernel32 0 10
imp '__CreateThread' CreateThread kernel32 0 6
imp '__DeleteFile' DeleteFileW kernel32 0 1
imp '__DeviceIoControl' DeviceIoControl kernel32 0 8
imp '__FindFirstFile' FindFirstFileW kernel32 0 2
imp '__FindNextFile' FindNextFileW kernel32 0 2
imp '__FlushFileBuffers' FlushFileBuffers kernel32 0 1
imp '__FlushViewOfFile' FlushViewOfFile kernel32 0 2
imp '__GenerateConsoleCtrlEvent' GenerateConsoleCtrlEvent kernel32 0 2

View file

@ -1,8 +1,8 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_CXAATEXIT_H_
#define COSMOPOLITAN_LIBC_RUNTIME_CXAATEXIT_H_
#include "libc/stdio/stdio.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#include "libc/stdio/stdio.h"
struct CxaAtexitBlocks {
struct CxaAtexitBlock {

View file

@ -33,7 +33,7 @@
* @param fd is the file descriptor returned by socket()
* @param addr is usually the binary-encoded ip:port on which to listen
* @param addrsize is the byte-length of addr's true polymorphic form
* @return socket file descriptor or -1 w/ errno
* @return 0 on success or -1 w/ errno
* @error ENETDOWN, EPFNOSUPPORT, etc.
* @asyncsignalsafe
*/

View file

@ -25,7 +25,9 @@
* Creates bidirectional pipe.
*
* @param family should be AF_UNIX or synonymously AF_LOCAL
* @param type may be or'd with SOCK_CLOEXEC
* @param type can be SOCK_STREAM (for TCP), SOCK_DGRAM (e.g. UDP), or
* SOCK_RAW (IP) so long as IP_HDRINCL was passed to setsockopt();
* and additionally, may be or'd with SOCK_NONBLOCK, SOCK_CLOEXEC
* @param sv a vector of 2 integers to store the created sockets
* @return 0 if success, -1 in case of error
* @error EFAULT, EPFNOSUPPORT, etc.

View file

@ -116,16 +116,18 @@ struct dirent_netbsd {
static textwindows DIR *opendir_nt_impl(char16_t *name, size_t len) {
DIR *res;
if (len + 2 + 1 <= PATH_MAX) {
if (len > 1 && name[len - 1] != u'\\') {
name[len++] = u'\\';
if (len == 1 && name[0] == '.') {
name[0] = '*';
} else {
if (len > 1 && name[len - 1] != u'\\') {
name[len++] = u'\\';
}
name[len++] = u'*';
}
name[len++] = u'*';
name[len] = u'\0';
if ((res = calloc(1, sizeof(DIR)))) {
if ((res->fd = FindFirstFile(name, &res->windata)) != -1) {
return res;
} else {
__winerr();
}
free(res);
}
@ -342,6 +344,7 @@ struct dirent *readdir(DIR *dir) {
if (dir->buf_pos >= dir->buf_end) {
basep = dir->tell; /* TODO(jart): what does xnu do */
rc = getdents(dir->fd, dir->buf, sizeof(dir->buf) - 256, &basep);
STRACE("getdents(%d) → %d% m", dir->fd, rc);
if (!rc || rc == -1) return NULL;
dir->buf_pos = 0;
dir->buf_end = rc;

View file

@ -17,11 +17,10 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/fmt/kerrornames.internal.h"
#include "libc/macros.internal.h"
#include "libc/str/str.h"
extern const struct { int x, s; } kStrSignal[];
static char g_strsignal[12];
/**

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall umask,0x03c03c03c203c05f,globl
.scall sys_umask,0x03c03c03c203c05f,globl

View file

@ -619,9 +619,9 @@ syscon clock CLOCK_REALTIME_COARSE 5 -1 -1 -1 -1 -1 # Linux 2.6.32
syscon clock CLOCK_MONOTONIC_COARSE 6 -1 -1 -1 -1 -1 # Linux 2.6.32+; bsd consensus; not available on RHEL5
syscon clock CLOCK_PROF -1 -1 2 -1 2 -1 #
syscon clock CLOCK_BOOTTIME 7 -1 -1 6 6 -1 #
syscon clock CLOCK_REALTIME_ALARM 8 -1 -1 -1 -1 -1 # bsd consensus
syscon clock CLOCK_BOOTTIME_ALARM 9 -1 -1 -1 -1 -1 # bsd consensus
syscon clock CLOCK_TAI 11 -1 -1 -1 -1 -1 # bsd consensus
syscon clock CLOCK_REALTIME_ALARM 8 -1 -1 -1 -1 -1 #
syscon clock CLOCK_BOOTTIME_ALARM 9 -1 -1 -1 -1 -1 #
syscon clock CLOCK_TAI 11 -1 -1 -1 -1 -1 #
# poll()
#

View file

@ -134,7 +134,7 @@ scall sys_fchmod 0x07c07c07c207c05b globl hidden
scall sys_chown 0x010010010201005c globl hidden # impl. w/ fchownat() @asyncsignalsafe
scall sys_fchown 0x07b07b07b207b05d globl hidden # @asyncsignalsafe
scall sys_lchown 0x1130fe0fe216c05e globl hidden # impl. w/ fchownat()
scall umask 0x03c03c03c203c05f globl
scall sys_umask 0x03c03c03c203c05f globl
scall sys_gettimeofday 0x1a20430742074060 globl hidden # xnu esi/edx=0
scall sys_getrlimit 0x0c20c20c220c2061 globl hidden
scall __sys_getrusage 0x1bd0130752075062 globl hidden