mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-28 15:28:30 +00:00
Make fixes and improvements
- Invent iso8601us() for faster timestamps - Improve --strace descriptions of sigset_t - Rebuild the Landlock Make bootstrap binary - Introduce MODE=sysv for non-Windows builds - Permit OFD fcntl() locks under pledge(flock) - redbean can now protect your kernel from ddos - Have vfork() fallback to sys_fork() not fork() - Change kmalloc() to not die when out of memory - Improve documentation for some termios functions - Rewrite putenv() and friends to conform to POSIX - Fix linenoise + strace verbosity issue on Windows - Fix regressions in our ability to show backtraces - Change redbean SetHeader() to no-op if value is nil - Improve fcntl() so SQLite locks work in non-WAL mode - Remove some unnecessary work during fork() on Windows - Create redbean-based SSL reverse proxy for IPv4 TurfWar - Fix ape/apeinstall.sh warning when using non-bash shells - Add ProgramTrustedIp(), and IsTrustedIp() APIs to redbean - Support $PWD, $UID, $GID, and $EUID in command interpreter - Introduce experimental JTqFpD APE prefix for non-Windows builds - Invent blackhole daemon for firewalling IP addresses via UNIX named socket - Add ProgramTokenBucket(), AcquireToken(), and CountTokens() APIs to redbean
This commit is contained in:
parent
648bf6555c
commit
f7ff77d865
209 changed files with 3818 additions and 998 deletions
|
@ -16,7 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
|
19
libc/calls/blocksigs.internal.h
Normal file
19
libc/calls/blocksigs.internal.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_INTERNAL_H_
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define BLOCK_SIGNALS \
|
||||
do { \
|
||||
sigset_t _SigMask; \
|
||||
_SigMask = _sigblockall()
|
||||
|
||||
#define ALLOW_SIGNALS \
|
||||
_sigsetmask(_SigMask); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_INTERNAL_H_ */
|
|
@ -65,13 +65,13 @@ char *ttyname(int);
|
|||
int access(const char *, int) dontthrow;
|
||||
int arch_prctl();
|
||||
int chdir(const char *);
|
||||
int chmod(const char *, uint32_t);
|
||||
int chown(const char *, uint32_t, uint32_t);
|
||||
int chmod(const char *, unsigned);
|
||||
int chown(const char *, unsigned, unsigned);
|
||||
int chroot(const char *);
|
||||
int close(int);
|
||||
int close_range(unsigned, unsigned, unsigned);
|
||||
int closefrom(int);
|
||||
int creat(const char *, uint32_t);
|
||||
int creat(const char *, unsigned);
|
||||
int dup(int);
|
||||
int dup2(int, int);
|
||||
int dup3(int, int, int);
|
||||
|
@ -84,25 +84,22 @@ int execv(const char *, char *const[]);
|
|||
int execve(const char *, char *const[], char *const[]);
|
||||
int execvp(const char *, char *const[]);
|
||||
int execvpe(const char *, char *const[], char *const[]);
|
||||
int fexecve(int, char *const[], char *const[]);
|
||||
int faccessat(int, const char *, int, int);
|
||||
int fadvise(int, uint64_t, uint64_t, int);
|
||||
int fchdir(int);
|
||||
int fchmod(int, uint32_t) dontthrow;
|
||||
int fchmodat(int, const char *, uint32_t, int);
|
||||
int fchown(int, uint32_t, uint32_t);
|
||||
int fchownat(int, const char *, uint32_t, uint32_t, int);
|
||||
int fchmod(int, unsigned) dontthrow;
|
||||
int fchmodat(int, const char *, unsigned, int);
|
||||
int fchown(int, unsigned, unsigned);
|
||||
int fchownat(int, const char *, unsigned, unsigned, int);
|
||||
int fcntl(int, int, ...);
|
||||
int fdatasync(int);
|
||||
int fexecve(int, char *const[], char *const[]);
|
||||
int flock(int, int);
|
||||
int fork(void);
|
||||
int fsync(int);
|
||||
int ftruncate(int, int64_t);
|
||||
int getdomainname(char *, size_t);
|
||||
uint32_t getegid(void) nosideeffect;
|
||||
uint32_t geteuid(void) nosideeffect;
|
||||
uint32_t getgid(void) nosideeffect;
|
||||
int getgroups(int size, uint32_t list[]);
|
||||
int getgroups(int, unsigned[]);
|
||||
int gethostname(char *, size_t);
|
||||
int getloadavg(double *, int);
|
||||
int getpgid(int) libcesque;
|
||||
|
@ -110,36 +107,29 @@ int getpgrp(void) nosideeffect;
|
|||
int getpid(void) nosideeffect libcesque;
|
||||
int getppid(void);
|
||||
int getpriority(int, unsigned);
|
||||
int getresgid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int getresuid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int getresgid(unsigned *, unsigned *, unsigned *);
|
||||
int getresuid(unsigned *, unsigned *, unsigned *);
|
||||
int getsid(int) nosideeffect libcesque;
|
||||
int gettid(void) libcesque;
|
||||
uint32_t getuid(void) libcesque;
|
||||
int sys_iopl(int);
|
||||
int ioprio_get(int, int);
|
||||
int ioprio_set(int, int, int);
|
||||
int issetugid(void);
|
||||
int kill(int, int);
|
||||
int killpg(int, int);
|
||||
int lchmod(const char *, uint32_t);
|
||||
int lchown(const char *, uint32_t, uint32_t);
|
||||
int lchmod(const char *, unsigned);
|
||||
int lchown(const char *, unsigned, unsigned);
|
||||
int link(const char *, const char *) dontthrow;
|
||||
int linkat(int, const char *, int, const char *, int);
|
||||
int madvise(void *, uint64_t, int);
|
||||
int makedirs(const char *, unsigned);
|
||||
int memfd_create(const char *, unsigned int);
|
||||
int mincore(void *, size_t, unsigned char *);
|
||||
int mkdir(const char *, unsigned);
|
||||
int mkdirat(int, const char *, unsigned);
|
||||
int makedirs(const char *, unsigned);
|
||||
int mkfifo(const char *, uint32_t);
|
||||
int mkfifoat(int, const char *, uint32_t);
|
||||
int mknod(const char *, uint32_t, uint64_t);
|
||||
int mknodat(int, const char *, int32_t, uint64_t);
|
||||
int sys_mlock(const void *, size_t);
|
||||
int sys_mlock2(const void *, size_t, int);
|
||||
int sys_mlockall(int);
|
||||
int sys_munlock(const void *, size_t);
|
||||
int sys_munlockall(void);
|
||||
int mkfifo(const char *, unsigned);
|
||||
int mkfifoat(int, const char *, unsigned);
|
||||
int mknod(const char *, unsigned, uint64_t);
|
||||
int mknodat(int, const char *, int, uint64_t);
|
||||
int nice(int);
|
||||
int open(const char *, int, ...);
|
||||
int openat(int, const char *, int, ...);
|
||||
|
@ -161,19 +151,19 @@ int renameat2(long, const char *, long, const char *, int);
|
|||
int rmdir(const char *);
|
||||
int sched_yield(void);
|
||||
int seccomp(unsigned, unsigned, void *);
|
||||
int setegid(uint32_t);
|
||||
int seteuid(uint32_t);
|
||||
int setegid(unsigned);
|
||||
int seteuid(unsigned);
|
||||
int setfsgid(unsigned);
|
||||
int setfsuid(unsigned);
|
||||
int setgid(unsigned);
|
||||
int setgroups(size_t, const uint32_t[]);
|
||||
int setgroups(size_t, const unsigned[]);
|
||||
int setpgid(int, int);
|
||||
int setpgrp(void);
|
||||
int setpriority(int, unsigned, int);
|
||||
int setregid(uint32_t, uint32_t);
|
||||
int setresgid(uint32_t, uint32_t, uint32_t);
|
||||
int setresuid(uint32_t, uint32_t, uint32_t);
|
||||
int setreuid(uint32_t, uint32_t);
|
||||
int setregid(unsigned, unsigned);
|
||||
int setresgid(unsigned, unsigned, unsigned);
|
||||
int setresuid(unsigned, unsigned, unsigned);
|
||||
int setreuid(unsigned, unsigned);
|
||||
int setsid(void);
|
||||
int setuid(unsigned);
|
||||
int sigignore(int);
|
||||
|
@ -181,16 +171,22 @@ int siginterrupt(int, int);
|
|||
int symlink(const char *, const char *);
|
||||
int symlinkat(const char *, int, const char *);
|
||||
int sync_file_range(int, int64_t, int64_t, unsigned);
|
||||
int sys_iopl(int);
|
||||
int sys_mlock(const void *, size_t);
|
||||
int sys_mlock2(const void *, size_t, int);
|
||||
int sys_mlockall(int);
|
||||
int sys_munlock(const void *, size_t);
|
||||
int sys_munlockall(void);
|
||||
int sys_ptrace(int, ...);
|
||||
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
int tcsetpgrp(int, int32_t);
|
||||
int tcgetpgrp(int);
|
||||
int tcsetpgrp(int, int);
|
||||
int tgkill(int, int, int);
|
||||
int tkill(int, int);
|
||||
int tmpfd(void);
|
||||
int touch(const char *, uint32_t);
|
||||
int touch(const char *, unsigned);
|
||||
int truncate(const char *, int64_t);
|
||||
int ttyname_r(int, char *, size_t);
|
||||
unsigned umask(unsigned);
|
||||
int unlink(const char *);
|
||||
int unlink_s(const char **);
|
||||
int unlinkat(int, const char *, int);
|
||||
|
@ -199,11 +195,10 @@ int usleep(unsigned);
|
|||
int vfork(void) returnstwice;
|
||||
int wait(int *);
|
||||
int waitpid(int, int *, int);
|
||||
int32_t tcgetpgrp(int);
|
||||
intptr_t syscall(int, ...);
|
||||
long ptrace(int, ...);
|
||||
ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t);
|
||||
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, uint32_t);
|
||||
ssize_t copy_file_range(int, long *, int, long *, size_t, unsigned);
|
||||
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, unsigned);
|
||||
ssize_t getfiledescriptorsize(int);
|
||||
ssize_t lseek(int, int64_t, int);
|
||||
ssize_t pread(int, void *, size_t, int64_t);
|
||||
|
@ -212,8 +207,13 @@ ssize_t read(int, void *, size_t);
|
|||
ssize_t readansi(int, char *, size_t);
|
||||
ssize_t readlink(const char *, char *, size_t);
|
||||
ssize_t readlinkat(int, const char *, char *, size_t);
|
||||
ssize_t splice(int, int64_t *, int, int64_t *, size_t, uint32_t);
|
||||
ssize_t splice(int, int64_t *, int, int64_t *, size_t, unsigned);
|
||||
ssize_t write(int, const void *, size_t);
|
||||
unsigned getegid(void) nosideeffect;
|
||||
unsigned geteuid(void) nosideeffect;
|
||||
unsigned getgid(void) nosideeffect;
|
||||
unsigned getuid(void) libcesque;
|
||||
unsigned umask(unsigned);
|
||||
void sync(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -17,17 +17,72 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns input baud rate.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
uint32_t cfgetispeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ispeed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns output baud rate.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
uint32_t cfgetospeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ospeed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets input baud rate.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int cfsetispeed(struct termios *t, unsigned speed) {
|
||||
if (speed) {
|
||||
if (CBAUD) {
|
||||
if (speed & ~CBAUD) return einval();
|
||||
t->c_cflag &= ~CBAUD;
|
||||
t->c_cflag |= speed;
|
||||
if (!(speed & ~CBAUD)) {
|
||||
t->c_cflag &= ~CBAUD;
|
||||
t->c_cflag |= speed;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
} else {
|
||||
t->c_ispeed = speed;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets output baud rate.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int cfsetospeed(struct termios *t, unsigned speed) {
|
||||
if (CBAUD) {
|
||||
if (!(speed & ~CBAUD)) {
|
||||
t->c_cflag &= ~CBAUD;
|
||||
t->c_cflag |= speed;
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
} else {
|
||||
t->c_ospeed = speed;
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -18,15 +18,22 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
textwindows int sys_close_nt(struct Fd *fd) {
|
||||
void sys_fcntl_nt_lock_cleanup(int) hidden;
|
||||
|
||||
textwindows int sys_close_nt(struct Fd *fd, int fildes) {
|
||||
int e;
|
||||
bool ok = true;
|
||||
|
||||
if (_weaken(sys_fcntl_nt_lock_cleanup)) {
|
||||
_weaken(sys_fcntl_nt_lock_cleanup)(fildes);
|
||||
}
|
||||
|
||||
if (fd->kind == kFdFile && ((fd->flags & O_ACCMODE) != O_RDONLY &&
|
||||
GetFileType(fd->handle) == kNtFileTypeDisk)) {
|
||||
// Like Linux, closing a file on Windows doesn't guarantee it's
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -81,7 +81,7 @@ int close(int fd) {
|
|||
} else if (__isfdkind(fd, kFdFile) || //
|
||||
__isfdkind(fd, kFdConsole) || //
|
||||
__isfdkind(fd, kFdProcess)) { //
|
||||
rc = sys_close_nt(g_fds.p + fd);
|
||||
rc = sys_close_nt(g_fds.p + fd, fd);
|
||||
} else {
|
||||
rc = eio();
|
||||
}
|
||||
|
|
|
@ -27,12 +27,9 @@
|
|||
/**
|
||||
* Closes extra file descriptors, e.g.
|
||||
*
|
||||
* // close all non-stdio file descriptors
|
||||
* if (closefrom(3) == -1) {
|
||||
* for (int i = 3; i < 256; ++i) {
|
||||
* if (closefrom(3))
|
||||
* for (int i = 3; i < 256; ++i)
|
||||
* close(i);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EBADF if `first` is negative
|
||||
|
|
|
@ -45,27 +45,18 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
|||
}
|
||||
|
||||
// allocate a new file descriptor
|
||||
for (;;) {
|
||||
if (newfd == -1) {
|
||||
if ((newfd = __reservefd_unlocked(start)) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if (__ensurefds_unlocked(newfd) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
if (g_fds.p[newfd].kind) {
|
||||
__fds_unlock();
|
||||
close(newfd);
|
||||
__fds_lock();
|
||||
}
|
||||
if (!g_fds.p[newfd].kind) {
|
||||
g_fds.p[newfd].kind = kFdReserved;
|
||||
break;
|
||||
}
|
||||
if (newfd == -1) {
|
||||
if ((newfd = __reservefd_unlocked(start)) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (__ensurefds_unlocked(newfd) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
if (g_fds.p[newfd].kind) {
|
||||
sys_close_nt(g_fds.p + newfd, newfd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +77,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
|||
}
|
||||
rc = newfd;
|
||||
} else {
|
||||
__releasefd_unlocked(newfd);
|
||||
__releasefd(newfd);
|
||||
rc = __winerr();
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blocksigs.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -40,7 +41,9 @@ static bool IsApeBinary(const char *path) {
|
|||
char buf[8];
|
||||
bool res = false;
|
||||
if ((fd = sys_open(path, O_RDONLY, 0)) != -1) {
|
||||
if (sys_read(fd, buf, 8) == 8 && READ64LE(buf) == READ64LE("MZqFpD='")) {
|
||||
if (sys_read(fd, buf, 8) == 8 && //
|
||||
(READ64LE(buf) == READ64LE("MZqFpD='") ||
|
||||
READ64LE(buf) == READ64LE("JTqFpD='"))) {
|
||||
res = true;
|
||||
}
|
||||
sys_close(fd);
|
||||
|
@ -61,35 +64,41 @@ static const char *Join(const char *a, const char *b, char buf[PATH_MAX]) {
|
|||
}
|
||||
|
||||
int sys_execve(const char *prog, char *const argv[], char *const envp[]) {
|
||||
int e;
|
||||
size_t i;
|
||||
int e, rc;
|
||||
char *buf;
|
||||
char **shargs;
|
||||
const char *ape;
|
||||
e = errno;
|
||||
__sys_execve(prog, argv, envp);
|
||||
if (errno != ENOEXEC) return -1;
|
||||
for (i = 0; argv[i];) ++i;
|
||||
buf = alloca(PATH_MAX);
|
||||
shargs = alloca((i + 4) * sizeof(char *));
|
||||
if (IsApeBinary(prog) &&
|
||||
(CanExecute((ape = "/usr/bin/ape")) ||
|
||||
CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"),
|
||||
firstnonnull(getenv("HOME"), ".")),
|
||||
".ape", buf))) ||
|
||||
CanExecute(
|
||||
(ape = Join(firstnonnull(getenv("HOME"), "."), ".ape", buf))))) {
|
||||
shargs[0] = ape;
|
||||
shargs[1] = "-";
|
||||
shargs[2] = prog;
|
||||
memcpy(shargs + 3, argv, (i + 1) * sizeof(char *));
|
||||
} else if (CanExecute(prog)) {
|
||||
shargs[0] = _PATH_BSHELL;
|
||||
shargs[1] = prog;
|
||||
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
|
||||
if (errno == ENOEXEC) {
|
||||
for (i = 0; argv[i];) ++i;
|
||||
buf = alloca(PATH_MAX);
|
||||
shargs = alloca((i + 4) * sizeof(char *));
|
||||
if (IsApeBinary(prog) &&
|
||||
(CanExecute((ape = "/usr/bin/ape")) ||
|
||||
CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"),
|
||||
firstnonnull(getenv("HOME"), ".")),
|
||||
".ape", buf))) ||
|
||||
CanExecute(
|
||||
(ape = Join(firstnonnull(getenv("HOME"), "."), ".ape", buf))))) {
|
||||
shargs[0] = ape;
|
||||
shargs[1] = "-";
|
||||
shargs[2] = prog;
|
||||
memcpy(shargs + 3, argv, (i + 1) * sizeof(char *));
|
||||
errno = e;
|
||||
rc = __sys_execve(shargs[0], shargs, envp);
|
||||
} else if (CanExecute(prog)) {
|
||||
shargs[0] = _PATH_BSHELL;
|
||||
shargs[1] = prog;
|
||||
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
|
||||
errno = e;
|
||||
rc = __sys_execve(shargs[0], shargs, envp);
|
||||
} else {
|
||||
rc = enoexec();
|
||||
}
|
||||
} else {
|
||||
return enoexec();
|
||||
rc = -1;
|
||||
}
|
||||
errno = e;
|
||||
return __sys_execve(shargs[0], shargs, envp);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -54,9 +54,9 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
|
|||
int rc;
|
||||
size_t i;
|
||||
if (!prog || !argv || !envp ||
|
||||
(IsAsan() &&
|
||||
(!__asan_is_valid(prog, 1) || !__asan_is_valid_strlist(argv) ||
|
||||
!__asan_is_valid_strlist(envp)))) {
|
||||
(IsAsan() && (!__asan_is_valid(prog, 1) || //
|
||||
!__asan_is_valid_strlist(argv) || //
|
||||
!__asan_is_valid_strlist(envp)))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
STRACE("execve(%#s, %s, %s) → ...", prog, DescribeStringList(argv),
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
|
@ -24,63 +25,131 @@
|
|||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/wincrash.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kmalloc.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/filelockflags.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/byhandlefileinformation.h"
|
||||
#include "libc/nt/struct/overlapped.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
|
||||
if (start < 0) return einval();
|
||||
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
|
||||
struct FileLock {
|
||||
struct FileLock *next;
|
||||
int64_t off;
|
||||
int64_t len;
|
||||
int fd;
|
||||
bool exc;
|
||||
};
|
||||
|
||||
struct FileLocks {
|
||||
pthread_mutex_t mu;
|
||||
struct FileLock *list;
|
||||
struct FileLock *free;
|
||||
};
|
||||
|
||||
static struct FileLocks g_locks;
|
||||
|
||||
static textwindows struct FileLock *NewFileLock(void) {
|
||||
struct FileLock *fl;
|
||||
if (g_locks.free) {
|
||||
fl = g_locks.free;
|
||||
g_locks.free = fl->next;
|
||||
} else {
|
||||
fl = kmalloc(sizeof(*fl));
|
||||
}
|
||||
bzero(fl, sizeof(*fl));
|
||||
fl->next = g_locks.list;
|
||||
g_locks.list = fl;
|
||||
return fl;
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
||||
static textwindows void FreeFileLock(struct FileLock *fl) {
|
||||
fl->next = g_locks.free;
|
||||
g_locks.free = fl;
|
||||
}
|
||||
|
||||
static textwindows bool OverlapsFileLock(struct FileLock *fl, int64_t off,
|
||||
int64_t len) {
|
||||
uint64_t BegA, EndA, BegB, EndB;
|
||||
BegA = off;
|
||||
EndA = off + (len - 1);
|
||||
BegB = fl->off;
|
||||
EndB = fl->off + (fl->len - 1);
|
||||
return MAX(BegA, BegB) < MIN(EndA, EndB);
|
||||
}
|
||||
|
||||
static textwindows bool EncompassesFileLock(struct FileLock *fl, int64_t off,
|
||||
int64_t len) {
|
||||
return off <= fl->off && fl->off + fl->len <= off + len;
|
||||
}
|
||||
|
||||
static textwindows bool EqualsFileLock(struct FileLock *fl, int64_t off,
|
||||
int64_t len) {
|
||||
return fl->off == off && off + len == fl->off + fl->len;
|
||||
}
|
||||
|
||||
hidden textwindows void sys_fcntl_nt_lock_cleanup(int fd) {
|
||||
struct FileLock *fl, *ft, **flp;
|
||||
pthread_mutex_lock(&g_locks.mu);
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
if (fl->fd == fd) {
|
||||
*flp = fl->next;
|
||||
ft = fl->next;
|
||||
FreeFileLock(fl);
|
||||
fl = ft;
|
||||
} else {
|
||||
flp = &fl->next;
|
||||
fl = *flp;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&g_locks.mu);
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
|
||||
uintptr_t arg) {
|
||||
int e;
|
||||
struct flock *l;
|
||||
uint32_t flags, err;
|
||||
int64_t pos, off, len, size;
|
||||
struct NtByHandleFileInformation info;
|
||||
|
||||
if (!GetFileInformationByHandle(f->handle, &info)) {
|
||||
return __winerr();
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
if (!SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) {
|
||||
return __winerr();
|
||||
}
|
||||
struct FileLock *fl, *ft, **flp;
|
||||
int64_t pos, off, len, end, size;
|
||||
|
||||
l = (struct flock *)arg;
|
||||
len = l->l_len;
|
||||
off = l->l_start;
|
||||
size = (uint64_t)info.nFileSizeHigh << 32 | info.nFileSizeLow;
|
||||
|
||||
switch (l->l_whence) {
|
||||
case SEEK_SET:
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
off = pos + off;
|
||||
pos = 0;
|
||||
if (SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) {
|
||||
off = pos + off;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
break;
|
||||
case SEEK_END:
|
||||
off = size - off;
|
||||
off = INT64_MAX - off;
|
||||
break;
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (!len) {
|
||||
len = size - off;
|
||||
len = INT64_MAX - off;
|
||||
}
|
||||
|
||||
if (off < 0 || len < 0) {
|
||||
if (off < 0 || len < 0 || __builtin_add_overflow(off, len, &end)) {
|
||||
return einval();
|
||||
}
|
||||
|
||||
|
@ -89,8 +158,57 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
|||
.Pointer = (void *)(uintptr_t)off};
|
||||
|
||||
if (l->l_type == F_RDLCK || l->l_type == F_WRLCK) {
|
||||
|
||||
if (cmd == F_SETLK || cmd == F_SETLKW) {
|
||||
// make it possible to transition read locks to write locks
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
if (fl->fd == fd) {
|
||||
if (EqualsFileLock(fl, off, len)) {
|
||||
if (fl->exc == l->l_type == F_WRLCK) {
|
||||
// we already have this lock
|
||||
return 0;
|
||||
} else {
|
||||
// unlock our read lock and acquire write lock below
|
||||
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
*flp = fl->next;
|
||||
ft = fl->next;
|
||||
FreeFileLock(fl);
|
||||
fl = ft;
|
||||
continue;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else if (OverlapsFileLock(fl, off, len)) {
|
||||
return enotsup();
|
||||
}
|
||||
}
|
||||
flp = &fl->next;
|
||||
fl = *flp;
|
||||
}
|
||||
}
|
||||
|
||||
// return better information on conflicting locks if possible
|
||||
if (cmd == F_GETLK) {
|
||||
for (fl = g_locks.list; fl; fl = fl->next) {
|
||||
if (fl->fd == fd && //
|
||||
OverlapsFileLock(fl, off, len) &&
|
||||
(l->l_type == F_WRLCK || !fl->exc)) {
|
||||
l->l_whence = SEEK_SET;
|
||||
l->l_start = fl->off;
|
||||
l->l_len = fl->len;
|
||||
l->l_type == fl->exc ? F_WRLCK : F_RDLCK;
|
||||
l->l_pid = getpid();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
if (cmd != F_SETLKW) {
|
||||
// TODO(jart): we should use expo backoff in wrapper function
|
||||
// should not matter since sqlite doesn't need it
|
||||
flags |= kNtLockfileFailImmediately;
|
||||
}
|
||||
if (l->l_type == F_WRLCK) {
|
||||
|
@ -101,68 +219,133 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
|||
if (ok) {
|
||||
l->l_type = F_UNLCK;
|
||||
if (!UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
notpossible;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
l->l_pid = -1;
|
||||
ok = true;
|
||||
}
|
||||
} else if (ok) {
|
||||
fl = NewFileLock();
|
||||
fl->off = off;
|
||||
fl->len = len;
|
||||
fl->exc = l->l_type == F_WRLCK;
|
||||
fl->fd = fd;
|
||||
}
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
if (l->l_type == F_UNLCK) {
|
||||
if (cmd == F_GETLK) return einval();
|
||||
e = errno;
|
||||
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
return 0;
|
||||
} else if (errno == ENOLCK) {
|
||||
errno = e;
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
|
||||
// allow a big range to unlock many small ranges
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
if (fl->fd == fd && EncompassesFileLock(fl, off, len)) {
|
||||
struct NtOverlapped ov = {.hEvent = f->handle,
|
||||
.Pointer = (void *)(uintptr_t)fl->off};
|
||||
if (UnlockFileEx(f->handle, 0, fl->len, fl->len >> 32, &ov)) {
|
||||
*flp = fl->next;
|
||||
ft = fl->next;
|
||||
FreeFileLock(fl);
|
||||
fl = ft;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
flp = &fl->next;
|
||||
fl = *flp;
|
||||
}
|
||||
}
|
||||
|
||||
// win32 won't let us carve up existing locks
|
||||
int overlap_count = 0;
|
||||
for (fl = g_locks.list; fl; fl = fl->next) {
|
||||
if (fl->fd == fd && //
|
||||
OverlapsFileLock(fl, off, len)) {
|
||||
++overlap_count;
|
||||
}
|
||||
}
|
||||
|
||||
// try to handle the carving cases needed by sqlite
|
||||
if (overlap_count == 1) {
|
||||
for (fl = g_locks.list; fl; fl = fl->next) {
|
||||
if (fl->fd == fd && //
|
||||
off <= fl->off && //
|
||||
off + len >= fl->off && //
|
||||
off + len < fl->off + fl->len) {
|
||||
// cleave left side of lock
|
||||
struct NtOverlapped ov = {.hEvent = f->handle,
|
||||
.Pointer = (void *)(uintptr_t)fl->off};
|
||||
if (!UnlockFileEx(f->handle, 0, fl->len, fl->len >> 32, &ov)) {
|
||||
return -1;
|
||||
}
|
||||
fl->len = (fl->off + fl->len) - (off + len);
|
||||
fl->off = off + len;
|
||||
ov.Pointer = (void *)(uintptr_t)fl->off;
|
||||
if (!LockFileEx(f->handle, kNtLockfileExclusiveLock, 0, fl->len,
|
||||
fl->len >> 32, &ov)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (overlap_count) {
|
||||
return enotsup();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return einval();
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
|
||||
if (start < 0) return einval();
|
||||
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
|
||||
}
|
||||
|
||||
textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
|
||||
int rc;
|
||||
uint32_t flags;
|
||||
if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdSocket)) {
|
||||
if (cmd == F_GETFL) {
|
||||
return g_fds.p[fd].flags &
|
||||
(O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME |
|
||||
O_NONBLOCK | O_RANDOM | O_SEQUENTIAL);
|
||||
rc = g_fds.p[fd].flags &
|
||||
(O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME | O_NONBLOCK |
|
||||
O_RANDOM | O_SEQUENTIAL);
|
||||
} else if (cmd == F_SETFL) {
|
||||
// O_APPEND doesn't appear to be tunable at cursory glance
|
||||
// O_NONBLOCK might require we start doing all i/o in threads
|
||||
// O_DSYNC / O_RSYNC / O_SYNC maybe if we fsync() everything
|
||||
// O_DIRECT | O_RANDOM | O_SEQUENTIAL | O_NDELAY possible but
|
||||
// not worth it.
|
||||
return einval();
|
||||
rc = einval();
|
||||
} else if (cmd == F_GETFD) {
|
||||
if (g_fds.p[fd].flags & O_CLOEXEC) {
|
||||
return FD_CLOEXEC;
|
||||
rc = FD_CLOEXEC;
|
||||
} else {
|
||||
return 0;
|
||||
rc = 0;
|
||||
}
|
||||
} else if (cmd == F_SETFD) {
|
||||
if (arg & FD_CLOEXEC) {
|
||||
g_fds.p[fd].flags |= O_CLOEXEC;
|
||||
return FD_CLOEXEC;
|
||||
rc = FD_CLOEXEC;
|
||||
} else {
|
||||
g_fds.p[fd].flags &= ~O_CLOEXEC;
|
||||
return 0;
|
||||
rc = 0;
|
||||
}
|
||||
} else if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK) {
|
||||
return sys_fcntl_nt_lock(g_fds.p + fd, cmd, arg);
|
||||
pthread_mutex_lock(&g_locks.mu);
|
||||
rc = sys_fcntl_nt_lock(g_fds.p + fd, fd, cmd, arg);
|
||||
pthread_mutex_unlock(&g_locks.mu);
|
||||
} else if (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC) {
|
||||
return sys_fcntl_nt_dupfd(fd, cmd, arg);
|
||||
rc = sys_fcntl_nt_dupfd(fd, cmd, arg);
|
||||
} else {
|
||||
return einval();
|
||||
rc = einval();
|
||||
}
|
||||
} else {
|
||||
return ebadf();
|
||||
rc = ebadf();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Does things with file descriptor, via re-imagined hourglass api, e.g.
|
||||
* Does things with file descriptor, e.g.
|
||||
*
|
||||
* CHECK_NE(-1, fcntl(fd, F_SETFD, FD_CLOEXEC));
|
||||
*
|
||||
|
@ -41,12 +41,14 @@
|
|||
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD, 3)), 3);
|
||||
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD_CLOEXEC, 3)), 3);
|
||||
*
|
||||
* This function implements POSIX Advisory Locks, which let independent
|
||||
* processes (and on Windows, threads too!) read/write lock byte ranges
|
||||
* of files. See `test/libc/calls/lock_test.c` for an example.
|
||||
* This function implements file record locking, which lets independent
|
||||
* processes (and on Linux 3.15+, threads too!) lock arbitrary ranges
|
||||
* associated with a file. See `test/libc/calls/lock_test.c` and other
|
||||
* locking related tests in that folder.
|
||||
*
|
||||
* Please be warned that locks currently do nothing on Windows since
|
||||
* figuring out how to polyfill them correctly is a work in progress.
|
||||
* On Windows, the Cosmopolitan Libc polyfill for POSIX advisory locks
|
||||
* only implements enough of its nuances to support SQLite's needs. Some
|
||||
* possibilities, e.g. punching holes in lock, will raise `ENOTSUP`.
|
||||
*
|
||||
* @param fd is the file descriptor
|
||||
* @param cmd can be one of:
|
||||
|
@ -56,12 +58,12 @@
|
|||
* - `F_SETFL` sets file descriptor status flags
|
||||
* - `F_DUPFD` is like dup() but `arg` is a minimum result, e.g. 3
|
||||
* - `F_DUPFD_CLOEXEC` ditto but sets `O_CLOEXEC` on returned fd
|
||||
* - `F_SETLK` for record locking where `arg` is `struct flock`
|
||||
* - `F_SETLKW` ditto but waits (i.e. blocks) for lock
|
||||
* - `F_SETLK` for record locking where `arg` is `struct flock *`
|
||||
* - `F_SETLKW` ditto but waits for lock (SQLite avoids this)
|
||||
* - `F_GETLK` to retrieve information about a record lock
|
||||
* - `F_OFD_SETLK` for better locks on Linux and XNU
|
||||
* - `F_OFD_SETLKW` for better locks on Linux and XNU
|
||||
* - `F_OFD_GETLK` for better locks on Linux and XNU
|
||||
* - `F_OFD_SETLK` for better non-blocking lock (Linux 3.15+ only)
|
||||
* - `F_OFD_SETLKW` for better blocking lock (Linux 3.15+ only)
|
||||
* - `F_OFD_GETLK` for better lock querying (Linux 3.15+ only)
|
||||
* - `F_FULLFSYNC` on MacOS for fsync() with release barrier
|
||||
* - `F_BARRIERFSYNC` on MacOS for fsync() with even more barriers
|
||||
* - `F_SETNOSIGPIPE` on MacOS and NetBSD to control `SIGPIPE`
|
||||
|
@ -71,7 +73,7 @@
|
|||
* - `F_NOCACHE` on MacOS to toggle data caching
|
||||
* - `F_GETPIPE_SZ` on Linux to get pipe size
|
||||
* - `F_SETPIPE_SZ` on Linux to set pipe size
|
||||
* - `F_NOTIFY` raise `SIGIO` upon `fd` events in `arg` on Linux
|
||||
* - `F_NOTIFY` raise `SIGIO` upon `fd` events in `arg` (Linux only)
|
||||
* - `DN_ACCESS` for file access
|
||||
* - `DN_MODIFY` for file modifications
|
||||
* - `DN_CREATE` for file creations
|
||||
|
@ -88,6 +90,7 @@
|
|||
* @raise ENOLCK if `F_SETLKW` would have exceeded `RLIMIT_LOCKS`
|
||||
* @raise EPERM if `cmd` is `F_SETOWN` and we weren't authorized
|
||||
* @raise ESRCH if `cmd` is `F_SETOWN` and process group not found
|
||||
* @raise ENOTSUP on Windows if locking operation isn't supported yet
|
||||
* @raise EDEADLK if `cmd` was `F_SETLKW` and waiting would deadlock
|
||||
* @raise EMFILE if `cmd` is `F_DUPFD` or `F_DUPFD_CLOEXEC` and
|
||||
* `RLIMIT_NOFILE` would be exceeded
|
||||
|
|
|
@ -18,7 +18,6 @@ hidden extern const struct Fd kEmptyFd;
|
|||
int __reservefd(int) hidden;
|
||||
int __reservefd_unlocked(int) hidden;
|
||||
void __releasefd(int) hidden;
|
||||
void __releasefd_unlocked(int) hidden;
|
||||
int __ensurefds(int) hidden;
|
||||
int __ensurefds_unlocked(int) hidden;
|
||||
void __printfds(void) hidden;
|
||||
|
@ -43,7 +42,7 @@ forceinline size_t _clampio(size_t size) {
|
|||
}
|
||||
}
|
||||
|
||||
int sys_close_nt(struct Fd *) hidden;
|
||||
int sys_close_nt(struct Fd *, int) hidden;
|
||||
bool _check_interrupts(bool, struct Fd *) hidden;
|
||||
int sys_openat_metal(int, const char *, int, unsigned);
|
||||
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
|
@ -38,6 +38,10 @@
|
|||
* >0 can be SIGINT, SIGTERM, SIGKILL, SIGUSR1, etc.
|
||||
* =0 checks both if pid exists and we can signal it
|
||||
* @return 0 if something was accomplished, or -1 w/ errno
|
||||
* @raise ESRCH if `pid` couldn't be found
|
||||
* @raise EPERM if lacked permission to signal process
|
||||
* @raise EPERM if pledge() is in play without `proc` promised
|
||||
* @raise EINVAL if the provided `sig` is invalid or unsupported
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int kill(int pid, int sig) {
|
||||
|
|
|
@ -88,7 +88,7 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
|
|||
rc = sys_open_nt_file(dirfd, file, flags, mode, fd);
|
||||
}
|
||||
if (rc == -1) {
|
||||
__releasefd_unlocked(fd);
|
||||
__releasefd(fd);
|
||||
}
|
||||
__fds_unlock();
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) {
|
|||
return -1;
|
||||
}
|
||||
if ((writer = __reservefd_unlocked(-1)) == -1) {
|
||||
__releasefd_unlocked(reader);
|
||||
__releasefd(reader);
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
|
@ -73,8 +73,8 @@ textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) {
|
|||
CloseHandle(hin);
|
||||
}
|
||||
}
|
||||
__releasefd_unlocked(writer);
|
||||
__releasefd_unlocked(reader);
|
||||
__releasefd(writer);
|
||||
__releasefd(reader);
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -1606,19 +1606,26 @@ static privileged void AllowFcntlStdio(struct Filter *f) {
|
|||
|
||||
// The second argument of fcntl() must be one of:
|
||||
//
|
||||
// - F_GETLK (5)
|
||||
// - F_SETLK (6)
|
||||
// - F_SETLKW (7)
|
||||
// - F_GETLK (0x05)
|
||||
// - F_SETLK (0x06)
|
||||
// - F_SETLKW (0x07)
|
||||
// - F_OFD_GETLK (0x24)
|
||||
// - F_OFD_SETLK (0x25)
|
||||
// - F_OFD_SETLKW (0x26)
|
||||
//
|
||||
static privileged void AllowFcntlLock(struct Filter *f) {
|
||||
static const struct sock_filter fragment[] = {
|
||||
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_fcntl, 0, 6 - 1),
|
||||
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
/*L2*/ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 5, 0, 5 - 3),
|
||||
/*L3*/ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 8, 5 - 4, 0),
|
||||
/*L4*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
/*L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/*L6*/ /* next filter */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_fcntl, 0, 9),
|
||||
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x05, 5, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x06, 4, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x07, 3, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x24, 2, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x25, 1, 0),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x26, 0, 1),
|
||||
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
|
||||
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
/* next filter */
|
||||
};
|
||||
AppendFilter(f, PLEDGE(fragment));
|
||||
}
|
||||
|
|
|
@ -16,12 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -31,16 +28,13 @@
|
|||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
|
||||
int e, i;
|
||||
size_t got;
|
||||
bool masked;
|
||||
ssize_t rc, toto;
|
||||
sigset_t mask, oldmask;
|
||||
|
||||
if (fd < 0) {
|
||||
return ebadf();
|
||||
|
@ -94,26 +88,17 @@ static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
|
|||
if (rc == -1) {
|
||||
if (!toto) {
|
||||
toto = -1;
|
||||
} else if (errno != EINTR) {
|
||||
notpossible;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
got = rc;
|
||||
toto += got;
|
||||
off += got;
|
||||
if (got != iov[i].iov_len) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!masked) {
|
||||
sigfillset(&mask);
|
||||
_npassert(!sys_sigprocmask(SIG_SETMASK, &mask, &oldmask));
|
||||
masked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (masked) {
|
||||
_npassert(!sys_sigprocmask(SIG_SETMASK, &oldmask, 0));
|
||||
}
|
||||
|
||||
return toto;
|
||||
|
|
|
@ -16,12 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -31,17 +28,14 @@
|
|||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
static ssize_t Pwritev(int fd, const struct iovec *iov, int iovlen,
|
||||
int64_t off) {
|
||||
int i, e;
|
||||
bool masked;
|
||||
size_t sent;
|
||||
ssize_t rc, toto;
|
||||
sigset_t mask, oldmask;
|
||||
|
||||
if (fd < 0) {
|
||||
return ebadf();
|
||||
|
@ -95,26 +89,17 @@ static ssize_t Pwritev(int fd, const struct iovec *iov, int iovlen,
|
|||
if (rc == -1) {
|
||||
if (!toto) {
|
||||
toto = -1;
|
||||
} else if (errno != EINTR) {
|
||||
notpossible;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
sent = rc;
|
||||
toto += sent;
|
||||
off += sent;
|
||||
if (sent != iov[i].iov_len) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!masked) {
|
||||
sigfillset(&mask);
|
||||
_npassert(!sys_sigprocmask(SIG_SETMASK, &mask, &oldmask));
|
||||
masked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (masked) {
|
||||
_npassert(!sys_sigprocmask(SIG_SETMASK, &oldmask, 0));
|
||||
}
|
||||
|
||||
return toto;
|
||||
|
|
|
@ -16,13 +16,19 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
uint32_t cfgetospeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ospeed;
|
||||
}
|
||||
// really want to avoid locking here so close() needn't block signals
|
||||
void __releasefd(int fd) {
|
||||
int f1, f2;
|
||||
if (!(0 <= fd && fd < g_fds.n)) return;
|
||||
bzero(g_fds.p + fd, sizeof(*g_fds.p));
|
||||
f1 = atomic_load_explicit(&g_fds.f, memory_order_relaxed);
|
||||
do {
|
||||
f2 = MIN(fd, f1);
|
||||
} while (!atomic_compare_exchange_weak_explicit(
|
||||
&g_fds.f, &f1, f2, memory_order_release, memory_order_relaxed));
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/extend.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
|
@ -36,6 +37,8 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
// TODO(jart): make more of this code lockless
|
||||
|
||||
static volatile size_t mapsize;
|
||||
|
||||
/**
|
||||
|
@ -71,9 +74,10 @@ int __ensurefds(int fd) {
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int __reservefd_unlocked(int start) {
|
||||
int fd;
|
||||
int fd, f1, f2;
|
||||
for (;;) {
|
||||
for (fd = MAX(start, g_fds.f); fd < g_fds.n; ++fd) {
|
||||
f1 = atomic_load_explicit(&g_fds.f, memory_order_acquire);
|
||||
for (fd = MAX(start, f1); fd < g_fds.n; ++fd) {
|
||||
if (!g_fds.p[fd].kind) {
|
||||
break;
|
||||
}
|
||||
|
@ -81,7 +85,11 @@ int __reservefd_unlocked(int start) {
|
|||
fd = __ensurefds_unlocked(fd);
|
||||
bzero(g_fds.p + fd, sizeof(*g_fds.p));
|
||||
if (_cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
|
||||
_cmpxchg(&g_fds.f, fd, fd + 1);
|
||||
// g_fds.f isn't guarded by our mutex
|
||||
do {
|
||||
f2 = MAX(fd + 1, f1);
|
||||
} while (!atomic_compare_exchange_weak_explicit(
|
||||
&g_fds.f, &f1, f2, memory_order_release, memory_order_relaxed));
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/blocksigs.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
|
@ -29,6 +30,7 @@
|
|||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigaction.internal.h"
|
||||
#include "libc/calls/struct/siginfo.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
|
@ -474,9 +476,11 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
if (sig == SIGKILL || sig == SIGSTOP) {
|
||||
rc = einval();
|
||||
} else {
|
||||
BLOCK_SIGNALS;
|
||||
__sig_lock();
|
||||
rc = __sigaction(sig, act, oldact);
|
||||
__sig_unlock();
|
||||
ALLOW_SIGNALS;
|
||||
}
|
||||
STRACE("sigaction(%G, %s, [%s]) → %d% m", sig, DescribeSigaction(0, act),
|
||||
DescribeSigaction(rc, oldact), rc);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||
│ 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 │
|
||||
|
@ -16,13 +16,16 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
|
||||
uint32_t cfgetispeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ispeed;
|
||||
}
|
||||
/**
|
||||
* Blocks all signals without strace logging.
|
||||
*
|
||||
* @param neu is new signal mask for process
|
||||
* @return old signal mask
|
||||
*/
|
||||
sigset_t _sigblockall(void) {
|
||||
sigset_t ss;
|
||||
sigfillset(&ss);
|
||||
return _sigsetmask(ss);
|
||||
}
|
|
@ -49,8 +49,8 @@ privileged void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo,
|
|||
__repstosb(&g.uc, 0, sizeof(g.uc));
|
||||
__siginfo2cosmo(&g.si, (void *)openbsdinfo);
|
||||
g.uc.uc_mcontext.fpregs = &g.uc.__fpustate;
|
||||
__repmovsb(&g.uc.uc_sigmask, &ctx->sc_mask,
|
||||
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->sc_mask)));
|
||||
g.uc.uc_sigmask.__bits[0] = ctx->sc_mask;
|
||||
g.uc.uc_sigmask.__bits[1] = 0;
|
||||
g.uc.uc_mcontext.rdi = ctx->sc_rdi;
|
||||
g.uc.uc_mcontext.rsi = ctx->sc_rsi;
|
||||
g.uc.uc_mcontext.rdx = ctx->sc_rdx;
|
||||
|
|
|
@ -473,6 +473,7 @@ privileged void __sigenter_xnu(void *fn, int infostyle, int sig,
|
|||
if (xnuctx) {
|
||||
g.uc.uc_flags = xnuctx->uc_onstack ? SA_ONSTACK : 0;
|
||||
g.uc.uc_sigmask.__bits[0] = xnuctx->uc_sigmask;
|
||||
g.uc.uc_sigmask.__bits[1] = 0;
|
||||
g.uc.uc_stack.ss_sp = xnuctx->uc_stack.ss_sp;
|
||||
g.uc.uc_stack.ss_flags = xnuctx->uc_stack.ss_flags;
|
||||
g.uc.uc_stack.ss_size = xnuctx->uc_stack.ss_size;
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||
│ 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 │
|
||||
|
@ -16,21 +16,25 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
int cfsetospeed(struct termios *t, unsigned speed) {
|
||||
if (CBAUD) {
|
||||
if (!(speed & ~CBAUD)) {
|
||||
t->c_cflag &= ~CBAUD;
|
||||
t->c_cflag |= speed;
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
/**
|
||||
* Sets signal mask without strace logging.
|
||||
*
|
||||
* @param neu is new signal mask for process
|
||||
* @return old signal mask
|
||||
*/
|
||||
sigset_t _sigsetmask(sigset_t neu) {
|
||||
sigset_t res;
|
||||
if (IsMetal() || IsWindows()) {
|
||||
__sig_mask(SIG_SETMASK, &neu, &res);
|
||||
} else {
|
||||
t->c_ospeed = speed;
|
||||
return 0;
|
||||
_npassert(!sys_sigprocmask(SIG_SETMASK, &neu, &res));
|
||||
}
|
||||
return res;
|
||||
}
|
|
@ -25,7 +25,7 @@ struct Fd {
|
|||
};
|
||||
|
||||
struct Fds {
|
||||
int f; /* lowest free slot */
|
||||
_Atomic(int) f; /* lowest free slot */
|
||||
size_t n;
|
||||
struct Fd *p, *e;
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ struct flock { /* cosmopolitan abi */
|
|||
int64_t l_start; /* starting offset */
|
||||
int64_t l_len; /* no. bytes (0 means to end of file) */
|
||||
int32_t l_pid; /* lock owner */
|
||||
int32_t l_sysid; /* remote system id or zero for local */
|
||||
int32_t l_sysid; /* remote system id or zero for local (freebsd) */
|
||||
};
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -21,6 +21,8 @@ int sigprocmask(int, const sigset_t *, sigset_t *);
|
|||
int sigsuspend(const sigset_t *);
|
||||
int sigpending(sigset_t *);
|
||||
int pthread_sigmask(int, const sigset_t *, sigset_t *);
|
||||
sigset_t _sigsetmask(sigset_t);
|
||||
sigset_t _sigblockall(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -10,8 +10,8 @@ COSMOPOLITAN_C_START_
|
|||
│ cosmopolitan § syscalls » system five » structless synthetic jump slots ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
axdx_t __sys_fork(void) hidden;
|
||||
axdx_t __sys_pipe(i32[hasatleast 2], i32) hidden;
|
||||
axdx_t sys_fork(void) hidden;
|
||||
axdx_t sys_getpid(void) hidden;
|
||||
char *sys_getcwd(char *, u64) hidden;
|
||||
char *sys_getcwd_xnu(char *, u64) hidden;
|
||||
|
@ -46,6 +46,7 @@ i32 sys_fchownat(i32, const char *, u32, u32, u32) hidden;
|
|||
i32 sys_fcntl(i32, i32, u64) hidden;
|
||||
i32 sys_fdatasync(i32) hidden;
|
||||
i32 sys_flock(i32, i32) hidden;
|
||||
i32 sys_fork(void) hidden;
|
||||
i32 sys_fsync(i32) hidden;
|
||||
i32 sys_ftruncate(i32, i64, i64) hidden;
|
||||
i32 sys_getcontext(void *) hidden;
|
||||
|
|
|
@ -16,8 +16,41 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int tcdrain(int fd) {
|
||||
return ioctl(fd, TCSBRK, (void *)(intptr_t)1);
|
||||
static textwindows int sys_tcdrain_nt(int fd) {
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
if (!FlushFileBuffers(g_fds.p[fd].handle)) return __winerr();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until all written output is transmitted.
|
||||
*
|
||||
* @param fd is file descriptor of tty
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise ENOTTY if `fd` is open but not a teletypewriter
|
||||
* @raise EIO if process group of writer is orphoned, calling thread is
|
||||
* not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU`
|
||||
* @raise ENOSYS on bare metal
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tcdrain(int fd) {
|
||||
int rc;
|
||||
if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_ioctl(fd, TCSBRK, (void *)(intptr_t)1);
|
||||
} else {
|
||||
rc = sys_tcdrain_nt(fd);
|
||||
}
|
||||
STRACE("tcdrain(%d) → %d% m", fd, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,31 +16,91 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/comms.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define kNtPurgeTxabort 1
|
||||
#define kNtPurgeRxabort 2
|
||||
|
||||
static const char *DescribeFlow(char buf[12], int action) {
|
||||
if (action == TCOOFF) return "TCOOFF";
|
||||
if (action == TCOON) return "TCOON";
|
||||
if (action == TCIOFF) return "TCIOFF";
|
||||
if (action == TCION) return "TCION";
|
||||
FormatInt32(buf, action);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int sys_tcflow_bsd(int fd, int action) {
|
||||
int rc;
|
||||
uint8_t c;
|
||||
struct termios t;
|
||||
if (action == TCOOFF) return sys_ioctl(fd, TIOCSTOP, 0);
|
||||
if (action == TCOON) return sys_ioctl(fd, TIOCSTART, 0);
|
||||
if (action != TCIOFF && action != TCION) return einval();
|
||||
if (sys_ioctl(fd, TCGETS, &t) == -1) return -1;
|
||||
c = t.c_cc[action == TCIOFF ? VSTOP : VSTART];
|
||||
if (c == 255) return 0; // code is disabled
|
||||
if (sys_write(fd, &c, 1) == -1) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static dontinline textwindows int sys_tcflow_nt(int fd, int action) {
|
||||
bool32 ok;
|
||||
int64_t h;
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
h = g_fds.p[fd].handle;
|
||||
if (action == TCOOFF) {
|
||||
ok = PurgeComm(h, kNtPurgeTxabort);
|
||||
} else if (action == TCIOFF) {
|
||||
ok = PurgeComm(h, kNtPurgeRxabort);
|
||||
} else if (action == TCOON || action == TCION) {
|
||||
ok = ClearCommBreak(h);
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
return ok ? 0 : __winerr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes flow of teletypewriter data.
|
||||
*
|
||||
* - `TCOOFF` suspends output
|
||||
* - `TCOON` resumes output
|
||||
* - `TCIOFF` transmits a STOP character
|
||||
* - `TCION` transmits a START character
|
||||
* @param fd is file descriptor of tty
|
||||
* @param action may be one of:
|
||||
* - `TCOOFF` to suspend output
|
||||
* - `TCOON` to resume output
|
||||
* - `TCIOFF` to transmit a `STOP` character
|
||||
* - `TCION` to transmit a `START` character
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINVAL if `action` is invalid
|
||||
* @raise ENOSYS on Windows and Bare Metal
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise ENOTTY if `fd` is open but not a teletypewriter
|
||||
* @raise EIO if process group of writer is orphoned, calling thread is
|
||||
* not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU`
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tcflow(int fd, int action) {
|
||||
uint8_t c;
|
||||
struct termios t;
|
||||
if (!IsBsd()) return sys_ioctl(fd, TCXONC, action);
|
||||
if (action == TCOOFF) return sys_ioctl(fd, TIOCSTOP, 0);
|
||||
if (action == TCOON) return sys_ioctl(fd, TIOCSTART, 0);
|
||||
if (action != TCIOFF && action != TCION) return einval();
|
||||
if (tcgetattr(fd, &t) == -1) return -1;
|
||||
if ((c = t.c_cc[action == TCIOFF ? VSTOP : VSTART]) != 255) {
|
||||
if (sys_write(fd, &c, 1) == -1) return -1;
|
||||
int rc;
|
||||
if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (IsBsd()) {
|
||||
rc = sys_ioctl(fd, TCXONC, action);
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_ioctl(fd, TCXONC, action);
|
||||
} else {
|
||||
rc = sys_tcflow_nt(fd, action);
|
||||
}
|
||||
return 0;
|
||||
STRACE("tcflow(%d, %s) → %d% m", fd, DescribeFlow(alloca(12), action), rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,17 +16,70 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/comms.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define kNtPurgeTxclear 4
|
||||
#define kNtPurgeRxclear 8
|
||||
|
||||
static const char *DescribeFlush(char buf[12], int action) {
|
||||
if (action == TCIFLUSH) return "TCIFLUSH";
|
||||
if (action == TCOFLUSH) return "TCOFLUSH";
|
||||
if (action == TCIOFLUSH) return "TCIOFLUSH";
|
||||
FormatInt32(buf, action);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static dontinline textwindows int sys_tcflush_nt(int fd, int queue) {
|
||||
bool32 ok;
|
||||
int64_t h;
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
ok = true;
|
||||
h = g_fds.p[fd].handle;
|
||||
if (queue == TCIFLUSH || queue == TCIOFLUSH) {
|
||||
ok &= !!PurgeComm(h, kNtPurgeRxclear);
|
||||
}
|
||||
if (queue == TCOFLUSH || queue == TCIOFLUSH) {
|
||||
ok &= !!PurgeComm(h, kNtPurgeTxclear);
|
||||
}
|
||||
return ok ? 0 : __winerr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes teletypewriter data.
|
||||
* Discards queued data on teletypewriter.
|
||||
*
|
||||
* - `TCIFLUSH` flushes data received but not read
|
||||
* - `TCOFLUSH` flushes data written but not transmitted
|
||||
* - `TCIOFLUSH` does both `TCOFLUSH` and `TCIFLUSH`
|
||||
* @param queue may be one of:
|
||||
* - `TCIFLUSH` flushes data received but not read
|
||||
* - `TCOFLUSH` flushes data written but not transmitted
|
||||
* - `TCIOFLUSH` does both `TCOFLUSH` and `TCIFLUSH`
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINVAL if `action` is invalid
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise ENOTTY if `fd` is open but not a teletypewriter
|
||||
* @raise EIO if process group of writer is orphoned, calling thread is
|
||||
* not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU`
|
||||
* @raise ENOSYS on bare metal
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tcflush(int fd, int queue) {
|
||||
/* TODO(jart): Windows? */
|
||||
return sys_ioctl(fd, TCFLSH, queue);
|
||||
int rc;
|
||||
if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_ioctl(fd, TCFLSH, queue);
|
||||
} else {
|
||||
rc = sys_tcflush_nt(fd, queue);
|
||||
}
|
||||
STRACE("tcflush(%d, %s) → %d% m", fd, DescribeFlush(alloca(12), queue), rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,16 +16,29 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns which process group controls terminal.
|
||||
*
|
||||
* @return process group id on success, or -1 w/ errno
|
||||
* @raise ENOTTY if `fd` is isn't controlling teletypewriter
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise ENOSYS on Windows and Bare Metal
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int32_t tcgetpgrp(int fd) {
|
||||
int pgrp;
|
||||
if (ioctl(fd, TIOCGPGRP, &pgrp) < 0) return -1;
|
||||
return pgrp;
|
||||
int tcgetpgrp(int fd) {
|
||||
int rc, pgrp;
|
||||
if (IsWindows() || IsMetal()) {
|
||||
rc = enosys();
|
||||
} else {
|
||||
rc = sys_ioctl(fd, TIOCGPGRP, &pgrp);
|
||||
}
|
||||
STRACE("tcgetpgrp(%d) → %d% m", fd, rc == -1 ? rc : pgrp);
|
||||
return rc == -1 ? rc : pgrp;
|
||||
}
|
||||
|
|
|
@ -17,18 +17,53 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/comms.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int tcsendbreak(int fd, int len) {
|
||||
if (!IsBsd()) {
|
||||
return sys_ioctl(fd, TCSBRK, 0);
|
||||
} else {
|
||||
if (sys_ioctl(fd, TIOCSBRK, 0) == -1) return -1;
|
||||
usleep(400000);
|
||||
if (sys_ioctl(fd, TIOCCBRK, 0) == -1) return -1;
|
||||
return 0;
|
||||
}
|
||||
static int sys_tcsendbreak_bsd(int fd) {
|
||||
if (sys_ioctl(fd, TIOCSBRK, 0) == -1) return -1;
|
||||
usleep(400000);
|
||||
if (sys_ioctl(fd, TIOCCBRK, 0) == -1) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static textwindows int sys_tcsendbreak_nt(int fd) {
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
if (!TransmitCommChar(g_fds.p[fd].handle, '\0')) return __winerr();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends break.
|
||||
*
|
||||
* @param fd is file descriptor of tty
|
||||
* @param duration of 0 sends a break for 0.25-0.5 seconds, and other
|
||||
* durations are treated the same by this implementation
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise ENOTTY if `fd` is open but not a teletypewriter
|
||||
* @raise EIO if process group of writer is orphoned, calling thread is
|
||||
* not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU`
|
||||
* @raise ENOSYS on bare metal
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tcsendbreak(int fd, int duration) {
|
||||
int rc;
|
||||
if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (IsBsd()) {
|
||||
rc = sys_tcsendbreak_bsd(fd);
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_ioctl(fd, TCSBRK, 0);
|
||||
} else {
|
||||
rc = sys_tcsendbreak_nt(fd);
|
||||
}
|
||||
STRACE("tcsendbreak(%d, %u) → %d% m", fd, duration, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -17,14 +17,33 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Puts process group in control of terminal.
|
||||
* Sets foreground process group id.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINVAL if `pgrp` is invalid
|
||||
* @raise ENOSYS on Windows and Bare Metal
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise EPERM if `pgrp` didn't match process in our group
|
||||
* @raise ENOTTY if `fd` is isn't controlling teletypewriter
|
||||
* @raise EIO if process group of writer is orphoned, calling thread is
|
||||
* not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU`
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tcsetpgrp(int fd, int32_t pgrp) {
|
||||
int pgrp_int = pgrp;
|
||||
return ioctl(fd, TIOCSPGRP, &pgrp_int);
|
||||
int tcsetpgrp(int fd, int pgrp) {
|
||||
int rc;
|
||||
if (IsWindows() || IsMetal()) {
|
||||
rc = enosys();
|
||||
} else {
|
||||
rc = sys_ioctl(fd, TIOCSPGRP, &pgrp);
|
||||
}
|
||||
STRACE("tcsetpgrp(%d, %d) → %d% m", fd, pgrp, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
/*-*- 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 2020 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/dce.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/mem/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
#define ToUpper(c) \
|
||||
(IsWindows() && (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
|
||||
/**
|
||||
* Removes environment variable.
|
||||
*/
|
||||
int unsetenv(const char *s) {
|
||||
char **p;
|
||||
size_t i, j, k;
|
||||
if (s && (p = environ)) {
|
||||
for (i = 0; p[i]; ++i) {
|
||||
for (j = 0;; ++j) {
|
||||
if (!s[j]) {
|
||||
if (p[i][j] == '=') {
|
||||
if (_weaken(__freeenv)) {
|
||||
_weaken(__freeenv)(p[i]);
|
||||
}
|
||||
k = i + 1;
|
||||
do {
|
||||
p[k - 1] = p[k];
|
||||
} while (p[k++]);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ToUpper(s[j]) != ToUpper(p[i][j])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue