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

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