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

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

View file

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

View file

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