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:
Justine Tunney 2022-04-28 09:42:36 -07:00
parent 9a6bd304a5
commit 47b3274665
212 changed files with 2251 additions and 834 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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]);

View file

@ -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;

View file

@ -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)

View file

@ -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"`.
────────────────────────────────────────────────────────────────────────────────

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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()));

View file

@ -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_ */

View file

@ -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",