Make improvements

- Polyfill pselect() on Windows
- Add -O NOFILE flag to pledge.com
- Polyfill ppoll() on NetBSD, XNU, and Windows
- Support negative numbers and errno in sizetol()
- Add .RSS, .NOFILE, and .MAXCORE to Landlock Make
- Fix issue with .PLEDGE preventing touching of output files
- Add __watch() function (like ftrace) for logging memory changes
This commit is contained in:
Justine Tunney 2022-08-15 15:18:37 -07:00
parent d3b599a796
commit f0701d2a24
35 changed files with 635 additions and 340 deletions

View file

@ -23,7 +23,7 @@
# - tool/build/runitd.c
.PRECIOUS: o/$(MODE)/%.com.ok
o/$(MODE)/%.com.ok: .PLEDGE = stdio rpath wpath cpath proc inet
o/$(MODE)/%.com.ok: .PLEDGE = stdio rpath wpath cpath proc fattr inet
o/$(MODE)/%.com.ok: \
o/$(MODE)/tool/build/runit.com \
o/$(MODE)/tool/build/runitd.com \

View file

@ -35,7 +35,7 @@ static void SetLimit(int resource, uint64_t soft, uint64_t hard) {
if (setrlimit(resource, &lim) == -1) {
if (!getrlimit(resource, &old)) {
lim.rlim_max = MIN(hard, old.rlim_max);
lim.rlim_cur = MIN(soft, lim.rlim_max);
lim.rlim_cur = MIN(soft, old.rlim_max);
if (!setrlimit(resource, &lim)) {
fprintf(stderr, "%sNOTE: SETRLIMIT(%s) DOWNGRADED TO {%,ld, %,ld}\n",
DescribeRlimitName(resource), lim.rlim_cur, lim.rlim_max);

View file

@ -19,7 +19,6 @@
#include "libc/assert.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/macros.internal.h"
#include "libc/math.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/itimer.h"
#include "libc/time/time.h"

View file

@ -16,10 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/termios.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
@ -36,8 +36,8 @@
*/
int getttysize(int fd, struct winsize *out) {
if (__nocolor) {
out->ws_col = strtoimax(firstnonnull(getenv("COLUMNS"), "80"), NULL, 0);
out->ws_row = strtoimax(firstnonnull(getenv("ROWS"), "40"), NULL, 0);
out->ws_col = atoi(firstnonnull(getenv("COLUMNS"), "80"));
out->ws_row = atoi(firstnonnull(getenv("ROWS"), "40"));
out->ws_xpixel = 0;
out->ws_ypixel = 0;
return 0;

View file

@ -39,6 +39,7 @@
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/sock/struct/pollfd.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sig.h"
@ -51,9 +52,11 @@
* on both sockets and files at the same time. We also poll for signals
* while poll is polling.
*/
textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) {
textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
const sigset_t *sigmask) {
bool ok;
uint32_t avail;
sigset_t oldmask;
struct sys_pollfd_nt pipefds[8];
struct sys_pollfd_nt sockfds[64];
int pipeindices[ARRAYLEN(pipefds)];
@ -61,6 +64,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) {
int i, sn, pn, failed, gotinvals, gotpipes, gotsocks, waitfor;
// check for interrupts early before doing work
if (sigmask && __sig_mask(SIG_SETMASK, sigmask, &oldmask)) return -1;
if (_check_interrupts(false, g_fds.p)) return eintr();
// do the planning

View file

@ -81,7 +81,7 @@ int poll(struct pollfd *fds, size_t nfds, int timeout_ms) {
}
} else {
millis = timeout_ms;
rc = sys_poll_nt(fds, nfds, &millis);
rc = sys_poll_nt(fds, nfds, &millis, 0);
}
#if defined(SYSDEBUG) && _POLLTRACE

107
libc/calls/ppoll.c Normal file
View file

@ -0,0 +1,107 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/sock/ppoll.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/sock/struct/pollfd.internal.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
/**
* Waits for something to happen on multiple file descriptors at once.
*
* This function is the same as saying:
*
* sigset_t old;
* sigprocmask(SIG_SETMASK, sigmask, &old);
* poll(fds, nfds, timeout);
* sigprocmask(SIG_SETMASK, old, 0);
*
* Except it'll happen atomically if the kernel supports doing that. On
* kernel such as XNU and NetBSD which don't, this wrapper falls back to
* doing the thing described above.
*
* @param timeout if null will block indefinitely
* @param sigmask may be null in which case no mask change happens
* @asyncsignalsafe
* @threadsafe
* @norestart
*/
int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
const sigset_t *sigmask) {
int e, i, rc;
uint64_t millis;
sigset_t oldmask;
if (IsAsan() && (!__asan_is_valid(fds, nfds * sizeof(struct pollfd)) ||
(timeout && !__asan_is_valid(timeout, sizeof(timeout))) ||
(sigmask && !__asan_is_valid(sigmask, sizeof(sigmask))))) {
rc = efault();
} else if (!IsWindows()) {
e = errno;
rc = sys_ppoll(fds, nfds, timeout, sigmask);
if (rc == -1 && errno == ENOSYS) {
errno = e;
if (!timeout ||
__builtin_add_overflow(timeout->tv_sec, timeout->tv_nsec / 1000000,
&millis)) {
millis = -1;
}
if (sigmask) sys_sigprocmask(SIG_SETMASK, sigmask, &oldmask);
rc = poll(fds, nfds, millis);
if (sigmask) sys_sigprocmask(SIG_SETMASK, &oldmask, 0);
}
} else {
if (!timeout || __builtin_add_overflow(
timeout->tv_sec, timeout->tv_nsec / 1000000, &millis)) {
millis = -1;
}
rc = sys_poll_nt(fds, nfds, &millis, sigmask);
}
#if defined(SYSDEBUG) && _POLLTRACE
if (UNLIKELY(__strace > 0)) {
kprintf(STRACE_PROLOGUE "ppoll(");
if ((!IsAsan() && kisdangerous(fds)) ||
(IsAsan() && !__asan_is_valid(fds, nfds * sizeof(struct pollfd)))) {
kprintf("%p", fds);
} else {
kprintf("[{");
for (i = 0; i < MIN(5, nfds); ++i) {
kprintf("%s{%d, %s, %s}", i ? ", " : "", fds[i].fd,
DescribePollFlags(fds[i].events),
DescribePollFlags(fds[i].revents));
}
kprintf("%s}]", i == 5 ? "..." : "");
}
kprintf(", %'zu, %s, %s) → %d% lm\n", nfds, DescribeTimeval(0, timeout),
DescribeSigset(0, sigmask), rc);
}
#endif
return rc;
}

View file

@ -19,6 +19,7 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
static int GetExponent(int c) {
switch (c) {
@ -65,27 +66,41 @@ static int GetExponent(int c) {
* characters after it (e.g. kbit, Mibit, TiB) are ignored. Spaces
* before the integer are ignored, and overflows will be detected.
*
* Negative numbers are permissible, as well as a leading `+` sign. To
* tell the difference between an error return and `-1` you must clear
* `errno` before calling and test whether it changed.
*
* @param s is non-null nul-terminated input string
* @param b is multiplier which should be 1000 or 1024
* @return size greater than or equal 0 or -1 on error
* @error EINVAL if error is due to bad syntax
* @error EOVERFLOW if error is due to overflow
*/
long sizetol(const char *s, long b) {
long x;
int c, e;
int c, e, d;
do {
c = *s++;
} while (c == ' ' || c == '\t');
if (!isdigit(c)) return -1;
d = c == '-' ? -1 : 1;
if (c == '-' || c == '+') c = *s++;
if (!isdigit(c)) {
return einval();
}
x = 0;
do {
if (__builtin_mul_overflow(x, 10, &x) ||
__builtin_add_overflow(x, c - '0', &x)) {
return -1;
__builtin_add_overflow(x, (c - '0') * d, &x)) {
return eoverflow();
}
} while (isdigit((c = *s++)));
if ((e = GetExponent(c)) == -1) return -1;
if ((e = GetExponent(c)) == -1) {
return einval();
}
while (e--) {
if (__builtin_mul_overflow(x, b, &x)) return -1;
if (__builtin_mul_overflow(x, b, &x)) {
return eoverflow();
}
}
return x;
}

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
#include "libc/nt/runtime.h"
#include "libc/str/str.h"

View file

@ -16,10 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/safemacros.internal.h"
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/formatmessageflags.h"
#include "libc/nt/enum/lang.h"

View file

@ -36,6 +36,7 @@ COSMOPOLITAN_C_START_
extern FILE *__log_file;
int __watch(void *, size_t);
void __die(void) relegated wontreturn; /* print backtrace and abort() */
void meminfo(int); /* shows malloc statistics &c. */
void memsummary(int); /* light version of same thing */

View file

@ -65,6 +65,10 @@ o/$(MODE)/libc/log/checkfail.o: private \
OVERRIDE_CFLAGS += \
-mgeneral-regs-only
o/$(MODE)/libc/log/watch.o: private \
OVERRIDE_CFLAGS += \
-ffreestanding
o/$(MODE)/libc/log/attachdebugger.o \
o/$(MODE)/libc/log/checkaligned.o \
o/$(MODE)/libc/log/checkfail.o \

65
libc/log/watch-hook.S Normal file
View file

@ -0,0 +1,65 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2021 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/macros.internal.h"
__watch_hook:
push %rbp
mov %rsp,%rbp
and $-16,%rsp
sub $0x80,%rsp
movaps %xmm0,0x00(%rsp)
movaps %xmm1,0x10(%rsp)
movaps %xmm2,0x20(%rsp)
movaps %xmm3,0x30(%rsp)
movaps %xmm4,0x40(%rsp)
movaps %xmm5,0x50(%rsp)
movaps %xmm6,0x60(%rsp)
movaps %xmm7,0x70(%rsp)
push %rax
push %rax
push %rdi
push %rsi
push %rdx
push %rcx
push %r8
push %r9
push %r10
push %r11
call __watcher
pop %r11
pop %r10
pop %r9
pop %r8
pop %rcx
pop %rdx
pop %rsi
pop %rdi
pop %rax
pop %rax
movaps 0x00(%rsp),%xmm0
movaps 0x10(%rsp),%xmm1
movaps 0x20(%rsp),%xmm2
movaps 0x30(%rsp),%xmm3
movaps 0x40(%rsp),%xmm4
movaps 0x50(%rsp),%xmm5
movaps 0x60(%rsp),%xmm6
movaps 0x70(%rsp),%xmm7
leave
ret
.endfn __watch_hook,globl

87
libc/log/watch.c Normal file
View file

@ -0,0 +1,87 @@
/*-*- 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/intrin/bits.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/sysv/errfuns.h"
static bool __watch_busy;
static void *__watch_addr;
static size_t __watch_size;
static char __watch_last[4096];
void __watch_hook(void);
static noinstrument inline void Copy(char *p, char *q, size_t n) {
size_t i;
for (i = 0; i < n; ++i) {
p[i] = q[i];
}
}
static noinstrument inline int Cmp(char *p, char *q, size_t n) {
int c;
if (n == 8) return READ64LE(p) != READ64LE(q);
if (n == 4) return READ32LE(p) != READ32LE(q);
for (; n; ++p, ++q, --n) {
if (*p != *q) {
return 1;
}
}
return 0;
}
noinstrument void __watcher(void) {
if (__watch_busy) return;
__watch_busy = true;
if (Cmp(__watch_last, __watch_addr, __watch_size)) {
kprintf("watchpoint %p changed:\n"
"%#.*hhs\n"
"%#.*hhs\n",
__watch_addr, //
__watch_size, __watch_last, //
__watch_size, __watch_addr);
Copy(__watch_last, __watch_addr, __watch_size);
ShowBacktrace(2, __builtin_frame_address(0));
}
__watch_busy = false;
}
/**
* Watches memory address for changes.
*
* It's useful for situations when ASAN and GDB both aren't working.
*/
int __watch(void *addr, size_t size) {
static bool once;
if (__watch_busy) ebusy();
if (size > sizeof(__watch_last)) return einval();
if (!once) {
if (!GetSymbolTable()) return -1;
if (__hook(__watch_hook, GetSymbolTable()) == -1) return -1;
once = true;
}
__watch_addr = addr;
__watch_size = size;
Copy(__watch_last, __watch_addr, __watch_size);
return 0;
}

View file

@ -111,10 +111,6 @@ o//libc/runtime/opensymboltable.greg.o: private \
OVERRIDE_CFLAGS += \
-Os
o/$(MODE)/libc/runtime/ftrace.greg.o: private \
OVERRIDE_CFLAGS += \
-mgeneral-regs-only
LIBC_RUNTIME_LIBS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)))
LIBC_RUNTIME_SRCS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_SRCS))
LIBC_RUNTIME_HDRS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_HDRS))

