mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Make improvements
- Introduce path module to redbean - Fix glitch with linenoise printing extra line on eof - Introduce closefrom() and close_range() system calls - Make file descriptor closing more secure in pledge.com
This commit is contained in:
parent
439ad21b12
commit
1837dc2e85
31 changed files with 806 additions and 75 deletions
23
examples/tls.c
Normal file
23
examples/tls.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @fileoverview thread local storage
|
||||
*
|
||||
* Cosmopolitan guarantees `_Thread_local` variables are always
|
||||
* accessible, even if you're not using threads.
|
||||
*/
|
||||
|
||||
_Thread_local int x;
|
||||
_Thread_local int y = 42;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return x + y;
|
||||
}
|
|
@ -69,6 +69,8 @@ int chown(const char *, uint32_t, uint32_t);
|
|||
int chroot(const char *);
|
||||
int clone(void *, void *, size_t, int, void *, int *, void *, int *);
|
||||
int close(int);
|
||||
int close_range(unsigned, unsigned, unsigned);
|
||||
int closefrom(int);
|
||||
int creat(const char *, uint32_t);
|
||||
int dup(int);
|
||||
int dup2(int, int);
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
/**
|
||||
* Closes file descriptor.
|
||||
*
|
||||
* This function may be used for file descriptors returned by socket,
|
||||
* accept, epoll_create, and zipos file descriptors too.
|
||||
* This function may be used for file descriptors returned by functions
|
||||
* like open, socket, accept, epoll_create, and landlock_create_ruleset.
|
||||
*
|
||||
* This function should never be called twice for the same file
|
||||
* descriptor, regardless of whether or not an error happened. However
|
||||
|
|
65
libc/calls/close_range.c
Normal file
65
libc/calls/close_range.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*-*- 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/strace.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
|
||||
/**
|
||||
* Closes inclusive range of file descriptors, e.g.
|
||||
*
|
||||
* // close all non-stdio file descriptors
|
||||
* if (close_range(3, -1, 0) == -1) {
|
||||
* for (int i = 3; i < 256; ++i) {
|
||||
* close(i);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* This is supported on Linux 5.9+, FreeBSD, and OpenBSD. On FreeBSD,
|
||||
* `flags` must be zero. On OpenBSD, we call closefrom(int) so `last`
|
||||
* should be `-1` in order to get OpenBSD support, otherwise `ENOSYS`
|
||||
* will be returned. We also polyfill closefrom on FreeBSD since it's
|
||||
* available on older kernels.
|
||||
*
|
||||
* On Linux, the following flags are supported:
|
||||
*
|
||||
* - CLOSE_RANGE_UNSHARE
|
||||
* - CLOSE_RANGE_CLOEXEC
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error ENOSYS if not Linux 5.9+ / FreeBSD / OpenBSD
|
||||
* @error EBADF on OpenBSD if `first` is greater than highest fd
|
||||
* @error EINVAL if flags are bad or first is greater than last
|
||||
* @error EMFILE if a weird race condition happens on Linux
|
||||
* @error EINTR possibly on OpenBSD
|
||||
* @error ENOMEM on Linux maybe
|
||||
*/
|
||||
int close_range(unsigned int first, unsigned int last, unsigned int flags) {
|
||||
int rc, err;
|
||||
err = errno;
|
||||
if ((rc = sys_close_range(first, last, flags)) == -1) {
|
||||
if (errno == ENOSYS && first <= INT_MAX && last == UINT_MAX && !flags) {
|
||||
errno = err;
|
||||
rc = sys_closefrom(first);
|
||||
}
|
||||
}
|
||||
STRACE("close_range(%d, %d, %#x) → %d% m", first, last, flags, rc);
|
||||
return rc;
|
||||
}
|
60
libc/calls/closefrom.c
Normal file
60
libc/calls/closefrom.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*-*- 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/strace.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Closes extra file descriptors, e.g.
|
||||
*
|
||||
* // close all non-stdio file descriptors
|
||||
* if (closefrom(3) == -1) {
|
||||
* for (int i = 3; i < 256; ++i) {
|
||||
* close(i);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error ENOSYS if not Linux 5.9+ / FreeBSD / OpenBSD
|
||||
* @error EBADF on OpenBSD if `first` is greater than highest fd
|
||||
* @error EINVAL if flags are bad or first is greater than last
|
||||
* @error EMFILE if a weird race condition happens on Linux
|
||||
* @error EINTR possibly on OpenBSD
|
||||
* @error ENOMEM on Linux maybe
|
||||
* @note supported on Linux 5.9+, FreeBSD 8+, and OpenBSD
|
||||
*/
|
||||
int closefrom(int first) {
|
||||
int rc, err;
|
||||
if (first >= 0) {
|
||||
err = errno;
|
||||
if ((rc = sys_close_range(first, -1, 0)) == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
errno = err;
|
||||
rc = sys_closefrom(first);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
STRACE("closefrom(%d) → %d% m", first, rc);
|
||||
return rc;
|
||||
}
|
|
@ -28,6 +28,8 @@ i32 sys_arch_prctl(i32, i64) hidden;
|
|||
i32 sys_chdir(const char *) hidden;
|
||||
i32 sys_chroot(const char *) hidden;
|
||||
i32 sys_close(i32) hidden;
|
||||
i32 sys_close_range(u32, u32, u32) hidden;
|
||||
i32 sys_closefrom(i32) hidden;
|
||||
i32 sys_dup(i32) hidden;
|
||||
i32 sys_dup2(i32, i32) hidden;
|
||||
i32 sys_dup3(i32, i32, i32) hidden;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
*
|
||||
* path │ dirname() │ basename()
|
||||
* ─────────────────────────────────
|
||||
* 0 │ . │ .
|
||||
* . │ . │ .
|
||||
* .. │ . │ ..
|
||||
* / │ / │ /
|
||||
|
@ -48,7 +49,7 @@ char *basename(char *path) {
|
|||
for (; i && _isdirsep(path[i]); i--) {
|
||||
path[i] = 0;
|
||||
}
|
||||
for (; i && !_isdirsep(path[i - 1]);) {
|
||||
while (i && !_isdirsep(path[i - 1])) {
|
||||
i--;
|
||||
}
|
||||
return path + i;
|
||||
|
|
|
@ -24,12 +24,18 @@
|
|||
/**
|
||||
* Joins paths, e.g.
|
||||
*
|
||||
* 0 + 0 → 0
|
||||
* "" + "" → ""
|
||||
* "a" + 0 → "a"
|
||||
* "a" + "" → "a/"
|
||||
* 0 + "b" → "b"
|
||||
* "" + "b" → "b"
|
||||
* "." + "b" → "./b"
|
||||
* "b" + "." → "b/."
|
||||
* "a" + "b" → "a/b"
|
||||
* "a/" + "b" → "a/b"
|
||||
* "a" + "b/" → "a/b/"
|
||||
* "a" + "/b" → "/b"
|
||||
* "." + "b" → "b"
|
||||
* "" + "b" → "b"
|
||||
*
|
||||
* @return joined path, which may be `buf`, `path`, or `other`, or null
|
||||
* if (1) `buf` didn't have enough space, or (2) both `path` and
|
||||
|
@ -39,14 +45,11 @@ char *_joinpaths(char *buf, size_t size, const char *path, const char *other) {
|
|||
size_t pathlen, otherlen;
|
||||
if (!other) return path;
|
||||
if (!path) return other;
|
||||
otherlen = strlen(other);
|
||||
if (!otherlen) {
|
||||
return (/*unconst*/ char *)path;
|
||||
}
|
||||
pathlen = strlen(path);
|
||||
if (!pathlen || (READ16LE(path) == READ16LE(".")) || *other == '/') {
|
||||
if (!pathlen || *other == '/') {
|
||||
return (/*unconst*/ char *)other;
|
||||
}
|
||||
otherlen = strlen(other);
|
||||
if (path[pathlen - 1] == '/') {
|
||||
if (pathlen + otherlen + 1 <= size) {
|
||||
memmove(buf, path, pathlen);
|
||||
|
|
|
@ -84,6 +84,7 @@ static const uint16_t kPledgeLinuxStdio[] = {
|
|||
__NR_linux_clock_getres, //
|
||||
__NR_linux_clock_gettime, //
|
||||
__NR_linux_clock_nanosleep, //
|
||||
__NR_linux_close_range, //
|
||||
__NR_linux_close, //
|
||||
__NR_linux_write, //
|
||||
__NR_linux_writev, //
|
||||
|
|
|
@ -296,6 +296,9 @@ static int sys_unveil_linux(const char *path, const char *permissions) {
|
|||
* possible to use opendir() and go fishing for paths which weren't
|
||||
* previously known.
|
||||
*
|
||||
* 5. Always specify at least one path. OpenBSD has unclear semantics
|
||||
* when `pledge(0,0)` is used without any previous calls.
|
||||
*
|
||||
* This system call is supported natively on OpenBSD and polyfilled on
|
||||
* Linux using the Landlock LSM[1].
|
||||
*
|
||||
|
@ -321,6 +324,7 @@ static int sys_unveil_linux(const char *path, const char *permissions) {
|
|||
* @raise EINVAL if one argument is set and the other is not
|
||||
* @raise EINVAL if an invalid character in `permissions` was found
|
||||
* @raise EPERM if unveil() is called after locking
|
||||
* @note on Linux this function requires Linux Kernel 5.13+
|
||||
* @see [1] https://docs.kernel.org/userspace-api/landlock.html
|
||||
*/
|
||||
int unveil(const char *path, const char *permissions) {
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall close_range,0xfffffffffffff1b4,globl
|
|
@ -1,2 +0,0 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall closefrom,0xfff11f1fdfffffff,globl
|
2
libc/sysv/calls/sys_close_range.s
Normal file
2
libc/sysv/calls/sys_close_range.s
Normal file
|
@ -0,0 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_close_range,0xffffff23fffff1b4,globl,hidden
|
2
libc/sysv/calls/sys_closefrom.s
Normal file
2
libc/sysv/calls/sys_closefrom.s
Normal file
|
@ -0,0 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_closefrom,0xfff11f1fdfffffff,globl,hidden
|
|
@ -586,6 +586,12 @@ syscon ss MINSIGSTKSZ 2048 32768 2048 12288 8192 2048 # overlayed
|
|||
syscon ss SS_ONSTACK 1 1 1 1 1 1 # unix consensus
|
||||
syscon ss SS_DISABLE 2 4 4 4 4 2 # bsd consensus
|
||||
|
||||
# close_range() values
|
||||
#
|
||||
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||
syscon close CLOSE_RANGE_UNSHARE 2 -1 -1 -1 -1 -1 #
|
||||
syscon close CLOSE_RANGE_CLOEXEC 4 -1 -1 -1 -1 -1 #
|
||||
|
||||
# clock_{gettime,settime} timers
|
||||
#
|
||||
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||
|
|
16
libc/sysv/consts/close.h
Normal file
16
libc/sysv/consts/close.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_CLOSE_H_
|
||||
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_CLOSE_H_
|
||||
#include "libc/runtime/symbolic.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const long CLOSE_RANGE_UNSHARE;
|
||||
extern const long CLOSE_RANGE_CLOEXEC;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
#define CLOSE_RANGE_UNSHARE SYMBOLIC(CLOSE_RANGE_UNSHARE)
|
||||
#define CLOSE_RANGE_CLOEXEC SYMBOLIC(CLOSE_RANGE_CLOEXEC)
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_CLOSE_H_ */
|
|
@ -383,7 +383,7 @@ scall fsmount 0xfffffffffffff1b0 globl
|
|||
scall fspick 0xfffffffffffff1b1 globl
|
||||
scall pidfd_open 0xfffffffffffff1b2 globl
|
||||
scall clone3 0xfffffffffffff1b3 globl
|
||||
scall close_range 0xfffffffffffff1b4 globl
|
||||
scall sys_close_range 0xffffff23fffff1b4 globl hidden # linux 5.9
|
||||
scall sys_openat2 0xfffffffffffff1b5 globl hidden # Linux 5.6
|
||||
scall pidfd_getfd 0xfffffffffffff1b6 globl
|
||||
scall sys_faccessat2 0xfffffffffffff1b7 globl hidden
|
||||
|
@ -463,7 +463,7 @@ scall chflagsat 0xfff06b21cfffffff globl
|
|||
scall profil 0x02c02c02cfffffff globl
|
||||
scall fhstatfs 0xfff04122efffffff globl
|
||||
scall utrace 0x1320d114ffffffff globl
|
||||
scall closefrom 0xfff11f1fdfffffff globl
|
||||
scall sys_closefrom 0xfff11f1fdfffffff globl hidden
|
||||
#───────────────────────────XNU──────────────────────────────
|
||||
scall __pthread_markcancel 0xfffffffff214cfff globl
|
||||
scall __pthread_kill 0xfffffffff2148fff globl
|
||||
|
|
61
test/libc/calls/closefrom_test.c
Normal file
61
test/libc/calls/closefrom_test.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*-*- 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/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
void SetUp(void) {
|
||||
if (closefrom(3) == -1) {
|
||||
if (IsOpenbsd()) {
|
||||
ASSERT_EQ(EBADF, errno);
|
||||
} else {
|
||||
ASSERT_EQ(ENOSYS, errno);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(closefrom, test) {
|
||||
ASSERT_SYS(0, 3, dup(2));
|
||||
ASSERT_SYS(0, 4, dup(2));
|
||||
ASSERT_SYS(0, 5, dup(2));
|
||||
ASSERT_SYS(0, 6, dup(2));
|
||||
EXPECT_SYS(0, 0, closefrom(3));
|
||||
ASSERT_SYS(0, 0, fcntl(2, F_GETFD));
|
||||
ASSERT_SYS(EBADF, -1, fcntl(3, F_GETFD));
|
||||
ASSERT_SYS(EBADF, -1, fcntl(4, F_GETFD));
|
||||
ASSERT_SYS(EBADF, -1, fcntl(5, F_GETFD));
|
||||
ASSERT_SYS(EBADF, -1, fcntl(6, F_GETFD));
|
||||
}
|
||||
|
||||
TEST(close_range, test) {
|
||||
ASSERT_SYS(0, 3, dup(2));
|
||||
ASSERT_SYS(0, 4, dup(2));
|
||||
ASSERT_SYS(0, 5, dup(2));
|
||||
ASSERT_SYS(0, 6, dup(2));
|
||||
EXPECT_SYS(0, 0, close_range(3, -1, 0));
|
||||
ASSERT_SYS(0, 0, fcntl(2, F_GETFD));
|
||||
ASSERT_SYS(EBADF, -1, fcntl(3, F_GETFD));
|
||||
ASSERT_SYS(EBADF, -1, fcntl(4, F_GETFD));
|
||||
ASSERT_SYS(EBADF, -1, fcntl(5, F_GETFD));
|
||||
ASSERT_SYS(EBADF, -1, fcntl(6, F_GETFD));
|
||||
}
|
|
@ -16,23 +16,37 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/path.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
char b[PATH_MAX];
|
||||
|
||||
TEST(xjoinpaths, test) {
|
||||
char b[PATH_MAX];
|
||||
EXPECT_EQ(NULL, _joinpaths(b, sizeof(b), 0, 0));
|
||||
EXPECT_STREQ("x", _joinpaths(b, sizeof(b), "x", 0));
|
||||
EXPECT_STREQ("x", _joinpaths(b, sizeof(b), 0, "x"));
|
||||
EXPECT_STREQ("", _joinpaths(b, sizeof(b), "", ""));
|
||||
EXPECT_STREQ("", _joinpaths(b, sizeof(b), "", 0));
|
||||
EXPECT_STREQ("", _joinpaths(b, sizeof(b), 0, ""));
|
||||
EXPECT_STREQ("", _joinpaths(b, sizeof(b), "", ""));
|
||||
EXPECT_STREQ("b", _joinpaths(b, sizeof(b), "", "b"));
|
||||
EXPECT_STREQ("a/", _joinpaths(b, sizeof(b), "a", ""));
|
||||
EXPECT_STREQ("a/b", _joinpaths(b, sizeof(b), "a", "b"));
|
||||
EXPECT_STREQ("a/b", _joinpaths(b, sizeof(b), "a/", "b"));
|
||||
EXPECT_STREQ("a/b/", _joinpaths(b, sizeof(b), "a", "b/"));
|
||||
EXPECT_STREQ("/b", _joinpaths(b, sizeof(b), "a", "/b"));
|
||||
EXPECT_STREQ("b", _joinpaths(b, sizeof(b), ".", "b"));
|
||||
EXPECT_STREQ("./b", _joinpaths(b, sizeof(b), ".", "b"));
|
||||
EXPECT_STREQ("b/.", _joinpaths(b, sizeof(b), "b", "."));
|
||||
EXPECT_EQ(NULL, _joinpaths(b, 3, "a", "b/"));
|
||||
EXPECT_EQ(NULL, _joinpaths(b, 4, "a", "b/"));
|
||||
EXPECT_STREQ("a/b", _joinpaths(b, 4, "a/", "b"));
|
||||
EXPECT_STREQ("a/b/", _joinpaths(b, 5, "a", "b/"));
|
||||
}
|
||||
|
||||
BENCH(joinpaths, bench) {
|
||||
EZBENCH2("_joinpaths", donothing, _joinpaths(b, sizeof(b), "care", "bear"));
|
||||
EZBENCH2("xjoinpaths", donothing, free(xjoinpaths("care", "bear")));
|
||||
}
|
||||
|
|
|
@ -182,6 +182,18 @@ TEST(unveil, dirfdHacking_doesntWork) {
|
|||
EXITS(0);
|
||||
}
|
||||
|
||||
TEST(unveil, mostRestrictivePolicy) {
|
||||
if (IsOpenbsd()) return; // openbsd behaves oddly; see docs
|
||||
SPAWN();
|
||||
ASSERT_SYS(0, 0, mkdir("jail", 0755));
|
||||
ASSERT_SYS(0, 0, mkdir("garden", 0755));
|
||||
ASSERT_SYS(0, 0, touch("garden/secret.txt", 0644));
|
||||
ASSERT_SYS(0, 0, unveil(0, 0));
|
||||
ASSERT_SYS(EACCES_OR_ENOENT, -1, open("jail", O_RDONLY | O_DIRECTORY));
|
||||
ASSERT_SYS(EACCES_OR_ENOENT, -1, open("garden/secret.txt", O_RDONLY));
|
||||
EXITS(0);
|
||||
}
|
||||
|
||||
TEST(unveil, overlappingDirectories_inconsistentBehavior) {
|
||||
SPAWN();
|
||||
ASSERT_SYS(0, 0, makedirs("f1/f2", 0755));
|
||||
|
|
28
test/libc/runtime/tls_test.c
Normal file
28
test/libc/runtime/tls_test.c
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*-*- 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/runtime/runtime.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
_Thread_local int x;
|
||||
_Thread_local int y = 40;
|
||||
int z = 2;
|
||||
|
||||
TEST(tls, test) {
|
||||
EXPECT_EQ(42, x + y + z);
|
||||
}
|
77
test/tool/net/path_test.lua
Normal file
77
test/tool/net/path_test.lua
Normal file
|
@ -0,0 +1,77 @@
|
|||
-- 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.
|
||||
|
||||
assert("/usr/lib" == path.dirname("/usr/lib/foo.bar"))
|
||||
assert("/usr" == path.dirname("/usr/lib"))
|
||||
assert("usr" == path.dirname("usr/lib"))
|
||||
assert("/" == path.dirname("/usr//"))
|
||||
assert("/" == path.dirname("/usr/"))
|
||||
assert("." == path.dirname("usr"))
|
||||
assert("/" == path.dirname("/"))
|
||||
assert("." == path.dirname("."))
|
||||
assert("." == path.dirname(".."))
|
||||
assert("." == path.dirname(""))
|
||||
assert("." == path.dirname(nil))
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
assert("lib" == path.basename("/usr/lib"))
|
||||
assert("lib" == path.basename("usr/lib"))
|
||||
assert("usr" == path.basename("/usr/"))
|
||||
assert("usr" == path.basename("/usr"))
|
||||
assert("/" == path.basename("/"))
|
||||
assert("." == path.basename("."))
|
||||
assert(".." == path.basename(".."))
|
||||
assert("." == path.basename(""))
|
||||
assert("foo" == path.basename("foo/"))
|
||||
assert("foo" == path.basename("foo//"))
|
||||
assert("/" == path.basename("///"))
|
||||
assert("0" == path.basename(0))
|
||||
assert("." == path.basename(nil))
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
assert("a" == path.join("a"))
|
||||
assert("a/b/c" == path.join("a", "b", "c"))
|
||||
assert("/c" == path.join("a", "b", "/c"))
|
||||
assert("/b/c" == path.join("a", "/b", "c"))
|
||||
assert("/c" == path.join("a", "/b", "/c"))
|
||||
assert("./." == path.join(".", "."))
|
||||
assert("./.." == path.join(".", ".."))
|
||||
assert("../." == path.join("..", "."))
|
||||
assert("./a" == path.join(".", "a"))
|
||||
assert("c//c" == path.join("c//", "c"))
|
||||
assert("a/." == path.join("a", "."))
|
||||
assert("a/b" == path.join("a", "b"))
|
||||
assert("a/b" == path.join("a/", "b"))
|
||||
assert("a/b/" == path.join("a", "b/"))
|
||||
assert("/b" == path.join("a", "/b"))
|
||||
assert("./b" == path.join(".", "b"))
|
||||
assert("a" * 3000 .."/123/".. "b" * 3000 .. "/123" == path.join("a" * 3000, 123, "b" * 3000, 123))
|
||||
assert("1/2/3" == path.join(1, 2, 3))
|
||||
assert(nil == path.join(nil))
|
||||
assert(nil == path.join(nil, nil))
|
||||
assert("a" == path.join("a", nil))
|
||||
assert("a" == path.join(nil, "a"))
|
||||
assert("a/a" == path.join("a", nil, "a"))
|
||||
assert("a/a" == path.join("a/", nil, "a"))
|
||||
assert("" == path.join(""))
|
||||
assert("" == path.join("", ""))
|
||||
assert("b" == path.join("", "b"))
|
||||
assert("a" == path.join("", "a"))
|
||||
assert("a/" == path.join("a", ""))
|
||||
assert("a/b" == path.join("a", "", "b"))
|
||||
assert("a/b" == path.join("a", "", "", "b"))
|
||||
assert("a/b/" == path.join("a", "", "", "b", ""))
|
4
third_party/linenoise/linenoise.c
vendored
4
third_party/linenoise/linenoise.c
vendored
|
@ -2428,7 +2428,9 @@ char *linenoiseRaw(const char *prompt, int infd, int outfd) {
|
|||
rc = -1;
|
||||
}
|
||||
if (rc != -1) {
|
||||
linenoiseWriteStr(outfd, "\n");
|
||||
if (buf) {
|
||||
linenoiseWriteStr(outfd, "\n");
|
||||
}
|
||||
return buf;
|
||||
} else {
|
||||
return 0;
|
||||
|
|
93
third_party/lua/lunix.c
vendored
93
third_party/lua/lunix.c
vendored
|
@ -35,6 +35,7 @@
|
|||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
|
@ -49,6 +50,7 @@
|
|||
#include "libc/sock/syslog.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/path.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
@ -89,6 +91,7 @@
|
|||
#include "third_party/lua/lgc.h"
|
||||
#include "third_party/lua/lua.h"
|
||||
#include "third_party/lua/luaconf.h"
|
||||
#include "third_party/lua/lunix.h"
|
||||
#include "tool/net/luacheck.h"
|
||||
|
||||
/**
|
||||
|
@ -96,12 +99,6 @@
|
|||
* @support Linux, Mac, Windows, FreeBSD, NetBSD, OpenBSD
|
||||
*/
|
||||
|
||||
struct UnixErrno {
|
||||
int errno_;
|
||||
int winerr;
|
||||
const char *call;
|
||||
};
|
||||
|
||||
static lua_State *GL;
|
||||
|
||||
static void *LuaRealloc(lua_State *L, void *p, size_t n) {
|
||||
|
@ -177,7 +174,7 @@ static dontinline int ReturnString(lua_State *L, const char *x) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int SysretErrno(lua_State *L, const char *call, int olderr) {
|
||||
int LuaUnixSysretErrno(lua_State *L, const char *call, int olderr) {
|
||||
struct UnixErrno *ep;
|
||||
int i, unixerr, winerr;
|
||||
unixerr = errno;
|
||||
|
@ -195,7 +192,7 @@ static int SysretErrno(lua_State *L, const char *call, int olderr) {
|
|||
return 2;
|
||||
}
|
||||
|
||||
int SysretBool(lua_State *L, const char *call, int olderr, int rc) {
|
||||
static int SysretBool(lua_State *L, const char *call, int olderr, int rc) {
|
||||
if (!IsTiny() && (rc != 0 && rc != -1)) {
|
||||
WARNF("syscall supposed to return 0 / -1 but got %d", rc);
|
||||
}
|
||||
|
@ -203,7 +200,7 @@ int SysretBool(lua_State *L, const char *call, int olderr, int rc) {
|
|||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
} else {
|
||||
return SysretErrno(L, call, olderr);
|
||||
return LuaUnixSysretErrno(L, call, olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,7 +213,7 @@ static int SysretInteger(lua_State *L, const char *call, int olderr,
|
|||
lua_pushinteger(L, rc);
|
||||
return 1;
|
||||
} else {
|
||||
return SysretErrno(L, call, olderr);
|
||||
return LuaUnixSysretErrno(L, call, olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -502,7 +499,7 @@ static int LuaUnixReadlink(lua_State *L) {
|
|||
}
|
||||
}
|
||||
free(buf);
|
||||
return SysretErrno(L, "readlink", olderr);
|
||||
return LuaUnixSysretErrno(L, "readlink", olderr);
|
||||
}
|
||||
|
||||
// unix.getcwd()
|
||||
|
@ -516,7 +513,7 @@ static int LuaUnixGetcwd(lua_State *L) {
|
|||
free(path);
|
||||
return 1;
|
||||
} else {
|
||||
return SysretErrno(L, "getcwd", olderr);
|
||||
return LuaUnixSysretErrno(L, "getcwd", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -558,14 +555,14 @@ static int LuaUnixExecve(lua_State *L) {
|
|||
freeme2 = envp;
|
||||
} else {
|
||||
FreeStringList(argv);
|
||||
return SysretErrno(L, "execve", olderr);
|
||||
return LuaUnixSysretErrno(L, "execve", olderr);
|
||||
}
|
||||
} else {
|
||||
envp = environ;
|
||||
freeme2 = 0;
|
||||
}
|
||||
} else {
|
||||
return SysretErrno(L, "execve", olderr);
|
||||
return LuaUnixSysretErrno(L, "execve", olderr);
|
||||
}
|
||||
} else {
|
||||
ezargs[0] = prog;
|
||||
|
@ -578,7 +575,7 @@ static int LuaUnixExecve(lua_State *L) {
|
|||
execve(prog, argv, envp);
|
||||
FreeStringList(freeme1);
|
||||
FreeStringList(freeme2);
|
||||
return SysretErrno(L, "execve", olderr);
|
||||
return LuaUnixSysretErrno(L, "execve", olderr);
|
||||
}
|
||||
|
||||
// unix.commandv(prog:str)
|
||||
|
@ -597,7 +594,7 @@ static int LuaUnixCommandv(lua_State *L) {
|
|||
return 1;
|
||||
} else {
|
||||
free(pathbuf);
|
||||
return SysretErrno(L, "commandv", olderr);
|
||||
return LuaUnixSysretErrno(L, "commandv", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -615,7 +612,7 @@ static int LuaUnixRealpath(lua_State *L) {
|
|||
free(resolved);
|
||||
return 1;
|
||||
} else {
|
||||
return SysretErrno(L, "realpath", olderr);
|
||||
return LuaUnixSysretErrno(L, "realpath", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -656,7 +653,7 @@ static int LuaUnixGetrlimit(lua_State *L) {
|
|||
lua_pushinteger(L, FixLimit(rlim.rlim_max));
|
||||
return 2;
|
||||
} else {
|
||||
return SysretErrno(L, "getrlimit", olderr);
|
||||
return LuaUnixSysretErrno(L, "getrlimit", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -670,7 +667,7 @@ static int LuaUnixGetrusage(lua_State *L) {
|
|||
LuaPushRusage(L, &ru);
|
||||
return 1;
|
||||
} else {
|
||||
return SysretErrno(L, "getrusage", olderr);
|
||||
return LuaUnixSysretErrno(L, "getrusage", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -704,7 +701,7 @@ static int LuaUnixWait(lua_State *L) {
|
|||
LuaPushRusage(L, &ru);
|
||||
return 3;
|
||||
} else {
|
||||
return SysretErrno(L, "wait", olderr);
|
||||
return LuaUnixSysretErrno(L, "wait", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -745,7 +742,7 @@ static int LuaUnixPipe(lua_State *L) {
|
|||
lua_pushinteger(L, pipefd[1]);
|
||||
return 2;
|
||||
} else {
|
||||
return SysretErrno(L, "pipe", olderr);
|
||||
return LuaUnixSysretErrno(L, "pipe", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -898,7 +895,7 @@ static int LuaUnixGettime(lua_State *L) {
|
|||
lua_pushinteger(L, ts.tv_nsec);
|
||||
return 2;
|
||||
} else {
|
||||
return SysretErrno(L, "clock_gettime", olderr);
|
||||
return LuaUnixSysretErrno(L, "clock_gettime", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -915,7 +912,7 @@ static int LuaUnixNanosleep(lua_State *L) {
|
|||
lua_pushinteger(L, rem.tv_nsec);
|
||||
return 2;
|
||||
} else {
|
||||
return SysretErrno(L, "nanosleep", olderr);
|
||||
return LuaUnixSysretErrno(L, "nanosleep", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1016,7 +1013,7 @@ static int LuaUnixRead(lua_State *L) {
|
|||
return 1;
|
||||
} else {
|
||||
free(buf);
|
||||
return SysretErrno(L, "read", olderr);
|
||||
return LuaUnixSysretErrno(L, "read", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1052,7 +1049,7 @@ static int LuaUnixStat(lua_State *L) {
|
|||
LuaPushStat(L, &st);
|
||||
return 1;
|
||||
} else {
|
||||
return SysretErrno(L, "stat", olderr);
|
||||
return LuaUnixSysretErrno(L, "stat", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1066,7 +1063,7 @@ static int LuaUnixFstat(lua_State *L) {
|
|||
LuaPushStat(L, &st);
|
||||
return 1;
|
||||
} else {
|
||||
return SysretErrno(L, "fstat", olderr);
|
||||
return LuaUnixSysretErrno(L, "fstat", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1140,7 +1137,7 @@ static int LuaUnixSetsockopt(lua_State *L) {
|
|||
if (level == -1 || optname == 0) {
|
||||
NoProtocolOption:
|
||||
enoprotoopt();
|
||||
return SysretErrno(L, "setsockopt", olderr);
|
||||
return LuaUnixSysretErrno(L, "setsockopt", olderr);
|
||||
}
|
||||
if (IsSockoptBool(level, optname)) {
|
||||
// unix.setsockopt(fd:int, level:int, optname:int, value:bool)
|
||||
|
@ -1191,7 +1188,7 @@ static int LuaUnixGetsockopt(lua_State *L) {
|
|||
if (level == -1 || optname == 0) {
|
||||
NoProtocolOption:
|
||||
enoprotoopt();
|
||||
return SysretErrno(L, "setsockopt", olderr);
|
||||
return LuaUnixSysretErrno(L, "setsockopt", olderr);
|
||||
}
|
||||
if (IsSockoptBool(level, optname) || IsSockoptInt(level, optname)) {
|
||||
// unix.getsockopt(fd:int, level:int, optname:int)
|
||||
|
@ -1240,7 +1237,7 @@ static int LuaUnixGetsockopt(lua_State *L) {
|
|||
} else {
|
||||
goto NoProtocolOption;
|
||||
}
|
||||
return SysretErrno(L, "getsockopt", olderr);
|
||||
return LuaUnixSysretErrno(L, "getsockopt", olderr);
|
||||
}
|
||||
|
||||
// unix.socket([family:int[, type:int[, protocol:int]]])
|
||||
|
@ -1266,7 +1263,7 @@ static int LuaUnixSocketpair(lua_State *L) {
|
|||
lua_pushinteger(L, sv[1]);
|
||||
return 2;
|
||||
} else {
|
||||
return SysretErrno(L, "socketpair", olderr);
|
||||
return LuaUnixSysretErrno(L, "socketpair", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1315,7 +1312,7 @@ static int LuaUnixGetname(lua_State *L, const char *name,
|
|||
if (!func(luaL_checkinteger(L, 1), &ss, &addrsize)) {
|
||||
return PushSockaddr(L, &ss);
|
||||
} else {
|
||||
return SysretErrno(L, name, olderr);
|
||||
return LuaUnixSysretErrno(L, name, olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1348,14 +1345,14 @@ static int LuaUnixSiocgifconf(lua_State *L) {
|
|||
data = LuaAllocOrDie(L, (n = 4096));
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
|
||||
free(data);
|
||||
return SysretErrno(L, "siocgifconf", olderr);
|
||||
return LuaUnixSysretErrno(L, "siocgifconf", olderr);
|
||||
}
|
||||
conf.ifc_buf = data;
|
||||
conf.ifc_len = n;
|
||||
if (ioctl(fd, SIOCGIFCONF, &conf) == -1) {
|
||||
close(fd);
|
||||
free(data);
|
||||
return SysretErrno(L, "siocgifconf", olderr);
|
||||
return LuaUnixSysretErrno(L, "siocgifconf", olderr);
|
||||
}
|
||||
lua_newtable(L);
|
||||
i = 0;
|
||||
|
@ -1415,7 +1412,7 @@ static int LuaUnixGethostname(lua_State *L) {
|
|||
enomem();
|
||||
}
|
||||
}
|
||||
return SysretErrno(L, "gethostname", olderr);
|
||||
return LuaUnixSysretErrno(L, "gethostname", olderr);
|
||||
}
|
||||
|
||||
// unix.accept(serverfd:int[, flags:int])
|
||||
|
@ -1435,7 +1432,7 @@ static int LuaUnixAccept(lua_State *L) {
|
|||
lua_pushinteger(L, clientfd);
|
||||
return 1 + PushSockaddr(L, &ss);
|
||||
} else {
|
||||
return SysretErrno(L, "accept", olderr);
|
||||
return LuaUnixSysretErrno(L, "accept", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1458,7 +1455,7 @@ static int LuaUnixPoll(lua_State *L) {
|
|||
++nfds;
|
||||
} else {
|
||||
free(fds);
|
||||
return SysretErrno(L, "poll", olderr);
|
||||
return LuaUnixSysretErrno(L, "poll", olderr);
|
||||
}
|
||||
} else {
|
||||
// ignore non-integer key
|
||||
|
@ -1478,7 +1475,7 @@ static int LuaUnixPoll(lua_State *L) {
|
|||
return 1;
|
||||
} else {
|
||||
free(fds);
|
||||
return SysretErrno(L, "poll", olderr);
|
||||
return LuaUnixSysretErrno(L, "poll", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1508,7 +1505,7 @@ static int LuaUnixRecvfrom(lua_State *L) {
|
|||
return pushed;
|
||||
} else {
|
||||
free(buf);
|
||||
return SysretErrno(L, "recvfrom", olderr);
|
||||
return LuaUnixSysretErrno(L, "recvfrom", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1534,7 +1531,7 @@ static int LuaUnixRecv(lua_State *L) {
|
|||
return 1;
|
||||
} else {
|
||||
free(buf);
|
||||
return SysretErrno(L, "recv", olderr);
|
||||
return LuaUnixSysretErrno(L, "recv", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1591,7 +1588,7 @@ static int LuaUnixSigprocmask(lua_State *L) {
|
|||
LuaPushSigset(L, oldmask);
|
||||
return 1;
|
||||
} else {
|
||||
return SysretErrno(L, "sigprocmask", olderr);
|
||||
return LuaUnixSysretErrno(L, "sigprocmask", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1692,7 +1689,7 @@ static int LuaUnixSigaction(lua_State *L) {
|
|||
LuaPushSigset(L, oldsa.sa_mask);
|
||||
return 3;
|
||||
} else {
|
||||
return SysretErrno(L, "sigaction", olderr);
|
||||
return LuaUnixSysretErrno(L, "sigaction", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1701,7 +1698,7 @@ static int LuaUnixSigaction(lua_State *L) {
|
|||
static int LuaUnixSigsuspend(lua_State *L) {
|
||||
int olderr = errno;
|
||||
sigsuspend(!lua_isnoneornil(L, 1) ? luaL_checkudata(L, 1, "unix.Sigset") : 0);
|
||||
return SysretErrno(L, "sigsuspend", olderr);
|
||||
return LuaUnixSysretErrno(L, "sigsuspend", olderr);
|
||||
}
|
||||
|
||||
// unix.setitimer(which[, intervalsec, intns, valuesec, valuens])
|
||||
|
@ -1727,7 +1724,7 @@ static int LuaUnixSetitimer(lua_State *L) {
|
|||
lua_pushinteger(L, oldit.it_value.tv_usec * 1000);
|
||||
return 4;
|
||||
} else {
|
||||
return SysretErrno(L, "setitimer", olderr);
|
||||
return LuaUnixSysretErrno(L, "setitimer", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1785,7 +1782,7 @@ static dontinline int LuaUnixTime(lua_State *L, const char *call,
|
|||
lua_pushstring(L, tm.tm_zone);
|
||||
return 11;
|
||||
} else {
|
||||
return SysretErrno(L, call, olderr);
|
||||
return LuaUnixSysretErrno(L, call, olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1883,7 +1880,7 @@ static int LuaUnixTiocgwinsz(lua_State *L) {
|
|||
lua_pushinteger(L, ws.ws_col);
|
||||
return 2;
|
||||
} else {
|
||||
return SysretErrno(L, "tiocgwinsz", olderr);
|
||||
return LuaUnixSysretErrno(L, "tiocgwinsz", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2459,7 +2456,7 @@ static int LuaUnixDirFd(lua_State *L) {
|
|||
lua_pushinteger(L, fd);
|
||||
return 1;
|
||||
} else {
|
||||
return SysretErrno(L, "dirfd", olderr);
|
||||
return LuaUnixSysretErrno(L, "dirfd", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2494,7 +2491,7 @@ static int LuaUnixOpendir(lua_State *L) {
|
|||
if ((dir = opendir(luaL_checkstring(L, 1)))) {
|
||||
return ReturnDir(L, dir);
|
||||
} else {
|
||||
return SysretErrno(L, "opendir", olderr);
|
||||
return LuaUnixSysretErrno(L, "opendir", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2507,7 +2504,7 @@ static int LuaUnixFdopendir(lua_State *L) {
|
|||
if ((dir = fdopendir(luaL_checkinteger(L, 1)))) {
|
||||
return ReturnDir(L, dir);
|
||||
} else {
|
||||
return SysretErrno(L, "fdopendir", olderr);
|
||||
return LuaUnixSysretErrno(L, "fdopendir", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
7
third_party/lua/lunix.h
vendored
7
third_party/lua/lunix.h
vendored
|
@ -4,7 +4,14 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct UnixErrno {
|
||||
int errno_;
|
||||
int winerr;
|
||||
const char *call;
|
||||
};
|
||||
|
||||
int LuaUnix(lua_State *);
|
||||
int LuaUnixSysretErrno(lua_State *, const char *, int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -214,8 +214,11 @@ int GetPollMaxFds(void) {
|
|||
}
|
||||
|
||||
void NormalizeFileDescriptors(void) {
|
||||
int i, n, fd;
|
||||
int e, i, n, fd;
|
||||
n = GetPollMaxFds();
|
||||
e = errno;
|
||||
closefrom(3); // more secure if linux 5.9+
|
||||
errno = e;
|
||||
for (i = 0; i < n; ++i) {
|
||||
pfds[i].fd = i;
|
||||
pfds[i].events = POLLIN;
|
||||
|
|
|
@ -1959,6 +1959,96 @@ RE MODULE
|
|||
and re.Regex:search.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
PATH MODULE
|
||||
|
||||
The path module may be used to manipulate unix paths.
|
||||
|
||||
Note that we use unix paths on Windows. For example, if you have a
|
||||
path like C:\foo\bar then it should be /c/foo/bar with redbean. It
|
||||
should also be noted the unix module is more permissive when using
|
||||
Windows paths, where translation to win32 is very light.
|
||||
|
||||
path.dirname(str)
|
||||
└─→ str
|
||||
|
||||
Strips final component of path, e.g.
|
||||
|
||||
path │ dirname
|
||||
───────────────────
|
||||
. │ .
|
||||
.. │ .
|
||||
/ │ /
|
||||
usr │ .
|
||||
/usr/ │ /
|
||||
/usr/lib │ /usr
|
||||
/usr/lib/ │ /usr
|
||||
|
||||
path.basename(path:str)
|
||||
└─→ str
|
||||
|
||||
Returns final component of path, e.g.
|
||||
|
||||
path │ basename
|
||||
─────────────────────
|
||||
. │ .
|
||||
.. │ ..
|
||||
/ │ /
|
||||
usr │ usr
|
||||
/usr/ │ usr
|
||||
/usr/lib │ lib
|
||||
/usr/lib/ │ lib
|
||||
|
||||
path.join(str, ...)
|
||||
└─→ str
|
||||
|
||||
Concatenates path components, e.g.
|
||||
|
||||
x │ y │ joined
|
||||
─────────────────────────────────
|
||||
/ │ / │ /
|
||||
/usr │ lib │ /usr/lib
|
||||
/usr/ │ lib │ /usr/lib
|
||||
/usr/lib │ /lib │ /lib
|
||||
|
||||
You may specify 1+ arguments.
|
||||
|
||||
Specifying no arguments will raise an error. If nil arguments are
|
||||
specified, then they're skipped over. If exclusively nil arguments
|
||||
are passed, then nil is returned. Empty strings behave similarly to
|
||||
nil, but unlike nil may coerce a trailing slash.
|
||||
|
||||
path.exists(path:str)
|
||||
└─→ bool
|
||||
|
||||
Returns true if path exists.
|
||||
|
||||
This function is inclusive of regular files, directories, and
|
||||
special files. Symbolic links are followed are resolved. On error,
|
||||
false is returned.
|
||||
|
||||
path.isfile(path:str)
|
||||
└─→ bool
|
||||
|
||||
Returns true if path exists and is regular file.
|
||||
|
||||
Symbolic links are not followed. On error, false is returned.
|
||||
|
||||
path.isdir(path:str)
|
||||
└─→ bool
|
||||
|
||||
Returns true if path exists and is directory.
|
||||
|
||||
Symbolic links are not followed. On error, false is returned.
|
||||
|
||||
path.islink(path:str)
|
||||
└─→ bool
|
||||
|
||||
Returns true if path exists and is symbolic link.
|
||||
|
||||
Symbolic links are not followed. On error, false is returned.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
MAXMIND MODULE
|
||||
|
||||
|
@ -2220,12 +2310,36 @@ UNIX MODULE
|
|||
|
||||
Closes file descriptor.
|
||||
|
||||
This function should never be called twice for the same file
|
||||
descriptor, regardless of whether or not an error happened. The file
|
||||
descriptor is always gone after close is called. So it technically
|
||||
always succeeds, but that doesn't mean an error should be ignored.
|
||||
For example, on NFS a close failure could indicate data loss.
|
||||
|
||||
Closing does not mean that scheduled i/o operations have been
|
||||
completed. You'd need to use fsync() or fdatasync() beforehand to
|
||||
ensure that. You shouldn't need to do that normally, because our
|
||||
close implementation guarantees a consistent view, since on systems
|
||||
where it isn't guaranteed (like Windows) close will implicitly sync.
|
||||
|
||||
File descriptors are automatically closed on exit().
|
||||
|
||||
Returns `EBADF` if `fd` wasn't valid.
|
||||
|
||||
Returns `EINTR` possibly maybe.
|
||||
|
||||
Returns `EIO` if an i/o error occurred.
|
||||
|
||||
unix.read(fd:int[, bufsiz:str[, offset:int]])
|
||||
├─→ data:str
|
||||
└─→ nil, unix.Errno
|
||||
|
||||
Reads from file descriptor.
|
||||
|
||||
This function returns empty string on end of file. The exception is
|
||||
if `bufsiz` is zero, in which case an empty returned string means
|
||||
the file descriptor works.
|
||||
|
||||
unix.write(fd:int, data:str[, offset:int])
|
||||
├─→ wrotebytes:int
|
||||
└─→ nil, unix.Errno
|
||||
|
@ -3778,14 +3892,66 @@ UNIX MODULE
|
|||
├─→ true
|
||||
└─→ nil, unix.Errno
|
||||
|
||||
Unveil parts of a restricted filesystem view, e.g.
|
||||
Restricts filesystem operations, e.g.
|
||||
|
||||
unix.unveil(".", "r")
|
||||
unix.unveil(nil, nil)
|
||||
unix.unveil(".", "r"); -- current dir + children visible
|
||||
unix.unveil("/etc", "r"); -- make /etc readable too
|
||||
unix.unveil(0, 0); -- commit and lock policy
|
||||
|
||||
This can be used for sandboxing file system access.
|
||||
Unveiling restricts a thread's view of the filesystem to a set of
|
||||
allowed paths with specific privileges.
|
||||
|
||||
Unveil support is a work in progress.
|
||||
Once you start using unveil(), the entire file system is considered
|
||||
hidden. You then specify, by repeatedly calling unveil(), which paths
|
||||
should become unhidden. When you're finished, you call `unveil(0,0)`
|
||||
which commits your policy, after which further use is forbidden, in
|
||||
the current thread, as well as any threads or processes it spawns.
|
||||
|
||||
There are some differences between unveil() on Linux versus OpenBSD.
|
||||
|
||||
1. Build your policy and lock it in one go. On OpenBSD, policies take
|
||||
effect immediately and may evolve as you continue to call unveil()
|
||||
but only in a more restrictive direction. On Linux, nothing will
|
||||
happen until you call `unveil(0,0)` which commits and locks.
|
||||
|
||||
2. Try not to overlap directory trees. On OpenBSD, if directory trees
|
||||
overlap, then the most restrictive policy will be used for a given
|
||||
file. On Linux overlapping may result in a less restrictive policy
|
||||
and possibly even undefined behavior.
|
||||
|
||||
3. OpenBSD and Linux disagree on error codes. On OpenBSD, accessing
|
||||
paths outside of the allowed set raises ENOENT, and accessing ones
|
||||
with incorrect permissions raises EACCES. On Linux, both these
|
||||
cases raise EACCES.
|
||||
|
||||
4. Unlike OpenBSD, Linux does nothing to conceal the existence of
|
||||
paths. Even with an unveil() policy in place, it's still possible
|
||||
to access the metadata of all files using functions like stat()
|
||||
and open(O_PATH), provided you know the path. A sandboxed process
|
||||
can always, for example, determine how many bytes of data are in
|
||||
/etc/passwd, even if the file isn't readable. But it's still not
|
||||
possible to use opendir() and go fishing for paths which weren't
|
||||
previously known.
|
||||
|
||||
This system call is supported natively on OpenBSD and polyfilled on
|
||||
Linux using the Landlock LSM[1].
|
||||
|
||||
`path` is the file or directory to unveil
|
||||
|
||||
`permissions` is a string consisting of zero or more of the
|
||||
following characters:
|
||||
|
||||
- 'r' makes `path` available for read-only path operations,
|
||||
corresponding to the pledge promise "rpath".
|
||||
|
||||
- `w` makes `path` available for write operations, corresponding
|
||||
to the pledge promise "wpath".
|
||||
|
||||
- `x` makes `path` available for execute operations,
|
||||
corresponding to the pledge promises "exec" and "execnative".
|
||||
|
||||
- `c` allows `path` to be created and removed, corresponding to
|
||||
the pledge promise "cpath".
|
||||
|
||||
unix.gmtime(unixts:int)
|
||||
├─→ year,mon,mday,hour,min,sec,gmtoffsec,wday,yday,dst:int,zone:str
|
||||
|
|
166
tool/net/lpath.c
Normal file
166
tool/net/lpath.c
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*-*- 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/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "third_party/lua/lauxlib.h"
|
||||
|
||||
/**
|
||||
* @fileoverview redbean unix path manipulation module
|
||||
*/
|
||||
|
||||
// path.basename(str)
|
||||
// └─→ str
|
||||
static int LuaPathBasename(lua_State *L) {
|
||||
size_t i, n;
|
||||
const char *p;
|
||||
if ((p = luaL_optlstring(L, 1, 0, &n)) && n) {
|
||||
while (n > 1 && p[n - 1] == '/') --n;
|
||||
i = n - 1;
|
||||
while (i && p[i - 1] != '/') --i;
|
||||
lua_pushlstring(L, p + i, n - i);
|
||||
} else {
|
||||
lua_pushlstring(L, ".", 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// path.dirname(str)
|
||||
// └─→ str
|
||||
static int LuaPathDirname(lua_State *L) {
|
||||
size_t n;
|
||||
const char *p;
|
||||
if ((p = luaL_optlstring(L, 1, 0, &n)) && n--) {
|
||||
for (; p[n] == '/'; n--) {
|
||||
if (!n) goto ReturnSlash;
|
||||
}
|
||||
for (; p[n] != '/'; n--) {
|
||||
if (!n) goto ReturnDot;
|
||||
}
|
||||
for (; p[n] == '/'; n--) {
|
||||
if (!n) goto ReturnSlash;
|
||||
}
|
||||
lua_pushlstring(L, p, n + 1);
|
||||
return 1;
|
||||
}
|
||||
ReturnDot:
|
||||
lua_pushlstring(L, ".", 1);
|
||||
return 1;
|
||||
ReturnSlash:
|
||||
lua_pushlstring(L, "/", 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// path.join(str, ...)
|
||||
// └─→ str
|
||||
static int LuaPathJoin(lua_State *L) {
|
||||
int i, n;
|
||||
size_t z;
|
||||
bool gotstr;
|
||||
const char *c;
|
||||
luaL_Buffer b;
|
||||
bool needslash;
|
||||
if ((n = lua_gettop(L))) {
|
||||
luaL_buffinit(L, &b);
|
||||
gotstr = false;
|
||||
needslash = false;
|
||||
for (i = 1; i <= n; ++i) {
|
||||
if (lua_isnoneornil(L, i)) continue;
|
||||
gotstr = true;
|
||||
c = luaL_checklstring(L, i, &z);
|
||||
if (z) {
|
||||
if (c[0] == '/') {
|
||||
luaL_buffsub(&b, luaL_bufflen(&b));
|
||||
} else if (needslash) {
|
||||
luaL_addchar(&b, '/');
|
||||
}
|
||||
luaL_addlstring(&b, c, z);
|
||||
needslash = c[z - 1] != '/';
|
||||
} else if (needslash) {
|
||||
luaL_addchar(&b, '/');
|
||||
needslash = false;
|
||||
}
|
||||
}
|
||||
if (gotstr) {
|
||||
luaL_pushresult(&b);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
luaL_error(L, "missing argument");
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
static int CheckPath(lua_State *L, int type, int flags) {
|
||||
int olderr;
|
||||
struct stat st;
|
||||
const char *path;
|
||||
path = luaL_checkstring(L, 1);
|
||||
olderr = errno;
|
||||
if (fstatat(AT_FDCWD, path, &st, flags) != -1) {
|
||||
lua_pushboolean(L, !type || (st.st_mode & S_IFMT) == type);
|
||||
} else {
|
||||
errno = olderr;
|
||||
lua_pushboolean(L, false);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// path.exists(str)
|
||||
// └─→ bool
|
||||
static int LuaPathExists(lua_State *L) {
|
||||
return CheckPath(L, 0, 0);
|
||||
}
|
||||
|
||||
// path.isfile(str)
|
||||
// └─→ bool
|
||||
static int LuaPathIsfile(lua_State *L) {
|
||||
return CheckPath(L, S_IFREG, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
||||
// path.islink(str)
|
||||
// └─→ bool
|
||||
static int LuaPathIslink(lua_State *L) {
|
||||
return CheckPath(L, S_IFLNK, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
||||
// path.isdir(str)
|
||||
// └─→ bool
|
||||
static int LuaPathIsdir(lua_State *L) {
|
||||
return CheckPath(L, S_IFDIR, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
||||
static const luaL_Reg kLuaPath[] = {
|
||||
{"basename", LuaPathBasename}, //
|
||||
{"dirname", LuaPathDirname}, //
|
||||
{"exists", LuaPathExists}, //
|
||||
{"isdir", LuaPathIsdir}, //
|
||||
{"isfile", LuaPathIsfile}, //
|
||||
{"islink", LuaPathIslink}, //
|
||||
{"join", LuaPathJoin}, //
|
||||
{0}, //
|
||||
};
|
||||
|
||||
int LuaPath(lua_State *L) {
|
||||
luaL_newlib(L, kLuaPath);
|
||||
return 1;
|
||||
}
|
11
tool/net/lpath.h
Normal file
11
tool/net/lpath.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_NET_LPATH_H_
|
||||
#define COSMOPOLITAN_TOOL_NET_LPATH_H_
|
||||
#include "third_party/lua/lauxlib.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int LuaPath(lua_State *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_NET_LPATH_H_ */
|
|
@ -96,6 +96,7 @@ o/$(MODE)/tool/net/redbean.com.dbg: \
|
|||
$(TOOL_NET_DEPS) \
|
||||
o/$(MODE)/tool/net/redbean.o \
|
||||
o/$(MODE)/tool/net/lfuncs.o \
|
||||
o/$(MODE)/tool/net/lpath.o \
|
||||
o/$(MODE)/tool/net/lfinger.o \
|
||||
o/$(MODE)/tool/net/lre.o \
|
||||
o/$(MODE)/tool/net/ljson.o \
|
||||
|
@ -217,6 +218,7 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \
|
|||
$(TOOL_NET_DEPS) \
|
||||
o/$(MODE)/tool/net/redbean.o \
|
||||
o/$(MODE)/tool/net/lfuncs.o \
|
||||
o/$(MODE)/tool/net/lpath.o \
|
||||
o/$(MODE)/tool/net/lfinger.o \
|
||||
o/$(MODE)/tool/net/lre.o \
|
||||
o/$(MODE)/tool/net/ljson.o \
|
||||
|
@ -336,6 +338,7 @@ o/$(MODE)/tool/net/redbean-unsecure.com.dbg: \
|
|||
$(TOOL_NET_DEPS) \
|
||||
o/$(MODE)/tool/net/redbean-unsecure.o \
|
||||
o/$(MODE)/tool/net/lfuncs.o \
|
||||
o/$(MODE)/tool/net/lpath.o \
|
||||
o/$(MODE)/tool/net/lfinger.o \
|
||||
o/$(MODE)/tool/net/lre.o \
|
||||
o/$(MODE)/tool/net/ljson.o \
|
||||
|
|
|
@ -115,6 +115,7 @@
|
|||
#include "tool/net/lfinger.h"
|
||||
#include "tool/net/lfuncs.h"
|
||||
#include "tool/net/ljson.h"
|
||||
#include "tool/net/lpath.h"
|
||||
#include "tool/net/luacheck.h"
|
||||
#include "tool/net/sandbox.h"
|
||||
|
||||
|
@ -5272,6 +5273,7 @@ static const luaL_Reg kLuaLibs[] = {
|
|||
{"lsqlite3", luaopen_lsqlite3}, //
|
||||
{"maxmind", LuaMaxmind}, //
|
||||
{"finger", LuaFinger}, //
|
||||
{"path", LuaPath}, //
|
||||
{"re", LuaRe}, //
|
||||
{"unix", LuaUnix}, //
|
||||
};
|
||||
|
@ -6323,8 +6325,7 @@ static bool HandleMessageActual(void) {
|
|||
if (hasonloglatency) LuaOnLogLatency(reqtime, contime);
|
||||
if (loglatency || LOGGABLE(kLogDebug))
|
||||
LOGF(kLogDebug, "(stat) %`'.*s latency r: %,ldµs c: %,ldµs",
|
||||
msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a,
|
||||
reqtime, contime);
|
||||
msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a, reqtime, contime);
|
||||
}
|
||||
if (!generator) {
|
||||
return TransmitResponse(p);
|
||||
|
|
Loading…
Reference in a new issue