mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-02 17:28:30 +00:00
Make fixes and improvements
- Invent iso8601us() for faster timestamps - Improve --strace descriptions of sigset_t - Rebuild the Landlock Make bootstrap binary - Introduce MODE=sysv for non-Windows builds - Permit OFD fcntl() locks under pledge(flock) - redbean can now protect your kernel from ddos - Have vfork() fallback to sys_fork() not fork() - Change kmalloc() to not die when out of memory - Improve documentation for some termios functions - Rewrite putenv() and friends to conform to POSIX - Fix linenoise + strace verbosity issue on Windows - Fix regressions in our ability to show backtraces - Change redbean SetHeader() to no-op if value is nil - Improve fcntl() so SQLite locks work in non-WAL mode - Remove some unnecessary work during fork() on Windows - Create redbean-based SSL reverse proxy for IPv4 TurfWar - Fix ape/apeinstall.sh warning when using non-bash shells - Add ProgramTrustedIp(), and IsTrustedIp() APIs to redbean - Support $PWD, $UID, $GID, and $EUID in command interpreter - Introduce experimental JTqFpD APE prefix for non-Windows builds - Invent blackhole daemon for firewalling IP addresses via UNIX named socket - Add ProgramTokenBucket(), AcquireToken(), and CountTokens() APIs to redbean
This commit is contained in:
parent
648bf6555c
commit
f7ff77d865
209 changed files with 3818 additions and 998 deletions
|
@ -16,13 +16,26 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/_getenv.internal.h"
|
||||
|
||||
void __releasefd_unlocked(int fd) {
|
||||
if (0 <= fd && fd < g_fds.n) {
|
||||
bzero(g_fds.p + fd, sizeof(*g_fds.p));
|
||||
g_fds.f = MIN(fd, g_fds.f);
|
||||
#define ToUpper(c) \
|
||||
(IsWindows() && (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
|
||||
struct Env _getenv(char **p, const char *k) {
|
||||
char *t;
|
||||
int i, j;
|
||||
for (i = 0; (t = p[i]); ++i) {
|
||||
for (j = 0;; ++j) {
|
||||
if (!k[j] || k[j] == '=') {
|
||||
if (!t[j]) return (struct Env){t + j, i};
|
||||
if (t[j] == '=') return (struct Env){t + j + 1, i};
|
||||
break;
|
||||
}
|
||||
if (ToUpper(k[j] & 255) != ToUpper(t[j] & 255)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (struct Env){0, i};
|
||||
}
|
15
libc/intrin/_getenv.internal.h
Normal file
15
libc/intrin/_getenv.internal.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN__GETENV_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN__GETENV_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Env {
|
||||
char *s;
|
||||
int i;
|
||||
};
|
||||
|
||||
struct Env _getenv(char **, const char *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN__GETENV_INTERNAL_H_ */
|
|
@ -17,10 +17,12 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/intrin.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
||||
static _Thread_local bool noreentry;
|
||||
|
||||
/**
|
||||
* Shows backtrace if crash reporting facilities are linked.
|
||||
|
@ -28,12 +30,20 @@
|
|||
void _bt(const char *fmt, ...) {
|
||||
int e;
|
||||
va_list va;
|
||||
|
||||
if (!noreentry) {
|
||||
noreentry = true;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fmt) {
|
||||
va_start(va, fmt);
|
||||
kvprintf(fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
if (_weaken(ShowBacktrace)) {
|
||||
|
||||
if (_weaken(ShowBacktrace) && _weaken(GetSymbolTable)) {
|
||||
e = errno;
|
||||
_weaken(ShowBacktrace)(2, __builtin_frame_address(0));
|
||||
errno = e;
|
||||
|
@ -41,5 +51,18 @@ void _bt(const char *fmt, ...) {
|
|||
kprintf("_bt() can't show backtrace because you need:\n"
|
||||
"\tSTATIC_YOINK(\"ShowBacktrace\");\n"
|
||||
"to be linked.\n");
|
||||
if (_weaken(PrintBacktraceUsingSymbols) && _weaken(GetSymbolTable)) {
|
||||
e = errno;
|
||||
_weaken(PrintBacktraceUsingSymbols)(2, __builtin_frame_address(0),
|
||||
_weaken(GetSymbolTable)());
|
||||
errno = e;
|
||||
} else {
|
||||
kprintf("_bt() can't show backtrace because you need:\n"
|
||||
"\tSTATIC_YOINK(\"PrintBacktraceUsingSymbols\");\n"
|
||||
"\tSTATIC_YOINK(\"GetSymbolTable\");\n"
|
||||
"to be linked.\n");
|
||||
}
|
||||
}
|
||||
|
||||
noreentry = false;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2020 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 │
|
||||
|
@ -16,12 +16,16 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
void __releasefd(int fd) {
|
||||
__fds_lock();
|
||||
__releasefd_unlocked(fd);
|
||||
__fds_unlock();
|
||||
/**
|
||||
* Removes all environment variables.
|
||||
*
|
||||
* @return 0 on success, or nonzero on error
|
||||
*/
|
||||
int clearenv(void) {
|
||||
environ = 0;
|
||||
STRACE("clearenv() → 0");
|
||||
return 0;
|
||||
}
|
|
@ -56,7 +56,7 @@ const char *(DescribeFlock)(char buf[N], int cmd, const struct flock *l) {
|
|||
append(", .l_pid=%d", l->l_pid);
|
||||
}
|
||||
|
||||
if (l->l_sysid) {
|
||||
if (IsFreebsd() && l->l_sysid) {
|
||||
append(", .l_sysid=%d", l->l_sysid);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,23 +16,68 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
|
||||
const char *(DescribeSigaction)(char buf[256], int rc,
|
||||
static const char *DescribeSigHandler(char buf[64], void f(int)) {
|
||||
if (f == SIG_ERR) return "SIG_ERR";
|
||||
if (f == SIG_DFL) return "SIG_DFL";
|
||||
if (f == SIG_IGN) return "SIG_IGN";
|
||||
ksnprintf(buf, 64, "%t", f);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char *DescribeSigFlags(char buf[64], int x) {
|
||||
const struct DescribeFlags kSigFlags[] = {
|
||||
{SA_NOCLDSTOP, "NOCLDSTOP"}, //
|
||||
{SA_NOCLDWAIT, "NOCLDWAIT"}, //
|
||||
{SA_SIGINFO, "SIGINFO"}, //
|
||||
{SA_ONSTACK, "ONSTACK"}, //
|
||||
{SA_RESTART, "RESTART"}, //
|
||||
{SA_NODEFER, "NODEFER"}, //
|
||||
{SA_RESETHAND, "RESETHAND"}, //
|
||||
{SA_NOMASK, "NOMASK"}, //
|
||||
{SA_ONESHOT, "ONESHOT"}, //
|
||||
};
|
||||
return DescribeFlags(buf, 64, kSigFlags, ARRAYLEN(kSigFlags), "SA_", x);
|
||||
}
|
||||
|
||||
#define N 256
|
||||
|
||||
#define append(...) o += ksnprintf(buf + o, N - o, __VA_ARGS__)
|
||||
|
||||
const char *(DescribeSigaction)(char buf[N], int rc,
|
||||
const struct sigaction *sa) {
|
||||
int o = 0;
|
||||
char b64[64];
|
||||
|
||||
if (rc == -1) return "n/a";
|
||||
if (!sa) return "NULL";
|
||||
if ((!IsAsan() && kisdangerous(sa)) ||
|
||||
(IsAsan() && !__asan_is_valid(sa, sizeof(*sa)))) {
|
||||
ksnprintf(buf, 256, "%p", sa);
|
||||
} else {
|
||||
ksnprintf(buf, 256, "{.sa_handler=%t, .sa_flags=%#lx, .sa_mask=%s}",
|
||||
sa->sa_handler, sa->sa_flags, DescribeSigset(rc, &sa->sa_mask));
|
||||
ksnprintf(buf, N, "%p", sa);
|
||||
return buf;
|
||||
}
|
||||
|
||||
append("{.sa_handler=%s", DescribeSigHandler(b64, sa->sa_handler));
|
||||
|
||||
if (sa->sa_flags) {
|
||||
append(", .sa_flags=%s", DescribeSigFlags(b64, sa->sa_flags));
|
||||
}
|
||||
|
||||
if (!sigisemptyset(&sa->sa_mask)) {
|
||||
append(", .sa_mask=%s", DescribeSigset(rc, &sa->sa_mask));
|
||||
}
|
||||
|
||||
append("}");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/popcnt.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
#define N 128
|
||||
|
@ -31,6 +32,7 @@
|
|||
|
||||
const char *(DescribeSigset)(char buf[N], int rc, const sigset_t *ss) {
|
||||
bool gotsome;
|
||||
const char *s;
|
||||
int sig, o = 0;
|
||||
sigset_t sigset;
|
||||
|
||||
|
@ -45,9 +47,9 @@ const char *(DescribeSigset)(char buf[N], int rc, const sigset_t *ss) {
|
|||
if (sigcountset(ss) > 16) {
|
||||
append("~");
|
||||
sigemptyset(&sigset);
|
||||
for (sig = 1; sig <= NSIG; ++sig) {
|
||||
for (sig = 1; sig <= _NSIG; ++sig) {
|
||||
if (!sigismember(ss, sig)) {
|
||||
sigaddset(&sigset, sig);
|
||||
sigset.__bits[(sig - 1) >> 6] |= 1ull << ((sig - 1) & 63);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -56,14 +58,18 @@ const char *(DescribeSigset)(char buf[N], int rc, const sigset_t *ss) {
|
|||
|
||||
append("{");
|
||||
gotsome = false;
|
||||
for (sig = 1; sig <= NSIG; ++sig) {
|
||||
for (sig = 1; sig <= _NSIG; ++sig) {
|
||||
if (sigismember(&sigset, sig) > 0) {
|
||||
if (gotsome) {
|
||||
append(",");
|
||||
} else {
|
||||
gotsome = true;
|
||||
}
|
||||
append("%s", strsignal(sig) + 3);
|
||||
s = strsignal(sig);
|
||||
if (s[0] == 'S' && s[1] == 'I' && s[2] == 'G') {
|
||||
s += 3;
|
||||
}
|
||||
append("%s", s);
|
||||
}
|
||||
}
|
||||
append("}");
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/asancodes.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -29,17 +30,26 @@
|
|||
|
||||
#define G FRAMESIZE
|
||||
|
||||
static void _mapframe(void *p, int f) {
|
||||
int prot, flags;
|
||||
static void *_mapframe(void *p, int f) {
|
||||
int rc, prot, flags;
|
||||
struct DirectMap dm;
|
||||
prot = PROT_READ | PROT_WRITE;
|
||||
flags = f | MAP_ANONYMOUS | MAP_FIXED;
|
||||
_npassert((dm = sys_mmap(p, G, prot, flags, -1, 0)).addr == p);
|
||||
__mmi_lock();
|
||||
_npassert(!TrackMemoryInterval(&_mmi, (uintptr_t)p >> 16, (uintptr_t)p >> 16,
|
||||
dm.maphandle, prot, flags, false, false, 0,
|
||||
G));
|
||||
__mmi_unlock();
|
||||
if ((dm = sys_mmap(p, G, prot, flags, -1, 0)).addr == p) {
|
||||
__mmi_lock();
|
||||
rc = TrackMemoryInterval(&_mmi, (uintptr_t)p >> 16, (uintptr_t)p >> 16,
|
||||
dm.maphandle, prot, flags, false, false, 0, G);
|
||||
__mmi_unlock();
|
||||
if (!rc) {
|
||||
return p;
|
||||
} else {
|
||||
_unassert(errno == ENOMEM);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
_unassert(errno == ENOMEM);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,7 +68,8 @@ static void _mapframe(void *p, int f) {
|
|||
* @param e points to end of memory that's allocated
|
||||
* @param h is highest address to which `e` may grow
|
||||
* @param f should be `MAP_PRIVATE` or `MAP_SHARED`
|
||||
* @return new value for `e`
|
||||
* @return new value for `e` or null w/ errno
|
||||
* @raise ENOMEM if we require more vespene gas
|
||||
*/
|
||||
noasan void *_extend(void *p, size_t n, void *e, int f, intptr_t h) {
|
||||
char *q;
|
||||
|
@ -67,10 +78,10 @@ noasan void *_extend(void *p, size_t n, void *e, int f, intptr_t h) {
|
|||
for (q = e; q < ((char *)p + n); q += 8) {
|
||||
if (!((uintptr_t)q & (G - 1))) {
|
||||
_unassert(q + G <= (char *)h);
|
||||
_mapframe(q, f);
|
||||
if (!_mapframe(q, f)) return 0;
|
||||
if (IsAsan()) {
|
||||
if (!((uintptr_t)SHADOW(q) & (G - 1))) {
|
||||
_mapframe(SHADOW(q), f);
|
||||
if (!_mapframe(SHADOW(q), f)) return 0;
|
||||
__asan_poison(q, G << kAsanScale, kAsanProtected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,62 +16,28 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/_getenv.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
forceinline int Identity(int c) {
|
||||
return c;
|
||||
}
|
||||
|
||||
forceinline int ToUpper(int c) {
|
||||
return 'a' <= c && c <= 'z' ? c - ('a' - 'A') : c;
|
||||
}
|
||||
|
||||
forceinline char *GetEnv(const char *s, int xlat(int)) {
|
||||
char **p;
|
||||
size_t i, j;
|
||||
if ((p = environ)) {
|
||||
for (i = 0; p[i]; ++i) {
|
||||
for (j = 0;; ++j) {
|
||||
if (!s[j]) {
|
||||
if (p[i][j] == '=') {
|
||||
return p[i] + j + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (xlat(s[j]) != xlat(p[i][j])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns value of environment variable, or NULL if not found.
|
||||
*
|
||||
* Environment variables can store empty string on Unix but not Windows.
|
||||
*
|
||||
* @note should not be used after __cxa_finalize() is called
|
||||
* @return pointer to value of `environ` entry, or null if not found
|
||||
*/
|
||||
char *getenv(const char *s) {
|
||||
char *r;
|
||||
char **p;
|
||||
struct Env e;
|
||||
if (!s) return 0;
|
||||
if (!IsWindows()) {
|
||||
r = GetEnv(s, Identity);
|
||||
} else {
|
||||
r = GetEnv(s, ToUpper);
|
||||
}
|
||||
if (!(p = environ)) return 0;
|
||||
e = _getenv(p, s);
|
||||
#if SYSDEBUG
|
||||
if (!(s[0] == 'T' && s[1] == 'Z' && !s[2])) {
|
||||
// TODO(jart): memoize TZ or something
|
||||
STRACE("getenv(%#s) → %#s", s, r);
|
||||
STRACE("getenv(%#s) → %#s", s, e.s);
|
||||
}
|
||||
#endif
|
||||
return r;
|
||||
return e.s;
|
||||
}
|
|
@ -7,6 +7,7 @@ LIBC_INTRIN_ARTIFACTS += LIBC_INTRIN_A
|
|||
LIBC_INTRIN = $(LIBC_INTRIN_A_DEPS) $(LIBC_INTRIN_A)
|
||||
LIBC_INTRIN_A = o/$(MODE)/libc/intrin/intrin.a
|
||||
LIBC_INTRIN_A_HDRS = $(filter %.h,$(LIBC_INTRIN_A_FILES))
|
||||
LIBC_INTRIN_A_INCS = $(filter %.inc,$(LIBC_INTRIN_A_FILES))
|
||||
LIBC_INTRIN_A_SRCS_S = $(filter %.S,$(LIBC_INTRIN_A_FILES))
|
||||
LIBC_INTRIN_A_SRCS_C = $(filter %.c,$(LIBC_INTRIN_A_FILES))
|
||||
LIBC_INTRIN_A_SRCS = $(LIBC_INTRIN_A_SRCS_S) $(LIBC_INTRIN_A_SRCS_C)
|
||||
|
@ -121,7 +122,6 @@ o/$(MODE)/libc/intrin/describeprotflags.o: private \
|
|||
-fno-sanitize=address
|
||||
|
||||
o/$(MODE)/libc/intrin/exit1.greg.o \
|
||||
o/$(MODE)/libc/intrin/getenv.greg.o \
|
||||
o/$(MODE)/libc/intrin/wsarecv.o \
|
||||
o/$(MODE)/libc/intrin/wsarecvfrom.o \
|
||||
o/$(MODE)/libc/intrin/createfile.o \
|
||||
|
@ -182,6 +182,7 @@ o/$(MODE)/libc/intrin/memmove.o: private \
|
|||
|
||||
LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)))
|
||||
LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS))
|
||||
LIBC_INTRIN_INCS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_INCS))
|
||||
LIBC_INTRIN_SRCS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_SRCS))
|
||||
LIBC_INTRIN_CHECKS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_CHECKS))
|
||||
LIBC_INTRIN_OBJS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_OBJS))
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
#define KMALLOC_ALIGN __BIGGEST_ALIGNMENT__
|
||||
#define KMALLOC_ALIGN sizeof(intptr_t)
|
||||
|
||||
static struct {
|
||||
char *endptr;
|
||||
|
@ -55,21 +55,37 @@ __attribute__((__constructor__)) static void kmalloc_init(void) {
|
|||
* The code malloc() depends upon uses this function to allocate memory.
|
||||
* The returned memory can't be freed, and leak detection is impossible.
|
||||
* This function panics when memory isn't available.
|
||||
*
|
||||
* Memory returned by this function is aligned on the word size, and as
|
||||
* such, kmalloc() shouldn't be used for vector operations.
|
||||
*
|
||||
* @return zero-initialized memory on success, or null w/ errno
|
||||
* @raise ENOMEM if we require more vespene gas
|
||||
*/
|
||||
void *kmalloc(size_t size) {
|
||||
char *start;
|
||||
size_t i, n;
|
||||
char *p, *e;
|
||||
size_t i, n, t;
|
||||
n = ROUNDUP(size + (IsAsan() * 8), KMALLOC_ALIGN);
|
||||
kmalloc_lock();
|
||||
i = g_kmalloc.total;
|
||||
g_kmalloc.total += n;
|
||||
start = (char *)kMemtrackKmallocStart;
|
||||
if (!g_kmalloc.endptr) g_kmalloc.endptr = start;
|
||||
g_kmalloc.endptr =
|
||||
_extend(start, g_kmalloc.total, g_kmalloc.endptr, MAP_PRIVATE,
|
||||
kMemtrackKmallocStart + kMemtrackKmallocSize);
|
||||
t = g_kmalloc.total;
|
||||
e = g_kmalloc.endptr;
|
||||
i = t;
|
||||
t += n;
|
||||
p = (char *)kMemtrackKmallocStart;
|
||||
if (!e) e = p;
|
||||
if ((e = _extend(p, t, e, MAP_PRIVATE,
|
||||
kMemtrackKmallocStart + kMemtrackKmallocSize))) {
|
||||
g_kmalloc.endptr = e;
|
||||
g_kmalloc.total = t;
|
||||
} else {
|
||||
p = 0;
|
||||
}
|
||||
kmalloc_unlock();
|
||||
_unassert(!((intptr_t)(start + i) & (KMALLOC_ALIGN - 1)));
|
||||
if (IsAsan()) __asan_poison(start + i + size, n - size, kAsanHeapOverrun);
|
||||
return start + i;
|
||||
if (p) {
|
||||
_unassert(!((intptr_t)(p + i) & (KMALLOC_ALIGN - 1)));
|
||||
if (IsAsan()) __asan_poison(p + i + size, n - size, kAsanHeapOverrun);
|
||||
return p + i;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void *kmalloc(size_t) attributeallocsize((1)) mallocesque returnsnonnull;
|
||||
void *kmalloc(size_t) mallocesque attributeallocsize((1)) returnsaligned((8));
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
102
libc/intrin/putenv.c
Normal file
102
libc/intrin/putenv.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*-*- 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 2020 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/_getenv.internal.h"
|
||||
#include "libc/intrin/kmalloc.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
|
||||
static char **expected;
|
||||
static size_t capacity;
|
||||
|
||||
static size_t GetEnvironLen(char **env) {
|
||||
char **p = env;
|
||||
while (*p) ++p;
|
||||
return p - env;
|
||||
}
|
||||
|
||||
static char **GrowEnviron(char **a) {
|
||||
size_t n, c;
|
||||
char **b, **p;
|
||||
if (!a) a = environ;
|
||||
n = a ? GetEnvironLen(a) : 0;
|
||||
c = MAX(16ul, n) << 1;
|
||||
if ((b = kmalloc(c * sizeof(char *)))) {
|
||||
if (a) {
|
||||
for (p = b; *a;) {
|
||||
*p++ = *a++;
|
||||
}
|
||||
}
|
||||
environ = b;
|
||||
expected = b;
|
||||
capacity = c;
|
||||
return b;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int PutEnvImpl(char *s, bool overwrite) {
|
||||
char **p;
|
||||
struct Env e;
|
||||
if (!(p = environ)) {
|
||||
if (!(p = GrowEnviron(0))) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
e = _getenv(p, s);
|
||||
if (e.s && !overwrite) {
|
||||
return 0;
|
||||
}
|
||||
if (e.s) {
|
||||
p[e.i] = s;
|
||||
return 0;
|
||||
}
|
||||
if (p != expected) {
|
||||
capacity = e.i;
|
||||
}
|
||||
if (e.i + 1 >= capacity) {
|
||||
if (!(p = GrowEnviron(p))) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
p[e.i + 1] = 0;
|
||||
p[e.i] = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emplaces environment key=value.
|
||||
*
|
||||
* @param s should be a string that looks like `"name=value"` and it'll
|
||||
* become part of the environment; changes to its memory will change
|
||||
* the environment too
|
||||
* @return 0 on success, or non-zero w/ errno on error
|
||||
* @raise ENOMEM if we require more vespene gas
|
||||
* @see setenv(), getenv()
|
||||
*/
|
||||
int putenv(char *s) {
|
||||
int rc;
|
||||
rc = PutEnvImpl(s, true);
|
||||
STRACE("putenv(%#s) → %d% m", s, rc);
|
||||
return rc;
|
||||
}
|
50
libc/intrin/setenv.c
Normal file
50
libc/intrin/setenv.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*-*- 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 2020 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/kmalloc.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/mem/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Copies variable to environment.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno and environment is unchanged
|
||||
* @raise EINVAL if `name` is empty or contains `'='`
|
||||
* @raise ENOMEM if we require more vespene gas
|
||||
* @see putenv(), getenv()
|
||||
*/
|
||||
int setenv(const char *name, const char *value, int overwrite) {
|
||||
int rc;
|
||||
char *s;
|
||||
size_t n, m;
|
||||
const char *t;
|
||||
if (!name || !*name || !value) return einval();
|
||||
for (t = name; *t; ++t) {
|
||||
if (*t == '=') return einval();
|
||||
}
|
||||
n = strlen(name);
|
||||
m = strlen(value);
|
||||
if (!(s = kmalloc(n + 1 + m + 1))) return -1;
|
||||
memcpy(mempcpy(mempcpy(s, name, n), "=", 1), value, m + 1);
|
||||
rc = PutEnvImpl(s, overwrite);
|
||||
STRACE("setenv(%#s, %#s, %d) → %d% m", name, value, overwrite, rc);
|
||||
return rc;
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
@ -28,10 +29,16 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigaddset(sigset_t *set, int sig) {
|
||||
_Static_assert(NSIG == sizeof(set->__bits) * CHAR_BIT, "");
|
||||
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
if (!sigisprecious(sig)) {
|
||||
set->__bits[(sig - 1) >> 6] |= 1ull << ((sig - 1) & 63);
|
||||
if (1 <= sig && sig <= _NSIG) {
|
||||
if (
|
||||
#define M(x) sig != x &&
|
||||
#include "libc/intrin/sigisprecious.inc"
|
||||
1) {
|
||||
set->__bits[(sig - 1) >> 6] |= 1ull << ((sig - 1) & 63);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/intrin/popcnt.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
|
||||
/**
|
||||
* Returns population count of signal set.
|
||||
|
@ -27,9 +28,22 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigcountset(const sigset_t *set) {
|
||||
int r, i;
|
||||
for (r = i = 0; i < ARRAYLEN(set->__bits); ++i) {
|
||||
r += popcnt(set->__bits[i]);
|
||||
int r, i, x, y;
|
||||
switch (_NSIG) {
|
||||
case 32:
|
||||
x = (uint32_t)set->__bits[0];
|
||||
y = 0;
|
||||
break;
|
||||
case 64:
|
||||
x = set->__bits[0];
|
||||
y = 0;
|
||||
break;
|
||||
case 128:
|
||||
x = set->__bits[0];
|
||||
y = set->__bits[1];
|
||||
break;
|
||||
default:
|
||||
notpossible;
|
||||
}
|
||||
return r;
|
||||
return popcnt(x) + popcnt(y);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigdelset(sigset_t *set, int sig) {
|
||||
_Static_assert(NSIG == sizeof(set->__bits) * CHAR_BIT, "");
|
||||
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
set->__bits[(sig - 1) >> 6] &= ~(1ull << ((sig - 1) & 63));
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
/**
|
||||
|
@ -29,7 +30,17 @@
|
|||
*/
|
||||
int sigfillset(sigset_t *set) {
|
||||
memset(set->__bits, -1, sizeof(set->__bits));
|
||||
sigdelset(set, SIGKILL);
|
||||
sigdelset(set, SIGSTOP);
|
||||
#define M(x) set->__bits[(x - 1) >> 6] &= ~(1ull << ((x - 1) & 63));
|
||||
#include "libc/intrin/sigisprecious.inc"
|
||||
switch (_NSIG) {
|
||||
case 32:
|
||||
set->__bits[0] &= 0xffffffff;
|
||||
break;
|
||||
case 64:
|
||||
set->__bits[1] = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
@ -30,7 +31,11 @@
|
|||
int sigismember(const sigset_t *set, int sig) {
|
||||
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
return !!(set->__bits[(sig - 1) >> 6] & (1ull << ((sig - 1) & 63)));
|
||||
if (1 <= sig && sig <= _NSIG) {
|
||||
return !!(set->__bits[(sig - 1) >> 6] & (1ull << ((sig - 1) & 63)));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
* Returns true if you're not authorized to block this signal.
|
||||
*/
|
||||
int sigisprecious(int sig) {
|
||||
return sig == SIGKILL || //
|
||||
sig == SIGSTOP;
|
||||
return 0
|
||||
#define M(x) || sig == x
|
||||
#include "libc/intrin/sigisprecious.inc"
|
||||
;
|
||||
}
|
||||
|
|
3
libc/intrin/sigisprecious.inc
Normal file
3
libc/intrin/sigisprecious.inc
Normal file
|
@ -0,0 +1,3 @@
|
|||
M(SIGKILL)
|
||||
M(SIGABRT)
|
||||
M(SIGSTOP)
|
|
@ -33,6 +33,7 @@
|
|||
* @param buf may be used to store output having at least 15 bytes
|
||||
* @return pointer to .rodata string, or to `buf` after mutating
|
||||
* @see sigaction()
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
char *strsignal_r(int sig, char buf[hasatleast 15]) {
|
||||
|
|
46
libc/intrin/unsetenv.c
Normal file
46
libc/intrin/unsetenv.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*-*- 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 2020 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/dce.h"
|
||||
#include "libc/intrin/_getenv.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Removes environment variable.
|
||||
*
|
||||
* @param s is non-empty environment key which can't contain `'='`
|
||||
* @return 0 on success, or -1 w/ errno and environment is unchanged
|
||||
* @raise EINVAL if `s` is an empty string or has a `'='` character
|
||||
*/
|
||||
int unsetenv(const char *s) {
|
||||
char **p, *t;
|
||||
struct Env e;
|
||||
if (!s || !*s) return einval();
|
||||
for (t = s; *t; ++t) {
|
||||
if (*t == '=') return einval();
|
||||
}
|
||||
if ((p = environ)) {
|
||||
e = _getenv(p, s);
|
||||
while (p[e.i]) {
|
||||
p[e.i] = p[e.i + 1];
|
||||
++e.i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue