From f0701d2a24d5feccaca9bf2f7731068fafeded95 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Mon, 15 Aug 2022 15:18:37 -0700 Subject: [PATCH] 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 --- build/online.mk | 2 +- examples/rlimit.c | 2 +- libc/calls/alarm.c | 1 - libc/calls/getttysize.c | 6 +- libc/calls/poll-nt.c | 6 +- libc/calls/poll.c | 2 +- libc/calls/ppoll.c | 107 ++++++++++++++ libc/fmt/sizetol.c | 27 +++- libc/fmt/strerror_r.c | 1 - libc/intrin/strerror_wr.greg.c | 2 +- libc/log/log.h | 1 + libc/log/log.mk | 4 + libc/log/watch-hook.S | 65 +++++++++ libc/log/watch.c | 87 ++++++++++++ libc/runtime/runtime.mk | 4 - libc/sock/internal.h | 3 +- libc/sock/pselect.c | 33 ++++- libc/sock/select-nt.c | 9 +- libc/sock/select.c | 14 +- libc/sock/select.h | 3 +- libc/sock/struct/pollfd.internal.h | 6 +- libc/testlib/testmain.c | 5 +- test/libc/fmt/sizetol_test.c | 16 ++- test/libc/sock/test.mk | 6 +- test/tool/net/test.mk | 4 +- third_party/make/README.cosmo | 3 + third_party/make/config.h | 126 +--------------- third_party/make/job.c | 221 +++++++++++++++++++---------- third_party/make/make.mk | 1 + third_party/make/makeint.inc | 5 +- third_party/make/posixos.c | 16 +-- third_party/python/python.mk | 8 +- tool/build/compile.c | 13 +- tool/build/pledge.c | 144 ++++++++++--------- tool/emacs/cosmo-stuff.el | 22 +-- 35 files changed, 635 insertions(+), 340 deletions(-) create mode 100644 libc/calls/ppoll.c create mode 100644 libc/log/watch-hook.S create mode 100644 libc/log/watch.c diff --git a/build/online.mk b/build/online.mk index cbd401e1c..0c405ca88 100644 --- a/build/online.mk +++ b/build/online.mk @@ -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 \ diff --git a/examples/rlimit.c b/examples/rlimit.c index fefa9f43f..894d2a665 100644 --- a/examples/rlimit.c +++ b/examples/rlimit.c @@ -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); diff --git a/libc/calls/alarm.c b/libc/calls/alarm.c index b51624411..0a26ca372 100644 --- a/libc/calls/alarm.c +++ b/libc/calls/alarm.c @@ -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" diff --git a/libc/calls/getttysize.c b/libc/calls/getttysize.c index 9b3c55b9d..518aee917 100644 --- a/libc/calls/getttysize.c +++ b/libc/calls/getttysize.c @@ -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; diff --git a/libc/calls/poll-nt.c b/libc/calls/poll-nt.c index c2fcd8f65..589d1a87b 100644 --- a/libc/calls/poll-nt.c +++ b/libc/calls/poll-nt.c @@ -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 diff --git a/libc/calls/poll.c b/libc/calls/poll.c index ffc140c80..d9575006d 100644 --- a/libc/calls/poll.c +++ b/libc/calls/poll.c @@ -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 diff --git a/libc/calls/ppoll.c b/libc/calls/ppoll.c new file mode 100644 index 000000000..701ba5eae --- /dev/null +++ b/libc/calls/ppoll.c @@ -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; +} diff --git a/libc/fmt/sizetol.c b/libc/fmt/sizetol.c index d6006cf31..708159532 100644 --- a/libc/fmt/sizetol.c +++ b/libc/fmt/sizetol.c @@ -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; } diff --git a/libc/fmt/strerror_r.c b/libc/fmt/strerror_r.c index 0671fec2a..789ce7148 100644 --- a/libc/fmt/strerror_r.c +++ b/libc/fmt/strerror_r.c @@ -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" diff --git a/libc/intrin/strerror_wr.greg.c b/libc/intrin/strerror_wr.greg.c index c6b94fc4b..1c7543c6f 100644 --- a/libc/intrin/strerror_wr.greg.c +++ b/libc/intrin/strerror_wr.greg.c @@ -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" diff --git a/libc/log/log.h b/libc/log/log.h index 2ac9f18fa..7d9a5283f 100644 --- a/libc/log/log.h +++ b/libc/log/log.h @@ -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 */ diff --git a/libc/log/log.mk b/libc/log/log.mk index 1e5c7a86e..53db6cbcd 100644 --- a/libc/log/log.mk +++ b/libc/log/log.mk @@ -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 \ diff --git a/libc/log/watch-hook.S b/libc/log/watch-hook.S new file mode 100644 index 000000000..2ea78fd19 --- /dev/null +++ b/libc/log/watch-hook.S @@ -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 diff --git a/libc/log/watch.c b/libc/log/watch.c new file mode 100644 index 000000000..e34e39d55 --- /dev/null +++ b/libc/log/watch.c @@ -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; +} diff --git a/libc/runtime/runtime.mk b/libc/runtime/runtime.mk index 5d2decf1e..4f8828973 100644 --- a/libc/runtime/runtime.mk +++ b/libc/runtime/runtime.mk @@ -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)) diff --git a/libc/sock/internal.h b/libc/sock/internal.h index 7d4438b7c..9a7b6981a 100644 --- a/libc/sock/internal.h +++ b/libc/sock/internal.h @@ -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; diff --git a/libc/sock/pselect.c b/libc/sock/pselect.c index 698cc8bad..91b94f93c 100644 --- a/libc/sock/pselect.c +++ b/libc/sock/pselect.c @@ -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; } diff --git a/libc/sock/select-nt.c b/libc/sock/select-nt.c index bd5da7e13..e0d91de3b 100644 --- a/libc/sock/select-nt.c +++ b/libc/sock/select-nt.c @@ -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 diff --git a/libc/sock/select.c b/libc/sock/select.c index 7afa8f3b8..c8f3f2cfe 100644 --- a/libc/sock/select.c +++ b/libc/sock/select.c @@ -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); diff --git a/libc/sock/select.h b/libc/sock/select.h index b9e4f3c8e..d8743b79e 100644 --- a/libc/sock/select.h +++ b/libc/sock/select.h @@ -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 *, diff --git a/libc/sock/struct/pollfd.internal.h b/libc/sock/struct/pollfd.internal.h index 9c6cf2d63..ccd539951 100644 --- a/libc/sock/struct/pollfd.internal.h +++ b/libc/sock/struct/pollfd.internal.h @@ -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) */ diff --git a/libc/testlib/testmain.c b/libc/testlib/testmain.c index 3e6263e9c..4eed3f7fa 100644 --- a/libc/testlib/testmain.c +++ b/libc/testlib/testmain.c @@ -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 { diff --git a/test/libc/fmt/sizetol_test.c b/test/libc/fmt/sizetol_test.c index ec1030cb0..708c9ec9d 100644 --- a/test/libc/fmt/sizetol_test.c +++ b/test/libc/fmt/sizetol_test.c @@ -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)); } diff --git a/test/libc/sock/test.mk b/test/libc/sock/test.mk index 73f2e7482..9b8c60578 100644 --- a/test/libc/sock/test.mk +++ b/test/libc/sock/test.mk @@ -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 diff --git a/test/tool/net/test.mk b/test/tool/net/test.mk index ad84e2bdf..42af903e4 100644 --- a/test/tool/net/test.mk +++ b/test/tool/net/test.mk @@ -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: \ diff --git a/third_party/make/README.cosmo b/third_party/make/README.cosmo index 1549174df..520f21dfc 100644 --- a/third_party/make/README.cosmo +++ b/third_party/make/README.cosmo @@ -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 diff --git a/third_party/make/config.h b/third_party/make/config.h index 16f429cfa..d0c98acfa 100644 --- a/third_party/make/config.h +++ b/third_party/make/config.h @@ -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 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. */ diff --git a/third_party/make/job.c b/third_party/make/job.c index a24ff4edb..c7a75cfd8 100644 --- a/third_party/make/job.c +++ b/third_party/make/job.c @@ -55,6 +55,8 @@ this program. If not, see . */ #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))); } } diff --git a/third_party/make/make.mk b/third_party/make/make.mk index b034c1cf8..7a9d1240a 100644 --- a/third_party/make/make.mk +++ b/third_party/make/make.mk @@ -119,6 +119,7 @@ THIRD_PARTY_MAKE_DIRECTDEPS = \ LIBC_STDIO \ LIBC_STR \ LIBC_SOCK \ + LIBC_NT_KERNEL32 \ LIBC_SYSV \ LIBC_SYSV_CALLS \ LIBC_TIME \ diff --git a/third_party/make/makeint.inc b/third_party/make/makeint.inc index 9a6421ae2..192e84fa4 100644 --- a/third_party/make/makeint.inc +++ b/third_party/make/makeint.inc @@ -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 . */ -#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 . */ #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 . */ #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" diff --git a/third_party/make/posixos.c b/third_party/make/posixos.c index 058fbfb19..a507de594 100644 --- a/third_party/make/posixos.c +++ b/third_party/make/posixos.c @@ -16,7 +16,11 @@ this program. If not, see . */ #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 diff --git a/third_party/python/python.mk b/third_party/python/python.mk index fee9648cc..8c6ae3d76 100644 --- a/third_party/python/python.mk +++ b/third_party/python/python.mk @@ -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 diff --git a/tool/build/compile.c b/tool/build/compile.c index 610ad98d0..483869eb3 100644 --- a/tool/build/compile.c +++ b/tool/build/compile.c @@ -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)) { diff --git a/tool/build/pledge.c b/tool/build/pledge.c index 84947b8dc..a85ff5092 100644 --- a/tool/build/pledge.c +++ b/tool/build/pledge.c @@ -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); diff --git a/tool/emacs/cosmo-stuff.el b/tool/emacs/cosmo-stuff.el index b072d6cc6..9766bd835 100644 --- a/tool/emacs/cosmo-stuff.el +++ b/tool/emacs/cosmo-stuff.el @@ -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)))