View file

@ -87,7 +87,8 @@ int sys_socketpair_nt_stream(int, int, int, int[2]) hidden;
int sys_socketpair_nt_dgram(int, int, int, int[2]) hidden;
*/
int sys_socketpair_nt(int, int, int, int[2]) hidden;
int sys_select_nt(int, fd_set *, fd_set *, fd_set *, struct timeval *) hidden;
int sys_select_nt(int, fd_set *, fd_set *, fd_set *, struct timeval *,
const sigset_t *) hidden;
size_t __iovec2nt(struct NtIovec[hasatleast 16], const struct iovec *,
size_t) hidden;

View file

@ -18,9 +18,13 @@
*/
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sock/internal.h"
#include "libc/sock/select.h"
#include "libc/sysv/errfuns.h"
/**
* Does what poll() does except with bitset API.
@ -32,9 +36,30 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
const struct timespec *timeout, const sigset_t *sigmask) {
int rc;
sigset_t oldmask;
rc = sys_pselect(nfds, readfds, writefds, exceptfds, timeout, sigmask);
POLLTRACE("pselect(%d, %p, %p, %p, [%s], %s) → %d% m", nfds, readfds,
writefds, exceptfds, DescribeTimeval(rc, timeout),
DescribeSigset(0, sigmask), rc);
struct timeval tv, *tvp;
if (nfds < 0) {
rc = einval();
} else if (IsAsan() &&
((readfds && !__asan_is_valid(readfds, FD_SIZE(nfds))) ||
(writefds && !__asan_is_valid(writefds, FD_SIZE(nfds))) ||
(exceptfds && !__asan_is_valid(exceptfds, FD_SIZE(nfds))) ||
(timeout && !__asan_is_valid(timeout, sizeof(*timeout))) ||
(sigmask && !__asan_is_valid(sigmask, sizeof(*sigmask))))) {
rc = efault();
} else if (!IsWindows()) {
rc = sys_pselect(nfds, readfds, writefds, exceptfds, timeout, sigmask);
} else {
if (timeout) {
tv.tv_sec = timeout->tv_sec;
tv.tv_usec = timeout->tv_nsec / 1000;
tvp = &tv;
} else {
tvp = 0;
}
rc = sys_select_nt(nfds, readfds, writefds, exceptfds, tvp, sigmask);
}
POLLTRACE("pselect(%d, %p, %p, %p, %s, %s) → %d% m", nfds, readfds, writefds,
exceptfds, DescribeTimeval(0, timeout), DescribeSigset(0, sigmask),
rc);
return rc;
}

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/macros.internal.h"
#include "libc/sock/select.h"
@ -27,14 +28,12 @@
#include "libc/sysv/errfuns.h"
int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout) {
fd_set *exceptfds, struct timeval *timeout,
const sigset_t *sigmask) {
uint64_t millis;
int i, pfds, events, fdcount;
struct pollfd fds[64];
// check for interrupts early before doing work
if (_check_interrupts(false, g_fds.p)) return eintr();
// convert bitsets to pollfd
for (pfds = i = 0; i < nfds; ++i) {
events = 0;
@ -60,7 +59,7 @@ int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds,
}
// call our nt poll implementation
fdcount = sys_poll_nt(fds, pfds, &millis);
fdcount = sys_poll_nt(fds, pfds, &millis, sigmask);
if (fdcount == -1) return -1;
// convert pollfd back to bitsets

View file

@ -19,9 +19,11 @@
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sock/internal.h"
#include "libc/sock/select.h"
#include "libc/sysv/errfuns.h"
/**
* Does what poll() does except with bitset API.
@ -35,10 +37,18 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
int rc;
POLLTRACE("select(%d, %p, %p, %p, %s) → ...", nfds, readfds, writefds,
exceptfds, DescribeTimeval(0, timeout));
if (!IsWindows()) {
if (nfds < 0) {
rc = einval();
} else if (IsAsan() &&
((readfds && !__asan_is_valid(readfds, FD_SIZE(nfds))) ||
(writefds && !__asan_is_valid(writefds, FD_SIZE(nfds))) ||
(exceptfds && !__asan_is_valid(exceptfds, FD_SIZE(nfds))) ||
(timeout && !__asan_is_valid(timeout, sizeof(*timeout))))) {
rc = efault();
} else if (!IsWindows()) {
rc = sys_select(nfds, readfds, writefds, exceptfds, timeout);
} else {
rc = sys_select_nt(nfds, readfds, writefds, exceptfds, timeout);
rc = sys_select_nt(nfds, readfds, writefds, exceptfds, timeout, 0);
}
POLLTRACE("select(%d, %p, %p, %p, [%s]) → %d% m", nfds, readfds, writefds,
exceptfds, DescribeTimeval(rc, timeout), rc);

View file

@ -11,13 +11,14 @@
COSMOPOLITAN_C_START_
typedef struct fd_set {
uint64_t fds_bits[FD_SETSIZE / 64];
unsigned long fds_bits[FD_SETSIZE / (sizeof(long) * CHAR_BIT)];
} fd_set;
#define FD_ISSET(FD, SET) (((SET)->fds_bits[(FD) >> 6] >> ((FD)&63)) & 1)
#define FD_SET(FD, SET) ((SET)->fds_bits[(FD) >> 6] |= 1ull << ((FD)&63))
#define FD_CLR(FD, SET) ((SET)->fds_bits[(FD) >> 6] &= ~(1ull << ((FD)&63)))
#define FD_ZERO(SET) bzero((SET)->fds_bits, sizeof((SET)->fds_bits))
#define FD_SIZE(bits) (((bits) + (sizeof(long) * CHAR_BIT) - 1) / sizeof(long))
int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
int pselect(int, fd_set *, fd_set *, fd_set *, const struct timespec *,

View file

@ -1,12 +1,16 @@
#ifndef COSMOPOLITAN_LIBC_SOCK_STRUCT_POLLFD_INTERNAL_H_
#define COSMOPOLITAN_LIBC_SOCK_STRUCT_POLLFD_INTERNAL_H_
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/timespec.h"
#include "libc/sock/struct/pollfd.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int32_t sys_poll(struct pollfd *, uint64_t, signed) hidden;
int sys_ppoll(struct pollfd *, size_t, const struct timespec *,
const sigset_t *);
int sys_poll_metal(struct pollfd *, size_t, unsigned);
int sys_poll_nt(struct pollfd *, uint64_t, uint64_t *) hidden;
int sys_poll_nt(struct pollfd *, uint64_t, uint64_t *, const sigset_t *) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -105,7 +105,7 @@ static void EmptySignalMask(void) {
}
static void FixIrregularFds(void) {
int i, fd, maxfds;
int e, i, fd, maxfds;
struct rlimit rlim;
struct pollfd *pfds;
for (i = 0; i < 3; ++i) {
@ -118,6 +118,9 @@ static void FixIrregularFds(void) {
}
}
}
e = errno;
if (!closefrom(3)) return;
errno = e;
if (IsWindows()) {
maxfds = 64;
} else {

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/testlib/testlib.h"
@ -24,7 +25,10 @@ TEST(sizetol, test) {
EXPECT_EQ(0, sizetol("0", 1000));
EXPECT_EQ(0, sizetol("0kb", 1000));
EXPECT_EQ(31337, sizetol("31337", 1000));
EXPECT_EQ(+123, sizetol("+123", 1000));
EXPECT_EQ(-123, sizetol("-123", 1000));
EXPECT_EQ(1000, sizetol("1kb", 1000));
EXPECT_EQ(-1000, sizetol("-1kb", 1000));
EXPECT_EQ(2000, sizetol("2k", 1000));
EXPECT_EQ(1024, sizetol("1kb", 1024));
EXPECT_EQ(2048, sizetol("2k", 1024));
@ -43,11 +47,13 @@ TEST(sizetol, test) {
EXPECT_EQ(100, sizetol("\t100\t", 1024));
}
TEST(sizetol, testNegative_notAllowed) {
EXPECT_EQ(-1, sizetol("-23", 1000));
}
TEST(sizetol, testOverflow_isDetected) {
EXPECT_EQ(9000000000000000000, sizetol("9eb", 1000));
EXPECT_EQ(-1, sizetol("10eb", 1000));
EXPECT_SYS(EOVERFLOW, -1, sizetol("10eb", 1000));
}
TEST(sizetol, badSyntax) {
EXPECT_SYS(EINVAL, -1, sizetol("- 1", 1000));
EXPECT_SYS(EINVAL, -1, sizetol("- 1", 1000));
EXPECT_SYS(EOVERFLOW, -1, sizetol("10eb", 1000));
}

View file

@ -56,17 +56,17 @@ o/$(MODE)/test/libc/sock/%.com.dbg: \
@$(APELINK)
o/$(MODE)/test/libc/sock/unix_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath proc unix
private .PLEDGE = stdio rpath wpath cpath fattr proc unix
o/$(MODE)/test/libc/sock/setsockopt_test.com.runs \
o/$(MODE)/test/libc/sock/sendfile_test.com.runs \
o/$(MODE)/test/libc/sock/poll_test.com.runs \
o/$(MODE)/test/libc/sock/pollfd_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath proc inet
private .PLEDGE = stdio rpath wpath cpath fattr proc inet
o/$(MODE)/test/libc/sock/sendrecvmsg_test.com.runs \
o/$(MODE)/test/libc/sock/nointernet_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath proc inet recvfd sendfd
private .PLEDGE = stdio rpath wpath cpath fattr proc inet recvfd sendfd
$(TEST_LIBC_SOCK_OBJS): test/libc/sock/test.mk

View file

@ -71,10 +71,10 @@ o/$(MODE)/test/tool/net/%.com.dbg: \
@$(APELINK)
o/$(MODE)/test/tool/net/redbean_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath proc inet
private .PLEDGE = stdio rpath wpath cpath fattr proc inet
o/$(MODE)/test/tool/net/sqlite_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath proc flock
private .PLEDGE = stdio rpath wpath cpath fattr proc flock
.PHONY: o/$(MODE)/test/tool/net
o/$(MODE)/test/tool/net: \

View file

@ -22,8 +22,11 @@ LOCAL CHANGES
- .UNSANDBOXED variable to disable pledge / unveil
- .CPU variable which tunes CPU rlimit in seconds
- .MEMORY variable for virtual memory limit, e.g. 512m
- .RSS variable for resident memory limit, e.g. 512m
- .FSIZE variable which tunes max file size, e.g. 1g
- .NPROC variable which tunes fork() / clone() limit
- .NOFILE variable which tunes file descriptor limit
- .MAXCORE variable to set upper limit on core dumps
- Do automatic setup and teardown of TMPDIR per rule
- Remove code that forces slow path if not using /bin/sh
- Remove 200,000 lines of VAX/OS2/DOS/AMIGA/etc. code

View file

@ -2,116 +2,6 @@
/* src/config.h.in. Generated from configure.ac by autoheader. */
#include "libc/calls/calls.h"
/* CPU and C ABI indicator */
#ifndef __i386__
/* #undef __i386__ */
#endif
#ifndef __x86_64_x32__
/* #undef __x86_64_x32__ */
#endif
#ifndef __x86_64__
#define __x86_64__ 1
#endif
#ifndef __alpha__
/* #undef __alpha__ */
#endif
#ifndef __arm__
/* #undef __arm__ */
#endif
#ifndef __armhf__
/* #undef __armhf__ */
#endif
#ifndef __arm64_ilp32__
/* #undef __arm64_ilp32__ */
#endif
#ifndef __arm64__
/* #undef __arm64__ */
#endif
#ifndef __hppa__
/* #undef __hppa__ */
#endif
#ifndef __hppa64__
/* #undef __hppa64__ */
#endif
#ifndef __ia64_ilp32__
/* #undef __ia64_ilp32__ */
#endif
#ifndef __ia64__
/* #undef __ia64__ */
#endif
#ifndef __m68k__
/* #undef __m68k__ */
#endif
#ifndef __mips__
/* #undef __mips__ */
#endif
#ifndef __mipsn32__
/* #undef __mipsn32__ */
#endif
#ifndef __mips64__
/* #undef __mips64__ */
#endif
#ifndef __powerpc__
/* #undef __powerpc__ */
#endif
#ifndef __powerpc64__
/* #undef __powerpc64__ */
#endif
#ifndef __powerpc64_elfv2__
/* #undef __powerpc64_elfv2__ */
#endif
#ifndef __riscv32__
/* #undef __riscv32__ */
#endif
#ifndef __riscv64__
/* #undef __riscv64__ */
#endif
#ifndef __riscv32_ilp32__
/* #undef __riscv32_ilp32__ */
#endif
#ifndef __riscv32_ilp32f__
/* #undef __riscv32_ilp32f__ */
#endif
#ifndef __riscv32_ilp32d__
/* #undef __riscv32_ilp32d__ */
#endif
#ifndef __riscv64_ilp32__
/* #undef __riscv64_ilp32__ */
#endif
#ifndef __riscv64_ilp32f__
/* #undef __riscv64_ilp32f__ */
#endif
#ifndef __riscv64_ilp32d__
/* #undef __riscv64_ilp32d__ */
#endif
#ifndef __riscv64_lp64__
/* #undef __riscv64_lp64__ */
#endif
#ifndef __riscv64_lp64f__
/* #undef __riscv64_lp64f__ */
#endif
#ifndef __riscv64_lp64d__
/* #undef __riscv64_lp64d__ */
#endif
#ifndef __s390__
/* #undef __s390__ */
#endif
#ifndef __s390x__
/* #undef __s390x__ */
#endif
#ifndef __sh__
/* #undef __sh__ */
#endif
#ifndef __sparc__
/* #undef __sparc__ */
#endif
#ifndef __sparc64__
/* #undef __sparc64__ */
#endif
/* Define if building universal (internal helper macro) */
/* #undef AC_APPLE_UNIVERSAL_BUILD */
/* Define to the number of bits in type 'ptrdiff_t'. */
#define BITSIZEOF_PTRDIFF_T 64
@ -401,7 +291,7 @@
#define HAVE_POSIX_SPAWNATTR_SETSIGMASK 1
/* Define to 1 if you have the `pselect' function. */
/* #undef HAVE_PSELECT */
#define HAVE_PSELECT 1
/* Define to 1 if you have the `pstat_getdynamic' function. */
/* #undef HAVE_PSTAT_GETDYNAMIC */
@ -425,7 +315,7 @@
#define HAVE_SETEUID 1
/* Define to 1 if you have the `setlinebuf' function. */
/* #undef HAVE_SETLINEBUF */
#define HAVE_SETLINEBUF 1
/* Define to 1 if you have the `setregid' function. */
#define HAVE_SETREGID 1
@ -451,12 +341,6 @@
/* Define to 1 if 'wint_t' is a signed integer type. */
/* #undef HAVE_SIGNED_WINT_T */
/* Define to 1 if you have the `sigsetmask' function. */
/* #undef HAVE_SIGSETMASK */
/* Define to 1 if you have the `socket' function. */
/* #undef HAVE_SOCKET */
/* Define to 1 if you have the <spawn.h> header file. */
#define HAVE_SPAWN_H 1
@ -623,7 +507,11 @@
#define MAKE_HOST "x86_64-cosmopolitan"
/* Define to 1 to enable job server support in GNU make. */
/* TODO(jart): make it work */
/*
* TODO(jart): Why does job server not work? We don't need it, since the
* last thing we'd ever want is a recursive make, however it
* would be nice to confirm it's not a bug in our libc impl.
*/
/* #define MAKE_JOBSERVER 1 */
/* Define to 1 to enable symbolic link timestamp checking. */

221
third_party/make/job.c vendored
View file

@ -55,6 +55,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/pr.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/rlimit.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "third_party/libcxx/math.h"
@ -416,7 +418,7 @@ get_target_variable (const char *name,
const char *
get_tmpdir (struct file *file)
{
return get_target_variable (STRING_SIZE_TUPLE("TMPDIR"), file, 0);
return get_target_variable (STRING_SIZE_TUPLE ("TMPDIR"), file, 0);
}
char *
@ -1798,61 +1800,28 @@ get_base_cpu_freq_mhz (void)
return KCPUIDS(16H, EAX) & 0x7fff;
}
void
int
set_limit (int r, long lo, long hi)
{
struct rlimit old;
struct rlimit lim = {lo, hi};
if (!setrlimit (r, &lim))
return 0;
if (getrlimit (r, &old))
return -1;
lim.rlim_cur = MIN (lim.rlim_cur, old.rlim_max);
lim.rlim_max = MIN (lim.rlim_max, old.rlim_max);
return setrlimit (r, &lim);
}
int
set_cpu_limit (int secs)
{
int mhz, lim;
struct rlimit rlim;
if (secs <= 0) return;
if (IsWindows()) return;
if (!(mhz = get_base_cpu_freq_mhz())) return;
if (secs <= 0) return 0;
if (!(mhz = get_base_cpu_freq_mhz())) return eopnotsupp();
lim = ceil(3100. / mhz * secs);
rlim.rlim_cur = lim;
rlim.rlim_max = lim + 1;
if (setrlimit(RLIMIT_CPU, &rlim) == -1)
{
if (getrlimit(RLIMIT_CPU, &rlim) == -1)
return;
if (lim < rlim.rlim_cur)
{
rlim.rlim_cur = lim;
setrlimit(RLIMIT_CPU, &rlim);
}
}
}
void
set_fsz_limit (long n)
{
struct rlimit rlim;
if (n <= 0) return;
if (IsWindows()) return;
rlim.rlim_cur = n;
rlim.rlim_max = n << 1;
if (setrlimit(RLIMIT_FSIZE, &rlim) == -1)
{
if (getrlimit(RLIMIT_FSIZE, &rlim) == -1)
return;
rlim.rlim_cur = n;
setrlimit(RLIMIT_FSIZE, &rlim);
}
}
void
set_mem_limit (long n)
{
struct rlimit rlim = {n, n};
if (n <= 0) return;
if (IsWindows() || IsXnu()) return;
setrlimit(RLIMIT_AS, &rlim);
}
void
set_pro_limit (long n)
{
struct rlimit rlim = {n, n};
if (n <= 0) return;
setrlimit(RLIMIT_NPROC, &rlim);
return set_limit (RLIMIT_CPU, lim, lim + 1);
}
static struct sysinfo g_sysinfo;
@ -1920,18 +1889,18 @@ child_execute_job (struct childbase *child,
}
internet = parse_bool (get_target_variable
(STRING_SIZE_TUPLE(".INTERNET"),
(STRING_SIZE_TUPLE (".INTERNET"),
c ? c->file : 0, "0"));
unsandboxed = parse_bool (get_target_variable
(STRING_SIZE_TUPLE(".UNSANDBOXED"),
(STRING_SIZE_TUPLE (".UNSANDBOXED"),
c ? c->file : 0, "0"));
if (c)
{
sandboxed = !unsandboxed;
strict = parse_bool (get_target_variable
(STRING_SIZE_TUPLE(".STRICT"),
(STRING_SIZE_TUPLE (".STRICT"),
c->file, "0"));
}
else
@ -1943,7 +1912,7 @@ child_execute_job (struct childbase *child,
if (!unsandboxed)
{
promises = emptytonull (get_target_variable
(STRING_SIZE_TUPLE(".PLEDGE"),
(STRING_SIZE_TUPLE (".PLEDGE"),
c ? c->file : 0, 0));
if (promises)
promises = xstrdup (promises);
@ -1968,52 +1937,158 @@ child_execute_job (struct childbase *child,
internet ? " with internet access" : ""));
/* [jart] Set cpu seconds quota. */
if ((s = get_target_variable (STRING_SIZE_TUPLE(".CPU"),
if (RLIMIT_CPU < RLIM_NLIMITS &&
(s = get_target_variable (STRING_SIZE_TUPLE (".CPU"),
c ? c->file : 0, 0)))
{
int secs;
secs = atoi (s);
DB (DB_JOBS, (_("Setting cpu limit of %d seconds\n"), secs));
set_cpu_limit (secs);
if (!set_cpu_limit (secs))
DB (DB_JOBS, (_("Set cpu limit of %d seconds\n"), secs));
else
DB (DB_JOBS, (_("Failed to set CPU limit: %s\n"), strerror (errno)));
}
/* [jart] Set virtual memory quota. */
if ((s = get_target_variable (STRING_SIZE_TUPLE(".MEMORY"),
if (RLIMIT_AS < RLIM_NLIMITS &&
(s = get_target_variable (STRING_SIZE_TUPLE (".MEMORY"),
c ? c->file : 0, 0)))
{
long bytes;
char buf[16];
errno = 0;
if (!strchr (s, '%'))
bytes = sizetol (s, 1024);
else
bytes = strtod (s, 0) / 100. * g_sysinfo.totalram;
DB (DB_JOBS, (_("Setting virtual memory limit of %s\n"),
(FormatMemorySize (buf, bytes, 1024), buf)));
set_mem_limit (bytes);
if (bytes > 0)
{
if (!set_limit (RLIMIT_AS, bytes, bytes))
DB (DB_JOBS, (_("Set virtual memory limit of %s\n"),
(FormatMemorySize (buf, bytes, 1024), buf)));
else
DB (DB_JOBS, (_("Failed to set virtual memory: %s\n"),
strerror (errno)));
}
else if (errno)
{
OSS (error, NILF, "%s: .MEMORY invalid: %s",
argv[0], strerror (errno));
_Exit (127);
}
}
/* [jart] Set file size limit. */
if ((s = get_target_variable (STRING_SIZE_TUPLE(".FSIZE"),
/* [jart] Set resident memory quota. */
if (RLIMIT_RSS < RLIM_NLIMITS &&
(s = get_target_variable (STRING_SIZE_TUPLE (".RSS"),
c ? c->file : 0, 0)))
{
long bytes;
char buf[16];
bytes = sizetol (s, 1000);
DB (DB_JOBS, (_("Setting file size limit of %s\n"),
(FormatMemorySize (buf, bytes, 1000), buf)));
set_fsz_limit (bytes);
errno = 0;
if (!strchr (s, '%'))
bytes = sizetol (s, 1024);
else
bytes = strtod (s, 0) / 100. * g_sysinfo.totalram;
if (bytes > 0)
{
if (!set_limit (RLIMIT_RSS, bytes, bytes))
DB (DB_JOBS, (_("Set resident memory limit of %s\n"),
(FormatMemorySize (buf, bytes, 1024), buf)));
else
DB (DB_JOBS, (_("Failed to set resident memory: %s\n"),
strerror (errno)));
}
else if (errno)
{
OSS (error, NILF, "%s: .RSS invalid: %s",
argv[0], strerror (errno));
_Exit (127);
}
}
/* [jart] Set file size limit. */
if (RLIMIT_FSIZE < RLIM_NLIMITS &&
(s = get_target_variable (STRING_SIZE_TUPLE (".FSIZE"),
c ? c->file : 0, 0)))
{
long bytes;
char buf[16];
errno = 0;
if ((bytes = sizetol (s, 1000)) > 0)
{
if (!set_limit (RLIMIT_FSIZE, bytes, bytes * 1.5))
DB (DB_JOBS, (_("Set file size limit of %s\n"),
(FormatMemorySize (buf, bytes, 1000), buf)));
else
DB (DB_JOBS, (_("Failed to set file size limit: %s\n"),
strerror (errno)));
}
else if (errno)
{
OSS (error, NILF, "%s: .FSIZE invalid: %s",
argv[0], strerror (errno));
_Exit (127);
}
}
/* [jart] Set core dump limit. */
if (RLIMIT_CORE < RLIM_NLIMITS &&
(s = get_target_variable (STRING_SIZE_TUPLE (".MAXCORE"),
c ? c->file : 0, 0)))
{
long bytes;
char buf[16];
errno = 0;
if ((bytes = sizetol (s, 1000)) > 0)
{
if (!set_limit (RLIMIT_CORE, bytes, bytes))
DB (DB_JOBS, (_("Set core dump limit of %s\n"),
(FormatMemorySize (buf, bytes, 1000), buf)));
else
DB (DB_JOBS, (_("Failed to set core dump limit: %s\n"),
strerror (errno)));
}
else if (errno)
{
OSS (error, NILF, "%s: .MAXCORE invalid: %s",
argv[0], strerror (errno));
_Exit (127);
}
}
/* [jart] Set process limit. */
if ((s = get_target_variable (STRING_SIZE_TUPLE(".NPROC"),
if (RLIMIT_NPROC < RLIM_NLIMITS &&
(s = get_target_variable (STRING_SIZE_TUPLE (".NPROC"),
c ? c->file : 0, 0)))
{
int procs;
if ((procs = atoi (s)) > 0)
{
DB (DB_JOBS, (_("Setting process limit to %d + %d preexisting\n"),
procs, g_sysinfo.procs));
set_pro_limit (procs + g_sysinfo.procs);
if (!set_limit (RLIMIT_NPROC,
procs + g_sysinfo.procs,
procs + g_sysinfo.procs))
DB (DB_JOBS, (_("Set process limit to %d + %d preexisting\n"),
procs, g_sysinfo.procs));
else
DB (DB_JOBS, (_("Failed to set process limit: %s\n"),
strerror (errno)));
}
}
/* [jart] Set file descriptor limit. */
if (RLIMIT_NOFILE < RLIM_NLIMITS &&
(s = get_target_variable (STRING_SIZE_TUPLE (".NOFILE"),
c ? c->file : 0, 0)))
{
int fds;
if ((fds = atoi (s)) > 0)
{
if (!set_limit (RLIMIT_NOFILE, fds, fds))
DB (DB_JOBS, (_("Set file descriptor limit to %d\n"), fds));
else
DB (DB_JOBS, (_("Failed to set process limit: %s\n"),
strerror (errno)));
}
}

View file

@ -119,6 +119,7 @@ THIRD_PARTY_MAKE_DIRECTDEPS = \
LIBC_STDIO \
LIBC_STR \
LIBC_SOCK \
LIBC_NT_KERNEL32 \
LIBC_SYSV \
LIBC_SYSV_CALLS \
LIBC_TIME \

View file

@ -14,7 +14,6 @@ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */
#include "libc/mem/alg.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/makedev.h"
@ -31,11 +30,13 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/alg.h"
#include "libc/mem/alloca.h"
#include "libc/mem/mem.h"
#include "libc/runtime/stack.h"
#include "libc/stdio/stdio.h"
#include "libc/stdio/temp.h"
#include "libc/str/locale.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/o.h"
@ -46,11 +47,9 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "libc/sysv/consts/s.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/utime.h"
#include "libc/sysv/consts/w.h"
#include "libc/time/struct/tm.h"
#include "libc/time/time.h"
#include "libc/str/locale.h"
#include "libc/x/x.h"
#include "third_party/gdtoa/gdtoa.h"
#include "third_party/musl/glob.h"

View file

@ -16,7 +16,11 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc"
/**/
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "third_party/make/config.h"
#include "third_party/make/debug.h"
#include "third_party/make/job.h"
#include "third_party/make/os.h"
@ -293,11 +297,6 @@ static RETSIGTYPE job_noop(int sig UNUSED) {
static void set_child_handler_action_flags(int set_handler, int set_alarm) {
struct sigaction sa;
#ifdef __EMX__
/* The child handler must be turned off here. */
signal(SIGCHLD, SIG_DFL);
#endif
memset(&sa, '\0', sizeof sa);
sa.sa_handler = child_handler;
sa.sa_flags = set_handler ? 0 : SA_RESTART;
@ -391,11 +390,8 @@ int get_bad_stdin(void) {
/* Set file descriptors to be inherited / not inherited by subprocesses. */
#if !defined(F_SETFD) || !defined(F_GETFD)
void fd_inherit(int fd) {
}
void fd_noinherit(int fd) {
}
void fd_inherit(int fd) {}
void fd_noinherit(int fd) {}
#else
#ifndef FD_CLOEXEC

View file

@ -2097,13 +2097,13 @@ o/$(MODE)/third_party/python/Lib/test/test_wsgiref.py.runs: private \
/usr/local/etc/mime.types
o/$(MODE)/third_party/python/Lib/test/test_epoll.py.runs: \
private .PLEDGE = stdio rpath wpath cpath proc inet
private .PLEDGE = stdio rpath wpath cpath fattr proc inet
o/$(MODE)/third_party/python/Lib/test/test_fcntl.py.runs: \
private .PLEDGE = stdio rpath wpath cpath proc flock
private .PLEDGE = stdio rpath wpath cpath fattr proc flock
o/$(MODE)/third_party/python/Lib/test/test_signal.py.runs: \
private .PLEDGE = stdio rpath wpath cpath proc flock inet
private .PLEDGE = stdio rpath wpath cpath fattr proc flock inet
o/$(MODE)/third_party/python/Lib/test/test_timeout.py.runs: \
private .PLEDGE = stdio rpath wpath cpath proc inet
private .PLEDGE = stdio rpath wpath cpath fattr proc inet
o/$(MODE)/third_party/python/Lib/test/test_grammar.py.runs: \
o/$(MODE)/third_party/python/pythontester.com

View file

@ -16,9 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/mem/alg.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/copyfile.h"
#include "libc/calls/ioctl.h"
@ -32,12 +29,15 @@
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/limits.h"
#include "libc/log/color.internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/math.h"
#include "libc/mem/alg.h"
#include "libc/mem/io.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/kcpuids.h"
@ -505,7 +505,7 @@ void SetFszLimit(long n) {
if (n <= 0) return;
if (IsWindows()) return;
rlim.rlim_cur = n;
rlim.rlim_max = n << 1;
rlim.rlim_max = n + (n >> 1);
if (setrlimit(RLIMIT_FSIZE, &rlim) == -1) {
if (getrlimit(RLIMIT_FSIZE, &rlim) == -1) return;
rlim.rlim_cur = n;
@ -1191,7 +1191,10 @@ int main(int argc, char *argv[]) {
if (!(exitcode = WEXITSTATUS(ws)) || exitcode == 254) {
if (touchtarget && target) {
makedirs(xdirname(target), 0755);
touch(target, 0644);
if (touch(target, 0644)) {
exitcode = 90;
appends(&output, "\nfailed to touch output file\n");
}
}
if (movepath) {
if (!MovePreservingDestinationInode(tmpout, movepath)) {

View file

@ -17,8 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/landlock.h"
#include "libc/calls/pledge.h"
@ -34,8 +32,10 @@
#include "libc/elf/struct/ehdr.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/promises.internal.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/macros.internal.h"
#include "libc/math.h"
#include "libc/mem/io.h"
@ -56,6 +56,7 @@
#include "libc/sysv/consts/pr.h"
#include "libc/sysv/consts/prio.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/rlim.h"
#include "libc/sysv/consts/rlimit.h"
#include "libc/sysv/consts/sched.h"
#include "libc/sysv/errfuns.h"
@ -86,7 +87,8 @@ usage: pledge.com [-hnN] PROG ARGS...\n\
-N don't normalize file descriptors\n\
-C SECS set cpu limit [default: inherited]\n\
-M BYTES set virtual memory limit [default: 4gb]\n\
-P PROCS set process limit [default: GetCpuCount()*2]\n\
-O FILES set file descriptor limit [default: 64]\n\
-P PROCS set process limit [default: preexisting + cpus]\n\
-F BYTES set individual file size limit [default: 4gb]\n\
-T pledge exits 0 if pledge() is supported by host system\n\
-T unveil exits 0 if unveil() is supported by host system\n\
@ -136,6 +138,7 @@ bool isdynamic;
bool g_noclose;
long g_cpuquota;
long g_fszquota;
long g_nfdquota;
long g_memquota;
long g_proquota;
long g_dontdrop;
@ -155,11 +158,16 @@ static void GetOpts(int argc, char *argv[]) {
int opt;
struct sysinfo si;
g_promises = 0;
g_nfdquota = 64;
g_fszquota = 256 * 1000 * 1000;
g_proquota = GetCpuCount() * 100;
g_memquota = 4L * 1024 * 1024 * 1024;
if (!sysinfo(&si)) g_memquota = si.totalram;
while ((opt = getopt(argc, argv, "hnqkNVT:p:u:g:c:C:D:P:M:F:v:")) != -1) {
if (!sysinfo(&si)) {
g_memquota = si.totalram;
g_proquota = GetCpuCount() + si.procs;
} else {
g_proquota = GetCpuCount() * 100;
g_memquota = 4L * 1024 * 1024 * 1024;
}
while ((opt = getopt(argc, argv, "hnqkNVT:p:u:g:c:C:D:P:M:F:O:v:")) != -1) {
switch (opt) {
case 'n':
g_nice = true;
@ -197,11 +205,24 @@ static void GetOpts(int argc, char *argv[]) {
case 'P':
g_proquota = atoi(optarg);
break;
case 'M':
g_memquota = sizetol(optarg, 1024);
case 'O':
g_nfdquota = atoi(optarg);
break;
case 'F':
errno = 0;
g_fszquota = sizetol(optarg, 1000);
if (errno) {
kprintf("error: invalid size: -F %s\n", optarg);
exit(1);
}
break;
case 'M':
errno = 0;
g_memquota = sizetol(optarg, 1024);
if (errno) {
kprintf("error: invalid size: -F %s\n", optarg);
exit(1);
}
break;
case 'p':
if (g_promises) {
@ -232,10 +253,6 @@ const char *prog;
char pathbuf[PATH_MAX];
struct pollfd pfds[256];
int GetBaseCpuFreqMhz(void) {
return KCPUIDS(16H, EAX) & 0x7fff;
}
static bool SupportsLandlock(void) {
int e = errno;
bool r = landlock_create_ruleset(0, 0, LANDLOCK_CREATE_RULESET_VERSION) >= 0;
@ -290,61 +307,27 @@ void NormalizeFileDescriptors(void) {
}
}
void SetCpuLimit(int secs) {
int SetLimit(int r, long lo, long hi) {
struct rlimit old;
struct rlimit lim = {lo, hi};
if (r < 0 || r >= RLIM_NLIMITS) return 0;
if (!setrlimit(r, &lim)) return 0;
if (getrlimit(r, &old)) return -1;
lim.rlim_cur = MIN(lim.rlim_cur, old.rlim_max);
lim.rlim_max = MIN(lim.rlim_max, old.rlim_max);
return setrlimit(r, &lim);
}
int GetBaseCpuFreqMhz(void) {
return KCPUIDS(16H, EAX) & 0x7fff;
}
int SetCpuLimit(int secs) {
int mhz, lim;
struct rlimit rlim;
if (secs <= 0) return;
if (!(mhz = GetBaseCpuFreqMhz())) return;
if (secs <= 0) return 0;
if (!(mhz = GetBaseCpuFreqMhz())) return eopnotsupp();
lim = ceil(3100. / mhz * secs);
rlim.rlim_cur = lim;
rlim.rlim_max = lim + 1;
if (setrlimit(RLIMIT_CPU, &rlim) != -1) {
return;
} else if (getrlimit(RLIMIT_CPU, &rlim) != -1) {
if (lim < rlim.rlim_cur) {
rlim.rlim_cur = lim;
if (setrlimit(RLIMIT_CPU, &rlim) != -1) {
return;
}
}
}
kprintf("error: setrlimit(RLIMIT_CPU) failed: %m\n");
exit(20);
}
void SetFszLimit(long n) {
struct rlimit rlim;
if (n <= 0) return;
rlim.rlim_cur = n;
rlim.rlim_max = n << 1;
if (setrlimit(RLIMIT_FSIZE, &rlim) != -1) {
return;
} else if (getrlimit(RLIMIT_FSIZE, &rlim) != -1) {
rlim.rlim_cur = n;
if (setrlimit(RLIMIT_FSIZE, &rlim) != -1) {
return;
}
}
kprintf("error: setrlimit(RLIMIT_FSIZE) failed: %m\n");
exit(21);
}
void SetMemLimit(long n) {
struct rlimit rlim = {n, n};
if (n <= 0) return;
if (setrlimit(RLIMIT_AS, &rlim) == -1) {
kprintf("error: setrlimit(RLIMIT_AS) failed: %m\n");
exit(22);
}
}
void SetProLimit(long n) {
struct rlimit rlim = {n, n};
if (n <= 0) return;
if (setrlimit(RLIMIT_NPROC, &rlim) == -1) {
kprintf("error: setrlimit(RLIMIT_NPROC) failed: %m\n");
exit(22);
}
return SetLimit(RLIMIT_CPU, lim, lim);
}
bool PathExists(const char *path) {
@ -610,10 +593,26 @@ int main(int argc, char *argv[]) {
// set resource limits
MakeProcessNice();
SetCpuLimit(g_cpuquota);
SetFszLimit(g_fszquota);
SetMemLimit(g_memquota);
SetProLimit(g_proquota);
if (SetCpuLimit(g_cpuquota) == -1) {
kprintf("error: setrlimit(%s) failed: %m\n", "RLIMIT_CPU");
exit(1);
}
if (SetLimit(RLIMIT_FSIZE, g_fszquota, g_fszquota * 1.5) == -1) {
kprintf("error: setrlimit(%s) failed: %m\n", "RLIMIT_FSIZE");
exit(1);
}
if (SetLimit(RLIMIT_AS, g_memquota, g_memquota) == -1) {
kprintf("error: setrlimit(%s) failed: %m\n", "RLIMIT_AS");
exit(1);
}
if (SetLimit(RLIMIT_NPROC, g_proquota, g_proquota) == -1) {
kprintf("error: setrlimit(%s) failed: %m\n", "RLIMIT_NPROC");
exit(1);
}
// test for weird chmod bits
usergid = getgid();
@ -786,6 +785,11 @@ int main(int argc, char *argv[]) {
putenv(buf);
}
if (SetLimit(RLIMIT_NOFILE, g_nfdquota, g_nfdquota) == -1) {
kprintf("error: setrlimit(%s) failed: %m\n", "RLIMIT_NOFILE");
exit(1);
}
// apply sandbox
if (pledge(g_promises, g_promises) == -1) {
kprintf("error: pledge(%#s) failed: %m\n", g_promises);

View file

@ -189,7 +189,7 @@
(runs (format "o/$m/%s.com%s V=5 TESTARGS=-b" name runsuffix))
(buns (format "o/$m/test/%s_test.com%s V=5 TESTARGS=-b" name runsuffix)))
(cond ((not (member ext '("c" "cc" "s" "S" "rl" "f")))
(format "m=%s; o//third_party/make/make.com -j12 -O MODE=$m o/$m/%s"
(format "m=%s; make -j12 -O MODE=$m o/$m/%s"
mode
(directory-file-name
(or (file-name-directory
@ -200,7 +200,7 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s.com"
,(concat "o//third_party/make/make.com -j12 -O $f MODE=$m")
,(concat "make -j12 -O $f MODE=$m")
"scp $f $f.dbg win7:"
"ssh win7 ./%s.com"))
mode name (file-name-nondirectory name)))
@ -209,7 +209,7 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s.com"
,(concat "o//third_party/make/make.com -j12 -O $f MODE=$m")
,(concat "make -j12 -O $f MODE=$m")
"scp $f $f.dbg win10:"
"ssh win10 ./%s.com"))
mode name (file-name-nondirectory name)))
@ -218,19 +218,19 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s.com"
,(concat "o//third_party/make/make.com -j12 -O $f MODE=$m")
,(concat "make -j12 -O $f MODE=$m")
"scp $f $f.dbg xnu:"
"ssh xnu ./%s.com"))
mode name (file-name-nondirectory name)))
((and (equal suffix "")
(cosmo-contains "_test." (buffer-file-name)))
(format "m=%s; o//third_party/make/make.com -j12 -O MODE=$m %s"
(format "m=%s; make -j12 -O MODE=$m %s"
mode runs))
((and (equal suffix "")
(file-exists-p (format "%s" buddy)))
(format (cosmo-join
" && "
'("m=%s; n=%s; o//third_party/make/make.com -j12 -O o/$m/$n%s.o MODE=$m"
'("m=%s; n=%s; make -j12 -O o/$m/$n%s.o MODE=$m"
;; "bloat o/$m/%s.o | head"
;; "nm -C --size o/$m/%s.o | sort -r"
"echo"
@ -242,11 +242,11 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s.com"
,(concat "o//third_party/make/make.com -j12 -O $f MODE=$m")
,(concat "make -j12 -O $f MODE=$m")
"./$f"))
mode name))
((eq kind 'test)
(format `"m=%s; f=o/$m/%s.com.ok && o//third_party/make/make.com -j12 -O $f MODE=$m" mode name))
(format `"m=%s; f=o/$m/%s.com.ok && make -j12 -O $f MODE=$m" mode name))
((and (file-regular-p this)
(file-executable-p this))
(format "./%s" file))
@ -255,7 +255,7 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s%s.o"
,(concat "o//third_party/make/make.com -j12 -O $f MODE=$m")
,(concat "make -j12 -O $f MODE=$m")
;; "nm -C --size $f | sort -r"
"echo"
"size -A $f | grep '^[.T]' | grep -v 'debug\\|command.line\\|stack' | sort -rnk2"
@ -626,11 +626,11 @@
((eq major-mode 'lua-mode)
(let* ((mode (cosmo--make-mode arg))
(redbean ))
(compile (format "o//third_party/make/make.com -j16 MODE=%s o/%s/tool/net/redbean.com && o/%s/tool/net/redbean.com -i %s" mode mode mode file))))
(compile (format "make -j16 MODE=%s o/%s/tool/net/redbean.com && o/%s/tool/net/redbean.com -i %s" mode mode mode file))))
((and (eq major-mode 'python-mode)
(cosmo-startswith "third_party/python/Lib/test/" file))
(let ((mode (cosmo--make-mode arg)))
(compile (format "o//third_party/make/make.com -j12 MODE=%s PYHARNESSARGS=-vv PYTESTARGS=-v o/%s/%s.py.runs"
(compile (format "make -j12 MODE=%s PYHARNESSARGS=-vv PYTESTARGS=-v o/%s/%s.py.runs"
mode mode (file-name-sans-extension file)))))
((eq major-mode 'python-mode)
(compile (format "python.com %s" file)))