mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-27 13:00:28 +00:00
Make improvements
- Add rusage to redbean Lua API - Add more redbean documentation - Add pledge() to redbean Lua API - Polyfill OpenBSD pledge() for Linux - Increase PATH_MAX limit to 1024 characters - Untrack sibling processes after fork() on Windows
This commit is contained in:
parent
9a6bd304a5
commit
47b3274665
212 changed files with 2251 additions and 834 deletions
|
@ -173,7 +173,7 @@ char *shortened;
|
|||
char *cachedcmd;
|
||||
char *colorflag;
|
||||
char *originalcmd;
|
||||
char ccpath[PATH_MAX + 1];
|
||||
char ccpath[PATH_MAX];
|
||||
|
||||
struct stat st;
|
||||
struct Strings env;
|
||||
|
|
|
@ -42,7 +42,7 @@ void CloseCxxFilt(void) {
|
|||
void SpawnCxxFilt(void) {
|
||||
int pipefds[2][2];
|
||||
const char *cxxfilt;
|
||||
char path[PATH_MAX + 1];
|
||||
char path[PATH_MAX];
|
||||
cxxfilt = firstnonnull(emptytonull(getenv("CXXFILT")), "c++filt");
|
||||
if (commandv(cxxfilt, path, sizeof(path))) {
|
||||
pipe2(pipefds[0], O_CLOEXEC);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -200,7 +201,8 @@ int Run(char **paths, size_t count) {
|
|||
rc = RunLengthCode();
|
||||
} else {
|
||||
suffixlen = strlen(suffix_);
|
||||
if (!IsTrustworthy() && strlen(paths[i]) + suffixlen + 1 > PATH_MAX) {
|
||||
if (!IsTrustworthy() &&
|
||||
strlen(paths[i]) + suffixlen >= ARRAYLEN(pathbuf)) {
|
||||
return eoverflow();
|
||||
}
|
||||
p = stpcpy(pathbuf, paths[i]);
|
||||
|
|
|
@ -116,7 +116,7 @@ uint16_t g_sshport;
|
|||
char g_hostname[128];
|
||||
uint16_t g_runitdport;
|
||||
volatile bool alarmed;
|
||||
char g_ssh[PATH_MAX + 1];
|
||||
char g_ssh[PATH_MAX];
|
||||
|
||||
int __sys_execve(const char *, char *const[], char *const[]) hidden;
|
||||
|
||||
|
|
|
@ -46,7 +46,9 @@ function main()
|
|||
end
|
||||
end
|
||||
unix.close(reader)
|
||||
Log(kLogWarn, 'wait() begin')
|
||||
unix.wait(-1)
|
||||
Log(kLogWarn, 'wait() end')
|
||||
unix.sigaction(unix.SIGINT, oldint)
|
||||
unix.sigaction(unix.SIGQUIT, oldquit)
|
||||
unix.sigprocmask(unix.SIG_SETMASK, oldmask)
|
||||
|
|
|
@ -74,8 +74,8 @@ FLAGS
|
|||
-P PATH pid file location
|
||||
-U INT daemon set user id
|
||||
-G INT daemon set group id
|
||||
--strace enables system call tracing
|
||||
--ftrace enables function call tracing
|
||||
--strace enables system call tracing (see also -Z)
|
||||
--ftrace enables function call tracing (see also -f)
|
||||
|
||||
KEYBOARD
|
||||
|
||||
|
@ -303,7 +303,7 @@ REPL
|
|||
changes will propagate into forked clients.
|
||||
|
||||
Your REPL is displayed only when redbean is run as a non-daemon in a
|
||||
UNIX terminal or the Windows 10 command prompt or PowerShell. Since
|
||||
Unix terminal or the Windows 10 command prompt or PowerShell. Since
|
||||
the REPL is a Lua REPL it's not included in a redbean-static builds.
|
||||
|
||||
redbean uses the same keyboard shortcuts as GNU Readline and Emacs.
|
||||
|
@ -341,6 +341,26 @@ REPL
|
|||
setuid privileges, provided it's configured to drop privileges in the
|
||||
most appropriate manner; see the UNIX section for further details.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
LUA ENHANCEMENTS
|
||||
|
||||
We've made some enhancements to the Lua language that should make it
|
||||
more comfortable for C/C++ and Python developers. Some of these
|
||||
|
||||
- redbean supports a printf modulus operator, like Python. For
|
||||
example, you can say `"hello %s" % {"world"}` instead of
|
||||
`string.format("hello %s", "world")`.
|
||||
|
||||
- redbean supports octal (base 8) integer literals. For example
|
||||
`0644 == 420` is the case in redbean, whereas in upstream Lua
|
||||
`0644 == 644` would be the case.
|
||||
|
||||
- redbean supports the GNU syntax for the ASCII ESC character in
|
||||
string literals. For example, `"\e"` is the same as `"\x1b"`.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
GLOBALS
|
||||
|
@ -1239,6 +1259,27 @@ FUNCTIONS
|
|||
the density of information. Cryptographic random should be in
|
||||
the ballpark of 7.9 whereas plaintext will be more like 4.5.
|
||||
|
||||
Benchmark(func[, count[, maxattempts]])
|
||||
└─→ nanos:real, ticks:int, overhead-ticks:int, tries:int
|
||||
|
||||
Performs microbenchmark.
|
||||
|
||||
The first value returned is the average number of nanoseconds that
|
||||
`func` needed to execute. Nanoseconds are computed from RDTSC tick
|
||||
counts, using an approximation that's measured beforehand with the
|
||||
unix.clock_gettime() function.
|
||||
|
||||
The `ticks` result is the canonical average number of clock ticks.
|
||||
|
||||
This subroutine will subtract whatever the overhead happens to be
|
||||
for benchmarking a function that does nothing. This overhead value
|
||||
will be reported in the result.
|
||||
|
||||
`tries` indicates if your microbenchmark needed to be repeated,
|
||||
possibly because your system is under load and the benchmark was
|
||||
preempted by the operating system, or moved to a different core.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
CONSTANTS
|
||||
|
@ -1392,12 +1433,13 @@ MAXMIND MODULE
|
|||
|
||||
For further details, please see maxmind.lua in redbean-demo.com.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
UNIX MODULE
|
||||
|
||||
This module exposes the low-level UNIX system call interface. This
|
||||
module works on all supported platforms, including Windows NT.
|
||||
This module exposes the low-level System Five system call interface.
|
||||
This module works on all supported platforms, including Windows NT.
|
||||
|
||||
unix.open(path:str, flags:int[, mode:int[, dirfd:int]])
|
||||
├─→ fd:int
|
||||
|
@ -1655,8 +1697,8 @@ UNIX MODULE
|
|||
assert(unix.wait())
|
||||
end
|
||||
|
||||
unix.wait([pid:int, options:int])
|
||||
├─→ pid:int, wstatus:int
|
||||
unix.wait([pid:int[, options:int]])
|
||||
├─→ pid:int, wstatus:int, unix.Rusage
|
||||
└─→ nil, unix.Errno
|
||||
|
||||
Waits for subprocess to terminate.
|
||||
|
@ -2095,7 +2137,12 @@ UNIX MODULE
|
|||
├─→ seconds:int, nanos:int
|
||||
└─→ nil, unix.Errno
|
||||
|
||||
Returns nanosecond precision timestamp from the system.
|
||||
Returns nanosecond precision timestamp from system, e.g.
|
||||
|
||||
>: unix.clock_gettime()
|
||||
1651137352 774458779
|
||||
>: Benchmark(unix.clock_gettime)
|
||||
126 393 571 1
|
||||
|
||||
`clock` can be any one of of:
|
||||
|
||||
|
@ -2110,12 +2157,14 @@ UNIX MODULE
|
|||
- `CLOCK_BOOTTIME`: linux and openbsd
|
||||
- `CLOCK_REALTIME_ALARM`: linux-only
|
||||
- `CLOCK_BOOTTIME_ALARM`: linux-only
|
||||
- `CLOCK_TAI`: ilnux-only
|
||||
- `CLOCK_TAI`: linux-only
|
||||
|
||||
Returns `EINVAL` if clock isn't supported on platform.
|
||||
|
||||
This function only fails if `clock` is invalid.
|
||||
|
||||
This function goes fastest on Linux and Windows.
|
||||
|
||||
unix.nanosleep(seconds:int, nanos:int)
|
||||
├─→ remseconds:int, remnanos:int
|
||||
└─→ nil, unix.Errno
|
||||
|
@ -2631,7 +2680,25 @@ UNIX MODULE
|
|||
├─→ soft:int, hard:int
|
||||
└─→ nil, unix.Errno
|
||||
|
||||
Returns information about resource limit.
|
||||
Returns information about resource limits for current process.
|
||||
|
||||
unix.getrusage([who:int])
|
||||
├─→ unix.Rusage
|
||||
└─→ nil, unix.Errno
|
||||
|
||||
Returns information about resource usage for current process, e.g.
|
||||
|
||||
>: unix.getrusage()
|
||||
{utime={0, 53644000}, maxrss=44896, minflt=545, oublock=24, nvcsw=9}
|
||||
|
||||
`who` defaults to `RUSAGE_SELF` and can be any of:
|
||||
|
||||
- `RUSAGE_SELF`: current process
|
||||
- `RUSAGE_THREAD`: current thread
|
||||
- `RUSAGE_CHILDREN`: not supported on Windows NT
|
||||
- `RUSAGE_BOTH`: not supported on non-Linux
|
||||
|
||||
See the unix.Rusage section below for details on returned fields.
|
||||
|
||||
unix.gmtime(unixts:int)
|
||||
├─→ year,mon,mday,hour,min,sec,gmtoffsec,wday,yday,dst:int,zone:str
|
||||
|
@ -2653,7 +2720,10 @@ UNIX MODULE
|
|||
├─→ year,mon,mday,hour,min,sec,gmtoffsec,wday,yday,dst:int,zone:str
|
||||
└─→ nil,unix.Errno
|
||||
|
||||
Breaks down UNIX timestamp into local time numbers.
|
||||
Breaks down UNIX timestamp into local time numbers, e.g.
|
||||
|
||||
>: unix.localtime(unix.clock_gettime())
|
||||
2022 4 28 2 14 22 -25200 4 117 1 "PDT"
|
||||
|
||||
This follows the same API as gmtime() which has further details.
|
||||
|
||||
|
@ -2741,6 +2811,7 @@ UNIX MODULE
|
|||
returned unix.Dir ownership takes ownership of the file descriptor
|
||||
and will close it automatically when garbage collected.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
UNIX DIR OBJECT
|
||||
|
@ -2800,169 +2871,426 @@ UNIX MODULE
|
|||
|
||||
Resets stream back to beginning.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
UNIX RUSAGE OBJECT
|
||||
|
||||
unix.Rusage objects are created by wait() or getrusage(). The
|
||||
following accessor methods are available.
|
||||
|
||||
unix.Rusage:utime()
|
||||
└─→ seconds:int, nanos:int
|
||||
|
||||
Returns amount of CPU consumed in userspace.
|
||||
|
||||
It's always the case that `0 ≤ nanos < 1e9`.
|
||||
|
||||
On Windows NT this is collected from GetProcessTimes().
|
||||
|
||||
unix.Rusage:stime()
|
||||
└─→ seconds:int, nanos:int
|
||||
|
||||
Returns amount of CPU consumed in kernelspace.
|
||||
|
||||
It's always the case that `0 ≤ 𝑥 < 1e9`.
|
||||
|
||||
On Windows NT this is collected from GetProcessTimes().
|
||||
|
||||
unix.Rusage:maxrss()
|
||||
└─→ kilobytes:int
|
||||
|
||||
Returns amount of physical memory used at peak consumption.
|
||||
|
||||
On Windows NT this is collected from
|
||||
NtProcessMemoryCountersEx::PeakWorkingSetSize / 1024.
|
||||
|
||||
unid.Rusage:idrss()
|
||||
└─→ integralkilobytes:int
|
||||
|
||||
Returns integral private memory consumption w.r.t. scheduled ticks.
|
||||
|
||||
If you chart memory usage over the lifetime of your process, then
|
||||
this would be the space filled in beneath the chart. The frequency
|
||||
of kernel scheduling is defined as unix.CLK_TCK. Each time a tick
|
||||
happens, the kernel samples your process's memory usage, by adding
|
||||
it to this value. You can derive the average consumption from this
|
||||
value by computing how many ticks are in `utime + stime`.
|
||||
|
||||
Currently only available on FreeBSD and NetBSD.
|
||||
|
||||
unix.Rusage:ixrss()
|
||||
└─→ integralkilobytes:int
|
||||
|
||||
Returns integral shared memory consumption w.r.t. scheduled ticks.
|
||||
|
||||
If you chart memory usage over the lifetime of your process, then
|
||||
this would be the space filled in beneath the chart. The frequency
|
||||
of kernel scheduling is defined as unix.CLK_TCK. Each time a tick
|
||||
happens, the kernel samples your process's memory usage, by adding
|
||||
it to this value. You can derive the average consumption from this
|
||||
value by computing how many ticks are in `utime + stime`.
|
||||
|
||||
Currently only available on FreeBSD and NetBSD.
|
||||
|
||||
unis.Rusage:isrss()
|
||||
└─→ integralkilobytes:int
|
||||
|
||||
Returns integral stack memory consumption w.r.t. scheduled ticks.
|
||||
|
||||
If you chart memory usage over the lifetime of your process, then
|
||||
this would be the space filled in beneath the chart. The frequency
|
||||
of kernel scheduling is defined as unix.CLK_TCK. Each time a tick
|
||||
happens, the kernel samples your process's memory usage, by adding
|
||||
it to this value. You can derive the average consumption from this
|
||||
value by computing how many ticks are in `utime + stime`.
|
||||
|
||||
This is only applicable to redbean if its built with MODE=tiny,
|
||||
because redbean likes to allocate its own deterministic stack.
|
||||
|
||||
Currently only available on FreeBSD and NetBSD.
|
||||
|
||||
unix.Rusage:minflt()
|
||||
└─→ count:int
|
||||
|
||||
Returns number of minor page faults.
|
||||
|
||||
This number indicates how many times redbean was preempted by the
|
||||
kernel to memcpy() a 4096-byte page. This is one of the tradeoffs
|
||||
fork() entails. This number is usually tinier, when your binaries
|
||||
are tinier.
|
||||
|
||||
Not available on Windows NT.
|
||||
|
||||
unix.Rusage:majflt()
|
||||
└─→ count:int
|
||||
|
||||
Returns number of major page faults.
|
||||
|
||||
This number indicates how many times redbean was preempted by the
|
||||
kernel to perform i/o. For example, you might have used mmap() to
|
||||
load a large file into memory lazily.
|
||||
|
||||
On Windows NT this is NtProcessMemoryCountersEx::PageFaultCount.
|
||||
|
||||
unix.Rusage:nswap()
|
||||
└─→ count:int
|
||||
|
||||
Returns number of swap operations.
|
||||
|
||||
Operating systems like to reserve hard disk space to back their RAM
|
||||
guarantees, like using a gold standard for fiat currency. When your
|
||||
system is under heavy memory load, swap operations may happen while
|
||||
redbean is working. This number keeps track of them.
|
||||
|
||||
Not available on Linux, Windows NT.
|
||||
|
||||
unix.Rusage:inblock()
|
||||
└─→ count:int
|
||||
|
||||
Returns number of times filesystem had to perform input.
|
||||
|
||||
On Windows NT this is NtIoCounters::ReadOperationCount.
|
||||
|
||||
unix.Rusage:oublock()
|
||||
└─→ count:int
|
||||
|
||||
Returns number of times filesystem had to perform output.
|
||||
|
||||
On Windows NT this is NtIoCounters::WriteOperationCount.
|
||||
|
||||
unix.Rusage:msgsnd()
|
||||
└─→ count:int
|
||||
|
||||
Returns count of ipc messages sent.
|
||||
|
||||
Not available on Linux, Windows NT.
|
||||
|
||||
unix.Rusage:msgrcv()
|
||||
└─→ count:int
|
||||
|
||||
Returns count of ipc messages received.
|
||||
|
||||
Not available on Linux, Windows NT.
|
||||
|
||||
unix.Rusage:nsignals()
|
||||
└─→ count:int
|
||||
|
||||
Returns number of signals received.
|
||||
|
||||
Not available on Linux.
|
||||
|
||||
unix.Rusage:nvcsw()
|
||||
└─→ count:int
|
||||
|
||||
Returns number of voluntary context switches.
|
||||
|
||||
This number is a good thing. It means your redbean finished its work
|
||||
quickly enough within a time slice that it was able to give back the
|
||||
remaining time to the system.
|
||||
|
||||
unix.Rusage:nivcsw()
|
||||
└─→ count:int
|
||||
|
||||
Returns number of non-consensual context switches.
|
||||
|
||||
This number is a bad thing. It means your redbean was preempted by a
|
||||
higher priority process after failing to finish its work, within the
|
||||
allotted time slice.
|
||||
|
||||
sandbox.pledge([promises:str])
|
||||
├─→ true
|
||||
└─→ nil, unix.Errno
|
||||
|
||||
Restrict system operations.
|
||||
|
||||
This can be used to sandbox your redbean workers. It allows finer
|
||||
customization compared to the `-S` flag.
|
||||
|
||||
By default exit and exit_group are always allowed. This is useful
|
||||
for processes that perform pure computation and interface with the
|
||||
parent via shared memory.
|
||||
|
||||
Currently only available on OpenBSD and Linux. On Linux, the default
|
||||
action when your policy is violated is to return `EPERM`. On OpenBSD
|
||||
the kernel will kill the process.
|
||||
|
||||
`promises` is a string that may include any of the following groups
|
||||
delimited by spaces.
|
||||
|
||||
stdio
|
||||
|
||||
Allows clock_getres, clock_gettime, close, dup, dup2, dup3,
|
||||
fchdir, fstat, fsync, ftruncate, getdents, getegid, getrandom,
|
||||
geteuid, getgid, getgroups, getitimer, getpgid, getpgrp, getpid,
|
||||
getppid, getresgid, getresuid, getrlimit, getsid, gettimeofday,
|
||||
getuid, lseek, madvise, brk, mmap, mprotect, munmap, nanosleep,
|
||||
pipe, pipe2, poll, pread, preadv, pwrite, pwritev, read, readv,
|
||||
recvfrom, recvmsg, select, sendmsg, sendto, setitimer, shutdown,
|
||||
sigaction, sigprocmask, sigreturn, socketpair, umask, wait4,
|
||||
write, writev.
|
||||
|
||||
rpath
|
||||
|
||||
Allows chdir, getcwd, openat, fstatat, faccessat, readlinkat,
|
||||
lstat, chmod, fchmod, fchmodat, chown, fchown, fchownat, fstat.
|
||||
|
||||
wpath
|
||||
|
||||
Allows getcwd, openat, fstatat, faccessat, readlinkat, lstat,
|
||||
chmod, fchmod, fchmodat, chown, fchown, fchownat, fstat.
|
||||
|
||||
cpath
|
||||
|
||||
Allows rename, renameat, link, linkat, symlink, symlinkat, unlink,
|
||||
unlinkat, mkdir, mkdirat, rmdir.
|
||||
|
||||
dpath
|
||||
|
||||
Allows mknod
|
||||
|
||||
tmppath
|
||||
|
||||
Allows lstat, chmod, chown, unlink, fstat.
|
||||
|
||||
inet
|
||||
|
||||
Allows socket, listen, bind, connect, accept4, accept,
|
||||
getpeername, getsockname, setsockopt, getsockopt.
|
||||
|
||||
fattr
|
||||
|
||||
Allows utimes, utimensat, chmod, fchmod, fchmodat, chown,
|
||||
fchownat, lchown, fchown, utimes.
|
||||
|
||||
unix
|
||||
|
||||
Allows socket, listen, bind, connect, accept4, accept,
|
||||
getpeername, getsockname, setsockopt, getsockopt.
|
||||
|
||||
dns
|
||||
|
||||
Allows sendto, recvfrom, socket, connect.
|
||||
|
||||
proc
|
||||
|
||||
Allows fork, vfork, kill, getpriority, setpriority, setrlimit,
|
||||
setpgid, setsid.
|
||||
|
||||
exec
|
||||
|
||||
Allows execve.
|
||||
|
||||
id
|
||||
|
||||
Allows setuid, setreuid, setresuid, setgid, setregid, setresgid,
|
||||
setgroups, setrlimit, getpriority, setpriority.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
UNIX STAT OBJECT
|
||||
|
||||
unix.Stat objects are created by stat() or fstat(). The following
|
||||
methods are available:
|
||||
accessor methods are available.
|
||||
|
||||
unix.Stat:size()
|
||||
└─→ bytes:int
|
||||
unix.Stat:size()
|
||||
└─→ bytes:int
|
||||
|
||||
Size of file in bytes.
|
||||
Size of file in bytes.
|
||||
|
||||
unix.Stat:mode()
|
||||
└─→ mode:int
|
||||
unix.Stat:mode()
|
||||
└─→ mode:int
|
||||
|
||||
Contains file type and permissions.
|
||||
Contains file type and permissions.
|
||||
|
||||
For example, `0010644` is what you might see for a file and
|
||||
`0040755` is what you might see for a directory.
|
||||
For example, `0010644` is what you might see for a file and
|
||||
`0040755` is what you might see for a directory.
|
||||
|
||||
To determine the file type:
|
||||
To determine the file type:
|
||||
|
||||
- `(st:mode() & 0170000) == 0010000` means fifo or pipe
|
||||
- `(st:mode() & 0170000) == 0020000` means character device
|
||||
- `(st:mode() & 0170000) == 0040000` means directory
|
||||
- `(st:mode() & 0170000) == 0060000` means block device
|
||||
- `(st:mode() & 0170000) == 0100000` means regular file
|
||||
- `(st:mode() & 0170000) == 0120000` means symbolic link
|
||||
- `(st:mode() & 0170000) == 0140000` means socket
|
||||
- `(st:mode() & 0170000) == 0010000` means fifo or pipe
|
||||
- `(st:mode() & 0170000) == 0020000` means character device
|
||||
- `(st:mode() & 0170000) == 0040000` means directory
|
||||
- `(st:mode() & 0170000) == 0060000` means block device
|
||||
- `(st:mode() & 0170000) == 0100000` means regular file
|
||||
- `(st:mode() & 0170000) == 0120000` means symbolic link
|
||||
- `(st:mode() & 0170000) == 0140000` means socket
|
||||
|
||||
unix.Stat:uid()
|
||||
└─→ uid:int
|
||||
unix.Stat:uid()
|
||||
└─→ uid:int
|
||||
|
||||
User ID of file owner.
|
||||
User ID of file owner.
|
||||
|
||||
unix.Stat:gid()
|
||||
└─→ gid:int
|
||||
unix.Stat:gid()
|
||||
└─→ gid:int
|
||||
|
||||
Group ID of file owner.
|
||||
Group ID of file owner.
|
||||
|
||||
unix.Stat:birthtim()
|
||||
└─→ unixts:int, nanos:int
|
||||
unix.Stat:birthtim()
|
||||
└─→ unixts:int, nanos:int
|
||||
|
||||
File birth time.
|
||||
File birth time.
|
||||
|
||||
This field should be accurate on Apple, Windows, and BSDs. On Linux
|
||||
this is the mimimum of atim/mtim/ctim. On Windows NT nanos is only
|
||||
accurate to hectonanoseconds.
|
||||
This field should be accurate on Apple, Windows, and BSDs. On Linux
|
||||
this is the mimimum of atim/mtim/ctim. On Windows NT nanos is only
|
||||
accurate to hectonanoseconds.
|
||||
|
||||
Here's an example of how you might print a file timestamp:
|
||||
Here's an example of how you might print a file timestamp:
|
||||
|
||||
st = assert(unix.stat('/etc/passwd'))
|
||||
unixts, nanos = st:birthtim()
|
||||
year,mon,mday,hour,min,sec,gmtoffsec = unix.localtime(unixts)
|
||||
Write('%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.9d%+.2d%.2d % {
|
||||
year, mon, mday, hour, min, sec, nanos,
|
||||
gmtoffsec / (60 * 60), math.abs(gmtoffsec) % 60})
|
||||
st = assert(unix.stat('/etc/passwd'))
|
||||
unixts, nanos = st:birthtim()
|
||||
year,mon,mday,hour,min,sec,gmtoffsec = unix.localtime(unixts)
|
||||
Write('%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.9d%+.2d%.2d % {
|
||||
year, mon, mday, hour, min, sec, nanos,
|
||||
gmtoffsec / (60 * 60), math.abs(gmtoffsec) % 60})
|
||||
|
||||
unix.Stat:mtim()
|
||||
└─→ unixts:int, nanos:int
|
||||
unix.Stat:mtim()
|
||||
└─→ unixts:int, nanos:int
|
||||
|
||||
Last modified time.
|
||||
Last modified time.
|
||||
|
||||
unix.Stat:atim()
|
||||
└─→ unixts:int, nanos:int
|
||||
unix.Stat:atim()
|
||||
└─→ unixts:int, nanos:int
|
||||
|
||||
Last access time.
|
||||
Last access time.
|
||||
|
||||
Please note that file systems are sometimes mounted with `noatime`
|
||||
out of concern for i/o performance. Linux also provides `O_NOATIME`
|
||||
as an option for open().
|
||||
Please note that file systems are sometimes mounted with `noatime`
|
||||
out of concern for i/o performance. Linux also provides `O_NOATIME`
|
||||
as an option for open().
|
||||
|
||||
On Windows NT this is the same as birth time.
|
||||
On Windows NT this is the same as birth time.
|
||||
|
||||
unix.Stat:ctim()
|
||||
└─→ unixts:int, nanos:int
|
||||
unix.Stat:ctim()
|
||||
└─→ unixts:int, nanos:int
|
||||
|
||||
Complicated time.
|
||||
Complicated time.
|
||||
|
||||
Means time file status was last changed on UNIX.
|
||||
Means time file status was last changed on UNIX.
|
||||
|
||||
On Windows NT this is the same as birth time.
|
||||
On Windows NT this is the same as birth time.
|
||||
|
||||
unix.Stat:blocks()
|
||||
└─→ count512:int
|
||||
unix.Stat:blocks()
|
||||
└─→ count512:int
|
||||
|
||||
Number of 512-byte blocks used by storage medium.
|
||||
Number of 512-byte blocks used by storage medium.
|
||||
|
||||
This provides some indication of how much physical storage a file
|
||||
actually consumes. For example, for small file systems, your system
|
||||
might report this number as being 8, which means 4096 bytes.
|
||||
This provides some indication of how much physical storage a file
|
||||
actually consumes. For example, for small file systems, your system
|
||||
might report this number as being 8, which means 4096 bytes.
|
||||
|
||||
On Windows NT, if `O_COMPRESSED` is used for a file, then this
|
||||
number will reflect the size *after* compression. you can use:
|
||||
On Windows NT, if `O_COMPRESSED` is used for a file, then this
|
||||
number will reflect the size *after* compression. you can use:
|
||||
|
||||
st = assert(unix.stat("moby.txt"))
|
||||
print('file size is %d bytes' % {st:size()})
|
||||
print('file takes up %d bytes of space' % {st:blocks() * 512})
|
||||
if GetHostOs() == 'WINDOWS' and st:flags() & 0x800 then
|
||||
print('thanks to file system compression')
|
||||
end
|
||||
st = assert(unix.stat("moby.txt"))
|
||||
print('file size is %d bytes' % {st:size()})
|
||||
print('file takes up %d bytes of space' % {st:blocks() * 512})
|
||||
if GetHostOs() == 'WINDOWS' and st:flags() & 0x800 then
|
||||
print('thanks to file system compression')
|
||||
end
|
||||
|
||||
To tell whether or not compression is being used on a file,
|
||||
To tell whether or not compression is being used on a file,
|
||||
|
||||
unix.Stat:blksize()
|
||||
└─→ bytes:int
|
||||
unix.Stat:blksize()
|
||||
└─→ bytes:int
|
||||
|
||||
Block size that underlying device uses.
|
||||
Block size that underlying device uses.
|
||||
|
||||
This field might be of assistance in computing optimal i/o sizes.
|
||||
This field might be of assistance in computing optimal i/o sizes.
|
||||
|
||||
Please note this field has no relationship to blocks, as the latter
|
||||
is fixed at a 512 byte size.
|
||||
Please note this field has no relationship to blocks, as the latter
|
||||
is fixed at a 512 byte size.
|
||||
|
||||
unix.Stat:ino()
|
||||
└─→ inode:int
|
||||
unix.Stat:ino()
|
||||
└─→ inode:int
|
||||
|
||||
Inode number.
|
||||
Inode number.
|
||||
|
||||
This can be used to detect some other process used rename() to swap
|
||||
out a file underneath you, so you can do a refresh. redbean does it
|
||||
during each main process heartbeat for its own use cases.
|
||||
This can be used to detect some other process used rename() to swap
|
||||
out a file underneath you, so you can do a refresh. redbean does it
|
||||
during each main process heartbeat for its own use cases.
|
||||
|
||||
On Windows NT this is set to NtByHandleFileInformation::FileIndex.
|
||||
On Windows NT this is set to NtByHandleFileInformation::FileIndex.
|
||||
|
||||
unix.Stat:dev()
|
||||
└─→ dev:int
|
||||
unix.Stat:dev()
|
||||
└─→ dev:int
|
||||
|
||||
ID of device containing file.
|
||||
ID of device containing file.
|
||||
|
||||
On Windows NT this is set to
|
||||
NtByHandleFileInformation::VolumeSerialNumber.
|
||||
On Windows NT this is set to
|
||||
NtByHandleFileInformation::VolumeSerialNumber.
|
||||
|
||||
unix.Stat:rdev()
|
||||
└─→ rdev:int
|
||||
unix.Stat:rdev()
|
||||
└─→ rdev:int
|
||||
|
||||
Information about device type.
|
||||
Information about device type.
|
||||
|
||||
This value may be set to 0 or -1 for files that aren't devices,
|
||||
depending on the operating system. unix.major() and unix.minor()
|
||||
may be used to extract the device numbers.
|
||||
|
||||
This value may be set to 0 or -1 for files that aren't devices,
|
||||
depending on the operating system. unix.major() and unix.minor()
|
||||
may be used to extract the device numbers.
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
UNIX SIGSET OBJECT
|
||||
|
||||
The unix.Sigset class defines a mutable bitset that may currently
|
||||
contain 128 entries. See `unix.NSIG` to find out how many signals
|
||||
your operating system actually supports.
|
||||
|
||||
unix.Sigset(sig:int, ...)
|
||||
└─→ unix.Sigset
|
||||
|
||||
Creates new signal bitset.
|
||||
Constructs new signal bitset object.
|
||||
|
||||
unix.Sigset:add(sig:int)
|
||||
|
||||
Adds signal to bitset.
|
||||
|
||||
Invalid signal numbers are ignored.
|
||||
|
||||
unix.Sigset:remove(sig:int)
|
||||
|
||||
Removes signal from bitset.
|
||||
|
||||
Invalid signal numbers are ignored.
|
||||
|
||||
unix.Sigset:fill()
|
||||
|
||||
Sets all bits in signal bitset to true.
|
||||
|
@ -2981,9 +3309,10 @@ UNIX MODULE
|
|||
|
||||
Returns Lua code string that recreates object.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
UNIX SIGNALS
|
||||
UNIX SIGNAL MAGNUMS
|
||||
|
||||
unix.SIGINT
|
||||
Terminal CTRL-C keystroke.
|
||||
|
@ -3068,9 +3397,75 @@ UNIX MODULE
|
|||
unix.SIGPWR
|
||||
Not implemented in most community editions of system five.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
UNIX ERRORS
|
||||
UNIX ERRNO OBJECT
|
||||
|
||||
This object is returned by system calls that fail. We prefer returning
|
||||
an object because for many system calls, an error is part their normal
|
||||
operation. For example, it's often desirable to use the errno() method
|
||||
when performing a read() to check for EINTR.
|
||||
|
||||
unix.Errno:errno()
|
||||
└─→ errno:int
|
||||
|
||||
Returns error magic number.
|
||||
|
||||
The error number is always different for different platforms. On
|
||||
UNIX systems, error numbers occupy the range [1,127] in practice.
|
||||
The System V ABI reserves numbers as high as 4095. On Windows NT,
|
||||
error numbers can go up to 65535.
|
||||
|
||||
unix.Errno:winerr()
|
||||
└─→ errno:int
|
||||
|
||||
Returns Windows error number.
|
||||
|
||||
On UNIX systems this is always 0. On Windows NT this will normally
|
||||
be the same as errno(). Because Windows defines so many error codes,
|
||||
there's oftentimes a multimapping between its error codes and System
|
||||
Five. In those cases, this value reflect the GetLastError() result
|
||||
at the time the error occurred.
|
||||
|
||||
unix.Errno:name()
|
||||
└─→ symbol:str
|
||||
|
||||
Returns string of symbolic name of System Five error code.
|
||||
|
||||
For example, this might return `"EINTR"`.
|
||||
|
||||
unix.Errno:call()
|
||||
└─→ symbol:str
|
||||
|
||||
Returns name of system call that failed.
|
||||
|
||||
For example, this might return `"read"` if read() was what failed.
|
||||
|
||||
unix.Errno:doc()
|
||||
└─→ symbol:str
|
||||
|
||||
Returns English string describing System Five error code.
|
||||
|
||||
For example, this might return `"Interrupted system call"`.
|
||||
|
||||
unix.Errno:__tostring()
|
||||
└─→ str
|
||||
|
||||
Returns verbose string describing error.
|
||||
|
||||
Different information components are delimited by slash.
|
||||
|
||||
For example, this might return `"EINTR/4/Interrupted system call"`.
|
||||
|
||||
On Windows NT this will include additional information about the
|
||||
Windows error (including FormatMessage() output) if the WIN32 error
|
||||
differs from the System Five error code.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
UNIX ERROR MAGNUMS
|
||||
|
||||
unix.EINVAL
|
||||
Invalid argument.
|
||||
|
@ -3177,7 +3572,7 @@ UNIX MODULE
|
|||
|
||||
unix.ENAMETOOLONG
|
||||
Filename too long. Cosmopolitan Libc currently defines `PATH_MAX` as
|
||||
512 characters. On UNIX, that limit should only apply to system call
|
||||
1024 characters. On UNIX that limit should only apply to system call
|
||||
wrappers like realpath(). On Windows NT it's observed by all system
|
||||
calls that accept a pathname.
|
||||
|
||||
|
@ -3509,23 +3904,85 @@ UNIX MODULE
|
|||
no data available; barely in posix; returned by ioctl; very close in
|
||||
spirit to EPIPE?
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
LUA ENHANCEMENTS
|
||||
UNIX MISCELLANEOUS MAGNUMS
|
||||
|
||||
We've made some enhancements to the Lua language that should make it
|
||||
more comfortable for C/C++ and Python developers. Some of these
|
||||
unix.ARG_MAX
|
||||
|
||||
- redbean supports a printf modulus operator, like Python. For
|
||||
example, you can say `"hello %s" % {"world"}` instead of
|
||||
`string.format("hello %s", "world")`.
|
||||
Returns maximum length of arguments for new processes.
|
||||
|
||||
- redbean supports octal (base 8) integer literals. For example
|
||||
`0644 == 420` is the case in redbean, whereas in upstream Lua
|
||||
`0644 == 644` would be the case.
|
||||
This is the character limit when calling execve(). It's the sum of
|
||||
the lengths of `argv` and `envp` including any nul terminators and
|
||||
pointer arrays. For example to see how much your shell `envp` uses
|
||||
|
||||
$ echo $(($(env | wc -c) + 1 + ($(env | wc -l) + 1) * 8))
|
||||
758
|
||||
|
||||
POSIX mandates this be 4096 or higher. On Linux this it's 128*1024.
|
||||
On Windows NT it's 32767*2 because CreateProcess lpCommandLine and
|
||||
environment block are separately constrained to 32,767 characters.
|
||||
Most other systems define this limit much higher.
|
||||
|
||||
unix.BUFSIZ
|
||||
|
||||
Returns default buffer size.
|
||||
|
||||
The UNIX module does not perform any buffering between calls.
|
||||
|
||||
Each time a read or write is performed via the UNIX API your redbean
|
||||
will allocate a buffer of this size by default. This current default
|
||||
would be 4096 across platforms.
|
||||
|
||||
unix.CLK_TCK
|
||||
|
||||
Returns the scheduler frequency.
|
||||
|
||||
This is granularity at which the kernel does work. For example, the
|
||||
Linux kernel normally operates at 100hz so its CLK_TCK will be 100.
|
||||
|
||||
This value is useful for making sense out of unix.Rusage data.
|
||||
|
||||
unix.PIPE_BUF
|
||||
|
||||
Returns maximum size at which pipe i/o is guaranteed atomic.
|
||||
|
||||
POSIX requires this be at least 512. Linux is more generous and
|
||||
allows 4096. On Windows NT this is currently 4096, and it's the
|
||||
parameter redbean passes to CreateNamedPipe().
|
||||
|
||||
unix.PATH_MAX
|
||||
|
||||
Returns maximum length of file path.
|
||||
|
||||
This applies to a complete path being passed to system calls.
|
||||
|
||||
POSIX.1 XSI requires this be at least 1024 so that's what most
|
||||
platforms support. On Windows NT, the limit is technically 260
|
||||
characters. Your redbean works around that by prefixing `//?/`
|
||||
to your paths as needed. On Linux this limit will be 4096, but
|
||||
that won't be the case for functions such as realpath that are
|
||||
implemented at the C library level; however such functions are
|
||||
the exception rather than the norm, and report enametoolong(),
|
||||
when exceeding the libc limit.
|
||||
|
||||
unix.NAME_MAX
|
||||
|
||||
Returns maximum length of file path component.
|
||||
|
||||
POSIX requires this be at least 14. Most operating systems define it
|
||||
as 255. It's a good idea to not exceed 253 since that's the limit on
|
||||
DNS labels.
|
||||
|
||||
unix.NSIG
|
||||
|
||||
Returns maximum number of signals supported by underlying system.
|
||||
|
||||
The limit for unix.Sigset is 128 to support FreeBSD, but most
|
||||
operating systems define this much lower, like 32. This constant
|
||||
reflects the value chosen by the underlying operating system.
|
||||
|
||||
- redbean supports the GNU syntax for the ASCII ESC character in
|
||||
string literals. For example, `"\e"` is the same as `"\x1b"`.
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bench.h"
|
||||
#include "libc/nexgen32e/bsf.h"
|
||||
|
@ -33,6 +34,7 @@
|
|||
#include "libc/nexgen32e/rdtscp.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
|
@ -375,7 +377,7 @@ int LuaGetRandomBytes(lua_State *L) {
|
|||
luaL_argerror(L, 1, "not in range 1..256");
|
||||
unreachable;
|
||||
}
|
||||
p = malloc(n);
|
||||
p = xmalloc(n);
|
||||
CHECK_EQ(n, getrandom(p, n, 0));
|
||||
lua_pushlstring(L, p, n);
|
||||
free(p);
|
||||
|
@ -585,23 +587,30 @@ static int64_t GetInterrupts(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static int DoNothing(lua_State *L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LuaBenchmark(lua_State *L) {
|
||||
double avgticks;
|
||||
uint64_t t1, t2;
|
||||
int64_t interrupts;
|
||||
double avgticks, overhead;
|
||||
int core, iter, count, tries, attempts, maxattempts;
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
count = luaL_optinteger(L, 2, 100);
|
||||
maxattempts = luaL_optinteger(L, 3, 10);
|
||||
lua_gc(L, LUA_GCSTOP);
|
||||
|
||||
for (attempts = 0;;) {
|
||||
lua_gc(L, LUA_GCCOLLECT);
|
||||
sched_yield();
|
||||
core = TSC_AUX_CORE(Rdpid());
|
||||
interrupts = GetInterrupts();
|
||||
for (avgticks = iter = 1; iter < count; ++iter) {
|
||||
t1 = __startbench();
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pushcfunction(L, DoNothing);
|
||||
t1 = __startbench_m();
|
||||
lua_call(L, 0, 0);
|
||||
t2 = __endbench();
|
||||
t2 = __endbench_m();
|
||||
avgticks += 1. / iter * ((int)(t2 - t1) - avgticks);
|
||||
}
|
||||
++attempts;
|
||||
|
@ -611,8 +620,33 @@ int LuaBenchmark(lua_State *L) {
|
|||
return luaL_error(L, "system is under too much load to run benchmark");
|
||||
}
|
||||
}
|
||||
lua_pushnumber(L, ConvertTicksToNanos(avgticks));
|
||||
lua_pushinteger(L, avgticks);
|
||||
overhead = avgticks;
|
||||
|
||||
for (attempts = 0;;) {
|
||||
lua_gc(L, LUA_GCCOLLECT);
|
||||
sched_yield();
|
||||
core = TSC_AUX_CORE(Rdpid());
|
||||
interrupts = GetInterrupts();
|
||||
for (avgticks = iter = 1; iter < count; ++iter) {
|
||||
lua_pushvalue(L, 1);
|
||||
t1 = __startbench_m();
|
||||
lua_call(L, 0, 0);
|
||||
t2 = __endbench_m();
|
||||
avgticks += 1. / iter * ((int)(t2 - t1) - avgticks);
|
||||
}
|
||||
++attempts;
|
||||
if (TSC_AUX_CORE(Rdpid()) == core && GetInterrupts() == interrupts) {
|
||||
break;
|
||||
} else if (attempts >= maxattempts) {
|
||||
return luaL_error(L, "system is under too much load to run benchmark");
|
||||
}
|
||||
}
|
||||
avgticks = MAX(avgticks - overhead, 0);
|
||||
|
||||
lua_gc(L, LUA_GCRESTART);
|
||||
lua_pushinteger(L, ConvertTicksToNanos(round(avgticks)));
|
||||
lua_pushinteger(L, round(avgticks));
|
||||
lua_pushinteger(L, round(overhead));
|
||||
lua_pushinteger(L, attempts);
|
||||
return 3;
|
||||
return 4;
|
||||
}
|
||||
|
|
307
tool/net/lunix.c
307
tool/net/lunix.c
|
@ -26,6 +26,7 @@
|
|||
#include "libc/calls/struct/bpf.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/itimerval.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
|
@ -68,6 +69,7 @@
|
|||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/rlim.h"
|
||||
#include "libc/sysv/consts/rlimit.h"
|
||||
#include "libc/sysv/consts/rusage.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/shut.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
@ -125,6 +127,14 @@ static void *LuaUnixAlloc(lua_State *L, size_t n) {
|
|||
return p;
|
||||
}
|
||||
|
||||
static lua_Integer FixLimit(long x) {
|
||||
if (0 <= x && x < RLIM_INFINITY) {
|
||||
return x;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void LuaPushSigset(lua_State *L, struct sigset set) {
|
||||
struct sigset *sp = lua_newuserdatauv(L, sizeof(*sp), 1);
|
||||
luaL_setmetatable(L, "unix.Sigset");
|
||||
|
@ -137,6 +147,12 @@ static void LuaPushStat(lua_State *L, struct stat *st) {
|
|||
*stp = *st;
|
||||
}
|
||||
|
||||
static void LuaPushRusage(lua_State *L, struct rusage *set) {
|
||||
struct rusage *sp = lua_newuserdatauv(L, sizeof(*sp), 1);
|
||||
luaL_setmetatable(L, "unix.Rusage");
|
||||
*sp = *set;
|
||||
}
|
||||
|
||||
static void LuaSetIntField(lua_State *L, const char *k, lua_Integer v) {
|
||||
lua_pushinteger(L, v);
|
||||
lua_setfield(L, -2, k);
|
||||
|
@ -175,7 +191,7 @@ static int SysretErrno(lua_State *L, const char *call, int olderr) {
|
|||
return 2;
|
||||
}
|
||||
|
||||
static int SysretBool(lua_State *L, const char *call, int olderr, int rc) {
|
||||
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);
|
||||
}
|
||||
|
@ -525,8 +541,8 @@ static int LuaUnixCommandv(lua_State *L) {
|
|||
char *pathbuf, *resolved;
|
||||
olderr = errno;
|
||||
prog = luaL_checkstring(L, 1);
|
||||
if ((pathbuf = LuaUnixAllocRaw(L, PATH_MAX + 1))) {
|
||||
if ((resolved = commandv(prog, pathbuf, PATH_MAX + 1))) {
|
||||
if ((pathbuf = LuaUnixAllocRaw(L, PATH_MAX))) {
|
||||
if ((resolved = commandv(prog, pathbuf, PATH_MAX))) {
|
||||
lua_pushstring(L, resolved);
|
||||
free(pathbuf);
|
||||
return 1;
|
||||
|
@ -587,19 +603,31 @@ static int LuaUnixSetrlimit(lua_State *L) {
|
|||
// ├─→ soft:int, hard:int
|
||||
// └─→ nil, unix.Errno
|
||||
static int LuaUnixGetrlimit(lua_State *L) {
|
||||
int olderr = errno;
|
||||
struct rlimit rlim;
|
||||
int rc, olderr, resource;
|
||||
olderr = errno;
|
||||
resource = luaL_checkinteger(L, 1);
|
||||
if (!getrlimit(resource, &rlim)) {
|
||||
lua_pushinteger(L, rlim.rlim_cur < RLIM_INFINITY ? rlim.rlim_cur : -1);
|
||||
lua_pushinteger(L, rlim.rlim_max < RLIM_INFINITY ? rlim.rlim_max : -1);
|
||||
return 3;
|
||||
if (!getrlimit(luaL_checkinteger(L, 1), &rlim)) {
|
||||
lua_pushinteger(L, FixLimit(rlim.rlim_cur));
|
||||
lua_pushinteger(L, FixLimit(rlim.rlim_max));
|
||||
return 2;
|
||||
} else {
|
||||
return SysretErrno(L, "getrlimit", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
// unix.getrusage([who:int])
|
||||
// ├─→ unix.Rusage
|
||||
// └─→ nil, unix.Errno
|
||||
static int LuaUnixGetrusage(lua_State *L) {
|
||||
struct rusage ru;
|
||||
int olderr = errno;
|
||||
if (!getrusage(luaL_optinteger(L, 1, RUSAGE_SELF), &ru)) {
|
||||
LuaPushRusage(L, &ru);
|
||||
return 1;
|
||||
} else {
|
||||
return SysretErrno(L, "getrusage", olderr);
|
||||
}
|
||||
}
|
||||
|
||||
// unix.kill(pid:int, sig:int)
|
||||
// ├─→ true
|
||||
// └─→ nil, unix.Errno
|
||||
|
@ -621,11 +649,13 @@ static int LuaUnixRaise(lua_State *L) {
|
|||
// ├─→ pid:int, wstatus:int
|
||||
// └─→ nil, unix.Errno
|
||||
static int LuaUnixWait(lua_State *L) {
|
||||
struct rusage ru;
|
||||
int pid, wstatus, olderr = errno;
|
||||
if ((pid = wait4(luaL_optinteger(L, 1, -1), &wstatus,
|
||||
luaL_optinteger(L, 2, 0), 0)) != -1) {
|
||||
luaL_optinteger(L, 2, 0), &ru)) != -1) {
|
||||
lua_pushinteger(L, pid);
|
||||
lua_pushinteger(L, wstatus);
|
||||
LuaPushRusage(L, &ru);
|
||||
return 3;
|
||||
} else {
|
||||
return SysretErrno(L, "wait", olderr);
|
||||
|
@ -1254,6 +1284,14 @@ static int LuaUnixSiocgifconf(lua_State *L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// sandbox.pledge([promises:str])
|
||||
// ├─→ true
|
||||
// └─→ nil, unix.Errno
|
||||
static int LuaUnixPledge(lua_State *L) {
|
||||
int olderr = errno;
|
||||
return SysretBool(L, "pledge", olderr, pledge(luaL_checkstring(L, 1), 0));
|
||||
}
|
||||
|
||||
// unix.gethostname()
|
||||
// ├─→ host:str
|
||||
// └─→ nil, unix.Errno
|
||||
|
@ -1533,7 +1571,7 @@ static int LuaUnixSigaction(lua_State *L) {
|
|||
luaL_argerror(L, 2, "sigaction handler not integer or function");
|
||||
unreachable;
|
||||
}
|
||||
sa.sa_flags = luaL_optinteger(L, 3, SA_RESTART);
|
||||
sa.sa_flags = luaL_optinteger(L, 3, 0);
|
||||
if (!lua_isnoneornil(L, 4)) {
|
||||
mask = luaL_checkudata(L, 4, "unix.Sigset");
|
||||
sa.sa_mask.__bits[0] |= mask->__bits[0];
|
||||
|
@ -1611,34 +1649,16 @@ static int LuaUnixSetitimer(lua_State *L) {
|
|||
}
|
||||
}
|
||||
|
||||
static dontinline int LuaUnixStr(lua_State *L, char *f(int)) {
|
||||
static int LuaUnixStr(lua_State *L, char *f(int)) {
|
||||
return ReturnString(L, f(luaL_checkinteger(L, 1)));
|
||||
}
|
||||
|
||||
// unix.strerdoc(errno:int)
|
||||
// └─→ mediummessage:str
|
||||
static int LuaUnixStrerdoc(lua_State *L) {
|
||||
return LuaUnixStr(L, strerdoc);
|
||||
}
|
||||
|
||||
// unix.strsignal(sig:int)
|
||||
// └─→ symbol:str
|
||||
static int LuaUnixStrsignal(lua_State *L) {
|
||||
return LuaUnixStr(L, strsignal);
|
||||
}
|
||||
|
||||
// unix.strerrno(errno:int)
|
||||
// └─→ symbol:int
|
||||
static int LuaUnixStrerrno(lua_State *L) {
|
||||
return LuaUnixStr(L, strerrno);
|
||||
}
|
||||
|
||||
// unix.strerror(errno:int)
|
||||
// └─→ longmessage:str
|
||||
static int LuaUnixStrerror(lua_State *L) {
|
||||
return LuaUnixStr(L, strerror);
|
||||
}
|
||||
|
||||
// unix.WIFEXITED(wstatus)
|
||||
// └─→ bool
|
||||
static int LuaUnixWifexited(lua_State *L) {
|
||||
|
@ -1780,7 +1800,7 @@ static int LuaUnixStatBlksize(lua_State *L) {
|
|||
return ReturnInteger(L, GetUnixStat(L)->st_blksize);
|
||||
}
|
||||
|
||||
static dontinline int UnixStatTim(lua_State *L, struct timespec *ts) {
|
||||
static dontinline int ReturnTimespec(lua_State *L, struct timespec *ts) {
|
||||
lua_pushinteger(L, ts->tv_sec);
|
||||
lua_pushinteger(L, ts->tv_nsec);
|
||||
return 2;
|
||||
|
@ -1789,25 +1809,25 @@ static dontinline int UnixStatTim(lua_State *L, struct timespec *ts) {
|
|||
// unix.Stat:atim()
|
||||
// └─→ unixts:int, nanos:int
|
||||
static int LuaUnixStatAtim(lua_State *L) {
|
||||
return UnixStatTim(L, &GetUnixStat(L)->st_atim);
|
||||
return ReturnTimespec(L, &GetUnixStat(L)->st_atim);
|
||||
}
|
||||
|
||||
// unix.Stat:mtim()
|
||||
// └─→ unixts:int, nanos:int
|
||||
static int LuaUnixStatMtim(lua_State *L) {
|
||||
return UnixStatTim(L, &GetUnixStat(L)->st_mtim);
|
||||
return ReturnTimespec(L, &GetUnixStat(L)->st_mtim);
|
||||
}
|
||||
|
||||
// unix.Stat:ctim()
|
||||
// └─→ unixts:int, nanos:int
|
||||
static int LuaUnixStatCtim(lua_State *L) {
|
||||
return UnixStatTim(L, &GetUnixStat(L)->st_ctim);
|
||||
return ReturnTimespec(L, &GetUnixStat(L)->st_ctim);
|
||||
}
|
||||
|
||||
// unix.Stat:birthtim()
|
||||
// └─→ unixts:int, nanos:int
|
||||
static int LuaUnixStatBirthtim(lua_State *L) {
|
||||
return UnixStatTim(L, &GetUnixStat(L)->st_birthtim);
|
||||
return ReturnTimespec(L, &GetUnixStat(L)->st_birthtim);
|
||||
}
|
||||
|
||||
// unix.Stat:gen()
|
||||
|
@ -1824,7 +1844,7 @@ static int LuaUnixStatFlags(lua_State *L) {
|
|||
|
||||
static int LuaUnixStatToString(lua_State *L) {
|
||||
struct stat *st = GetUnixStat(L);
|
||||
lua_pushstring(L, "unix.Stat{}");
|
||||
lua_pushstring(L, "unix.Stat()");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1862,6 +1882,180 @@ static void LuaUnixStatObj(lua_State *L) {
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// unix.Rusage object
|
||||
|
||||
static struct rusage *GetUnixRusage(lua_State *L) {
|
||||
return luaL_checkudata(L, 1, "unix.Rusage");
|
||||
}
|
||||
|
||||
static dontinline int ReturnTimeval(lua_State *L, struct timeval *tv) {
|
||||
lua_pushinteger(L, tv->tv_sec);
|
||||
lua_pushinteger(L, tv->tv_usec * 1000);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// unix.Rusage:utime()
|
||||
// └─→ unixts:int, nanos:int
|
||||
static int LuaUnixRusageUtime(lua_State *L) {
|
||||
return ReturnTimeval(L, &GetUnixRusage(L)->ru_utime);
|
||||
}
|
||||
|
||||
// unix.Rusage:stime()
|
||||
// └─→ unixts:int, nanos:int
|
||||
static int LuaUnixRusageStime(lua_State *L) {
|
||||
return ReturnTimeval(L, &GetUnixRusage(L)->ru_stime);
|
||||
}
|
||||
|
||||
// unix.Rusage:maxrss()
|
||||
// └─→ kilobytes:int
|
||||
static int LuaUnixRusageMaxrss(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_maxrss);
|
||||
}
|
||||
|
||||
// unix.Rusage:ixrss()
|
||||
// └─→ integralkilobytes:int
|
||||
static int LuaUnixRusageIxrss(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_ixrss);
|
||||
}
|
||||
|
||||
// unid.Rusage:idrss()
|
||||
// └─→ integralkilobytes:int
|
||||
static int LuaUnixRusageIdrss(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_idrss);
|
||||
}
|
||||
|
||||
// unis.Rusage:isrss()
|
||||
// └─→ integralkilobytes:int
|
||||
static int LuaUnixRusageIsrss(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_isrss);
|
||||
}
|
||||
|
||||
// unix.Rusage:minflt()
|
||||
// └─→ count:int
|
||||
static int LuaUnixRusageMinflt(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_minflt);
|
||||
}
|
||||
|
||||
// unix.Rusage:majflt()
|
||||
// └─→ count:int
|
||||
static int LuaUnixRusageMajflt(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_majflt);
|
||||
}
|
||||
|
||||
// unix.Rusage:nswap()
|
||||
// └─→ count:int
|
||||
static int LuaUnixRusageNswap(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_nswap);
|
||||
}
|
||||
|
||||
// unix.Rusage:inblock()
|
||||
// └─→ count:int
|
||||
static int LuaUnixRusageInblock(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_inblock);
|
||||
}
|
||||
|
||||
// unix.Rusage:oublock()
|
||||
// └─→ count:int
|
||||
static int LuaUnixRusageOublock(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_oublock);
|
||||
}
|
||||
|
||||
// unix.Rusage:msgsnd()
|
||||
// └─→ count:int
|
||||
static int LuaUnixRusageMsgsnd(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_msgsnd);
|
||||
}
|
||||
|
||||
// unix.Rusage:msgrcv()
|
||||
// └─→ count:int
|
||||
static int LuaUnixRusageMsgrcv(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_msgrcv);
|
||||
}
|
||||
|
||||
// unix.Rusage:nsignals()
|
||||
// └─→ count:int
|
||||
static int LuaUnixRusageNsignals(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_nsignals);
|
||||
}
|
||||
|
||||
// unix.Rusage:nvcsw()
|
||||
// └─→ count:int
|
||||
static int LuaUnixRusageNvcsw(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_nvcsw);
|
||||
}
|
||||
|
||||
// unix.Rusage:nivcsw()
|
||||
// └─→ count:int
|
||||
static int LuaUnixRusageNivcsw(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixRusage(L)->ru_nivcsw);
|
||||
}
|
||||
|
||||
static int LuaUnixRusageToString(lua_State *L) {
|
||||
char *b = 0;
|
||||
struct rusage *ru = GetUnixRusage(L);
|
||||
appends(&b, "{");
|
||||
appendf(&b, "%s={%ld, %ld}", "utime", ru->ru_utime.tv_sec,
|
||||
ru->ru_utime.tv_usec * 1000);
|
||||
if (ru->ru_stime.tv_sec || ru->ru_stime.tv_usec) {
|
||||
appendw(&b, READ16LE(", "));
|
||||
appendf(&b, "%s={%ld, %ld}", "stime", ru->ru_stime.tv_sec,
|
||||
ru->ru_stime.tv_usec * 1000);
|
||||
}
|
||||
if (ru->ru_maxrss) appendf(&b, ", %s=%ld", "maxrss", ru->ru_maxrss);
|
||||
if (ru->ru_ixrss) appendf(&b, ", %s=%ld", "ixrss", ru->ru_ixrss);
|
||||
if (ru->ru_idrss) appendf(&b, ", %s=%ld", "idrss", ru->ru_idrss);
|
||||
if (ru->ru_isrss) appendf(&b, ", %s=%ld", "isrss", ru->ru_isrss);
|
||||
if (ru->ru_minflt) appendf(&b, ", %s=%ld", "minflt", ru->ru_minflt);
|
||||
if (ru->ru_majflt) appendf(&b, ", %s=%ld", "majflt", ru->ru_majflt);
|
||||
if (ru->ru_nswap) appendf(&b, ", %s=%ld", "nswap", ru->ru_nswap);
|
||||
if (ru->ru_inblock) appendf(&b, ", %s=%ld", "inblock", ru->ru_inblock);
|
||||
if (ru->ru_oublock) appendf(&b, ", %s=%ld", "oublock", ru->ru_oublock);
|
||||
if (ru->ru_msgsnd) appendf(&b, ", %s=%ld", "msgsnd", ru->ru_msgsnd);
|
||||
if (ru->ru_msgrcv) appendf(&b, ", %s=%ld", "msgrcv", ru->ru_msgrcv);
|
||||
if (ru->ru_nsignals) appendf(&b, ", %s=%ld", "nsignals", ru->ru_nsignals);
|
||||
if (ru->ru_nvcsw) appendf(&b, ", %s=%ld", "nvcsw", ru->ru_nvcsw);
|
||||
if (ru->ru_nivcsw) appendf(&b, ", %s=%ld", "nivcsw", ru->ru_nivcsw);
|
||||
appendw(&b, '}');
|
||||
lua_pushlstring(L, b, appendz(b).i);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg kLuaUnixRusageMeth[] = {
|
||||
{"utime", LuaUnixRusageUtime}, //
|
||||
{"stime", LuaUnixRusageStime}, //
|
||||
{"maxrss", LuaUnixRusageMaxrss}, //
|
||||
{"ixrss", LuaUnixRusageIxrss}, //
|
||||
{"idrss", LuaUnixRusageIdrss}, //
|
||||
{"isrss", LuaUnixRusageIsrss}, //
|
||||
{"minflt", LuaUnixRusageMinflt}, //
|
||||
{"majflt", LuaUnixRusageMajflt}, //
|
||||
{"nswap", LuaUnixRusageNswap}, //
|
||||
{"inblock", LuaUnixRusageInblock}, //
|
||||
{"oublock", LuaUnixRusageOublock}, //
|
||||
{"msgsnd", LuaUnixRusageMsgsnd}, //
|
||||
{"msgrcv", LuaUnixRusageMsgrcv}, //
|
||||
{"nsignals", LuaUnixRusageNsignals}, //
|
||||
{"nvcsw", LuaUnixRusageNvcsw}, //
|
||||
{"nivcsw", LuaUnixRusageNivcsw}, //
|
||||
{0}, //
|
||||
};
|
||||
|
||||
static const luaL_Reg kLuaUnixRusageMeta[] = {
|
||||
{"__repr", LuaUnixRusageToString}, //
|
||||
{"__tostring", LuaUnixRusageToString}, //
|
||||
{0}, //
|
||||
};
|
||||
|
||||
static void LuaUnixRusageObj(lua_State *L) {
|
||||
luaL_newmetatable(L, "unix.Rusage");
|
||||
luaL_setfuncs(L, kLuaUnixRusageMeta, 0);
|
||||
luaL_newlibtable(L, kLuaUnixRusageMeth);
|
||||
luaL_setfuncs(L, kLuaUnixRusageMeth, 0);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// unix.Errno object
|
||||
|
||||
|
@ -1869,6 +2063,8 @@ static struct UnixErrno *GetUnixErrno(lua_State *L) {
|
|||
return luaL_checkudata(L, 1, "unix.Errno");
|
||||
}
|
||||
|
||||
// unix.Errno:errno()
|
||||
// └─→ errno:int
|
||||
static int LuaUnixErrnoErrno(lua_State *L) {
|
||||
return ReturnInteger(L, GetUnixErrno(L)->errno);
|
||||
}
|
||||
|
@ -1885,6 +2081,10 @@ static int LuaUnixErrnoDoc(lua_State *L) {
|
|||
return ReturnString(L, strerdoc(GetUnixErrno(L)->errno));
|
||||
}
|
||||
|
||||
static int LuaUnixErrnoCall(lua_State *L) {
|
||||
return ReturnString(L, GetUnixErrno(L)->call);
|
||||
}
|
||||
|
||||
static int LuaUnixErrnoToString(lua_State *L) {
|
||||
char msg[256];
|
||||
struct UnixErrno *e;
|
||||
|
@ -1899,12 +2099,12 @@ static int LuaUnixErrnoToString(lua_State *L) {
|
|||
}
|
||||
|
||||
static const luaL_Reg kLuaUnixErrnoMeth[] = {
|
||||
{"strerror", LuaUnixErrnoToString}, //
|
||||
{"errno", LuaUnixErrnoErrno}, //
|
||||
{"winerr", LuaUnixErrnoWinerr}, //
|
||||
{"name", LuaUnixErrnoName}, //
|
||||
{"doc", LuaUnixErrnoDoc}, //
|
||||
{0}, //
|
||||
{"errno", LuaUnixErrnoErrno}, //
|
||||
{"winerr", LuaUnixErrnoWinerr}, //
|
||||
{"name", LuaUnixErrnoName}, //
|
||||
{"call", LuaUnixErrnoCall}, //
|
||||
{"doc", LuaUnixErrnoDoc}, //
|
||||
{0}, //
|
||||
};
|
||||
|
||||
static const luaL_Reg kLuaUnixErrnoMeta[] = {
|
||||
|
@ -2231,6 +2431,7 @@ static const luaL_Reg kLuaUnix[] = {
|
|||
{"chroot", LuaUnixChroot}, // change root directory
|
||||
{"setrlimit", LuaUnixSetrlimit}, // prevent cpu memory bombs
|
||||
{"getrlimit", LuaUnixGetrlimit}, // query resource limits
|
||||
{"getrusage", LuaUnixGetrusage}, // query resource usages
|
||||
{"getppid", LuaUnixGetppid}, // get parent process id
|
||||
{"getpgrp", LuaUnixGetpgrp}, // get process group id
|
||||
{"getpgid", LuaUnixGetpgid}, // get process group id of pid
|
||||
|
@ -2272,12 +2473,10 @@ static const luaL_Reg kLuaUnix[] = {
|
|||
{"sigsuspend", LuaUnixSigsuspend}, // wait for signal
|
||||
{"setitimer", LuaUnixSetitimer}, // set alarm clock
|
||||
{"gmtime", LuaUnixGmtime}, // destructure unix timestamp
|
||||
{"pledge", LuaUnixPledge}, // enables syscall sandbox
|
||||
{"localtime", LuaUnixLocaltime}, // localize unix timestamp
|
||||
{"major", LuaUnixMajor}, // extract device info
|
||||
{"minor", LuaUnixMinor}, // extract device info
|
||||
{"strerror", LuaUnixStrerror}, // turn errno into string
|
||||
{"strerrno", LuaUnixStrerrno}, // turn errno into string
|
||||
{"strerdoc", LuaUnixStrerdoc}, // turn errno into string
|
||||
{"strsignal", LuaUnixStrsignal}, // turn signal into string
|
||||
{"WIFEXITED", LuaUnixWifexited}, // gets exit code from wait status
|
||||
{"WEXITSTATUS", LuaUnixWexitstatus}, // gets exit status from wait status
|
||||
|
@ -2300,6 +2499,7 @@ int LuaUnix(lua_State *L) {
|
|||
GL = L;
|
||||
luaL_newlib(L, kLuaUnix);
|
||||
LuaUnixSigsetObj(L);
|
||||
LuaUnixRusageObj(L);
|
||||
LuaUnixErrnoObj(L);
|
||||
LuaUnixStatObj(L);
|
||||
LuaUnixDirObj(L);
|
||||
|
@ -2446,14 +2646,19 @@ int LuaUnix(lua_State *L) {
|
|||
LuaSetIntField(L, "SA_NOCLDWAIT", SA_NOCLDWAIT);
|
||||
LuaSetIntField(L, "SA_NOCLDSTOP", SA_NOCLDSTOP);
|
||||
|
||||
LuaSetIntField(L, "NSIG", NSIG);
|
||||
// getrusage() who
|
||||
LuaSetIntField(L, "RUSAGE_SELF", RUSAGE_SELF);
|
||||
LuaSetIntField(L, "RUSAGE_THREAD", RUSAGE_THREAD);
|
||||
LuaSetIntField(L, "RUSAGE_CHILDREN", RUSAGE_CHILDREN);
|
||||
LuaSetIntField(L, "RUSAGE_BOTH", RUSAGE_BOTH);
|
||||
|
||||
LuaSetIntField(L, "ARG_MAX", __arg_max());
|
||||
LuaSetIntField(L, "BUFSIZ", BUFSIZ);
|
||||
LuaSetIntField(L, "ARG_MAX", ARG_MAX);
|
||||
LuaSetIntField(L, "CLK_TCK", CLK_TCK);
|
||||
LuaSetIntField(L, "PATH_MAX", PATH_MAX);
|
||||
LuaSetIntField(L, "OPEN_MAX", OPEN_MAX);
|
||||
LuaSetIntField(L, "NAME_MAX", _NAME_MAX);
|
||||
LuaSetIntField(L, "NSIG", _NSIG);
|
||||
LuaSetIntField(L, "PATH_MAX", _PATH_MAX);
|
||||
LuaSetIntField(L, "PIPE_BUF", PIPE_BUF);
|
||||
LuaSetIntField(L, "CHILD_MAX", CHILD_MAX);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -2707,8 +2707,8 @@ static void LaunchBrowser(const char *path) {
|
|||
// assign a loopback address if no server or unknown server address
|
||||
if (!servers.n || !addr.s_addr) addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
if (*path != '/') path = gc(xasprintf("/%s", path));
|
||||
if ((prog = commandv(GetSystemUrlLauncherCommand(), gc(malloc(PATH_MAX + 1)),
|
||||
PATH_MAX + 1))) {
|
||||
if ((prog = commandv(GetSystemUrlLauncherCommand(), gc(malloc(PATH_MAX)),
|
||||
PATH_MAX))) {
|
||||
u = gc(xasprintf("http://%s:%d%s", inet_ntoa(addr), port,
|
||||
gc(EscapePath(path, -1, 0))));
|
||||
DEBUGF("(srvr) opening browser with command %`'s %s", prog, u);
|
||||
|
@ -6337,8 +6337,7 @@ static int EnableSandbox(void) {
|
|||
sandbox = &kSandboxOfflineProg;
|
||||
break;
|
||||
}
|
||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != -1 &&
|
||||
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, sandbox) != -1) {
|
||||
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, sandbox) != -1) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
|
@ -6899,6 +6898,11 @@ static void GetOpts(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
void RedBean(int argc, char *argv[]) {
|
||||
if (IsLinux()) {
|
||||
// disable sneak privilege since we don't use them
|
||||
// seccomp will fail later if this fails
|
||||
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
}
|
||||
reader = read;
|
||||
writer = WritevAll;
|
||||
gmtoff = GetGmtOffset((lastrefresh = startserver = nowl()));
|
||||
|
|
|
@ -29,4 +29,7 @@
|
|||
#define _SECCOMP_LOG_AND_RETURN_ERRNO(MAGNUM) \
|
||||
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | ((MAGNUM) & SECCOMP_RET_DATA))
|
||||
|
||||
#define _SECCOMP_LOG_AND_KILL_PROCESS() \
|
||||
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | SECCOMP_RET_KILL_PROCESS)
|
||||
|
||||
#endif /* COSMOPOLITAN_TOOL_NET_SANDBOX_H_ */
|
||||
|
|
|
@ -487,7 +487,7 @@ static void LoadFileViaImageMagick(const char *path, unsigned yn, unsigned xn,
|
|||
unsigned char rgb[yn][YS][xn][XS][CN]) {
|
||||
const char *convert;
|
||||
int pid, ws, pipefds[2];
|
||||
char pathbuf[PATH_MAX + 1], dim[32];
|
||||
char pathbuf[PATH_MAX], dim[32];
|
||||
if (!(convert = commandv("convert", pathbuf, sizeof(pathbuf)))) {
|
||||
fputs("error: `convert` command not found\n"
|
||||
"try: apt-get install imagemagick\n",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue