mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-23 19:10:30 +00:00
Fix bugs and add security features to redbean
- Fix a regression with the previous change that broke redbean - Add chroot(), resource limit, seccomp, and other stuff to redbean - Write lots and lots of documentation - Iron out more system call issues
This commit is contained in:
parent
f1dfa4bdfa
commit
7166679620
182 changed files with 1855 additions and 918 deletions
|
@ -3,7 +3,7 @@
|
|||
|
||||
#define RUNITD_PORT 31337
|
||||
#define RUNITD_MAGIC 0xFEEDABEEu
|
||||
#define RUNITD_TIMEOUT_MS (1000 * 30)
|
||||
#define RUNITD_TIMEOUT_MS (1000 * 60 * 60)
|
||||
|
||||
enum RunitCommand {
|
||||
kRunitExecute,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
SYNOPSIS
|
||||
|
||||
redbean.com [-hvduzmbagf] [-p PORT] [-D DIR] [-- SCRIPTARGS...]
|
||||
redbean.com [-?BVabdfghjkmsuvz] [-p PORT] [-D DIR] [-- SCRIPTARGS...]
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
|
@ -26,7 +26,7 @@ OVERVIEW
|
|||
|
||||
FLAGS
|
||||
|
||||
-h help
|
||||
-h or -? help
|
||||
-d daemonize
|
||||
-u uniprocess
|
||||
-z print port
|
||||
|
@ -39,6 +39,7 @@ FLAGS
|
|||
-E show crash reports to public ips
|
||||
-j enable ssl client verify
|
||||
-k disable ssl fetch verify
|
||||
-Z log worker system calls
|
||||
-f log worker function calls
|
||||
-B only use stronger cryptography
|
||||
-s increase silence [repeatable]
|
||||
|
@ -1184,7 +1185,7 @@ RE MODULE
|
|||
re.NEWLINE
|
||||
Use this flag to change the handling of NEWLINE (\x0a) characters.
|
||||
When this flag is set, (1) a NEWLINE shall not be matched by a "."
|
||||
or any form of a non-matching list, (2) a "^" shall match the
|
||||
or any form of a non-matching list, () a "^" shall match the
|
||||
zero-length string immediately after a NEWLINE (regardless of
|
||||
re.NOTBOL), and (3) a "$" shall match the zero-length string
|
||||
immediately before a NEWLINE (regardless of re.NOTEOL).
|
||||
|
@ -1226,53 +1227,57 @@ MAXMIND MODULE
|
|||
|
||||
UNIX MODULE
|
||||
|
||||
This module exports the best raw system calls from Cosmopolitan Libc.
|
||||
These UNIX APIs are supported across all supported operating systems,
|
||||
and that includes Windows.
|
||||
|
||||
fork exit stat open close seek read write access fcntl chdir chown
|
||||
chmod getcwd kill raise wait pipe dup mkdir rmdir opendir rename
|
||||
link unlink symlink sync fsync fdatasync truncate umask getppid
|
||||
getpgrp getpgid setpgid getsid setsid getpid getuid getgid gettime
|
||||
nanosleep socket socketpair bind listen accept connect recvfrom
|
||||
sendto shutdown getpeername getsockname sigaction sigprocmask
|
||||
strerror
|
||||
|
||||
This module also provides the following magic numbers:
|
||||
|
||||
O_RDONLY O_WRONLY O_RDWR O_ACCMODE O_CREAT O_EXCL O_TRUNC
|
||||
O_CLOEXEC O_APPEND O_TMPFILE O_NOFOLLOW O_SYNC O_ASYNC O_NOCTTY
|
||||
O_NOATIME O_EXEC O_SEARCH O_DSYNC O_RSYNC O_PATH O_VERIFY O_SHLOCK
|
||||
O_EXLOCK O_RANDOM O_SEQUENTIAL O_COMPRESSED O_INDEXED SEEK_SET
|
||||
SEEK_CUR SEEK_END F_GETFD F_SETFD F_GETFL F_SETFL F_UNLCK F_RDLCK
|
||||
F_WRLCK F_SETLK F_SETLKW FD_CLOEXEC R_OK W_OK X_OK F_OK WNOHANG
|
||||
CLOCK_REALTIME CLOCK_MONOTONIC CLOCK_MONOTONIC_RAW
|
||||
CLOCK_REALTIME_COARSE CLOCK_MONOTONIC_COARSE
|
||||
CLOCK_PROCESS_CPUTIME_ID CLOCK_TAI CLOCK_PROF CLOCK_BOOTTIME
|
||||
CLOCK_REALTIME_ALARM CLOCK_BOOTTIME_ALARM AF_UNSPEC AF_UNIX
|
||||
AF_INET SOCK_STREAM SOCK_DGRAM SOCK_CLOEXEC IPPROTO_TCP
|
||||
IPPROTO_UDP SHUT_RD SHUT_WR SHUT_RDWR MSG_WAITALL MSG_DONTROUTE
|
||||
MSG_PEEK MSG_OOB MSG_NOSIGNAL DT_UNKNOWN DT_REG DT_DIR DT_BLK
|
||||
DT_LNK DT_CHR DT_FIFO DT_SOCK AT_FDCWD AT_SYMLINK_NOFOLLOW
|
||||
SIG_BLOCK SIG_UNBLOCK SIG_SETMASK SIG_DFL SIG_IGN
|
||||
|
||||
Please see the Cosmopolitan Libc documentation for further details.
|
||||
There's also a /unix.lua file in redbean-demo.com that provides a
|
||||
glimpse of how these powerful APIs can be used. Here's a synopsis:
|
||||
|
||||
unix.open(path, flags[, mode]) → fd, errno
|
||||
|
||||
Opens file.
|
||||
|
||||
unix.read(fd[, bufsiz, offset]) → data, errno
|
||||
unix.read(fd:int[, bufsiz:int, offset:int]) → data:str, errno:int
|
||||
|
||||
Reads from file descriptor.
|
||||
|
||||
unix.write(fd, data[, offset]) → rc, errno
|
||||
unix.write(fd:int, data[, offset]) → rc:int, errno:int
|
||||
|
||||
Writes to file descriptor.
|
||||
|
||||
unix.close(fd) → rc, errno
|
||||
unix.open(path:str, flags:int[, mode:int]) → fd:int[, errno:int]
|
||||
|
||||
Opens file.
|
||||
|
||||
`flags` should have one of `O_RDONLY`, `O_WRONLY`, or `O_RDWR`.
|
||||
The following values may also be OR'd into `flags`:
|
||||
|
||||
- `O_CREAT`: Create file if it doesn't exist.
|
||||
- `O_TRUNC` Automatic truncate(fd,0) if exists.
|
||||
- `O_CLOEXEC`: Automatic close() upon execve().
|
||||
- `O_EXCL`: Exclusive access. See below.
|
||||
- `O_APPEND`: Open file for append only.
|
||||
- `O_DIRECT` (not supported on Apple and OpenBSD)
|
||||
- `O_DIRECTORY` (hint on UNIX but required on NT)
|
||||
- `O_TMPFILE` (for Linux and Windows only)
|
||||
- `O_NOFOLLOW` (zero on Windows)
|
||||
- `O_DSYNC` (zero on non-Linux/Apple)
|
||||
- `O_RSYNC` (zero on non-Linux/Apple)
|
||||
- `O_PATH` (zero on non-Linux)
|
||||
- `O_VERIFY` (zero on non-FreeBSD)
|
||||
- `O_SHLOCK` (zero on non-BSD)
|
||||
- `O_EXLOCK` (zero on non-BSD)
|
||||
- `O_RANDOM` (zero on non-Windows)
|
||||
- `O_SEQUENTIAL` (zero on non-Windows)
|
||||
- `O_COMPRESSED` (zero on non-Windows)
|
||||
- `O_INDEXED` (zero on non-Windows)
|
||||
|
||||
There are three regular combinations for the above flags:
|
||||
|
||||
- `O_RDONLY`: Opens existing file for reading. If it doesn't
|
||||
exist then nil is returned and errno will be `ENOENT` (or in
|
||||
some other cases `ENOTDIR`).
|
||||
|
||||
- `O_WRONLY|O_CREAT|O_TRUNC`: Creates file. If it already
|
||||
exists, then the existing copy is destroyed and the opened
|
||||
file will start off with a length of zero. This is the
|
||||
behavior of the traditional creat() system call.
|
||||
|
||||
- `O_WRONLY|O_CREAT|O_EXCL`: Create file only if doesn't exist
|
||||
already. If it does exist then `nil` is returned along with
|
||||
`errno` set to `EEXIST`.
|
||||
|
||||
unix.close(fd:int) → rc:int, errno:int
|
||||
|
||||
Closes file descriptor.
|
||||
|
||||
|
@ -1280,14 +1285,15 @@ UNIX MODULE
|
|||
|
||||
Invokes `_Exit(exitcode)` on the process. This will immediately
|
||||
halt the current process. Memory will be freed. File descriptors
|
||||
will be closed. Any open connections it owns will be reset.
|
||||
will be closed. Any open connections it owns will be reset. This
|
||||
function never returns.
|
||||
|
||||
unix.fork() → childpid|0, errno
|
||||
unix.fork() → childpid|0, errno:int
|
||||
|
||||
Creates a new process mitosis style. This returns twice. The
|
||||
parent process gets the nonzero pid. The child gets zero.
|
||||
|
||||
unix.commandv(prog) → path, errno
|
||||
unix.commandv(prog) → path, errno:int
|
||||
|
||||
Performs `$PATH` lookup of executable. We automatically suffix
|
||||
`.com` and `.exe` automatically for all platforms when path
|
||||
|
@ -1309,120 +1315,131 @@ UNIX MODULE
|
|||
The first element in `argv` should be `prog`. This function is
|
||||
normally called after forking.
|
||||
|
||||
unix.access(path, mode) → rc, errno
|
||||
unix.access(path:str, how) → rc:int, errno:int
|
||||
|
||||
Checks if effective user of current process has permission to
|
||||
access file. `mode` can be `R_OK`, `W_OK`, `X_OK`, or `F_OK` to
|
||||
access file. `how` can be `R_OK`, `W_OK`, `X_OK`, or `F_OK` to
|
||||
check for read, write, execute, and existence respectively.
|
||||
|
||||
unix.mkdir(path, mode) → rc, errno
|
||||
unix.mkdir(path:str, mode) → rc:int, errno:int
|
||||
|
||||
Makes directory. `mode` should be octal, e.g. `0755`.
|
||||
|
||||
unix.chdir(path) → rc, errno
|
||||
|
||||
unix.chdir(path:str) → rc:int, errno:int
|
||||
|
||||
Changes current directory to `path`.
|
||||
|
||||
unix.unlink(path) → rc, errno
|
||||
unix.unlink(path:str) → rc:int, errno:int
|
||||
|
||||
Removes file at `path`.
|
||||
|
||||
unix.rmdir(path) → rc, errno
|
||||
unix.rmdir(path:str) → rc:int, errno:int
|
||||
|
||||
Removes empty directory at `path`.
|
||||
|
||||
unix.rename(oldpath, newpath) → rc, errno
|
||||
unix.link(existingpath, newpath) → rc, errno
|
||||
unix.symlink(target, linkpath) → rc, errno
|
||||
unix.chown(path, uid, gid) → rc, errno
|
||||
unix.chmod(path, mode) → rc, errno
|
||||
unix.getcwd(path, mode) → rc, errno
|
||||
unix.chroot(path:str) → rc:int, errno:int
|
||||
|
||||
Changes root directory. Raises `ENOSYS` on Windows.
|
||||
|
||||
unix.dup(oldfd[, newfd[, flags]]) → newfd:int, errno:int
|
||||
|
||||
Duplicates file descriptor. `flags` can have `O_CLOEXEC`.
|
||||
|
||||
unix.pipe([flags]) → reader, writer, errno:int
|
||||
|
||||
Creates fifo which enables communication between processes.
|
||||
Returns two file descriptors: one for reading and one for
|
||||
writing. `flags` can have `O_CLOEXEC`. On error, `reader` and
|
||||
`writer` will be `nil` and `errno` will be set to non-nil.
|
||||
|
||||
unix.rename(oldpath, newpath) → rc:int, errno:int
|
||||
unix.link(existingpath, newpath) → rc:int, errno:int
|
||||
unix.symlink(target, linkpath) → rc:int, errno:int
|
||||
unix.chown(path:str, uid, gid) → rc:int, errno:int
|
||||
unix.chmod(path:str, mode) → rc:int, errno:int
|
||||
unix.getcwd(path:str, mode) → rc:int, errno:int
|
||||
unix.getpid() → pid
|
||||
unix.getppid() → pid
|
||||
unix.kill(pid, sig) → rc, errno
|
||||
unix.raise(sig) → rc, errno
|
||||
unix.wait(pid[, options]) → pid, wstatus, nil, errno
|
||||
unix.fcntl(fd, cmd[, arg]) → rc, errno
|
||||
unix.dup(oldfd[, newfd[, flags]]) → newfd, errno
|
||||
flags can have O_CLOEXEC
|
||||
unix.pipe([flags]) → reader, writer, errno
|
||||
flags can have O_CLOEXEC
|
||||
unix.getsid(pid) → sid, errno
|
||||
unix.getpgrp() → pgid, errno
|
||||
unix.getpgid(pid) → pgid, errno
|
||||
unix.setpgid(pid, pgid) → pgid, errno
|
||||
unix.setsid() → sid, errno
|
||||
unix.getuid() → uid, errno
|
||||
unix.getgid() → gid, errno
|
||||
unix.umask(mask) → rc, errno
|
||||
unix.gettime([clock]) → seconds, nanos, errno
|
||||
unix.nanosleep(seconds, nanos) → remseconds, remnanos, errno
|
||||
unix.sync(fd)
|
||||
unix.fsync(fd) → rc, errno
|
||||
unix.fdatasync(fd) → rc, errno
|
||||
unix.kill(pid, sig) → rc:int, errno:int
|
||||
unix.raise(sig) → rc:int, errno:int
|
||||
unix.wait(pid[, options]) → pid, wstatus, nil, errno:int
|
||||
unix.fcntl(fd:int, cmd[, arg]) → rc:int, errno:int
|
||||
unix.getsid(pid) → sid, errno:int
|
||||
unix.getpgrp() → pgid, errno:int
|
||||
unix.getpgid(pid) → pgid, errno:int
|
||||
unix.setpgid(pid, pgid) → pgid, errno:int
|
||||
unix.setsid() → sid, errno:int
|
||||
unix.getuid() → uid, errno:int
|
||||
unix.getgid() → gid, errno:int
|
||||
unix.umask(mask) → rc:int, errno:int
|
||||
unix.gettime([clock]) → seconds, nanos, errno:int
|
||||
unix.nanosleep(seconds, nanos) → remseconds, remnanos, errno:int
|
||||
unix.sync(fd:int)
|
||||
unix.fsync(fd:int) → rc:int, errno:int
|
||||
unix.fdatasync(fd:int) → rc:int, errno:int
|
||||
|
||||
unix.seek(fd, offset, whence) → newpos, errno
|
||||
unix.seek(fd:int, offset, whence) → newpos, errno:int
|
||||
where whence ∈ {SEEK_SET, SEEK_CUR, SEEK_END}
|
||||
whence defaults to SEEK_SET
|
||||
unix.truncate(path, length) → rc, errno
|
||||
unix.truncate(fd, length) → rc, errno
|
||||
unix.truncate(path:str, length) → rc:int, errno:int
|
||||
unix.truncate(fd:int, length) → rc:int, errno:int
|
||||
|
||||
unix.socket([family[, type[, protocol]]]) → fd, errno
|
||||
unix.socket([family[, type[, protocol]]]) → fd:int[, errno:int]
|
||||
|
||||
`SOCK_CLOEXEC` may be or'd into type
|
||||
`family` defaults to `AF_INET`
|
||||
`type` defaults to `SOCK_STREAM`
|
||||
`protocol` defaults to `IPPROTO_TCP`
|
||||
|
||||
unix.socketpair([family[, type[, protocol]]]) → fd1, fd2, errno
|
||||
unix.socketpair([family[, type[, protocol]]]) → fd1, fd2, errno:int
|
||||
|
||||
`SOCK_CLOEXEC` may be or'd into type
|
||||
`family` defaults to `AF_INET`
|
||||
`type` defaults to `SOCK_STREAM`
|
||||
`protocol` defaults to `IPPROTO_TCP`
|
||||
|
||||
unix.bind(fd, ip, port) → rc, errno
|
||||
unix.bind(fd:int, ip, port) → rc:int, errno:int
|
||||
|
||||
unix.connect(fd, ip, port) → rc, errno
|
||||
unix.connect(fd:int, ip, port) → rc:int, errno:int
|
||||
|
||||
unix.listen(fd[, backlog]) → rc, errno
|
||||
unix.listen(fd:int[, backlog]) → rc:int, errno:int
|
||||
|
||||
unix.getsockname(fd) → ip, port, errno
|
||||
unix.getsockname(fd:int) → ip, port, errno:int
|
||||
|
||||
unix.getpeername(fd) → ip, port, errno
|
||||
unix.getpeername(fd:int) → ip, port, errno:int
|
||||
|
||||
unix.accept(serverfd) → clientfd, ip, port, errno
|
||||
unix.accept(serverfd) → clientfd, ip, port, errno:int
|
||||
|
||||
unix.recv(fd[, bufsiz[, flags]]) → data, errno
|
||||
unix.recv(fd:int[, bufsiz[, flags]]) → data, errno:int
|
||||
|
||||
`flags` can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc.
|
||||
|
||||
unix.recvfrom(fd[, bufsiz[, flags]]) → data, ip, port, errno
|
||||
unix.recvfrom(fd:int[, bufsiz[, flags]]) → data, ip, port, errno:int
|
||||
|
||||
`flags` can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc.
|
||||
|
||||
unix.send(fd, data[, flags]) → sent, errno
|
||||
unix.send(fd:int, data[, flags]) → sent, errno:int
|
||||
|
||||
This is the same as `write` except it has a `flags` argument
|
||||
that's intended for sockets. `flags` can have `MSG_OOB`,
|
||||
`MSG_DONTROUTE`, or `MSG_NOSIGNAL`.
|
||||
|
||||
unix.sendto(fd, data, ip, port[, flags]) → sent, errno
|
||||
unix.sendto(fd:int, data, ip, port[, flags]) → sent, errno:int
|
||||
|
||||
This is useful for sending messages over UDP sockets to specific
|
||||
addresses. The `flags` parameter can have `MSG_OOB`,
|
||||
`MSG_DONTROUTE`, or `MSG_NOSIGNAL`.
|
||||
|
||||
unix.shutdown(fd, how) → rc, errno
|
||||
unix.shutdown(fd:int, how:int) → rc:int, errno:int
|
||||
|
||||
Partially closes socket. `how` can be `SHUT_RD`, `SHUT_WR`, or
|
||||
`SHUT_RDWR`.
|
||||
|
||||
unix.sigprocmask(how[, mask]) → oldmask, errno
|
||||
unix.sigprocmask(how[, mask]) → oldmask, errno:int
|
||||
|
||||
`how` can be `SIG_BLOCK`, `SIG_UNBLOCK`, `SIG_SETMASK`
|
||||
|
||||
unix.sigaction(sig[, handler[, flags[, mask]]]) → handler, flags, mask, errno
|
||||
unix.sigaction(sig[, handler[, flags[, mask]]]) → handler, flags, mask, errno:int
|
||||
|
||||
`handler` can be `SIG_IGN`, `SIG_DFL`, `intptr_t`, or a Lua
|
||||
function. `sig` can be `SIGINT`, `SIGQUIT`, `SIGTERM`, etc.
|
||||
|
@ -1443,7 +1460,7 @@ UNIX MODULE
|
|||
Waits for signal to be delivered.
|
||||
|
||||
unix.setitimer(which[, intsec, intmicros, valsec, valmicros])
|
||||
→ intsec, intns, valsec, valns, errno
|
||||
→ intsec, intns, valsec, valns, errno:int
|
||||
|
||||
Causes `SIGALRM` signals to be generated at some point(s) in the
|
||||
future. The `which` parameter should be `ITIMER_REAL`.
|
||||
|
@ -1474,38 +1491,387 @@ UNIX MODULE
|
|||
Turns platform-specific `sig` code into its name, e.g.
|
||||
`strsignal(9)` always returns `"SIGKILL"`.
|
||||
|
||||
Here's your UnixStat* object.
|
||||
unix.stat(x) → UnixStat*, errno:int
|
||||
|
||||
Gets information about file or directory. `x` may be a file or
|
||||
directory path string, or it may be a file descriptor int that
|
||||
was made by open().
|
||||
|
||||
unix.opendir(path:str) → UnixDir*, errno:int
|
||||
|
||||
Opens directory for listing its contents.
|
||||
|
||||
unix.opendir(fd:int) → UnixDir*, errno:int
|
||||
|
||||
Opens directory for listing its contents, using a file
|
||||
descriptor from `open(path, O_RDONLY|O_DIRECTORY)`.
|
||||
|
||||
UnixDir* Object
|
||||
|
||||
UnixDir:close() → rc:int[, errno:int]
|
||||
|
||||
may be called multiple times
|
||||
called by the garbage collector too
|
||||
|
||||
UnixDir:read() → name:str, kind:int, ino:int, off:int[, errno:int]
|
||||
|
||||
Returns `nil` if there are no more entries. Or error, `nil` will
|
||||
be returned and `errno` will be non-nil.
|
||||
|
||||
`kind` can be `DT_UNKNOWN`, `DT_REG`, `DT_DIR`, `DT_BLK`,
|
||||
`DT_LNK`, `DT_CHR`, `DT_FIFO`, or `DT_SOCK`.
|
||||
|
||||
UnixDir:fd() → fd:int[, errno:int]
|
||||
|
||||
EOPNOTSUPP if using /zip/
|
||||
EOPNOTSUPP if IsWindows()
|
||||
|
||||
UnixDir:tell() → offset:int
|
||||
|
||||
Returns current arbitrary offset into stream.
|
||||
|
||||
UnixDir:rewind()
|
||||
|
||||
Resets stream back to beginning.
|
||||
|
||||
UnixStat* object.
|
||||
|
||||
unix.stat(path) → UnixStat*, errno
|
||||
unix.stat(fd) → UnixStat*, errno
|
||||
UnixStat:size() → bytes:int
|
||||
|
||||
Size of file in bytes.
|
||||
|
||||
UnixStat:mode() → mode:int
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
UnixStat:atim() → secs:int, nanos:int
|
||||
|
||||
Size of file in bytes.
|
||||
|
||||
UnixStat:uid() → int
|
||||
|
||||
User ID of file owner.
|
||||
|
||||
UnixStat:gid() → int
|
||||
|
||||
Group ID of file owner.
|
||||
|
||||
UnixStat:mtim() → secs:int, nanos:int
|
||||
|
||||
Last modified time.
|
||||
|
||||
UnixStat:birthtim() → secs:int, nanos:int
|
||||
|
||||
Creation time. Note that on Linux this is the mimimum of
|
||||
atom/mtim/ctim.
|
||||
|
||||
UnixStat:ctim() → secs:int, nanos:int
|
||||
|
||||
Complicated time. Means time file status was last changed on
|
||||
UNIX. Means creation time on Windows.
|
||||
|
||||
UnixStat:blocks() → int
|
||||
|
||||
Number of blocks used by storage medium.
|
||||
|
||||
UnixStat:blksize() → int
|
||||
|
||||
Block size is usually 4096 for file system files.
|
||||
|
||||
UnixStat:dev() → int
|
||||
UnixStat:ino() → int
|
||||
UnixStat:rdev() → int
|
||||
UnixStat:uid() → int
|
||||
UnixStat:gid() → int
|
||||
UnixStat:atim() → secs:int, nanos:int
|
||||
UnixStat:mtim() → secs:int, nanos:int
|
||||
UnixStat:ctim() → secs:int, nanos:int
|
||||
UnixStat:blocks() → int
|
||||
UnixStat:blksize() → int
|
||||
|
||||
Here's your UnixDir* object.
|
||||
Here are your error numbers:
|
||||
|
||||
- `EINVAL`: Invalid argument. Raised by [pretty much everything].
|
||||
|
||||
- `ENOSYS`: System call not available on this platform. On Windows
|
||||
this is raised by chroot(), setuid(), setgid().
|
||||
|
||||
- `EPERM`: Operation not permitted. Raised by accept(), adjtimex(),
|
||||
arch_prctl(), bdflush(), capget(), chmod(), chown(), chroot(),
|
||||
clock_getres(), copy_file_range(), execve(), fcntl(),
|
||||
get_robust_list(), getdomainname(), getgroups(), gethostname(),
|
||||
getpriority(), getrlimit(), getsid(), gettimeofday(), kill(),
|
||||
link(), mbind(), membarrier(), migrate_pages(), mkdir(), mknod(),
|
||||
mlock(), mmap(), msgctl(), nice(), open(), prctl(), ptrace(),
|
||||
reboot(), rename(), rmdir(), sched_setaffinity(),
|
||||
sched_setattr(), sched_setparam(), sched_setscheduler(),
|
||||
seteuid(), setfsgid(), setfsuid(), setgid(), setpgid(),
|
||||
setresuid(), setreuid(), setsid(), setuid(), setup(), shmget(),
|
||||
sigaltstack(), stime(), swapon(), symlink(), syslog(),
|
||||
timer_create(), timerfd_create(), tkill(), truncate(), u
|
||||
unlink(), utime(), utimensat(), vhangup(), vm86(), write().
|
||||
|
||||
- `ENOENT`: no such file or directory. Raised by access(),
|
||||
alloc_hugepages(), bind(), chdir(), chmod(), chown(), chroot(),
|
||||
clock_getres(), execve(), opendir(), inotify_add_watch(), kcmp(),
|
||||
link(), mkdir(), mknod(), msgget(), open(), readlink(), rename(),
|
||||
rmdir(), semget(), shmget(), stat(), swapon(), symlink(),
|
||||
truncate(), unlink(), utime(), utimensat().
|
||||
|
||||
- `ESRCH`: No such process. Raised by getpriority(), getrlimit(),
|
||||
getsid(), ioprio_set(), kill(), setpgid(), tkill(), utimensat(),
|
||||
|
||||
- `EINTR`: The greatest of all errnos; crucial for building real
|
||||
time reliable software. Raised by accept(), clock_nanosleep(),
|
||||
close(), connect(), dup(), fcntl(), flock(), getrandom(),
|
||||
nanosleep(), open(), pause(), poll(), ptrace(), read(), recv(),
|
||||
select(), send(), sigsuspend(), sigwaitinfo(), truncate(),
|
||||
wait(), write()
|
||||
|
||||
- `EIO`: Raised by access() acct() chdir() chmod() chown() chroot()
|
||||
close() copy_file_range() execve() fallocate() fsync() ioperm()
|
||||
link() madvise() mbind() pciconfig_read() ptrace() read()
|
||||
readlink() sendfile() statfs() symlink() sync_file_range()
|
||||
truncate() unlink() write()
|
||||
|
||||
- `ENXIO`: No such device or address. Raised by lseek(), open(),
|
||||
prctl()
|
||||
|
||||
- `E2BIG`: Argument list too long. Raised by execve(), msgop(),
|
||||
sched_setattr(), semop()
|
||||
|
||||
- `ENOEXEC`: exec format error. Raised by execve(), kexec_load(),
|
||||
uselib()
|
||||
|
||||
- `EBADF`: bad file descriptor; cf. EBADFD. Raised by accept(),
|
||||
access(), bind(), chdir(), chmod(), chown(), close(), connect(),
|
||||
copy_file_range(), dup(), fcntl(), flock(), fsync(), futimesat(),
|
||||
opendir(), getpeername(), getsockname(), getsockopt(),
|
||||
inotify_add_watch(), inotify_rm_watch(), ioctl(), kcmp(),
|
||||
kexec_load(), link(), listen(), llseek(), lseek(), mkdir(),
|
||||
mknod(), mmap(), open(), prctl(), read(), readahead(),
|
||||
readlink(), recv(), rename(), select(), send(), shutdown(),
|
||||
splice(), stat(), symlink(), sync(), sync_file_range(),
|
||||
timerfd_create(), truncate(), unlink(), utimensat(), write(),
|
||||
|
||||
- `ECHILD`: no child process. Raised by wait(), waitpid(),
|
||||
waitid(), wait3(), wait4()
|
||||
|
||||
- `EAGAIN`: resource temporarily unavailable (e.g. SO_RCVTIMEO
|
||||
expired, too many processes, too much memory locked, read or
|
||||
write with O_NONBLOCK needs polling, etc.). Raised by accept(),
|
||||
connect(), eventfd(), fcntl(), fork(), getrandom(), mincore(),
|
||||
mlock(), mmap(), mremap(), msgop(), poll(), read(), select(),
|
||||
send(), setresuid(), setreuid(), setuid(), sigwaitinfo(),
|
||||
splice(), tee(), timer_create(), timerfd_create(), tkill(),
|
||||
write(),
|
||||
|
||||
- `ENOMEM`: We require more vespene gas. Raised by access(),
|
||||
bind(), chdir(), chmod(), chown(), chroot(), clone(),
|
||||
copy_file_range(), create_module(), eventfd(), execve(),
|
||||
fanotify_init(), fork(), getgroups(), getrlimit(),
|
||||
inotify_add_watch(), inotify_init(), ioperm(), kexec_load(),
|
||||
link(), mbind(), memfd_create(), mincore(), mkdir(), mknod(),
|
||||
mlock(), mmap(), mprotect(), mremap(), msgget(), msgop(),
|
||||
msync(), open(), poll(), readlink(), recv(), rename(), rmdir(),
|
||||
select(), semget(), send(), shmget(), sigaltstack(), splice(),
|
||||
stat(), subpage_prot(), swapon(), symlink(), sync_file_range(),
|
||||
tee(), timer_create(), timerfd_create(), unlink().
|
||||
|
||||
- `EACCES`: Permission denied. Raised by access(), bind(), bpf(),
|
||||
chdir(), chmod(), chown(), chroot(), clock_getres(), connect(),
|
||||
execve(), fcntl(), getpriority(), inotify_add_watch(), link(),
|
||||
mkdir(), mknod(), mmap(), mprotect(), msgctl(), msgget(),
|
||||
msgop(), open(), prctl(), ptrace(), readlink(), rename(),
|
||||
rmdir(), semget(), send(), setpgid(), shmget(), socket(), stat(),
|
||||
symlink(), truncate(), unlink(), uselib(), utime(), utimensat(),
|
||||
|
||||
- `ENOTBLK`: Block device required. Raised by umount().
|
||||
|
||||
- `EBUSY`: Device or resource busy. Raised by bdflush(), dup(),
|
||||
fcntl(), msync(), prctl(), ptrace(), rename(),
|
||||
rmdir().
|
||||
|
||||
- `EEXIST`: File exists. Raised by bpf(), create_module(),
|
||||
inotify_add_watch(), link(), mkdir(), mknod(), mmap(), msgget(),
|
||||
open(), rename(), rmdir(), semget(), shmget(), symlink()
|
||||
|
||||
- `EXDEV`: Improper link. Raised by copy_file_range(), link(),
|
||||
rename()
|
||||
|
||||
- `ENODEV`: No such device. Raised by arch_prctl(), eventfd(),
|
||||
mmap(), open(), prctl(), timerfd_create()
|
||||
|
||||
- `ENOTDIR`: Not a directory. This means that a directory component
|
||||
in a supplied path *existed* but wasn't a directory. For example,
|
||||
if you try to `open("foo/bar")` and `foo` is a regular file, then
|
||||
`ENOTDIR` will be returned. Raised by open(), access(), chdir(),
|
||||
chmod(), chown(), chroot(), execve(), fcntl(), futimesat(),
|
||||
inotify_add_watch(), link(), mkdir(), mknod(), opendir(),
|
||||
readlink(), rename(), rmdir(), stat(), symlink(), sysctl(),
|
||||
truncate(), unlink(), utimensat(), bind().
|
||||
|
||||
- `EISDIR`: Is a a directory. Raised by copy_file_range(),
|
||||
execve(), open(), read(), rename(), truncate(), unlink().
|
||||
|
||||
- `ENFILE`: Too many open files in system. Raised by accept(),
|
||||
eventfd(), execve(), inotify_init(), memfd_create(), mmap(),
|
||||
open(), pipe(), shmget(), socket(), socketpair(), swapon(),
|
||||
timerfd_create(), uselib(), userfaultfd().
|
||||
|
||||
- `EMFILE`: Too many open files. Raised by accept(), dup(),
|
||||
eventfd(), execve(), fanotify_init(), fcntl(), inotify_init(),
|
||||
memfd_create(), open(), pipe(), socket(), socketpair(),
|
||||
timerfd_create().
|
||||
|
||||
- `ENOTTY`: Inappropriate i/o control operation. Raised by ioctl().
|
||||
|
||||
- `ETXTBSY`: Won't open executable that's executing in write mode.
|
||||
Raised by access(), copy_file_range(), execve(), mmap(), open(),
|
||||
truncate().
|
||||
|
||||
- `EFBIG`: File too large. Raised by copy_file_range(), open(),
|
||||
truncate(), write().
|
||||
|
||||
- `ENOSPC`: No space left on device. Raised by copy_file_range(),
|
||||
fsync(), inotify_add_watch(), link(), mkdir(), mknod(), msgget(),
|
||||
open(), rename(), semget(), shmget(), symlink(),
|
||||
sync_file_range(), write().
|
||||
|
||||
- `EDQUOT`: Disk quota exceeded. Raised by link(), mkdir(),
|
||||
mknod(), open(), rename(), symlink(), write()
|
||||
|
||||
- `ESPIPE`: Invalid seek. Raised by lseek(), splice(),
|
||||
sync_file_range().
|
||||
|
||||
- `EROFS`: Read-only filesystem. Raised by access(), bind(),
|
||||
chmod(), chown(), link(), mkdir(), mknod(), open(), rename(),
|
||||
rmdir(), symlink(), truncate(), unlink(), utime(), utimensat()
|
||||
|
||||
- `EMLINK`: Too many links; raised by link(), mkdir(), rename()
|
||||
|
||||
- `EPIPE`: Broken pipe. Raised by send(), write().
|
||||
|
||||
- `ERANGE`: Result too large. Raised by prctl(), semop().
|
||||
|
||||
- `EDEADLK`: Resource deadlock avoided. Raised by fcntl().
|
||||
|
||||
- `ENAMETOOLONG`: Filename too long. Raised by access(), bind(),
|
||||
chdir(), chmod(), chown(), chroot(), execve(), gethostname(),
|
||||
inotify_add_watch(), link(), mkdir(), mknod(), open(),
|
||||
readlink(), rename(), rmdir(), stat(), symlink(),
|
||||
truncate(), u unlink(), utimensat()
|
||||
|
||||
- `ENOLCK`: No locks available. Raised by fcntl(), flock().
|
||||
|
||||
- `ENOTEMPTY`: Directory not empty. Raised by rmdir().
|
||||
|
||||
- `ELOOP`: Too many levels of symbolic links. Raised by access(),
|
||||
bind(), chdir(), chmod(), chown(), chroot(), execve(), link(),
|
||||
mkdir(), mknod(), open(), readlink(), rename(), rmdir(), stat(),
|
||||
symlink(), truncate(), unlink(), utimensat().
|
||||
|
||||
- `ENOMSG`: Raised by msgop().
|
||||
|
||||
- `EIDRM`: Identifier removed. Raised by msgctl(), msgget(),
|
||||
msgop(), shmget().
|
||||
|
||||
- `ETIME`: Timer expired; timer expired. Raised by connect().
|
||||
|
||||
- `EPROTO`: Raised by accept(), connect(), socket(), socketpair().
|
||||
|
||||
- `EOVERFLOW`: Raised by copy_file_range(), fanotify_init(),
|
||||
lseek(), mmap(), open(), stat(), statfs()
|
||||
|
||||
- `ENOTSOCK`: Not a socket. Raised by accept(), bind(),
|
||||
connect(), getpeername(), getsockname(), getsockopt(),
|
||||
listen(), recv(), send(), shutdown().
|
||||
|
||||
- `EDESTADDRREQ`: Destination address required. Raised by send(),
|
||||
write().
|
||||
|
||||
- `EMSGSIZE`: Message too long. Raised by send().
|
||||
|
||||
- `EPROTOTYPE`: Protocol wrong type for socket. Raised by
|
||||
connect().
|
||||
|
||||
- `ENOPROTOOPT`: Protocol not available. Raised by getsockopt(),
|
||||
accept().
|
||||
|
||||
- `EPROTONOSUPPORT`: Protocol not supported. Raised by socket(),
|
||||
socketpair().
|
||||
|
||||
- `ESOCKTNOSUPPORT`: Socket type not supported.
|
||||
|
||||
- `ENOTSUP`: Operation not supported. Raised by chmod(),
|
||||
clock_getres(), clock_nanosleep(), timer_create()
|
||||
|
||||
- `EOPNOTSUPP`: Socket operation not supported. Raised by accept(),
|
||||
listen(), mmap(), prctl(), readv(), send(), socketpair(),
|
||||
|
||||
- `EPFNOSUPPORT`: protocol family not supported
|
||||
|
||||
- `EAFNOSUPPORT`: address family not supported. Raised by
|
||||
connect(), socket(), socketpair()
|
||||
|
||||
- `EADDRINUSE`: address already in use. Raised by bind(),
|
||||
connect(), listen()
|
||||
|
||||
- `EADDRNOTAVAIL`: address not available. Raised by bind(),
|
||||
connect().
|
||||
|
||||
- `ENETDOWN`: network is down; ; WSAENETDOWN. Raised
|
||||
by accept()
|
||||
|
||||
- `ENETUNREACH`: host is unreachable; ;
|
||||
WSAENETUNREACH. Raised by accept(), connect()
|
||||
|
||||
- `ENETRESET`: connection reset by network
|
||||
|
||||
- `ECONNABORTED`: connection reset before accept. Raised by
|
||||
accept()
|
||||
|
||||
- `ECONNRESET`: connection reset by client. Raised by send(),
|
||||
|
||||
- `ENOBUFS`: no buffer space available;
|
||||
raised by getpeername(), getsockname(), send(),
|
||||
|
||||
- `EISCONN`: socket is connected. Raised by
|
||||
connect(), send().
|
||||
|
||||
- `ENOTCONN`: socket is not connected. Raised by getpeername(),
|
||||
recv(), send(), shutdown(),
|
||||
|
||||
- `ESHUTDOWN`: cannot send after transport endpoint shutdown; note
|
||||
that shutdown write is an `EPIPE`
|
||||
|
||||
- `ETOOMANYREFS`: too many references: cannot splice. Raised by
|
||||
sendmsg(),
|
||||
|
||||
- `ETIMEDOUT`: connection timed out; ; WSAETIMEDOUT; raised by
|
||||
connect(),
|
||||
|
||||
- `ECONNREFUSED`: system-imposed limit on the number of threads was
|
||||
encountered.; WSAECONNREFUSED. Raised by connect(), listen(),
|
||||
recv()
|
||||
|
||||
- `EHOSTDOWN`: Host is down. Raised by accept()
|
||||
|
||||
- `EHOSTUNREACH`: Host is unreachable. Raised by accept()
|
||||
|
||||
- `EALREADY`: Connection already in progress. Raised by connect(),
|
||||
send()
|
||||
|
||||
- `ENODATA`: No message is available in xsi stream or named pipe is
|
||||
being closed; no data available; barely in posix; returned by
|
||||
ioctl; very close in spirit to EPIPE?
|
||||
|
||||
unix.opendir(path) → UnixDir*, errno
|
||||
unix.opendir(fd) → UnixDir*, errno
|
||||
UnixDir:close()
|
||||
may be called multiple times
|
||||
called by the garbage collector too
|
||||
UnixDir:read() → name, kind, ino, off
|
||||
returns nil if no more entries
|
||||
kind can be DT_UNKNOWN/REG/DIR/BLK/LNK/CHR/FIFO/SOCK
|
||||
UnixDir:fd() → fd, errno
|
||||
EOPNOTSUPP if using /zip/
|
||||
EOPNOTSUPP if IsWindows()
|
||||
UnixDir:tell() → off
|
||||
UnixDir:rewind()
|
||||
|
||||
CONSTANTS
|
||||
|
||||
|
|
227
tool/net/lunix.c
227
tool/net/lunix.c
|
@ -47,8 +47,10 @@
|
|||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
#include "libc/sysv/consts/msg.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/consts/rlimit.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/shut.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
@ -132,12 +134,11 @@ static void FreeStringList(char **p) {
|
|||
// System Calls
|
||||
|
||||
// unix.exit([exitcode]) → ⊥
|
||||
static int LuaUnixExit(lua_State *L) {
|
||||
static wontreturn int LuaUnixExit(lua_State *L) {
|
||||
_Exit(luaL_optinteger(L, 1, 0));
|
||||
unreachable;
|
||||
}
|
||||
|
||||
// unix.access(path, mode) → rc, errno
|
||||
// unix.access(path, mode) → rc[, errno]
|
||||
// mode can be: R_OK, W_OK, X_OK, F_OK
|
||||
static int LuaUnixAccess(lua_State *L) {
|
||||
const char *file;
|
||||
|
@ -149,7 +150,7 @@ static int LuaUnixAccess(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.mkdir(path, mode) → rc, errno
|
||||
// unix.mkdir(path, mode) → rc[, errno]
|
||||
// mode should be octal
|
||||
static int LuaUnixMkdir(lua_State *L) {
|
||||
const char *file;
|
||||
|
@ -161,7 +162,7 @@ static int LuaUnixMkdir(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.chdir(path) → rc, errno
|
||||
// unix.chdir(path) → rc[, errno]
|
||||
static int LuaUnixChdir(lua_State *L) {
|
||||
int rc, olderr;
|
||||
const char *file;
|
||||
|
@ -171,7 +172,7 @@ static int LuaUnixChdir(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.unlink(path) → rc, errno
|
||||
// unix.unlink(path) → rc[, errno]
|
||||
static int LuaUnixUnlink(lua_State *L) {
|
||||
int rc, olderr;
|
||||
const char *file;
|
||||
|
@ -181,7 +182,7 @@ static int LuaUnixUnlink(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.rmdir(path) → rc, errno
|
||||
// unix.rmdir(path) → rc[, errno]
|
||||
static int LuaUnixRmdir(lua_State *L) {
|
||||
const char *file;
|
||||
int rc, olderr;
|
||||
|
@ -191,7 +192,7 @@ static int LuaUnixRmdir(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.rename(oldpath, newpath) → rc, errno
|
||||
// unix.rename(oldpath, newpath) → rc[, errno]
|
||||
static int LuaUnixRename(lua_State *L) {
|
||||
const char *oldpath, *newpath;
|
||||
int rc, olderr;
|
||||
|
@ -202,7 +203,7 @@ static int LuaUnixRename(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.link(existingpath, newpath) → rc, errno
|
||||
// unix.link(existingpath, newpath) → rc[, errno]
|
||||
static int LuaUnixLink(lua_State *L) {
|
||||
const char *existingpath, *newpath;
|
||||
int rc, olderr;
|
||||
|
@ -213,7 +214,7 @@ static int LuaUnixLink(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.symlink(target, linkpath) → rc, errno
|
||||
// unix.symlink(target, linkpath) → rc[, errno]
|
||||
static int LuaUnixSymlink(lua_State *L) {
|
||||
const char *target, *linkpath;
|
||||
int rc, olderr;
|
||||
|
@ -224,7 +225,7 @@ static int LuaUnixSymlink(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.chown(path, uid, gid) → rc, errno
|
||||
// unix.chown(path, uid, gid) → rc[, errno]
|
||||
static int LuaUnixChown(lua_State *L) {
|
||||
const char *file;
|
||||
int rc, uid, gid, olderr;
|
||||
|
@ -236,7 +237,7 @@ static int LuaUnixChown(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.chmod(path, mode) → rc, errno
|
||||
// unix.chmod(path, mode) → rc[, errno]
|
||||
static int LuaUnixChmod(lua_State *L) {
|
||||
const char *file;
|
||||
int rc, mode, olderr;
|
||||
|
@ -247,7 +248,7 @@ static int LuaUnixChmod(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.getcwd(path, mode) → rc, errno
|
||||
// unix.getcwd(path, mode) → rc[, errno]
|
||||
static int LuaUnixGetcwd(lua_State *L) {
|
||||
char *path;
|
||||
path = getcwd(0, 0);
|
||||
|
@ -297,24 +298,65 @@ static int LuaUnixExecve(lua_State *L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// unix.commandv(prog) → path, errno
|
||||
// unix.commandv(prog) → path[, errno]
|
||||
static int LuaUnixCommandv(lua_State *L) {
|
||||
int olderr;
|
||||
const char *prog;
|
||||
int rc, olderr, pushed;
|
||||
char *pathbuf, *resolved;
|
||||
olderr = errno;
|
||||
pathbuf = xmalloc(PATH_MAX);
|
||||
prog = luaL_checkstring(L, 1);
|
||||
if ((resolved = commandv(prog, pathbuf))) {
|
||||
lua_pushstring(L, resolved);
|
||||
lua_pushnil(L);
|
||||
pushed = 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushinteger(L, errno);
|
||||
errno = olderr;
|
||||
pushed = 2;
|
||||
}
|
||||
free(pathbuf);
|
||||
return 2;
|
||||
return pushed;
|
||||
}
|
||||
|
||||
// unix.chroot(path) → rc[, errno]
|
||||
static int LuaUnixChroot(lua_State *L) {
|
||||
int rc, olderr;
|
||||
const char *path;
|
||||
olderr = errno;
|
||||
path = luaL_checkstring(L, 1);
|
||||
rc = chroot(path);
|
||||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.setrlimit(resource:int, soft:int[, hard:int]) → rc:int[, errno:int]
|
||||
static int LuaUnixSetrlimit(lua_State *L) {
|
||||
struct rlimit rlim;
|
||||
int rc, olderr, resource;
|
||||
olderr = errno;
|
||||
resource = luaL_checkinteger(L, 1);
|
||||
rlim.rlim_cur = luaL_checkinteger(L, 2);
|
||||
rlim.rlim_max = luaL_optinteger(L, 3, rlim.rlim_cur);
|
||||
return ReturnRc(L, setrlimit(resource, &rlim), olderr);
|
||||
}
|
||||
|
||||
// unix.getrlimit(resource:int) → soft:int, hard:int[, errno:int]
|
||||
static int LuaUnixGetrlimit(lua_State *L) {
|
||||
struct rlimit rlim;
|
||||
int rc, olderr, resource;
|
||||
olderr = errno;
|
||||
resource = luaL_checkinteger(L, 1);
|
||||
if (!getrlimit(resource, &rlim)) {
|
||||
lua_pushinteger(L, rlim.rlim_cur);
|
||||
lua_pushinteger(L, rlim.rlim_max);
|
||||
return 2;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
lua_pushinteger(L, errno);
|
||||
errno = olderr;
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
// unix.getpid() → pid
|
||||
|
@ -329,7 +371,7 @@ static int LuaUnixGetppid(lua_State *L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// unix.kill(pid, sig) → rc, errno
|
||||
// unix.kill(pid, sig) → rc[, errno]
|
||||
static int LuaUnixKill(lua_State *L) {
|
||||
int rc, pid, sig, olderr;
|
||||
olderr = errno;
|
||||
|
@ -339,7 +381,7 @@ static int LuaUnixKill(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.raise(sig) → rc, errno
|
||||
// unix.raise(sig) → rc[, errno]
|
||||
static int LuaUnixRaise(lua_State *L) {
|
||||
int rc, sig, olderr;
|
||||
olderr = errno;
|
||||
|
@ -369,7 +411,7 @@ static int LuaUnixWait(lua_State *L) {
|
|||
}
|
||||
}
|
||||
|
||||
// unix.fcntl(fd, cmd[, arg]) → rc, errno
|
||||
// unix.fcntl(fd, cmd[, arg]) → rc[, errno]
|
||||
static int LuaUnixFcntl(lua_State *L) {
|
||||
intptr_t arg;
|
||||
int rc, fd, cmd, olderr;
|
||||
|
@ -442,7 +484,7 @@ static int LuaUnixGetpgid(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.umask(mask) → rc, errno
|
||||
// unix.umask(mask) → rc[, errno]
|
||||
static int LuaUnixUmask(lua_State *L) {
|
||||
int rc, mask, olderr;
|
||||
olderr = errno;
|
||||
|
@ -532,7 +574,7 @@ static int LuaUnixSync(lua_State *L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// unix.fsync(fd) → rc, errno
|
||||
// unix.fsync(fd) → rc[, errno]
|
||||
static int LuaUnixFsync(lua_State *L) {
|
||||
int rc, fd, olderr;
|
||||
olderr = errno;
|
||||
|
@ -541,7 +583,7 @@ static int LuaUnixFsync(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.fdatasync(fd) → rc, errno
|
||||
// unix.fdatasync(fd) → rc[, errno]
|
||||
static int LuaUnixFdatasync(lua_State *L) {
|
||||
int rc, fd, olderr;
|
||||
olderr = errno;
|
||||
|
@ -562,7 +604,7 @@ static int LuaUnixOpen(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.close(fd) → rc, errno
|
||||
// unix.close(fd) → rc[, errno]
|
||||
static int LuaUnixClose(lua_State *L) {
|
||||
int rc, fd, olderr;
|
||||
olderr = errno;
|
||||
|
@ -585,8 +627,8 @@ static int LuaUnixSeek(lua_State *L) {
|
|||
return ReturnRc(L, newpos, olderr);
|
||||
}
|
||||
|
||||
// unix.truncate(path, length) → rc, errno
|
||||
// unix.truncate(fd, length) → rc, errno
|
||||
// unix.truncate(path, length) → rc[, errno]
|
||||
// unix.truncate(fd, length) → rc[, errno]
|
||||
static int LuaUnixTruncate(lua_State *L) {
|
||||
int64_t length;
|
||||
const char *path;
|
||||
|
@ -611,7 +653,7 @@ static int LuaUnixTruncate(lua_State *L) {
|
|||
static int LuaUnixRead(lua_State *L) {
|
||||
char *buf;
|
||||
size_t got;
|
||||
int fd, olderr;
|
||||
int fd, olderr, pushed;
|
||||
int64_t rc, bufsiz, offset;
|
||||
olderr = errno;
|
||||
fd = luaL_checkinteger(L, 1);
|
||||
|
@ -627,17 +669,18 @@ static int LuaUnixRead(lua_State *L) {
|
|||
if (rc != -1) {
|
||||
got = rc;
|
||||
lua_pushlstring(L, buf, got);
|
||||
lua_pushnil(L);
|
||||
pushed = 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushinteger(L, errno);
|
||||
errno = olderr;
|
||||
pushed = 2;
|
||||
}
|
||||
free(buf);
|
||||
return 2;
|
||||
return pushed;
|
||||
}
|
||||
|
||||
// unix.write(fd, data[, offset]) → rc, errno
|
||||
// unix.write(fd, data[, offset]) → rc[, errno]
|
||||
static int LuaUnixWrite(lua_State *L) {
|
||||
size_t size;
|
||||
int fd, olderr;
|
||||
|
@ -656,8 +699,8 @@ static int LuaUnixWrite(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.stat(path) → UnixStat*, errno
|
||||
// unix.stat(fd) → UnixStat*, errno
|
||||
// unix.stat(path) → UnixStat*[, errno]
|
||||
// unix.stat(fd) → UnixStat*[, errno]
|
||||
static int LuaUnixStat(lua_State *L) {
|
||||
const char *path;
|
||||
int rc, fd, olderr;
|
||||
|
@ -688,8 +731,8 @@ static int LuaUnixStat(lua_State *L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// unix.opendir(path) → UnixDir*, errno
|
||||
// unix.opendir(fd) → UnixDir*, errno
|
||||
// unix.opendir(path) → UnixDir*[, errno]
|
||||
// unix.opendir(fd) → UnixDir*[, errno]
|
||||
static int LuaUnixOpendir(lua_State *L) {
|
||||
DIR *rc;
|
||||
int fd, olderr;
|
||||
|
@ -738,7 +781,7 @@ static int LuaUnixSocket(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.socketpair([family[, type[, protocol]]]) → fd1, fd2, errno
|
||||
// unix.socketpair([family[, type[, protocol]]]) → fd1, fd2[, errno]
|
||||
// SOCK_CLOEXEC may be or'd into type
|
||||
// family defaults to AF_INET
|
||||
// type defaults to SOCK_STREAM
|
||||
|
@ -762,7 +805,7 @@ static int LuaUnixSocketpair(lua_State *L) {
|
|||
}
|
||||
}
|
||||
|
||||
// unix.bind(fd, ip, port) → rc, errno
|
||||
// unix.bind(fd, ip, port) → rc[, errno]
|
||||
// SOCK_CLOEXEC may be or'd into type
|
||||
// family defaults to AF_INET
|
||||
// type defaults to SOCK_STREAM
|
||||
|
@ -779,7 +822,7 @@ static int LuaUnixBind(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.connect(fd, ip, port) → rc, errno
|
||||
// unix.connect(fd, ip, port) → rc[, errno]
|
||||
// SOCK_CLOEXEC may be or'd into type
|
||||
// family defaults to AF_INET
|
||||
// type defaults to SOCK_STREAM
|
||||
|
@ -796,7 +839,7 @@ static int LuaUnixConnect(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.listen(fd[, backlog]) → rc, errno
|
||||
// unix.listen(fd[, backlog]) → rc[, errno]
|
||||
static int LuaUnixListen(lua_State *L) {
|
||||
int rc, fd, olderr, backlog;
|
||||
olderr = errno;
|
||||
|
@ -875,7 +918,7 @@ static int LuaUnixAccept(lua_State *L) {
|
|||
}
|
||||
}
|
||||
|
||||
// unix.recvfrom(fd[, bufsiz[, flags]]) → data, ip, port, errno
|
||||
// unix.recvfrom(fd[, bufsiz[, flags]]) → data, ip, port[, errno]
|
||||
// flags can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc.
|
||||
static int LuaUnixRecvfrom(lua_State *L) {
|
||||
char *buf;
|
||||
|
@ -883,7 +926,7 @@ static int LuaUnixRecvfrom(lua_State *L) {
|
|||
ssize_t rc;
|
||||
uint32_t addrsize;
|
||||
struct sockaddr_in sa;
|
||||
int fd, flags, bufsiz, olderr;
|
||||
int fd, flags, bufsiz, olderr, pushed;
|
||||
olderr = errno;
|
||||
bzero(&sa, sizeof(sa));
|
||||
addrsize = sizeof(sa);
|
||||
|
@ -898,24 +941,25 @@ static int LuaUnixRecvfrom(lua_State *L) {
|
|||
lua_pushlstring(L, buf, got);
|
||||
lua_pushinteger(L, ntohl(sa.sin_addr.s_addr));
|
||||
lua_pushinteger(L, ntohs(sa.sin_port));
|
||||
lua_pushnil(L);
|
||||
pushed = 3;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
lua_pushinteger(L, errno);
|
||||
errno = olderr;
|
||||
pushed = 4;
|
||||
}
|
||||
free(buf);
|
||||
return 4;
|
||||
return pushed;
|
||||
}
|
||||
|
||||
// unix.recv(fd[, bufsiz[, flags]]) → data, errno
|
||||
// unix.recv(fd[, bufsiz[, flags]]) → data[, errno]
|
||||
static int LuaUnixRecv(lua_State *L) {
|
||||
char *buf;
|
||||
size_t got;
|
||||
ssize_t rc;
|
||||
int fd, flags, bufsiz, olderr;
|
||||
int fd, flags, bufsiz, olderr, pushed;
|
||||
olderr = errno;
|
||||
fd = luaL_checkinteger(L, 1);
|
||||
bufsiz = luaL_optinteger(L, 2, 1500);
|
||||
|
@ -926,14 +970,15 @@ static int LuaUnixRecv(lua_State *L) {
|
|||
if (rc != -1) {
|
||||
got = rc;
|
||||
lua_pushlstring(L, buf, got);
|
||||
lua_pushnil(L);
|
||||
pushed = 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushinteger(L, errno);
|
||||
errno = olderr;
|
||||
pushed = 2;
|
||||
}
|
||||
free(buf);
|
||||
return 4;
|
||||
return pushed;
|
||||
}
|
||||
|
||||
// unix.send(fd, data[, flags]) → sent, errno
|
||||
|
@ -971,7 +1016,7 @@ static int LuaUnixSendto(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.shutdown(fd, how) → rc, errno
|
||||
// unix.shutdown(fd, how) → rc[, errno]
|
||||
// how can be SHUT_RD, SHUT_WR, or SHUT_RDWR
|
||||
static int LuaUnixShutdown(lua_State *L) {
|
||||
int rc, fd, how, olderr;
|
||||
|
@ -982,7 +1027,7 @@ static int LuaUnixShutdown(lua_State *L) {
|
|||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// unix.sigprocmask(how[, mask]) → oldmask, errno
|
||||
// unix.sigprocmask(how[, mask]) → oldmask[, errno]
|
||||
// how can be SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK
|
||||
static int LuaUnixSigprocmask(lua_State *L) {
|
||||
uint64_t imask;
|
||||
|
@ -1025,7 +1070,7 @@ static void LuaUnixOnSignal(int sig, siginfo_t *si, ucontext_t *ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
// unix.sigaction(sig[, handler[, flags[, mask]]]) → handler, flags, mask, errno
|
||||
// unix.sigaction(sig[,handler[,flags[,mask]]]) → handler,flags,mask[,errno]
|
||||
//
|
||||
// unix = require "unix"
|
||||
// unix.sigaction(unix.SIGUSR1, function(sig)
|
||||
|
@ -1109,7 +1154,7 @@ static int LuaUnixSigaction(lua_State *L) {
|
|||
lua_pushnil(L);
|
||||
lua_pushinteger(L, errno);
|
||||
errno = olderr;
|
||||
return 2;
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1127,7 +1172,7 @@ static int LuaUnixSigsuspend(lua_State *L) {
|
|||
}
|
||||
|
||||
// unix.setitimer(which[, intsec, intmicros, valsec, valmicros])
|
||||
// → intsec, intns, valsec, valns, errno
|
||||
// → intsec, intns, valsec, valns[, errno]
|
||||
//
|
||||
// ticks = 0
|
||||
// unix.sigaction(unix.SIGALRM, function(sig)
|
||||
|
@ -1244,6 +1289,10 @@ static int LuaUnixStatCtim(lua_State *L) {
|
|||
return ReturnTimespec(L, &GetUnixStat(L)->st_ctim);
|
||||
}
|
||||
|
||||
static int LuaUnixStatBirthtim(lua_State *L) {
|
||||
return ReturnTimespec(L, &GetUnixStat(L)->st_birthtim);
|
||||
}
|
||||
|
||||
static void FreeUnixStat(struct UnixStat *stat) {
|
||||
if (!--stat->refs) {
|
||||
free(stat);
|
||||
|
@ -1261,20 +1310,21 @@ static int LuaUnixStatGc(lua_State *L) {
|
|||
}
|
||||
|
||||
static const luaL_Reg kLuaUnixStatMeth[] = {
|
||||
{"size", LuaUnixStatSize}, //
|
||||
{"mode", LuaUnixStatMode}, //
|
||||
{"dev", LuaUnixStatDev}, //
|
||||
{"ino", LuaUnixStatIno}, //
|
||||
{"nlink", LuaUnixStatNlink}, //
|
||||
{"rdev", LuaUnixStatRdev}, //
|
||||
{"uid", LuaUnixStatUid}, //
|
||||
{"gid", LuaUnixStatGid}, //
|
||||
{"atim", LuaUnixStatAtim}, //
|
||||
{"mtim", LuaUnixStatMtim}, //
|
||||
{"ctim", LuaUnixStatCtim}, //
|
||||
{"blocks", LuaUnixStatBlocks}, //
|
||||
{"blksize", LuaUnixStatBlksize}, //
|
||||
{0}, //
|
||||
{"size", LuaUnixStatSize}, //
|
||||
{"mode", LuaUnixStatMode}, //
|
||||
{"dev", LuaUnixStatDev}, //
|
||||
{"ino", LuaUnixStatIno}, //
|
||||
{"nlink", LuaUnixStatNlink}, //
|
||||
{"rdev", LuaUnixStatRdev}, //
|
||||
{"uid", LuaUnixStatUid}, //
|
||||
{"gid", LuaUnixStatGid}, //
|
||||
{"atim", LuaUnixStatAtim}, //
|
||||
{"mtim", LuaUnixStatMtim}, //
|
||||
{"ctim", LuaUnixStatCtim}, //
|
||||
{"birthtim", LuaUnixStatBirthtim}, //
|
||||
{"blocks", LuaUnixStatBlocks}, //
|
||||
{"blksize", LuaUnixStatBlksize}, //
|
||||
{0}, //
|
||||
};
|
||||
|
||||
static const luaL_Reg kLuaUnixStatMeta[] = {
|
||||
|
@ -1307,38 +1357,49 @@ static DIR *GetDirOrDie(lua_State *L) {
|
|||
unreachable;
|
||||
}
|
||||
|
||||
static void FreeUnixDir(struct UnixDir *dir) {
|
||||
if (!--dir->refs) {
|
||||
closedir(dir->dir);
|
||||
}
|
||||
static int FreeUnixDir(struct UnixDir *dir) {
|
||||
if (--dir->refs) return 0;
|
||||
return closedir(dir->dir);
|
||||
}
|
||||
|
||||
// UnixDir:close()
|
||||
// UnixDir:close() → rc[, errno]
|
||||
// may be called multiple times
|
||||
// called by the garbage collector too
|
||||
static int LuaUnixDirClose(lua_State *L) {
|
||||
int rc, olderr;
|
||||
struct UnixDir **udir;
|
||||
udir = GetUnixDirSelf(L);
|
||||
if (*udir) {
|
||||
FreeUnixDir(*udir);
|
||||
*udir = 0;
|
||||
}
|
||||
return 0;
|
||||
if (!*udir) return 0;
|
||||
olderr = 0;
|
||||
rc = FreeUnixDir(*udir);
|
||||
*udir = 0;
|
||||
return ReturnRc(L, rc, olderr);
|
||||
}
|
||||
|
||||
// UnixDir:read() → name, kind, ino, off
|
||||
// UnixDir:read() → name, kind, ino, off[, errno]
|
||||
// returns nil if no more entries
|
||||
// kind can be DT_UNKNOWN/REG/DIR/BLK/LNK/CHR/FIFO/SOCK
|
||||
static int LuaUnixDirRead(lua_State *L) {
|
||||
int olderr;
|
||||
struct dirent *ent;
|
||||
olderr = errno;
|
||||
errno = 0;
|
||||
if ((ent = readdir(GetDirOrDie(L)))) {
|
||||
lua_pushlstring(L, ent->d_name, strnlen(ent->d_name, sizeof(ent->d_name)));
|
||||
lua_pushinteger(L, ent->d_type);
|
||||
lua_pushinteger(L, ent->d_ino);
|
||||
lua_pushinteger(L, ent->d_off);
|
||||
return 4;
|
||||
} else if (!ent && !errno) {
|
||||
return 0; // end of listing
|
||||
} else {
|
||||
return 0;
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
lua_pushinteger(L, errno);
|
||||
errno = olderr;
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1433,7 +1494,10 @@ static const luaL_Reg kLuaUnix[] = {
|
|||
{"fsync", LuaUnixFsync}, // flush open file
|
||||
{"fdatasync", LuaUnixFdatasync}, // flush open file w/o metadata
|
||||
{"truncate", LuaUnixTruncate}, // shrink or extend file medium
|
||||
{"umask", LuaUnixUmask}, // set file mode creation mask
|
||||
{"umask", LuaUnixChroot}, // change root directory
|
||||
{"chroot", LuaUnixGetppid}, // get parent process id
|
||||
{"setrlimit", LuaUnixSetrlimit}, // prevent cpu memory bombs
|
||||
{"getrlimit", LuaUnixGetrlimit}, // query resource limits
|
||||
{"getppid", LuaUnixGetppid}, // get parent process id
|
||||
{"getpgrp", LuaUnixGetpgrp}, // get process group id
|
||||
{"getpgid", LuaUnixGetpgid}, // get process group id of pid
|
||||
|
@ -1544,6 +1608,13 @@ int LuaUnix(lua_State *L) {
|
|||
LuaSetIntField(L, "X_OK", X_OK);
|
||||
LuaSetIntField(L, "F_OK", F_OK);
|
||||
|
||||
// rlimit() resources
|
||||
LuaSetIntField(L, "RLIMIT_AS", RLIMIT_AS);
|
||||
LuaSetIntField(L, "RLIMIT_CPU", RLIMIT_CPU);
|
||||
LuaSetIntField(L, "RLIMIT_FSIZE", RLIMIT_FSIZE);
|
||||
LuaSetIntField(L, "RLIMIT_NPROC", RLIMIT_NPROC);
|
||||
LuaSetIntField(L, "RLIMIT_NOFILE", RLIMIT_NOFILE);
|
||||
|
||||
// wait() options
|
||||
LuaSetIntField(L, "WNOHANG", WNOHANG);
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/bits/popcnt.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/issandboxed.h"
|
||||
#include "libc/calls/math.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
|
@ -52,6 +53,7 @@
|
|||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/rdtscp.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/clktck.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
|
@ -81,11 +83,14 @@
|
|||
#include "libc/sysv/consts/madv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/msync.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/pr.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/rusage.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/consts/seccomp.h"
|
||||
#include "libc/sysv/consts/shut.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/so.h"
|
||||
|
@ -180,6 +185,11 @@ STATIC_YOINK("zip_uri_support");
|
|||
#define HeaderEqualCase(H, S) \
|
||||
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
|
||||
|
||||
// letters not used: EIJNOQWXYinoqwxy
|
||||
// digits not used: 0123456789
|
||||
// puncts not used: !"#$%&'()*+,-./;<=>@[\]^_`{|}~
|
||||
#define GETOPTS "BSVZabdfghjkmsuvzA:C:D:F:G:H:K:L:M:P:R:T:U:c:e:l:p:r:t:"
|
||||
|
||||
static const uint8_t kGzipHeader[] = {
|
||||
0x1F, // MAGNUM
|
||||
0x8B, // MAGNUM
|
||||
|
@ -345,6 +355,7 @@ static bool zombied;
|
|||
static bool gzipped;
|
||||
static bool branded;
|
||||
static bool funtrace;
|
||||
static bool systrace;
|
||||
static bool meltdown;
|
||||
static bool printport;
|
||||
static bool daemonize;
|
||||
|
@ -356,6 +367,7 @@ static bool terminated;
|
|||
static bool uniprocess;
|
||||
static bool invalidated;
|
||||
static bool logmessages;
|
||||
static bool issandboxed;
|
||||
static bool isinitialized;
|
||||
static bool checkedmethod;
|
||||
static bool sslinitialized;
|
||||
|
@ -5817,7 +5829,7 @@ static void HandleHeartbeat(void) {
|
|||
LuaRunAsset("/.heartbeat.lua", false);
|
||||
CollectGarbage();
|
||||
#endif
|
||||
for (i = 0; i < servers.n; ++i) {
|
||||
for (i = 1; i < servers.n; ++i) {
|
||||
if (polls[i].fd < 0) {
|
||||
polls[i].fd = -polls[i].fd;
|
||||
}
|
||||
|
@ -6569,12 +6581,11 @@ static void CloseServerFds(void) {
|
|||
}
|
||||
|
||||
static int ExitWorker(void) {
|
||||
if (!IsModeDbg()) {
|
||||
_Exit(0);
|
||||
} else {
|
||||
if (IsModeDbg() && !issandboxed) {
|
||||
isexitingworker = true;
|
||||
return eintr();
|
||||
}
|
||||
_Exit(0);
|
||||
}
|
||||
|
||||
// returns 0 otherwise -1 if worker needs to unwind stack and exit
|
||||
|
@ -6597,8 +6608,9 @@ static int HandleConnection(size_t i) {
|
|||
case 0:
|
||||
meltdown = false;
|
||||
connectionclose = false;
|
||||
if (funtrace && !IsTiny()) {
|
||||
ftrace_install();
|
||||
if (!IsTiny()) {
|
||||
if (systrace) __strace = 1;
|
||||
if (funtrace) ftrace_install();
|
||||
}
|
||||
if (hasonworkerstart) {
|
||||
CallSimpleHook("OnWorkerStart");
|
||||
|
@ -6990,19 +7002,19 @@ static void MemDestroy(void) {
|
|||
static void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
bool storeasset = false;
|
||||
while ((opt = getopt(argc, argv,
|
||||
"jkazhdugvVsmbfB"
|
||||
"e:A:l:p:r:R:H:c:L:P:U:G:D:t:M:C:K:F:T:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {
|
||||
switch (opt) {
|
||||
CASE('v', ++__log_level);
|
||||
CASE('s', --__log_level);
|
||||
CASE('f', funtrace = true);
|
||||
CASE('Z', systrace = true);
|
||||
CASE('b', logbodies = true);
|
||||
CASE('z', printport = true);
|
||||
CASE('d', daemonize = true);
|
||||
CASE('a', logrusage = true);
|
||||
CASE('u', uniprocess = true);
|
||||
CASE('g', loglatency = true);
|
||||
CASE('S', issandboxed = true);
|
||||
CASE('m', logmessages = true);
|
||||
CASE('l', ProgramAddr(optarg));
|
||||
CASE('H', ProgramHeader(optarg));
|
||||
|
|
188
tool/viz/getopts.c
Normal file
188
tool/viz/getopts.c
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Tool for printing which getopt() letters are used, e.g.
|
||||
*
|
||||
* o//tool/viz/getopts.com jkazhdugvVsmbBfe:A:l:p:r:R:H
|
||||
*/
|
||||
|
||||
int letters_used[256];
|
||||
bool letters_with_args[256];
|
||||
|
||||
bool IsLegal(int c) {
|
||||
return isgraph(c) && c != ':' && c != '?';
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i, j;
|
||||
bool hasargless;
|
||||
|
||||
for (i = 1; i < argc; ++i) {
|
||||
for (j = 0; argv[i][j]; ++j) {
|
||||
++letters_used[argv[i][j] & 255];
|
||||
if (argv[i][j + 1] == ':') {
|
||||
letters_with_args[argv[i][j] & 255] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// usage report
|
||||
fprintf(stderr, "options used: ");
|
||||
for (j = i = 0; i < 128; ++i) {
|
||||
if (!IsLegal(i)) continue;
|
||||
if (letters_used[i]) {
|
||||
if (j++) fprintf(stderr, "");
|
||||
fprintf(stderr, "%c", i);
|
||||
}
|
||||
}
|
||||
if (!j) fprintf(stderr, "none");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "letters not used: ");
|
||||
for (j = i = 0; i < 128; ++i) {
|
||||
if (!isalpha(i)) continue;
|
||||
if (!letters_used[i]) {
|
||||
if (j++) fprintf(stderr, "");
|
||||
fprintf(stderr, "%c", i);
|
||||
}
|
||||
}
|
||||
if (!j) fprintf(stderr, "none");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "digits not used: ");
|
||||
for (j = i = 0; i < 128; ++i) {
|
||||
if (!isdigit(i)) continue;
|
||||
if (!letters_used[i]) {
|
||||
if (j++) fprintf(stderr, "");
|
||||
fprintf(stderr, "%c", i);
|
||||
}
|
||||
}
|
||||
if (!j) fprintf(stderr, "none");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "puncts not used: ");
|
||||
for (j = i = 0; i < 128; ++i) {
|
||||
if (!IsLegal(i)) continue;
|
||||
if (isalnum(i)) continue;
|
||||
if (!letters_used[i]) {
|
||||
if (j++) fprintf(stderr, "");
|
||||
fprintf(stderr, "%c", i);
|
||||
}
|
||||
}
|
||||
if (!j) fprintf(stderr, "none");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "letters duplicated: ");
|
||||
for (j = i = 0; i < 128; ++i) {
|
||||
if (!IsLegal(i)) continue;
|
||||
if (letters_used[i] > 1) {
|
||||
if (j++) fprintf(stderr, "");
|
||||
fprintf(stderr, "%c", i);
|
||||
}
|
||||
}
|
||||
if (!j) fprintf(stderr, "none");
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
// generated code
|
||||
hasargless = false;
|
||||
printf("\n#define GETOPTS \"");
|
||||
for (j = i = 0; i < 128; ++i) {
|
||||
if (!IsLegal(i)) continue;
|
||||
if (letters_used[i] && !letters_with_args[i]) {
|
||||
printf("%c", i);
|
||||
hasargless = true;
|
||||
}
|
||||
}
|
||||
for (j = i = 0; i < 128; ++i) {
|
||||
if (!IsLegal(i)) continue;
|
||||
if (letters_used[i] && letters_with_args[i]) {
|
||||
printf("%c:", i);
|
||||
}
|
||||
}
|
||||
printf("\"\n");
|
||||
printf("\n#define USAGE \"\\\n");
|
||||
printf("Usage: program.com");
|
||||
if (hasargless) {
|
||||
printf(" [-");
|
||||
for (j = i = 0; i < 128; ++i) {
|
||||
if (!IsLegal(i)) continue;
|
||||
if (letters_used[i] && !letters_with_args[i]) {
|
||||
printf("%c", i);
|
||||
hasargless = true;
|
||||
}
|
||||
}
|
||||
printf("]");
|
||||
}
|
||||
printf(" ARGS...\\n\\\n");
|
||||
for (j = i = 0; i < 128; ++i) {
|
||||
if (!IsLegal(i)) continue;
|
||||
if (letters_used[i]) {
|
||||
printf(" -%c the %c option\\n\\\n", i, i);
|
||||
}
|
||||
}
|
||||
for (j = i = 0; i < 128; ++i) {
|
||||
if (!IsLegal(i)) continue;
|
||||
if (letters_used[i]) {
|
||||
printf(" -%c VAL the %c option\\n\\\n", i, i);
|
||||
}
|
||||
}
|
||||
printf("\"\n\n");
|
||||
|
||||
for (i = 0; i < 128; ++i) {
|
||||
if (!IsLegal(i)) continue;
|
||||
if (letters_used[i]) {
|
||||
if (isalpha(i) || i == '_') {
|
||||
printf("int %cflag;\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n\
|
||||
static void GetOpts(int argc, char *argv[]) {\n\
|
||||
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {\n\
|
||||
switch (opt) {\n");
|
||||
for (i = 0; i < 128; ++i) {
|
||||
if (!IsLegal(i)) continue;
|
||||
if (letters_used[i]) {
|
||||
printf(" case '%c':\n", i);
|
||||
if (isalpha(i) || i == '_') {
|
||||
printf(" %cflag", i);
|
||||
} else {
|
||||
printf(" XXXflag", i);
|
||||
}
|
||||
if (letters_with_args[i]) {
|
||||
printf(" = optarg;\n");
|
||||
} else {
|
||||
printf("++;\n");
|
||||
}
|
||||
printf(" break;\n");
|
||||
}
|
||||
}
|
||||
|
||||
printf(" case '?':\n");
|
||||
printf(" write(1, USAGE, strlen(USAGE));\n");
|
||||
printf(" exit(0);\n");
|
||||
printf(" default:\n");
|
||||
printf(" write(2, USAGE, strlen(USAGE));\n");
|
||||
printf(" exit(64);\n");
|
||||
printf(" }\n");
|
||||
printf(" }\n");
|
||||
printf("}\n");
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue