Add automatic TMPDIR setup/teardown to GNU Make

We now guarantee TMPDIR will be defined on a per build rule basis. It'll
be an absolute path. It'll be secure and unique. It'll be rm -rf'd after
the last shell script line in your build rule is executed. If $TMPDIR is
already defined, then it'll be created as a subdirectory of your $TMPDIR
and then replace the variable with the new definition. The Landlock Make
repository will be updated with examples shortly after this change which
shall be known as Landlock Make 1.1.1.

See #530
This commit is contained in:
Justine Tunney 2022-08-14 01:21:26 -07:00
parent e1699c5b68
commit d36d0634db
25 changed files with 387 additions and 357 deletions

View file

@ -83,7 +83,6 @@ o/$(MODE): \
.STRICT = 1
.UNVEIL = \
rwcx:o/tmp \
libc/integral \
libc/disclaimer.inc \
rx:build/bootstrap \

Binary file not shown.

View file

@ -103,6 +103,20 @@ textwindows int __mkntpath2(const char *path,
q += 3;
z -= 7;
x = 7;
} else if (IsSlash(q[0]) && IsAlpha(q[1]) && !q[2]) {
z = MIN(32767, PATH_MAX);
// turn "\c" into "\\?\c:\"
p[0] = '\\';
p[1] = '\\';
p[2] = '?';
p[3] = '\\';
p[4] = q[1];
p[5] = ':';
p[6] = '\\';
p += 7;
q += 2;
z -= 7;
x = 7;
} else if (IsSlash(q[0]) && IsAlpha(q[1]) && IsSlash(q[2])) {
z = MIN(32767, PATH_MAX);
// turn "c:\foo" into "\\?\c:\foo"

View file

@ -51,6 +51,6 @@ int symlinkat(const char *target, int newdirfd, const char *linkpath) {
rc = sys_symlinkat_nt(target, newdirfd, linkpath);
}
STRACE("symlinkat(%#s, %s, %#s) → %d% m", target, DescribeDirfd(newdirfd),
linkpath);
linkpath, rc);
return rc;
}

View file

@ -249,19 +249,12 @@ static int WaitForTrace(int main) {
// eintr isn't possible since we're blocking all signals
ORDIE(pid = waitpid(-1, &ws, __WALL));
LogProcessEvent(main, pid, ws);
// once main child exits or dies, we exit / die the same way. we're
// not currently tracking pids, so it's important that a child does
// not exit before its children. otherwise the grandchildren get in
// a permanently stopped state. to address that, we'll send sigterm
// to the process group which we defined earlier.
if (WIFEXITED(ws)) {
if (pid == main) {
kill(-getpid(), SIGTERM);
_Exit(WEXITSTATUS(ws));
}
} else if (WIFSIGNALED(ws)) {
if (pid == main) {
kill(-getpid(), SIGTERM);
Raise(WTERMSIG(ws));
}
} else if (WIFSTOPPED(ws)) {
@ -294,12 +287,6 @@ int nointernet(void) {
return enosys();
}
// ensure we're at the root of a process group, so we're able to
// broadcast a termination signal later on that catches dangling
// subprocesss our child forgot to destroy. without calling this
// subprocesses could end up permanently stopped if monitor dies
setpgrp();
// prevent crash handlers from intercepting sigsegv
ORDIE(sigfillset(&set));
ORDIE(sigprocmask(SIG_SETMASK, &set, &old));

View file

@ -16,15 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/str/str.h"
static inline noasan uint64_t UncheckedAlignedRead64(const char *p) {
return (uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 |
(uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 |
(uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 |
(uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000;
}
/**
* Compares NUL-terminated strings ascii case-insensitively.
*
@ -33,7 +28,7 @@ static inline noasan uint64_t UncheckedAlignedRead64(const char *p) {
* @return is <0, 0, or >0 based on tolower(uint8_t) comparison
* @asyncsignalsafe
*/
int strcasecmp(const char *a, const char *b) {
noasan int strcasecmp(const char *a, const char *b) {
int x, y;
size_t i = 0;
uint64_t v, w, d;
@ -41,13 +36,17 @@ int strcasecmp(const char *a, const char *b) {
if (((uintptr_t)a & 7) == ((uintptr_t)b & 7)) {
for (; (uintptr_t)(a + i) & 7; ++i) {
CheckEm:
if (IsAsan()) {
__asan_verify(a, i + 1);
__asan_verify(b, i + 1);
}
if ((x = kToLower[a[i] & 255]) != (y = kToLower[b[i] & 255]) || !y) {
return x - y;
}
}
for (;; i += 8) {
v = UncheckedAlignedRead64(a + i);
w = UncheckedAlignedRead64(b + i);
v = *(uint64_t *)(a + i);
w = *(uint64_t *)(b + i);
w = (v ^ w) | (~v & (v - 0x0101010101010101) & 0x8080808080808080);
if (w) {
i += (unsigned)__builtin_ctzll(w) >> 3;
@ -56,6 +55,10 @@ int strcasecmp(const char *a, const char *b) {
}
} else {
while ((x = kToLower[a[i] & 255]) == (y = kToLower[b[i] & 255]) && y) ++i;
if (IsAsan()) {
__asan_verify(a, i + 1);
__asan_verify(b, i + 1);
}
return x - y;
}
}

View file

@ -17,12 +17,9 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/str/str.h"
static inline noasan uint64_t UncheckedAlignedRead64(const char *p) {
return *(uint64_t *)p;
}
/**
* Compares NUL-terminated strings.
*
@ -31,7 +28,7 @@ static inline noasan uint64_t UncheckedAlignedRead64(const char *p) {
* @return is <0, 0, or >0 based on uint8_t comparison
* @asyncsignalsafe
*/
int strcmp(const char *a, const char *b) {
noasan int strcmp(const char *a, const char *b) {
int c;
size_t i = 0;
uint64_t v, w, d;
@ -44,16 +41,20 @@ int strcmp(const char *a, const char *b) {
}
}
for (;; i += 8) {
v = UncheckedAlignedRead64(a + i);
w = UncheckedAlignedRead64(b + i);
v = *(uint64_t *)(a + i);
w = *(uint64_t *)(b + i);
w = (v ^ w) | (~v & (v - 0x0101010101010101) & 0x8080808080808080);
if (w) {
i += (unsigned)__builtin_ctzll(w) >> 3;
return (a[i] & 255) - (b[i] & 255);
break;
}
}
} else {
while (a[i] == b[i] && b[i]) ++i;
return (a[i] & 255) - (b[i] & 255);
}
if (IsAsan()) {
__asan_verify(a, i + 1);
__asan_verify(b, i + 1);
}
return (a[i] & 255) - (b[i] & 255);
}

View file

@ -17,8 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/strace.internal.h"
@ -29,8 +27,10 @@
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/spinlock.h"
#include "libc/intrin/weaken.h"
#include "libc/log/check.h"
#include "libc/log/internal.h"
#include "libc/macros.internal.h"
@ -88,7 +88,7 @@ wontreturn void testlib_abort(void) {
static void SetupTmpDir(void) {
char *p = g_testlib_tmpdir;
p = stpcpy(p, "o/tmp/");
p = stpcpy(p, kTmpPath);
p = stpcpy(p, program_invocation_short_name), *p++ = '.';
p = FormatInt64(p, getpid()), *p++ = '.';
p = FormatInt64(p, x++);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#ifdef TINY
// fmod [sic] does (𝑥 rem 𝑦) w/ round()-style rounding.
//
@ -28,3 +29,5 @@
fmod: ezlea fmodl,ax
jmp _d2ld2
.endfn fmod,globl
#endif /* TINY */

105
libc/tinymath/fmod.c Normal file
View file

@ -0,0 +1,105 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "third_party/libcxx/math.h"
asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\"");
// clang-format off
/**
* Does (𝑥 rem 𝑦) w/ round()-style rounding.
* @return remainder (-|𝑦|,|𝑦|) in %xmm0
* @define 𝑥-trunc(𝑥/𝑦)*𝑦
*/
double fmod(double x, double y)
{
union {double f; uint64_t i;} ux = {x}, uy = {y};
int ex = ux.i>>52 & 0x7ff;
int ey = uy.i>>52 & 0x7ff;
int sx = ux.i>>63;
uint64_t i;
/* in the followings uxi should be ux.i, but then gcc wrongly adds */
/* float load/store to inner loops ruining performance and code size */
uint64_t uxi = ux.i;
if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff)
return (x*y)/(x*y);
if (uxi<<1 <= uy.i<<1) {
if (uxi<<1 == uy.i<<1)
return 0*x;
return x;
}
/* normalize x and y */
if (!ex) {
for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1);
uxi <<= -ex + 1;
} else {
uxi &= -1ULL >> 12;
uxi |= 1ULL << 52;
}
if (!ey) {
for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1);
uy.i <<= -ey + 1;
} else {
uy.i &= -1ULL >> 12;
uy.i |= 1ULL << 52;
}
/* x mod y */
for (; ex > ey; ex--) {
i = uxi - uy.i;
if (i >> 63 == 0) {
if (i == 0)
return 0*x;
uxi = i;
}
uxi <<= 1;
}
i = uxi - uy.i;
if (i >> 63 == 0) {
if (i == 0)
return 0*x;
uxi = i;
}
for (; uxi>>52 == 0; uxi <<= 1, ex--);
/* scale result */
if (ex > 0) {
uxi -= 1ULL << 52;
uxi |= (uint64_t)ex << 52;
} else {
uxi >>= -ex + 1;
}
uxi |= (uint64_t)sx << 63;
ux.i = uxi;
return ux.f;
}

View file

@ -58,6 +58,8 @@ static int rmrfdir(const char *dirpath) {
/**
* Recursively removes file or directory.
*
* @return 0 on success, or -1 w/ errno
*/
int rmrf(const char *path) {
int e;

View file

@ -50,3 +50,8 @@ TEST(mkntpath, testRemoveDoubleSlash) {
EXPECT_EQ(8, __mkntpath("\\\\?\\doge", p));
EXPECT_STREQ(u"\\\\?\\doge", p);
}
TEST(mkntpath, testJustC) {
EXPECT_EQ(7, __mkntpath("/C", p));
EXPECT_STREQ(u"\\\\?\\C:\\", p);
}

View file

@ -534,8 +534,8 @@ void longstringislong_dupe(size_t size, char data[size], char dupe[size]) {
BENCH(bench_00_strcmp, bench) {
size_t size;
char *dupe, *data;
size = ROUNDDOWN(MAX(FRAMESIZE, getcachesize(kCpuCacheTypeData, 1)) / 2,
PAGESIZE);
size = 14139;
data = gc(malloc(size));
dupe = gc(malloc(size));
@ -576,8 +576,7 @@ BENCH(bench_00_strcmp, bench) {
BENCH(bench_01_strcasecmp, bench) {
size_t size;
char *dupe, *data;
size = ROUNDDOWN(MAX(FRAMESIZE, getcachesize(kCpuCacheTypeData, 1)) / 2,
PAGESIZE);
size = 141393;
data = gc(malloc(size));
dupe = gc(malloc(size));

View file

@ -17,8 +17,8 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/math.h"
#include "libc/stdio/rand.h"
#include "libc/runtime/gc.internal.h"
#include "libc/stdio/rand.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
@ -67,7 +67,19 @@ TEST(fmodf, test) {
EXPECT_STREQ("8e+20", gc(xdtoaf(fmodf(8e20, 32e20))));
}
BENCH(fmod, bench) {
EZBENCH2("fmod eze", donothing, fmodl(8, 32));
EZBENCH2("fmod big", donothing, fmodl(5.319372648326541e+255, M_2_PI));
BENCH(fmodf, bench) {
EZBENCH2("fmodf eze", donothing, fmodf(8, 32));
EZBENCH2("fmodf big", donothing, fmodf(5.319372648326541e+255, M_2_PI));
}
BENCH(fmod, bench) {
// fmod-tiny.S goes slow in the average case, fast for big case
EZBENCH2("fmod eze", donothing, fmod(8, 32));
// fmod.c goes fast for the average case very slow for big case
EZBENCH2("fmod big", donothing, fmod(5.319372648326541e+255, M_2_PI));
}
BENCH(fmodl, bench) {
EZBENCH2("fmodl eze", donothing, fmodl(8, 32));
EZBENCH2("fmodl big", donothing, fmodl(5.319372648326541e+255, M_2_PI));
}

View file

@ -14,7 +14,7 @@
-- PERFORMANCE OF THIS SOFTWARE.
gotsigusr1 = false
tmpdir = "o/tmp/lunix_test.%d" % {unix.getpid()}
tmpdir = "%s/o/tmp/lunix_test.%d" % {os.getenv('TMPDIR'), unix.getpid()}
function string.starts(String,Start)
return string.sub(String,1,string.len(Start))==Start

View file

@ -13,7 +13,7 @@
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-- PERFORMANCE OF THIS SOFTWARE.
tmpdir = "o/tmp/lunix_test.%d" % {unix.getpid()}
tmpdir = "%s/o/tmp/lunix_test.%d" % {os.getenv('TMPDIR'), unix.getpid()}
local function Path(name)
return tmpdir .. '/' .. name

View file

@ -620,7 +620,7 @@
/* #undef HAVE__SET_INVALID_PARAMETER_HANDLER */
/* Build host information. */
#define MAKE_HOST "x86_64-pc-cosmopolitan"
#define MAKE_HOST "x86_64-cosmopolitan"
/* Define to 1 to enable job server support in GNU make. */
/* TODO(jart): make it work */

View file

@ -15,6 +15,8 @@ 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/intrin/likely.h"
#define DB_NONE (0x000)
#define DB_BASIC (0x001)
#define DB_VERBOSE (0x002)
@ -26,7 +28,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
extern int db_level;
#define ISDB(_l) ((_l)&db_level)
#define ISDB(_l) UNLIKELY((_l)&db_level)
/* When adding macros to this list be sure to update the value of
XGETTEXT_OPTIONS in the po/Makevars file. */

View file

@ -1,157 +0,0 @@
/* clang-format off */
/* Get the system load averages.
Copyright (C) 1985-1989, 1991-1995, 1997, 1999-2000, 2003-2020 Free Software
Foundation, Inc.
NOTE: The canonical source of this file is maintained with gnulib.
Bugs can be reported to bug-gnulib@gnu.org.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR 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 <https://www.gnu.org/licenses/>. */
/* Compile-time symbols that this file uses:
HAVE_PSTAT_GETDYNAMIC Define this if your system has the
pstat_getdynamic function. I think it
is unique to HPUX9. The best way to get the
definition is through the AC_FUNC_GETLOADAVG
macro that comes with autoconf 2.13 or newer.
If that isn't an option, then just put
AC_CHECK_FUNCS(pstat_getdynamic) in your
configure.ac file.
HAVE_LIBPERFSTAT Define this if your system has the
perfstat_cpu_total function in libperfstat (AIX).
FIXUP_KERNEL_SYMBOL_ADDR() Adjust address in returned struct nlist.
KERNEL_FILE Name of the kernel file to nlist.
LDAV_CVT() Scale the load average from the kernel.
Returns a double.
LDAV_SYMBOL Name of kernel symbol giving load average.
LOAD_AVE_TYPE Type of the load average array in the kernel.
Must be defined unless one of
apollo, DGUX, NeXT, or UMAX is defined;
or we have libkstat;
otherwise, no load average is available.
HAVE_NLIST_H nlist.h is available. NLIST_STRUCT defaults
to this.
NLIST_STRUCT Include nlist.h, not a.out.h.
N_NAME_POINTER The nlist n_name element is a pointer,
not an array.
HAVE_STRUCT_NLIST_N_UN_N_NAME 'n_un.n_name' is member of 'struct nlist'.
LINUX_LDAV_FILE [__linux__, __ANDROID__, __CYGWIN__]: File
containing load averages.
Specific system predefines this file uses, aside from setting
default values if not emacs:
apollo
BSD Real BSD, not just BSD-like.
DGUX
eunice UNIX emulator under VMS.
hpux
__MSDOS__ No-op for MSDOS.
NeXT
sgi
UMAX
UMAX4_3
VMS
_WIN32 Native Windows (possibly also defined on Cygwin)
__linux__, __ANDROID__ Linux: assumes /proc file system mounted.
Support from Michael K. Johnson.
__CYGWIN__ Cygwin emulates linux /proc/loadavg.
__NetBSD__ NetBSD: assumes /kern file system mounted.
In addition, to avoid nesting many #ifdefs, we internally set
LDAV_DONE to indicate that the load average has been computed.
We also #define LDAV_PRIVILEGED if a program will require
special installation to be able to call getloadavg. */
#include "libc/sysv/consts/o.h"
#include "libc/errno.h"
#include "libc/dce.h"
#include "libc/dce.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
#include "libc/stdio/stdio.h"
#include "third_party/make/config.h"
#include "third_party/make/intprops.h"
/* Put the 1 minute, 5 minute and 15 minute load averages
into the first NELEM elements of LOADAVG.
Return the number written (never more than 3, but may be less than NELEM),
or -1 (setting errno) if an error occurred. */
int
getloadavg (double loadavg[], int nelem)
{
int elem = 0; /* Return value. */
if (IsLinux()) {
char ldavgbuf[3 * (INT_STRLEN_BOUND (int) + sizeof ".00 ")];
char const *ptr = ldavgbuf;
int fd, count, saved_errno;
fd = open ("/proc/loadavg", O_RDONLY);
if (fd == -1)
return -1;
count = read (fd, ldavgbuf, sizeof ldavgbuf - 1);
saved_errno = errno;
(void) close (fd);
errno = saved_errno;
if (count <= 0)
return -1;
ldavgbuf[count] = '\0';
for (elem = 0; elem < nelem; elem++)
{
double numerator = 0;
double denominator = 1;
while (*ptr == ' ')
ptr++;
/* Finish if this number is missing, and report an error if all
were missing. */
if (! ('0' <= *ptr && *ptr <= '9'))
{
if (elem == 0)
return enotsup();
break;
}
while ('0' <= *ptr && *ptr <= '9')
numerator = 10 * numerator + (*ptr++ - '0');
if (*ptr == '.')
for (ptr++; '0' <= *ptr && *ptr <= '9'; ptr++)
numerator = 10 * numerator + (*ptr - '0'), denominator *= 10;
loadavg[elem++] = numerator / denominator;
}
} else if (IsNetbsd()) {
unsigned long int load_ave[3], scale;
int count;
FILE *fp;
fp = fopen ("/kern/loadavg", "r");
if (fp == NULL)
return -1;
count = fscanf (fp, "%lu %lu %lu %lu\n",
&load_ave[0], &load_ave[1], &load_ave[2],
&scale);
fclose (fp);
if (count != 4)
return enotsup();
for (elem = 0; elem < nelem; elem++)
loadavg[elem] = (double) load_ave[elem] / (double) scale;
} else if (IsWindows()) {
for ( ; elem < nelem; elem++)
loadavg[elem] = 0.0;
} else {
errno = ENOSYS;
elem = -1;
}
return elem;
}

320
third_party/make/job.c vendored
View file

@ -1,4 +1,3 @@
/* clang-format off */
/* Job execution and handling for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc.
This file is part of GNU Make.
@ -21,55 +20,40 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "third_party/make/filedef.h"
#include "third_party/make/job.h"
/**/
#include "third_party/make/commands.h"
#include "third_party/make/os.h"
#include "third_party/make/variable.h"
#include "libc/log/log.h"
#include "libc/runtime/stack.h"
#include "libc/calls/calls.h"
#include "libc/x/x.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/x/x.h"
#include "libc/runtime/runtime.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/elf/struct/ehdr.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/elf/def.h"
#include "libc/intrin/kprintf.h"
#include "libc/elf/struct/phdr.h"
#include "libc/elf/def.h"
#include "libc/elf/elf.h"
#include "libc/calls/calls.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/map.h"
#include "libc/intrin/kprintf.h"
#include "libc/sysv/consts/o.h"
#include "libc/calls/struct/timeval.h"
#include "libc/x/x.h"
#include "libc/intrin/kprintf.h"
#include "libc/time/time.h"
#include "libc/calls/calls.h"
#include "libc/intrin/kprintf.h"
#include "libc/assert.h"
#include "libc/sysv/consts/pr.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/bpf.h"
#include "libc/calls/struct/filter.h"
#include "libc/calls/struct/seccomp.h"
#include "libc/calls/struct/filter.h"
#include "libc/sysv/consts/pr.h"
#include "libc/sysv/consts/pr.h"
#include "libc/sysv/consts/audit.h"
#include "libc/sysv/consts/nrlinux.h"
#include "libc/macros.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/elf/def.h"
#include "libc/elf/elf.h"
#include "libc/elf/struct/ehdr.h"
#include "libc/elf/struct/phdr.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/log.h"
#include "libc/log/rop.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/sock/sock.h"
#include "libc/intrin/kprintf.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/audit.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/nrlinux.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/pr.h"
#include "libc/sysv/consts/prot.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "third_party/make/commands.h"
#include "third_party/make/dep.h"
#include "third_party/make/os.h"
#include "third_party/make/variable.h"
// clang-format off
#define GOTO_SLOW \
do { \
@ -391,6 +375,134 @@ child_error (struct child *child,
}
/* [jart] manage temporary directories per rule */
const char *
get_tmpdir (struct file *file)
{
const struct variable *var;
if ((var = lookup_variable_in_set (STRING_SIZE_TUPLE("TMPDIR"),
file->variables->set)) ||
(file->pat_variables &&
(var = lookup_variable_in_set (STRING_SIZE_TUPLE("TMPDIR"),
file->pat_variables->set))) ||
(var = lookup_variable (STRING_SIZE_TUPLE("TMPDIR"))))
return variable_expand (var->value);
else
return kTmpPath;
}
char *
new_tmpdir (const char *tmp, struct file *file)
{
const char *s;
int c, e, i, j;
char *dir, *tmpdir;
char cwd[PATH_MAX];
char path[PATH_MAX];
/* create temporary directory in tmp */
i = 0;
/* ensure tmpdir will be absolute */
if (tmp[0] != '/')
{
if (getcwd(cwd, sizeof(cwd)))
{
for (j = 0; cwd[j]; ++j)
if (i < PATH_MAX)
path[i++] = cwd[j];
if (i && path[i - 1] != '/')
if (i < PATH_MAX)
path[i++] = '/';
}
else
DB (DB_JOBS, (_("Failed to get current directory\n")));
}
/* copy old tmpdir */
for (j = 0; tmp[j]; ++j)
if (i < PATH_MAX)
path[i++] = tmp[j];
/* append slash */
if (i && path[i - 1] != '/')
if (i < PATH_MAX)
path[i++] = '/';
/* append target name safely */
for (j = 0; (c = file->name[j]); ++j)
{
if (isalnum(c))
c = tolower(c);
else
c = '_';
if (i < PATH_MAX)
path[i++] = c;
}
/* copy random template */
s = ".XXXXXX";
for (j = 0; s[j]; ++j)
if (i < PATH_MAX)
path[i++] = s[j];
/* add nul terminator */
if (i + 11 < PATH_MAX)
path[i] = 0;
else
{
DB (DB_JOBS, (_("Creating TMPDIR in %s for %s is too long\n"),
tmp, file->name));
return 0;
}
/* create temp directory with random data */
e = errno;
if (!(tmpdir = mkdtemp (path)) && errno == ENOENT)
{
/* create parent directories if necessary */
char *dir;
errno = e;
dir = xstrdup (path);
if (!makedirs (dirname (dir), 0700))
tmpdir = mkdtemp (path);
free (dir);
}
/* returned string must be free'd */
if (tmpdir)
{
tmpdir = xstrdup (tmpdir);
DB (DB_JOBS, (_("Created TMPDIR %s\n"), path));
}
else
DB (DB_JOBS, (_("Creating TMPDIR %s failed %s\n"),
path, strerror (errno)));
return tmpdir;
}
void
delete_tmpdir (struct child *c)
{
if (!c->tmpdir) return;
DB (DB_JOBS, (_("Deleting TMPDIR %s\n"), c->tmpdir));
if (!isdirectory (c->tmpdir))
DB (DB_JOBS, (_("Warning TMPDIR %s doesn't exist\n"), c->tmpdir));
errno = 0;
if (rmrf (c->tmpdir))
DB (DB_JOBS, (_("Deleting TMPDIR %s failed %s\n"),
c->tmpdir, strerror(errno)));
free (c->tmpdir);
c->tmpdir = 0;
}
/* Handle a dead child. This handler may or may not ever be installed.
If we're using the jobserver feature without pselect(), we need it.
@ -642,6 +754,7 @@ reap_children (int block, int err)
}
if (exit_sig != 0 || delete_on_error)
delete_child_targets (c);
delete_tmpdir (c);
}
else
{
@ -693,10 +806,13 @@ reap_children (int block, int err)
delete_child_targets (c);
}
else
/* There are no more commands. We got through them all
without an unignored error. Now the target has been
successfully updated. */
c->file->update_status = us_success;
{
/* There are no more commands. We got through them all
without an unignored error. Now the target has been
successfully updated. */
c->file->update_status = us_success;
delete_tmpdir (c);
}
}
/* When we get here, all the commands for c->file are finished. */
@ -800,6 +916,7 @@ free_child (struct child *child)
free (child->environment);
}
free (child->tmpdir);
free (child->cmd_name);
free (child);
}
@ -1133,10 +1250,12 @@ start_waiting_job (struct child *c)
void
new_job (struct file *file)
{
struct commands *cmds = file->cmds;
struct variable *var;
struct child *c;
char **lines;
unsigned int i;
char **lines;
/* Let any previously decided-upon jobs that are waiting
for the load to go down start before this new one. */
@ -1157,6 +1276,14 @@ new_job (struct file *file)
c->file = file;
c->sh_batch_file = NULL;
/* [jart] manage temporary directories per rule */
if ((c->tmpdir = new_tmpdir (get_tmpdir (file), file)))
{
var = define_variable_for_file ("TMPDIR", 6, c->tmpdir,
o_override, 0, file);
var->export = v_export;
}
/* Cache dontcare flag because file->dontcare can be changed once we
return. Check dontcare inheritance mechanism for details. */
c->dontcare = file->dontcare;
@ -1473,83 +1600,12 @@ load_too_high (void)
OK, I'm not sure exactly how to handle that, but for sure we need to
clamp this value at the number of cores before this can be enabled.
*/
#define PROC_FD_INIT -1
static int proc_fd = PROC_FD_INIT;
double load, guess;
time_t now;
#ifdef WINDOWS32
/* sub_proc.c is limited in the number of objects it can wait for. */
if (process_table_full ())
return 1;
#endif
if (max_load_average < 0)
return 0;
/* If we haven't tried to open /proc/loadavg, try now. */
#define LOADAVG "/proc/loadavg"
if (proc_fd == -2)
{
EINTRLOOP (proc_fd, open (LOADAVG, O_RDONLY));
if (proc_fd < 0)
DB (DB_JOBS, ("Using system load detection method.\n"));
else
{
DB (DB_JOBS, ("Using " LOADAVG " load detection method.\n"));
fd_noinherit (proc_fd);
}
}
/* Try to read /proc/loadavg if we managed to open it. */
if (proc_fd >= 0)
{
int r;
EINTRLOOP (r, lseek (proc_fd, 0, SEEK_SET));
if (r >= 0)
{
#define PROC_LOADAVG_SIZE 64
char avg[PROC_LOADAVG_SIZE+1];
EINTRLOOP (r, read (proc_fd, avg, PROC_LOADAVG_SIZE));
if (r >= 0)
{
const char *p;
/* The syntax of /proc/loadavg is:
<1m> <5m> <15m> <running>/<total> <pid>
The load is considered too high if there are more jobs
running than the requested average. */
avg[r] = '\0';
p = strchr (avg, ' ');
if (p)
p = strchr (p+1, ' ');
if (p)
p = strchr (p+1, ' ');
if (p && ISDIGIT(p[1]))
{
int cnt = atoi (p+1);
DB (DB_JOBS, ("Running: system = %d / make = %u (max requested = %f)\n",
cnt, job_slots_used, max_load_average));
return (double)cnt > max_load_average;
}
DB (DB_JOBS, ("Failed to parse " LOADAVG ": %s\n", avg));
}
}
/* If we 𝑔𝑜𝑡 𝑕𝑒𝑟𝑒, something went wrong. Give up on this method. */
if (r < 0)
DB (DB_JOBS, ("Failed to read " LOADAVG ": %s\n", strerror (errno)));
close (proc_fd);
proc_fd = -1;
}
/* Find the real system load average. */
make_access ();
if (getloadavg (&load, 1) != 1)
@ -1622,7 +1678,7 @@ start_waiting_jobs (void)
bool
GetPermPrefix (const char *path, char out_perm[5], const char **out_path)
get_perm_prefix (const char *path, char out_perm[5], const char **out_path)
{
int c, n;
for (n = 0;;)
@ -1656,7 +1712,7 @@ Unveil (const char *path, const char *perm)
char permprefix[5];
/* if path is like `rwcx:o/tmp` then `rwcx` will override perm */
if (path && GetPermPrefix (path, permprefix, &path))
if (path && get_perm_prefix (path, permprefix, &path))
perm = permprefix;
fp[0] = 0;
@ -1665,6 +1721,8 @@ Unveil (const char *path, const char *perm)
(fp[1] = tilde_expand ((fp[0] = xstrdup (path)))))
path = fp[1];
DB (DB_JOBS, (_("Unveiling %s with permissions %s\n"), path, perm));
e = errno;
if (unveil (path, perm) != -1)
{
@ -1690,7 +1748,7 @@ Unveil (const char *path, const char *perm)
}
int
UnveilVariable (const struct variable *var)
unveil_variable (const struct variable *var)
{
char *val, *tok, *state, *start;
if (!var) return 0;
@ -1759,7 +1817,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
if (fderr != FD_STDERR)
EINTRLOOP (r, dup2 (fderr, FD_STDERR));
g_strict = Vartoi (lookup_variable (STRING_SIZE_TUPLE(".STRICT")));
g_strict = Vartoi (lookup_variable (STRING_SIZE_TUPLE (".STRICT")));
intptr_t loc = (intptr_t)child; /* we can cast if it's on the heap ;_; */
if (!(GetStackAddr() < loc && loc < GetStackAddr() + GetStackSize())) {
@ -1798,6 +1856,8 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
errno = 0;
if (sandboxed)
{
DB (DB_JOBS, (_("Sandboxing %s\n"), c->file->name));
if (!g_strict && argv[0][0] == '/' && IsDynamicExecutable (argv[0]))
{
/*
@ -1854,10 +1914,14 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
/* unveil executable */
RETURN_ON_ERROR (Unveil (argv[0], "rx"));
/* unveil temporary directory */
if (c->tmpdir)
RETURN_ON_ERROR (Unveil (c->tmpdir, "rwcx"));
/* unveil lazy mode files */
if (!g_strict)
{
RETURN_ON_ERROR (Unveil ("/tmp", "rwc"));
RETURN_ON_ERROR (Unveil ("o/tmp", "rwcx"));
RETURN_ON_ERROR (Unveil ("/dev/zero", "r"));
RETURN_ON_ERROR (Unveil ("/dev/null", "rw"));
RETURN_ON_ERROR (Unveil ("/dev/full", "rw"));
@ -1893,6 +1957,8 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
c->file->name, strerror (errno));
return -1;
}
DB (DB_JOBS, (_("Unveiling %s with permissions %s\n"),
c->file->name, "rwx"));
if (unveil (c->file->name, "rwx") && errno != ENOSYS)
{
OSS (error, NILF, "%s: unveil target failed %s",
@ -1915,17 +1981,17 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
/* unveil explicit .UNVEIL entries */
RETURN_ON_ERROR
(UnveilVariable
(unveil_variable
(lookup_variable
(STRING_SIZE_TUPLE (".UNVEIL"))));
RETURN_ON_ERROR
(UnveilVariable
(unveil_variable
(lookup_variable_in_set
(STRING_SIZE_TUPLE (".UNVEIL"),
c->file->variables->set)));
if (c->file->pat_variables)
RETURN_ON_ERROR
(UnveilVariable
(unveil_variable
(lookup_variable_in_set
(STRING_SIZE_TUPLE (".UNVEIL"),
c->file->pat_variables->set)));

View file

@ -41,6 +41,7 @@ struct child
struct file *file; /* File being remade. */
char *tmpdir; /* Temporary directory */
char *sh_batch_file; /* Script file for shell commands */
char **command_lines; /* Array of variable-expanded cmd lines. */
char *command_ptr; /* Ptr into command_lines[command_line]. */

View file

@ -45,6 +45,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "libc/runtime/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/log/log.h"
#include "libc/log/log.h"
#include "third_party/make/getopt.h"
STATIC_STACK_SIZE(0x200000); // 2mb stack
@ -355,6 +357,10 @@ static const char *const usage[] =
Consider FILE to be infinitely new.\n"),
N_("\
--warn-undefined-variables Warn when an undefined variable is referenced.\n"),
N_("\
--strace Log system calls.\n"),
N_("\
--ftrace Log function calls.\n"),
NULL
};
@ -1101,11 +1107,7 @@ main (int argc, char **argv, char **envp)
/* Figure out where we are. */
#ifdef WINDOWS32
if (getcwd_fs (current_directory, GET_PATH_MAX) == 0)
#else
if (getcwd (current_directory, GET_PATH_MAX) == 0)
#endif
{
#ifdef HAVE_GETCWD
perror_with_name ("getcwd", "");
@ -2980,7 +2982,7 @@ print_version (void)
/* Do it only once. */
return;
printf ("%sLandlock Make 1.0.1 (GNU Make %s)\n", precede, version_string);
printf ("%sLandlock Make 1.1.1 (GNU Make %s)\n", precede, version_string);
if (!remote_description || *remote_description == '\0')
printf (_("%sBuilt for %s\n"), precede, make_host);
@ -2993,6 +2995,8 @@ print_version (void)
year, and none of the rest of it should be translated (including the
word "Copyright"), so it hardly seems worth it. */
printf ("%sCopyright (C) 2022 Justine Alexandra Roberts Tunney\n",
precede);
printf ("%sCopyright (C) 1988-2020 Free Software Foundation, Inc.\n",
precede);

View file

@ -65,7 +65,6 @@ THIRD_PARTY_MAKE_SRCS_LIB = \
third_party/make/fcntl.c \
third_party/make/fd-hook.c \
third_party/make/findprog-in.c \
third_party/make/getloadavg.c \
third_party/make/getprogname.c \
third_party/make/stripslash.c \
third_party/make/unistd.c \

View file

@ -408,6 +408,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.padding.com.dbg: \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/third_party/mbedtls/test/test_suite_ctr_drbg.com.runs: private .UNVEIL += rwc:o/tmp
o/$(MODE)/third_party/mbedtls/test/test_suite_ctr_drbg.com: o/$(MODE)/third_party/mbedtls/test/test_suite_ctr_drbg.com.dbg
o/$(MODE)/third_party/mbedtls/test/test_suite_ctr_drbg.com.dbg: \
$(THIRD_PARTY_MBEDTLS_TEST_DEPS) \
@ -586,6 +587,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_hkdf.com.dbg: \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.misc.com.runs: private .UNVEIL += rwc:o/tmp
o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.misc.com: o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.misc.com.dbg
o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.misc.com.dbg: \
$(THIRD_PARTY_MBEDTLS_TEST_DEPS) \
@ -668,6 +670,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_memory_buffer_alloc.com.dbg: \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/third_party/mbedtls/test/test_suite_mpi.com.runs: private .UNVEIL += rwc:o/tmp
o/$(MODE)/third_party/mbedtls/test/test_suite_mpi.com: o/$(MODE)/third_party/mbedtls/test/test_suite_mpi.com.dbg
o/$(MODE)/third_party/mbedtls/test/test_suite_mpi.com.dbg: \
$(THIRD_PARTY_MBEDTLS_TEST_DEPS) \

View file

@ -615,24 +615,6 @@ static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val,
return JS_NewString(ctx, str);
}
#if defined(_WIN32)
static void setenv(const char *name, const char *value, int overwrite)
{
char *str;
size_t name_len, value_len;
name_len = strlen(name);
value_len = strlen(value);
str = malloc(name_len + 1 + value_len + 1);
memcpy(str, name, name_len);
str[name_len] = '=';
memcpy(str + name_len + 1, value, value_len);
str[name_len + 1 + value_len] = '\0';
_putenv(str);
free(str);
}
#endif /* _WIN32 */
static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{