mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Make improvements
- Add GetCpuCount() API to redbean - Add unix.gmtime() API to redbean - Add unix.readlink() API to redbean - Add unix.localtime() API to redbean - Perfect the new redbean UNIX module APIs - Integrate with Linux clock_gettime() vDSO - Run Lua garbage collector when malloc() fails - Fix another regression quirk with linenoise repl - Fix GetProgramExecutableName() for systemwide installs - Fix a build flake with test/libc/mem/test.mk SRCS list
This commit is contained in:
parent
860ea18a87
commit
d57b81aac7
51 changed files with 3096 additions and 1395 deletions
|
@ -65,6 +65,7 @@ $(LIBC_CALLS_A).pkg: \
|
|||
$(LIBC_CALLS_A_OBJS) \
|
||||
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/libc/calls/vdsofunc.greg.o \
|
||||
o/$(MODE)/libc/calls/directmap.o \
|
||||
o/$(MODE)/libc/calls/directmap-nt.o \
|
||||
o/$(MODE)/libc/calls/raise.o: \
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime;
|
||||
|
||||
/**
|
||||
* Returns nanosecond time.
|
||||
*
|
||||
|
@ -52,7 +54,7 @@ noinstrument int clock_gettime(int clockid, struct timespec *ts) {
|
|||
rc = einval();
|
||||
} else if (!IsWindows()) {
|
||||
e = errno;
|
||||
if ((rc = sys_clock_gettime(clockid, ts))) {
|
||||
if ((rc = __clock_gettime(clockid, ts))) {
|
||||
errno = e;
|
||||
ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL);
|
||||
assert(ad.ax != -1);
|
||||
|
@ -72,3 +74,23 @@ noinstrument int clock_gettime(int clockid, struct timespec *ts) {
|
|||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns fast system clock_gettime() if it exists.
|
||||
*/
|
||||
void *__get_clock_gettime(void) {
|
||||
void *vdso;
|
||||
static bool once;
|
||||
static void *result;
|
||||
if (!once) {
|
||||
if ((vdso = __vdsofunc("__vdso_clock_gettime"))) {
|
||||
__clock_gettime = result = vdso;
|
||||
}
|
||||
once = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const void *const __clock_gettime_ctor[] initarray = {
|
||||
__get_clock_gettime,
|
||||
};
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
* file is a relative path, then file is opened relative to dirfd
|
||||
* @param path is a filename or directory
|
||||
* @param mode can be R_OK, W_OK, X_OK, F_OK
|
||||
* @param flags should be 0
|
||||
* @param flags can have AT_EACCESS, AT_SYMLINK_NOFOLLOW
|
||||
* @return 0 if ok, or -1 and sets errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
|
|
|
@ -106,7 +106,7 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
|
|||
st->st_size = (uint64_t)wst.nFileSizeHigh << 32 | wst.nFileSizeLow;
|
||||
st->st_blksize = PAGESIZE;
|
||||
st->st_dev = wst.dwVolumeSerialNumber;
|
||||
st->st_rdev = wst.dwVolumeSerialNumber;
|
||||
st->st_rdev = 0;
|
||||
st->st_ino = (uint64_t)wst.nFileIndexHigh << 32 | wst.nFileIndexLow;
|
||||
st->st_nlink = wst.nNumberOfLinks;
|
||||
if (S_ISLNK(st->st_mode)) {
|
||||
|
|
121
libc/calls/getexecutablename.c
Normal file
121
libc/calls/getexecutablename.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
|
||||
#define SIZE 1024
|
||||
#define CTL_KERN 1
|
||||
#define KERN_PROC 14
|
||||
#define KERN_PROC_PATHNAME_FREEBSD 12
|
||||
#define KERN_PROC_PATHNAME_NETBSD 5
|
||||
|
||||
char program_executable_name[PATH_MAX + 1];
|
||||
|
||||
static inline void GetProgramExecutableNameImpl(char *p, char *e) {
|
||||
char *q;
|
||||
ssize_t rc;
|
||||
size_t i, n;
|
||||
union {
|
||||
int cmd[4];
|
||||
char16_t path16[PATH_MAX + 1];
|
||||
} u;
|
||||
|
||||
if (IsWindows()) {
|
||||
n = GetModuleFileName(0, u.path16, ARRAYLEN(u.path16));
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (u.path16[i] == '\\') {
|
||||
u.path16[i] = '/';
|
||||
}
|
||||
}
|
||||
if (isalpha(u.path16[0]) && u.path16[1] == ':' && u.path16[2] == '/') {
|
||||
p[0] = '/';
|
||||
p[1] = '/';
|
||||
p[2] = '?';
|
||||
p[3] = '/';
|
||||
p += 4;
|
||||
}
|
||||
tprecode16to8(p, e - p, u.path16);
|
||||
return;
|
||||
}
|
||||
|
||||
if (__argc && (q = __argv[0]) && !sys_faccessat(AT_FDCWD, q, F_OK, 0)) {
|
||||
if (*q != '/') {
|
||||
if (q[0] == '.' && q[1] == '/') {
|
||||
q += 2;
|
||||
}
|
||||
if (getcwd(p, e - p)) {
|
||||
while (*p) ++p;
|
||||
*p++ = '/';
|
||||
}
|
||||
}
|
||||
for (i = 0; *q && p + 1 < e; ++p, ++q) {
|
||||
*p = *q;
|
||||
}
|
||||
*p = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((rc = sys_readlinkat(AT_FDCWD, "/proc/self/exe", p, e - p - 1)) > 0 ||
|
||||
(rc = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", p, e - p - 1)) > 0) {
|
||||
p[rc] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsFreebsd() || IsNetbsd()) {
|
||||
u.cmd[0] = CTL_KERN;
|
||||
u.cmd[1] = KERN_PROC;
|
||||
if (IsFreebsd()) {
|
||||
u.cmd[2] = KERN_PROC_PATHNAME_FREEBSD;
|
||||
} else {
|
||||
u.cmd[2] = KERN_PROC_PATHNAME_NETBSD;
|
||||
}
|
||||
u.cmd[3] = -1; // current process
|
||||
n = e - p;
|
||||
if (sysctl(u.cmd, ARRAYLEN(u.cmd), p, &n, 0, 0) != -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns absolute path of executable.
|
||||
*/
|
||||
char *GetProgramExecutableName(void) {
|
||||
int e;
|
||||
static bool once;
|
||||
if (!once) {
|
||||
e = errno;
|
||||
GetProgramExecutableNameImpl(
|
||||
program_executable_name,
|
||||
program_executable_name + sizeof(program_executable_name));
|
||||
errno = e;
|
||||
}
|
||||
return program_executable_name;
|
||||
}
|
||||
|
||||
const void *const GetProgramExecutableNameCtor[] initarray = {
|
||||
GetProgramExecutableName,
|
||||
};
|
|
@ -25,6 +25,8 @@
|
|||
#include "libc/time/struct/timezone.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
static typeof(sys_gettimeofday) *__gettimeofday = sys_gettimeofday;
|
||||
|
||||
/**
|
||||
* Returns system wall time in microseconds.
|
||||
*
|
||||
|
@ -40,7 +42,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) {
|
|||
return efault();
|
||||
}
|
||||
if (!IsWindows() && !IsMetal()) {
|
||||
ad = sys_gettimeofday(tv, tz, NULL);
|
||||
ad = __gettimeofday(tv, tz, NULL);
|
||||
assert(ad.ax != -1);
|
||||
if (SupportsXnu() && ad.ax && tv) {
|
||||
tv->tv_sec = ad.ax;
|
||||
|
@ -53,3 +55,14 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) {
|
|||
return sys_gettimeofday_nt(tv, tz);
|
||||
}
|
||||
}
|
||||
|
||||
static textstartup void __gettimeofday_init(void) {
|
||||
void *vdso;
|
||||
if ((vdso = __vdsofunc("__vdso_gettimeofday"))) {
|
||||
__gettimeofday = vdso;
|
||||
}
|
||||
}
|
||||
|
||||
const void *const __gettimeofday_ctor[] initarray = {
|
||||
__gettimeofday_init,
|
||||
};
|
||||
|
|
|
@ -245,6 +245,8 @@ void sys_exit(int) hidden;
|
|||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
void __onfork(void) hidden;
|
||||
void *__vdsofunc(const char *) hidden;
|
||||
void *__get_clock_gettime(void) hidden;
|
||||
i32 __fixupnewfd(i32, i32) hidden;
|
||||
void __restore_rt() hidden;
|
||||
int sys_utimensat_xnu(int, const char *, const struct timespec *, int) hidden;
|
||||
|
|
|
@ -31,9 +31,9 @@
|
|||
#include "libc/time/time.h"
|
||||
|
||||
static struct Now {
|
||||
bool once;
|
||||
uint64_t k0;
|
||||
long double r0, cpn;
|
||||
typeof(sys_clock_gettime) *clock_gettime;
|
||||
} g_now;
|
||||
|
||||
static long double GetTimeSample(void) {
|
||||
|
@ -73,22 +73,39 @@ void RefreshTime(void) {
|
|||
now.cpn = MeasureNanosPerCycle();
|
||||
now.r0 = dtime(CLOCK_REALTIME);
|
||||
now.k0 = rdtsc();
|
||||
now.once = true;
|
||||
memcpy(&g_now, &now, sizeof(now));
|
||||
}
|
||||
|
||||
long double ConvertTicksToNanos(uint64_t ticks) {
|
||||
if (!g_now.once) RefreshTime();
|
||||
return ticks * g_now.cpn; /* pico scale */
|
||||
}
|
||||
|
||||
long double nowl_sys(void) {
|
||||
static long double nowl_sys(void) {
|
||||
return dtime(CLOCK_REALTIME);
|
||||
}
|
||||
|
||||
long double nowl_art(void) {
|
||||
uint64_t ticks;
|
||||
if (!g_now.once) RefreshTime();
|
||||
ticks = unsignedsubtract(rdtsc(), g_now.k0);
|
||||
static long double nowl_art(void) {
|
||||
uint64_t ticks = rdtsc() - g_now.k0;
|
||||
return g_now.r0 + (1 / 1e9L * (ticks * g_now.cpn));
|
||||
}
|
||||
|
||||
static long double nowl_vdso(void) {
|
||||
long double secs;
|
||||
struct timespec tv;
|
||||
g_now.clock_gettime(CLOCK_REALTIME, &tv);
|
||||
secs = tv.tv_nsec;
|
||||
secs *= 1 / 1e9L;
|
||||
secs += tv.tv_sec;
|
||||
return secs;
|
||||
}
|
||||
|
||||
long double nowl_setup(void) {
|
||||
uint64_t ticks;
|
||||
if ((g_now.clock_gettime = __get_clock_gettime())) {
|
||||
nowl = nowl_vdso;
|
||||
} else if (X86_HAVE(INVTSC)) {
|
||||
RefreshTime();
|
||||
nowl = nowl_art;
|
||||
} else {
|
||||
nowl = nowl_sys;
|
||||
}
|
||||
return nowl();
|
||||
}
|
||||
|
||||
long double (*nowl)(void) = nowl_setup;
|
||||
|
|
83
libc/calls/oldbench.c
Normal file
83
libc/calls/oldbench.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*-*- 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/bits/bits.h"
|
||||
#include "libc/bits/initializer.internal.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
static struct Now {
|
||||
bool once;
|
||||
uint64_t k0;
|
||||
long double r0, cpn;
|
||||
} g_now;
|
||||
|
||||
static long double GetTimeSample(void) {
|
||||
uint64_t tick1, tick2;
|
||||
long double time1, time2;
|
||||
sched_yield();
|
||||
time1 = dtime(CLOCK_REALTIME);
|
||||
tick1 = rdtsc();
|
||||
nanosleep(&(struct timespec){0, 1000000}, NULL);
|
||||
time2 = dtime(CLOCK_REALTIME);
|
||||
tick2 = rdtsc();
|
||||
return (time2 - time1) * 1e9 / MAX(1, tick2 - tick1);
|
||||
}
|
||||
|
||||
static long double MeasureNanosPerCycle(void) {
|
||||
bool tc;
|
||||
int i, n;
|
||||
long double avg, samp;
|
||||
tc = __time_critical;
|
||||
__time_critical = true;
|
||||
if (IsWindows()) {
|
||||
n = 30;
|
||||
} else {
|
||||
n = 20;
|
||||
}
|
||||
for (avg = 1.0L, i = 1; i < n; ++i) {
|
||||
samp = GetTimeSample();
|
||||
avg += (samp - avg) / i;
|
||||
}
|
||||
__time_critical = tc;
|
||||
STRACE("MeasureNanosPerCycle cpn*1000=%d", (long)(avg * 1000));
|
||||
return avg;
|
||||
}
|
||||
|
||||
static void Refresh(void) {
|
||||
struct Now now;
|
||||
now.cpn = MeasureNanosPerCycle();
|
||||
now.r0 = dtime(CLOCK_REALTIME);
|
||||
now.k0 = rdtsc();
|
||||
now.once = true;
|
||||
memcpy(&g_now, &now, sizeof(now));
|
||||
}
|
||||
|
||||
long double ConvertTicksToNanos(uint64_t ticks) {
|
||||
if (!g_now.once) Refresh();
|
||||
return ticks * g_now.cpn; /* pico scale */
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/ipc.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
@ -42,9 +43,9 @@ textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) {
|
|||
} else {
|
||||
mode = kNtPipeTypeMessage | kNtPipeReadmodeMessage;
|
||||
}
|
||||
if ((hin = CreateNamedPipe(pipename,
|
||||
kNtPipeAccessInbound | kNtFileFlagOverlapped, mode,
|
||||
1, 512, 512, 0, &kNtIsInheritable)) != -1) {
|
||||
if ((hin = CreateNamedPipe(
|
||||
pipename, kNtPipeAccessInbound | kNtFileFlagOverlapped, mode, 1,
|
||||
PIPE_BUF, PIPE_BUF, 0, &kNtIsInheritable)) != -1) {
|
||||
if ((hout = CreateFile(pipename, kNtGenericWrite, 0, &kNtIsInheritable,
|
||||
kNtOpenExisting, kNtFileFlagOverlapped, 0)) != -1) {
|
||||
g_fds.p[reader].kind = kFdFile;
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/path.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
#include "libc/str/utf16.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
#define SIZE 1024
|
||||
#define CTL_KERN 1
|
||||
#define KERN_PROC 14
|
||||
#define KERN_PROC_PATHNAME_FREEBSD 12
|
||||
#define KERN_PROC_PATHNAME_NETBSD 5
|
||||
|
||||
char program_executable_name[SIZE];
|
||||
|
||||
static textwindows bool GetNtExePath(char exe[SIZE]) {
|
||||
bool32 rc;
|
||||
uint64_t w;
|
||||
wint_t x, y;
|
||||
uint32_t i, j;
|
||||
char16_t p[PATH_MAX + 1];
|
||||
p[0] = 0;
|
||||
rc = GetModuleFileName(0, p, ARRAYLEN(p));
|
||||
NTTRACE("GetModuleFileName(0, [%#hs]) → %hhhd", p, rc);
|
||||
if (!rc) return false;
|
||||
j = 0;
|
||||
if (p[0] != '\\' || p[1] != '\\' || p[2] != '?' || p[3] != '\\') {
|
||||
exe[j++] = '/';
|
||||
exe[j++] = '/';
|
||||
exe[j++] = '?';
|
||||
exe[j++] = '/';
|
||||
}
|
||||
for (i = 0; (x = p[i++] & 0xffff);) {
|
||||
if (!IsUcs2(x)) {
|
||||
y = p[i++] & 0xffff;
|
||||
x = MergeUtf16(x, y);
|
||||
}
|
||||
if (x == '\\') x = '/';
|
||||
w = tpenc(x);
|
||||
do {
|
||||
exe[j] = w;
|
||||
if (++j == SIZE) {
|
||||
return false;
|
||||
}
|
||||
} while ((w >>= 8));
|
||||
}
|
||||
exe[j] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ReadProgramExecutableName(char exe[SIZE], char *argv0,
|
||||
uintptr_t *auxv) {
|
||||
int e;
|
||||
size_t m;
|
||||
ssize_t n;
|
||||
int cmd[4];
|
||||
char *p, *t;
|
||||
e = errno;
|
||||
if (!IsWindows() || !GetNtExePath(exe)) {
|
||||
for (p = 0; *auxv; auxv += 2) {
|
||||
if (*auxv == AT_EXECFN) {
|
||||
p = (char *)auxv[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
n = 0;
|
||||
if (!p) p = argv0;
|
||||
if (p) {
|
||||
if (!_isabspath(p)) {
|
||||
if (getcwd(exe, SIZE - 1)) {
|
||||
n = strlen(exe);
|
||||
exe[n++] = '/';
|
||||
}
|
||||
}
|
||||
for (; *p; ++p) {
|
||||
if (n + 1 < SIZE) {
|
||||
exe[n++] = *p;
|
||||
}
|
||||
}
|
||||
}
|
||||
exe[n] = 0;
|
||||
}
|
||||
errno = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns absolute path of executable.
|
||||
*
|
||||
* This variable is initialized automatically at startup. The path is
|
||||
* basically `argv[0]` except some extra vetting is done to provide
|
||||
* stronger assurance that the path can be counted upon to exist.
|
||||
*
|
||||
* For example, if your program is executed as a relative path and then
|
||||
* your program calls `chdir()`, then `argv[0]` will be incorrect; but
|
||||
* `program_executable_name` will work, because it prefixed `getcwd()`
|
||||
* early in the initialization phase.
|
||||
*
|
||||
* @see GetInterpreterExecutableName()
|
||||
* @see program_invocation_short_name
|
||||
* @see program_invocation_name
|
||||
*/
|
||||
char *GetProgramExecutableName(void) {
|
||||
static bool once;
|
||||
if (!once) {
|
||||
ReadProgramExecutableName(program_executable_name, __argv[0], __auxv);
|
||||
once = true;
|
||||
}
|
||||
return program_executable_name;
|
||||
}
|
||||
|
||||
// try our best to memoize it before a chdir() happens
|
||||
const void *const program_executable_name_init_ctor[] initarray = {
|
||||
GetProgramExecutableName,
|
||||
};
|
|
@ -22,13 +22,14 @@
|
|||
/**
|
||||
* Adds signal to set.
|
||||
*
|
||||
* @return true, false, or -1 w/ errno
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raises EINVAL if `1 ≤ sig ≤ NSIG` isn't the case
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigaddset(sigset_t *set, int sig) {
|
||||
unsigned i = sig - 1;
|
||||
if (i < sizeof(set->__bits) * 8) {
|
||||
set->__bits[i >> 6] |= 1ull << (i & 63);
|
||||
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
set->__bits[(sig - 1) >> 6] |= 1ull << ((sig - 1) & 63);
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
|
|
|
@ -23,12 +23,13 @@
|
|||
* Removes signal from set.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raises EINVAL if `1 ≤ sig ≤ NSIG` isn't the case
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigdelset(sigset_t *set, int sig) {
|
||||
unsigned i = sig - 1;
|
||||
if (i < sizeof(set->__bits) * 8) {
|
||||
set->__bits[i >> 6] &= ~(1ull << (i & 63));
|
||||
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
set->__bits[(sig - 1) >> 6] &= ~(1ull << ((sig - 1) & 63));
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
|
|
|
@ -22,14 +22,15 @@
|
|||
/**
|
||||
* Returns true if signal is member of set.
|
||||
*
|
||||
* @return true, false, or -1 w/ errno
|
||||
* @return 1 if set, 0 if not set, or -1 w/ errno
|
||||
* @raises EINVAL if `1 ≤ sig ≤ NSIG` isn't the case
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int sigismember(const sigset_t *set, int sig) {
|
||||
unsigned i = sig - 1;
|
||||
if (i < sizeof(set->__bits) * 8) {
|
||||
return (set->__bits[i >> 6] >> (i & 63)) & 1;
|
||||
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
return !!(set->__bits[(sig - 1) >> 6] & (1ull << ((sig - 1) & 63)));
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ struct stat { /* cosmo abi */
|
|||
uint32_t st_mode; /* 24: octal file mask thing */
|
||||
uint32_t st_uid; /* 28: user id of owner */
|
||||
uint32_t st_gid; /* group id of owning group */
|
||||
uint32_t st_flags; /* flags (bsd-only) */
|
||||
uint32_t st_flags; /* nt/xnu/bsd-only */
|
||||
uint64_t st_rdev; /* id of device if a special file */
|
||||
int64_t st_size; /* bytes in file */
|
||||
int64_t st_blksize; /* preferred chunking for underlying filesystem */
|
||||
|
@ -19,7 +19,7 @@ struct stat { /* cosmo abi */
|
|||
struct timespec st_mtim; /* modified time */
|
||||
struct timespec st_ctim; /* complicated time */
|
||||
struct timespec st_birthtim;
|
||||
uint64_t st_gen;
|
||||
uint64_t st_gen; /* xnu/bsd only */
|
||||
};
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
94
libc/calls/vdsofunc.greg.c
Normal file
94
libc/calls/vdsofunc.greg.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*-*- 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/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/elf/scalar.h"
|
||||
#include "libc/elf/struct/ehdr.h"
|
||||
#include "libc/elf/struct/shdr.h"
|
||||
#include "libc/elf/struct/sym.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
|
||||
#define LAZY_RHEL7_RELOCATION 0xfffff
|
||||
|
||||
#define GetStr(tab, rva) ((char *)(tab) + (rva))
|
||||
#define GetSection(e, s) ((void *)((intptr_t)(e) + (size_t)(s)->sh_offset))
|
||||
#define GetShstrtab(e) GetSection(e, GetShdr(e, (e)->e_shstrndx))
|
||||
#define GetSectionName(e, s) GetStr(GetShstrtab(e), (s)->sh_name)
|
||||
#define GetPhdr(e, i) \
|
||||
((Elf64_Phdr *)((intptr_t)(e) + (e)->e_phoff + \
|
||||
(size_t)(e)->e_phentsize * (i)))
|
||||
#define GetShdr(e, i) \
|
||||
((Elf64_Shdr *)((intptr_t)(e) + (e)->e_shoff + \
|
||||
(size_t)(e)->e_shentsize * (i)))
|
||||
|
||||
static char *GetDynamicStringTable(Elf64_Ehdr *e, size_t *n) {
|
||||
char *name;
|
||||
Elf64_Half i;
|
||||
Elf64_Shdr *shdr;
|
||||
for (i = 0; i < e->e_shnum; ++i) {
|
||||
shdr = GetShdr(e, i);
|
||||
name = GetSectionName(e, GetShdr(e, i));
|
||||
if (shdr->sh_type == SHT_STRTAB) {
|
||||
name = GetSectionName(e, GetShdr(e, i));
|
||||
if (name && READ64LE(name) == READ64LE(".dynstr")) {
|
||||
if (n) *n = shdr->sh_size;
|
||||
return GetSection(e, shdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Elf64_Sym *GetDynamicSymbolTable(Elf64_Ehdr *e, Elf64_Xword *n) {
|
||||
Elf64_Half i;
|
||||
Elf64_Shdr *shdr;
|
||||
for (i = e->e_shnum; i > 0; --i) {
|
||||
shdr = GetShdr(e, i - 1);
|
||||
if (shdr->sh_type == SHT_DYNSYM) {
|
||||
if (shdr->sh_entsize != sizeof(Elf64_Sym)) continue;
|
||||
if (n) *n = shdr->sh_size / shdr->sh_entsize;
|
||||
return GetSection(e, shdr);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Linux Kernel Virtual Dynamic Shared Object function address.
|
||||
*/
|
||||
void *__vdsofunc(const char *name) {
|
||||
size_t m;
|
||||
char *names;
|
||||
Elf64_Ehdr *ehdr;
|
||||
Elf64_Xword i, n;
|
||||
Elf64_Sym *symtab, *sym;
|
||||
if ((ehdr = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR)) &&
|
||||
(names = GetDynamicStringTable(ehdr, &m)) &&
|
||||
(symtab = GetDynamicSymbolTable(ehdr, &n))) {
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (!__strcmp(names + symtab[i].st_name, name)) {
|
||||
return (char *)ehdr + (symtab[i].st_value & LAZY_RHEL7_RELOCATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -26,6 +26,8 @@ void GetElfVirtualAddressRange(const Elf64_Ehdr *, size_t, intptr_t *,
|
|||
intptr_t *);
|
||||
char *GetElfString(const Elf64_Ehdr *, size_t, const char *, Elf64_Word);
|
||||
const char *GetElfSectionName(const Elf64_Ehdr *, size_t, Elf64_Shdr *);
|
||||
Elf64_Sym *GetElfDynSymbolTable(const Elf64_Ehdr *, size_t, Elf64_Xword *);
|
||||
char *GetElfDynStringTable(const Elf64_Ehdr *, size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
40
libc/elf/getelfdynstringtable.c
Normal file
40
libc/elf/getelfdynstringtable.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*-*- 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/elf/def.h"
|
||||
#include "libc/elf/elf.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
char *GetElfDynStringTable(const Elf64_Ehdr *elf, size_t mapsize) {
|
||||
char *name;
|
||||
Elf64_Half i;
|
||||
Elf64_Shdr *shdr;
|
||||
if (elf->e_shentsize) {
|
||||
for (i = 0; i < elf->e_shnum; ++i) {
|
||||
shdr = GetElfSectionHeaderAddress(elf, mapsize, i);
|
||||
if (shdr->sh_type == SHT_STRTAB) {
|
||||
name = GetElfSectionName(elf, mapsize,
|
||||
GetElfSectionHeaderAddress(elf, mapsize, i));
|
||||
if (name && !strcmp(name, ".dynstr")) {
|
||||
return GetElfSectionAddress(elf, mapsize, shdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
37
libc/elf/getelfdynsymboltable.c
Normal file
37
libc/elf/getelfdynsymboltable.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*-*- 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/elf/def.h"
|
||||
#include "libc/elf/elf.h"
|
||||
|
||||
Elf64_Sym *GetElfDynSymbolTable(const Elf64_Ehdr *elf, size_t mapsize,
|
||||
Elf64_Xword *out_count) {
|
||||
Elf64_Half i;
|
||||
Elf64_Shdr *shdr;
|
||||
if (elf->e_shentsize) {
|
||||
for (i = elf->e_shnum; i > 0; --i) {
|
||||
shdr = GetElfSectionHeaderAddress(elf, mapsize, i - 1);
|
||||
if (shdr->sh_type == SHT_DYNSYM) {
|
||||
if (shdr->sh_entsize != sizeof(Elf64_Sym)) continue;
|
||||
if (out_count) *out_count = shdr->sh_size / shdr->sh_entsize;
|
||||
return GetElfSectionAddress(elf, mapsize, shdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ShouldUseMsabiAttribute() 1
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
|
@ -44,18 +43,18 @@ int strerror_wr(int err, uint32_t winerr, char *buf, size_t size) {
|
|||
for (; (c = *sym++); --size)
|
||||
if (size > 1) *buf++ = c;
|
||||
if (size) *buf = 0;
|
||||
} else if (!IsWindows()) {
|
||||
ksnprintf(buf, size, "%s[%d][%s]", sym, err, msg);
|
||||
} else if (!IsWindows() || err == winerr || !winerr) {
|
||||
ksnprintf(buf, size, "%s:%d:%s", sym, err, msg);
|
||||
} else {
|
||||
if ((n = __imp_FormatMessageW(
|
||||
if ((n = FormatMessage(
|
||||
kNtFormatMessageFromSystem | kNtFormatMessageIgnoreInserts, 0,
|
||||
winerr, MAKELANGID(kNtLangNeutral, kNtSublangDefault), winmsg,
|
||||
ARRAYLEN(winmsg), 0))) {
|
||||
while ((n && winmsg[n - 1] <= ' ') || winmsg[n - 1] == '.') --n;
|
||||
ksnprintf(buf, size, "%s[%d][%s][%.*hs][%d]", sym, err, msg, n, winmsg,
|
||||
winerr);
|
||||
ksnprintf(buf, size, "%s:%d:%s:%d:%.*hs", sym, err, msg, winerr, n,
|
||||
winmsg);
|
||||
} else {
|
||||
ksnprintf(buf, size, "%s[%d][%s][%d]", sym, err, msg, winerr);
|
||||
ksnprintf(buf, size, "%s:%d:%s:%d", sym, err, msg, winerr);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
#define CACHELINE 0x40 /* nexgen32e */
|
||||
#define CHAR_BIT 8 /* b/c von neumann */
|
||||
#define ARG_MAX 0x8000 /* b/c windows */
|
||||
#define PATH_MAX 512 /* b/c bloat */
|
||||
#define PATH_MAX 511 /* b/c bloat */
|
||||
#define NAME_MAX 63 /* b/c dns */
|
||||
#define CHILD_MAX 25 /* only if malloc isn't linked */
|
||||
#define OPEN_MAX 16 /* only if malloc isn't linked */
|
||||
|
|
|
@ -62,17 +62,17 @@ char *GetInterpreterExecutableName(char *p, size_t n) {
|
|||
} else if ((rc = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", p, n - 1)) >
|
||||
0) {
|
||||
errno = e;
|
||||
p[n] = 0;
|
||||
p[rc] = 0;
|
||||
return p;
|
||||
} else if (IsFreebsd() || IsNetbsd()) {
|
||||
cmd[0] = 1 /* CTL_KERN */;
|
||||
cmd[1] = 14 /* KERN_PROC */;
|
||||
if (IsFreebsd()) {
|
||||
cmd[2] = 12 /* KERN_PROC_PATHNAME */;
|
||||
} else {
|
||||
cmd[2] = 5 /* KERN_PROC_PATHNAME */;
|
||||
}
|
||||
cmd[3] = -1; /* current process */
|
||||
cmd[0] = 1; // CTL_KERN
|
||||
cmd[1] = 14; // KERN_PROC
|
||||
if (IsFreebsd()) { //
|
||||
cmd[2] = 12; // KERN_PROC_PATHNAME
|
||||
} else { //
|
||||
cmd[2] = 5; // KERN_PROC_PATHNAME
|
||||
} //
|
||||
cmd[3] = -1; // current process
|
||||
if (sysctl(cmd, ARRAYLEN(cmd), p, &n, 0, 0) != -1) {
|
||||
errno = e;
|
||||
return p;
|
||||
|
|
|
@ -324,8 +324,8 @@ textstartup void __printargs(const char *prologue) {
|
|||
PRINT(" ☼ %s = %#s", "kTmpPath", kTmpPath);
|
||||
PRINT(" ☼ %s = %#s", "kNtSystemDirectory", kNtSystemDirectory);
|
||||
PRINT(" ☼ %s = %#s", "kNtWindowsDirectory", kNtWindowsDirectory);
|
||||
PRINT(" ☼ %s = %#s", "program_executable_name", GetProgramExecutableName());
|
||||
PRINT(" ☼ %s = %#s", "GetInterpreterExecutableName()",
|
||||
PRINT(" ☼ %s = %#s", "GetProgramExecutableName", GetProgramExecutableName());
|
||||
PRINT(" ☼ %s = %#s", "GetInterpreterExecutableName",
|
||||
GetInterpreterExecutableName(path, sizeof(path)));
|
||||
PRINT(" ☼ %s = %p", "RSP", __builtin_frame_address(0));
|
||||
PRINT(" ☼ %s = %p", "GetStackAddr()", GetStackAddr(0));
|
||||
|
|
|
@ -14,7 +14,6 @@ extern char **__argv; /* CRT */
|
|||
extern char **__envp; /* CRT */
|
||||
extern unsigned long *__auxv; /* CRT */
|
||||
extern intptr_t __oldstack; /* CRT */
|
||||
extern char program_executable_name[]; /* RII */
|
||||
extern char *program_invocation_name; /* RII */
|
||||
extern char *program_invocation_short_name; /* RII */
|
||||
extern int g_ftrace; /* CRT */
|
||||
|
|
|
@ -219,9 +219,6 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
|||
}
|
||||
}
|
||||
env16 = GetEnvironmentStrings();
|
||||
for (char16_t *e = env16; *e; e += StrLen16(e) + 1) {
|
||||
NTTRACE("GetEnvironmentStrings() → %!#hs", e);
|
||||
}
|
||||
NTTRACE("WinMainNew() loading environment");
|
||||
GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp,
|
||||
ARRAYLEN(wa->envp) - 1);
|
||||
|
|
|
@ -436,10 +436,10 @@ syscon ioctl TIOCINQ 0x541b 0x4004667f 0x4004667f 0x4004667f 0x4004667f
|
|||
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||
syscon at AT_FDCWD -100 -2 -100 -100 -100 -100 # faked nt
|
||||
syscon at AT_SYMLINK_NOFOLLOW 0x0100 0x20 0x0200 2 0x200 0x0100 # faked nt
|
||||
syscon at AT_SYMLINK_FOLLOW 0x0400 0x40 0x0400 4 0x400 0 # see linkat(2)
|
||||
syscon at AT_REMOVEDIR 0x0200 0x80 0x0800 8 0x800 0x0200 # faked nt
|
||||
syscon at AT_EACCESS 0x0200 0x10 0x0100 1 0x100 0
|
||||
syscon at AT_EMPTY_PATH 0x1000 0 0 0 0 0 # linux 2.6.39+; see unlink, O_TMPFILE, etc.
|
||||
syscon at AT_SYMLINK_FOLLOW 0x0400 0x40 0x0400 4 0x400 0 # uhhh wut
|
||||
|
||||
# memfd_create() flags
|
||||
#
|
||||
|
@ -1229,6 +1229,11 @@ syscon mount MNT_NOCLUSTERR 0 0 0x40000000 0 0 0 # disable cluster
|
|||
syscon mount MNT_NOCLUSTERW 0 0 0x80000000 0 0 0 # disable cluster write
|
||||
syscon mount MNT_SNAPSHOT 0 0x40000000 0x01000000 0 0 0 # confusing
|
||||
|
||||
# limits
|
||||
#
|
||||
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||
syscon misc PIPE_BUF 4096 512 512 512 512 4096 # bsd consensus
|
||||
|
||||
# unmount() flags
|
||||
# a.k.a. umount2() on linux
|
||||
#
|
||||
|
@ -3055,7 +3060,6 @@ syscon misc NGREG 23 0 0 0 0 0
|
|||
syscon misc NOGROUP -1 0xffff 0xffff 0xffff 0xffff 0 # bsd consensus
|
||||
syscon misc ORDERED_QUEUE_TAG 34 0 0 0 0 0
|
||||
syscon misc ORIG_RAX 15 0 0 0 0 0
|
||||
syscon misc PIPE_BUF 0x1000 0x0200 0x0200 0x0200 0x0200 0 # bsd consensus
|
||||
syscon misc PRE_FETCH 52 0 0 0 0 0
|
||||
syscon misc QUEUE_FULL 20 0 0 0 0 0
|
||||
syscon misc REASSIGN_BLOCKS 7 0 0 0 0 0
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon misc,PIPE_BUF,0x1000,0x0200,0x0200,0x0200,0x0200,0
|
||||
.syscon misc,PIPE_BUF,4096,512,512,512,512,4096
|
||||
|
|
|
@ -72,5 +72,5 @@ TEST(access, testRequestWriteOnReadOnly_returnsEaccess) {
|
|||
}
|
||||
|
||||
TEST(access, runThisExecutable) {
|
||||
ASSERT_SYS(0, 0, access(program_executable_name, R_OK | X_OK));
|
||||
ASSERT_SYS(0, 0, access(GetProgramExecutableName(), R_OK | X_OK));
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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│
|
||||
/*-*- 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 │
|
||||
│ 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 │
|
||||
|
@ -16,22 +16,14 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
// Returns timestamp without needing system calls.
|
||||
//
|
||||
// @return seconds since unix epoch in %st0
|
||||
// @note uses microsecond scale fallback on k8 or vm
|
||||
.initbss 202,_init_nowl
|
||||
nowl: .quad 0
|
||||
.endobj nowl,globl
|
||||
.previous
|
||||
|
||||
.init.start 202,_init_nowl
|
||||
ezlea nowl_sys,ax
|
||||
ezlea nowl_art,cx
|
||||
testb X86_HAVE(INVTSC)+kCpuids(%rip)
|
||||
cmovnz %rcx,%rax
|
||||
stosq
|
||||
.init.end 202,_init_nowl
|
||||
BENCH(clock_gettime, bench) {
|
||||
struct timespec ts;
|
||||
EZBENCH2("nowl", donothing, nowl());
|
||||
EZBENCH2("clock_gettime", donothing, clock_gettime(CLOCK_REALTIME, &ts));
|
||||
}
|
|
@ -51,8 +51,8 @@ TEST(dup, clearsCloexecFlag) {
|
|||
ASSERT_NE(-1, (ws = xspawn(0)));
|
||||
if (ws == -2) {
|
||||
dup2(3, 0);
|
||||
execv(program_executable_name,
|
||||
(char *const[]){program_executable_name, "boop", 0});
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "boop", 0});
|
||||
_exit(127);
|
||||
}
|
||||
ASSERT_EQ(72, WEXITSTATUS(ws));
|
||||
|
|
|
@ -177,8 +177,8 @@ TEST(ShowCrashReports, testMemoryLeakCrash) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(program_executable_name,
|
||||
(char *const[]){program_executable_name, "6", 0});
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "6", 0});
|
||||
_exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
|
@ -255,8 +255,8 @@ TEST(ShowCrashReports, testStackOverrunCrash) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(program_executable_name,
|
||||
(char *const[]){program_executable_name, "5", 0});
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "5", 0});
|
||||
_exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
|
@ -364,8 +364,8 @@ TEST(ShowCrashReports, testDivideByZero) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(program_executable_name,
|
||||
(char *const[]){program_executable_name, "1", 0});
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "1", 0});
|
||||
_exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
|
@ -486,8 +486,8 @@ TEST(ShowCrashReports, testBssOverrunCrash) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(program_executable_name,
|
||||
(char *const[]){program_executable_name, "2", 0});
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "2", 0});
|
||||
_exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
|
@ -565,8 +565,8 @@ TEST(ShowCrashReports, testNpeCrash) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(program_executable_name,
|
||||
(char *const[]){program_executable_name, "7", 0});
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "7", 0});
|
||||
_exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
|
@ -625,8 +625,8 @@ TEST(ShowCrashReports, testDataOverrunCrash) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(program_executable_name,
|
||||
(char *const[]){program_executable_name, "4", 0});
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "4", 0});
|
||||
_exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
|
@ -680,8 +680,8 @@ TEST(ShowCrashReports, testNpeCrashAfterFinalize) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(program_executable_name,
|
||||
(char *const[]){program_executable_name, "8", 0});
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "8", 0});
|
||||
_exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
PKGS += TEST_LIBC_MEM
|
||||
|
||||
TEST_LIBC_MEM_FILES := $(wildcard test/libc/mem/*)
|
||||
TEST_LIBC_MEM_SRCS = $(TEST_LIBC_MEM_SRCS_C) $(TEST_LIBC_MEM_SRCS_CC)
|
||||
TEST_LIBC_MEM_SRCS_C = $(filter %_test.c,$(TEST_LIBC_MEM_FILES))
|
||||
TEST_LIBC_MEM_SRCS_CC = $(filter %_test.cc,$(TEST_LIBC_MEM_FILES))
|
||||
|
||||
|
@ -12,7 +13,7 @@ TEST_LIBC_MEM_OBJS = \
|
|||
$(TEST_LIBC_MEM_SRCS_CC:%.cc=o/$(MODE)/%.o)
|
||||
|
||||
TEST_LIBC_MEM_COMS = \
|
||||
$(TEST_LIBC_MEM_SRCS_C:%.c=o/$(MODE)/%.com) \
|
||||
$(TEST_LIBC_MEM_SRCS_C:%.c=o/$(MODE)/%.com) \
|
||||
$(TEST_LIBC_MEM_SRCS_CC:%.cc=o/$(MODE)/%.com)
|
||||
|
||||
TEST_LIBC_MEM_BINS = \
|
||||
|
@ -20,7 +21,7 @@ TEST_LIBC_MEM_BINS = \
|
|||
$(TEST_LIBC_MEM_COMS:%=%.dbg)
|
||||
|
||||
TEST_LIBC_MEM_TESTS = \
|
||||
$(TEST_LIBC_MEM_SRCS_C:%.c=o/$(MODE)/%.com.ok) \
|
||||
$(TEST_LIBC_MEM_SRCS_C:%.c=o/$(MODE)/%.com.ok) \
|
||||
$(TEST_LIBC_MEM_SRCS_CC:%.cc=o/$(MODE)/%.com.ok)
|
||||
|
||||
TEST_LIBC_MEM_CHECKS = \
|
||||
|
|
1
third_party/linenoise/linenoise.c
vendored
1
third_party/linenoise/linenoise.c
vendored
|
@ -1810,6 +1810,7 @@ struct linenoiseState *linenoiseBegin(const char *prompt, int ifd, int ofd) {
|
|||
}
|
||||
|
||||
void linenoiseReset(struct linenoiseState *l) {
|
||||
l->buf[0] = 0;
|
||||
l->dirty = true;
|
||||
l->final = 0;
|
||||
l->hindex = 0;
|
||||
|
|
1
third_party/lua/llimits.h
vendored
1
third_party/lua/llimits.h
vendored
|
@ -1,6 +1,7 @@
|
|||
#ifndef llimits_h
|
||||
#define llimits_h
|
||||
|
||||
#include "libc/limits.h"
|
||||
#include "libc/math.h"
|
||||
#include "third_party/lua/lua.h"
|
||||
|
||||
|
|
2
third_party/mbedtls/test/lib.c
vendored
2
third_party/mbedtls/test/lib.c
vendored
|
@ -1011,7 +1011,7 @@ int execute_tests(int argc, const char **argv, const char *default_filename) {
|
|||
file = fopen(test_filename, "r");
|
||||
if (file == NULL) {
|
||||
WRITE("%s (%s) failed to open test file: %s %m\n",
|
||||
program_invocation_short_name, program_executable_name,
|
||||
program_invocation_short_name, GetProgramExecutableName(),
|
||||
test_filename);
|
||||
if (outcome_file != NULL) fclose(outcome_file);
|
||||
return 1;
|
||||
|
|
2
third_party/python/Modules/getpath.c
vendored
2
third_party/python/Modules/getpath.c
vendored
|
@ -663,7 +663,7 @@ Py_GetProgramFullPath(void)
|
|||
{
|
||||
static bool once;
|
||||
if (_cmpxchg(&once, false, true)) {
|
||||
progpath = utf8toutf32(program_executable_name, -1, 0);
|
||||
progpath = utf8toutf32(GetProgramExecutableName(), -1, 0);
|
||||
__cxa_atexit(free, progpath, 0);
|
||||
}
|
||||
return progpath;
|
||||
|
|
32
tool/decode/dumpvdso.c
Normal file
32
tool/decode/dumpvdso.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*-*- 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/elf/struct/ehdr.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
|
||||
noasan int main(int argc, char *argv[]) {
|
||||
int i = 0;
|
||||
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR);
|
||||
if (isatty(1)) exit(1);
|
||||
for (;;) {
|
||||
write(1, ((char *)ehdr) + i++, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -27,8 +27,10 @@
|
|||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
@ -231,6 +233,21 @@ static void printelfsymboltable(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void printelfdynsymboltable(void) {
|
||||
size_t i, symcount = 0;
|
||||
Elf64_Sym *symtab = GetElfDynSymbolTable(elf, st->st_size, &symcount);
|
||||
char *strtab = GetElfDynStringTable(elf, st->st_size);
|
||||
char *shstrtab = GetElfSectionNameStringTable(elf, st->st_size);
|
||||
if (symtab && strtab) {
|
||||
printf("\n\n");
|
||||
printf("\t.org\t%#x\n", (intptr_t)symtab - (intptr_t)elf);
|
||||
for (i = 0; i < symcount; ++i) {
|
||||
printf(".Lsym%d:\n", i);
|
||||
printelfsymbol(&symtab[i], strtab, shstrtab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *getelfsymbolname(const Elf64_Ehdr *elf, size_t mapsize,
|
||||
const char *strtab, const char *shstrtab,
|
||||
const Elf64_Sym *sym) {
|
||||
|
@ -324,12 +341,14 @@ int main(int argc, char *argv[]) {
|
|||
fprintf(stderr, "error: not an elf executable: %'s\n", path);
|
||||
exit(1);
|
||||
}
|
||||
elf = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR);
|
||||
startfile();
|
||||
printelfehdr();
|
||||
printelfsegmentheaders();
|
||||
printelfsectionheaders();
|
||||
printelfrelocations();
|
||||
printelfsymboltable();
|
||||
printelfdynsymboltable();
|
||||
munmap(elf, st->st_size);
|
||||
close(fd);
|
||||
return 0;
|
||||
|
|
2
tool/net/demo/script.lua
Executable file
2
tool/net/demo/script.lua
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/redbean -i
|
||||
print('hello world')
|
93
tool/net/demo/unix-dir.lua
Normal file
93
tool/net/demo/unix-dir.lua
Normal file
|
@ -0,0 +1,93 @@
|
|||
Write('<!doctype html>\r\n')
|
||||
Write('<title>redbean</title>\r\n')
|
||||
Write('<style>\r\n')
|
||||
Write('td,th { padding: 2px 5px; }\r\n')
|
||||
Write('td { white-space: nowrap; }\r\n')
|
||||
Write('.l { text-align: left; }\r\n')
|
||||
Write('.r { text-align: right; }\r\n')
|
||||
Write('</style>\r\n')
|
||||
|
||||
Write('<h3>UNIX Directory Stream Demo</h3>\r\n')
|
||||
Write('<table>\r\n')
|
||||
Write('<thead>\r\n')
|
||||
Write('<tr>\r\n')
|
||||
Write('<th class=l>name\r\n')
|
||||
Write('<th>type\r\n')
|
||||
Write('<th class=r>ino\r\n')
|
||||
Write('<th class=r>off\r\n')
|
||||
Write('<th class=r>size\r\n')
|
||||
Write('<th class=r>blocks\r\n')
|
||||
Write('<th class=r>mode\r\n')
|
||||
Write('<th class=r>uid\r\n')
|
||||
Write('<th class=r>gid\r\n')
|
||||
Write('<th class=r>dev\r\n')
|
||||
Write('<th class=r>rdev\r\n')
|
||||
Write('<th class=r>nlink\r\n')
|
||||
Write('<th class=r>blksize\r\n')
|
||||
Write('<th class=r>gen\r\n')
|
||||
Write('<th class=r>flags\r\n')
|
||||
Write('<th class=r>birthtim\r\n')
|
||||
Write('<th class=r>mtim\r\n')
|
||||
Write('<th class=r>atim\r\n')
|
||||
Write('<th class=r>ctim\r\n')
|
||||
Write('<tbody>\r\n')
|
||||
|
||||
dir = '.'
|
||||
for name, kind, ino, off in assert(unix.opendir(dir)) do
|
||||
Write('<tr>\r\n')
|
||||
|
||||
Write('<td>')
|
||||
Write(EscapeHtml(name))
|
||||
if kind == unix.DT_DIR then
|
||||
Write('/')
|
||||
end
|
||||
Write('\r\n')
|
||||
|
||||
Write('<td>')
|
||||
if kind == unix.DT_REG then Write('DT_REG')
|
||||
elseif kind == unix.DT_DIR then Write('DT_DIR')
|
||||
elseif kind == unix.DT_FIFO then Write('DT_FIFO')
|
||||
elseif kind == unix.DT_CHR then Write('DT_CHR')
|
||||
elseif kind == unix.DT_BLK then Write('DT_BLK')
|
||||
elseif kind == unix.DT_LNK then Write('DT_LNK')
|
||||
elseif kind == unix.DT_SOCK then Write('DT_SOCK')
|
||||
else Write('DT_UNKNOWN')
|
||||
end
|
||||
Write('\r\n')
|
||||
|
||||
Write('<td class=r>%d\r\n' % {ino})
|
||||
Write('<td class=r>%d\r\n' % {off})
|
||||
|
||||
st,err = unix.stat(dir..'/'..name, unix.AT_SYMLINK_NOFOLLOW)
|
||||
if st then
|
||||
|
||||
Write('<td class=r>%d\r\n' % {st:size()})
|
||||
Write('<td class=r>%d\r\n' % {st:blocks()})
|
||||
Write('<td class=r>%.7o\r\n' % {st:mode()})
|
||||
Write('<td class=r>%d\r\n' % {st:uid()})
|
||||
Write('<td class=r>%d\r\n' % {st:gid()})
|
||||
Write('<td class=r>%d\r\n' % {st:dev()})
|
||||
Write('<td class=r>%d,%d\r\n' % {unix.major(st:rdev()), unix.minor(st:rdev())})
|
||||
Write('<td class=r>%d\r\n' % {st:nlink()})
|
||||
Write('<td class=r>%d\r\n' % {st:blksize()})
|
||||
Write('<td class=r>%d\r\n' % {st:gen()})
|
||||
Write('<td class=r>%#x\r\n' % {st:flags()})
|
||||
|
||||
function WriteTime(unixsec,nanos)
|
||||
year,mon,mday,hour,min,sec,gmtoffsec = unix.localtime(unixsec)
|
||||
Write('<td class=r>%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.9d%+.2d%.2d\r\n' % {
|
||||
year, mon, mday, hour, min, sec, nanos,
|
||||
gmtoffsec / (60 * 60), math.abs(gmtoffsec) % 60})
|
||||
end
|
||||
|
||||
WriteTime(st:birthtim())
|
||||
WriteTime(st:mtim())
|
||||
WriteTime(st:atim())
|
||||
WriteTime(st:ctim())
|
||||
|
||||
else
|
||||
Write('<td class=l colspan=15>%s\r\n' % {err})
|
||||
end
|
||||
|
||||
end
|
||||
Write('</table>\r\n')
|
|
@ -26,7 +26,7 @@ sid, errno = unix.getsid(0)
|
|||
if sid then
|
||||
Write('<dd>%d\r\n' % {sid})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {tostring(errno)})
|
||||
end
|
||||
|
||||
Write('<dt>unix.gethostname()\r\n')
|
||||
|
@ -54,7 +54,7 @@ function PrintResourceLimit(name, id)
|
|||
end
|
||||
Write('\r\n')
|
||||
else
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
end
|
||||
end
|
||||
PrintResourceLimit('RLIMIT_AS', unix.RLIMIT_AS)
|
||||
|
@ -77,13 +77,13 @@ if ifs then
|
|||
Write('%s %s/%d<br>\r\n' % {EscapeHtml(ifs[i].name), FormatIp(ifs[i].ip), cidr})
|
||||
end
|
||||
else
|
||||
Write('%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
end
|
||||
|
||||
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DEBUG)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DEBUG)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
@ -91,7 +91,7 @@ end
|
|||
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_ACCEPTCONN)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_ACCEPTCONN)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
@ -99,7 +99,7 @@ end
|
|||
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEADDR)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEADDR)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
@ -107,7 +107,7 @@ end
|
|||
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEPORT)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEPORT)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
@ -115,7 +115,7 @@ end
|
|||
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_KEEPALIVE)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_KEEPALIVE)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
@ -123,7 +123,7 @@ end
|
|||
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NODELAY)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NODELAY)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
@ -131,7 +131,7 @@ end
|
|||
secs, errno, micros = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVTIMEO)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVTIMEO)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d sec %d µs\r\n' % {secs, micros})
|
||||
end
|
||||
|
@ -139,7 +139,7 @@ end
|
|||
secs, errno, micros = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDTIMEO)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDTIMEO)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d sec %d µs\r\n' % {secs, micros})
|
||||
end
|
||||
|
@ -147,7 +147,7 @@ end
|
|||
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DONTROUTE)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DONTROUTE)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
@ -155,7 +155,7 @@ end
|
|||
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDBUF)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDBUF)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d\r\n' % {bytes})
|
||||
end
|
||||
|
@ -163,7 +163,7 @@ end
|
|||
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVBUF)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVBUF)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d\r\n' % {bytes})
|
||||
end
|
||||
|
@ -171,7 +171,7 @@ end
|
|||
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d\r\n' % {bytes})
|
||||
end
|
||||
|
@ -179,7 +179,7 @@ end
|
|||
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_BROADCAST)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_BROADCAST)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
@ -187,7 +187,7 @@ end
|
|||
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_CORK)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_CORK)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
@ -195,7 +195,7 @@ end
|
|||
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_QUICKACK)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_QUICKACK)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
@ -203,7 +203,7 @@ end
|
|||
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_DEFER_ACCEPT)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_DEFER_ACCEPT)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
@ -211,7 +211,7 @@ end
|
|||
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN_CONNECT)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN_CONNECT)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
@ -219,7 +219,7 @@ end
|
|||
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDLOWAT)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDLOWAT)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d\r\n' % {bytes})
|
||||
end
|
||||
|
@ -227,7 +227,7 @@ end
|
|||
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVLOWAT)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVLOWAT)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d\r\n' % {bytes})
|
||||
end
|
||||
|
@ -235,7 +235,7 @@ end
|
|||
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPCNT)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPCNT)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d\r\n' % {bytes})
|
||||
end
|
||||
|
@ -243,7 +243,7 @@ end
|
|||
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_MAXSEG)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_MAXSEG)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d\r\n' % {bytes})
|
||||
end
|
||||
|
@ -251,7 +251,7 @@ end
|
|||
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_SYNCNT)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_SYNCNT)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d\r\n' % {bytes})
|
||||
end
|
||||
|
@ -259,7 +259,7 @@ end
|
|||
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NOTSENT_LOWAT)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NOTSENT_LOWAT)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d\r\n' % {bytes})
|
||||
end
|
||||
|
@ -267,7 +267,7 @@ end
|
|||
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_WINDOW_CLAMP)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_WINDOW_CLAMP)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d\r\n' % {bytes})
|
||||
end
|
||||
|
@ -275,7 +275,7 @@ end
|
|||
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPIDLE)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPIDLE)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d\r\n' % {bytes})
|
||||
end
|
||||
|
@ -283,7 +283,7 @@ end
|
|||
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPINTVL)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPINTVL)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
|
||||
else
|
||||
Write('<dd>%d\r\n' % {bytes})
|
||||
end
|
||||
|
|
11
tool/net/demo/unix-raise.lua
Executable file
11
tool/net/demo/unix-raise.lua
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/home/jart/bin/redbean -i
|
||||
assert(unix.sigaction(unix.SIGUSR1, function(sig)
|
||||
gotsigusr1 = true
|
||||
end))
|
||||
gotsigusr1 = false
|
||||
assert(unix.raise(unix.SIGUSR1))
|
||||
if gotsigusr1 then
|
||||
print('hooray the signal was delivered')
|
||||
else
|
||||
print('oh no some other signal was handled')
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
local unix = require "unix"
|
||||
local unix = require 'unix'
|
||||
|
||||
local function main()
|
||||
if GetMethod() ~= 'GET' and GetMethod() ~= 'HEAD' then
|
||||
|
@ -45,7 +45,7 @@ local function main()
|
|||
Write(EncodeBase64(LoadAsset('/redbean.png')))
|
||||
Write('">\r\n')
|
||||
Write('redbean unix demo\r\n')
|
||||
Write('<span style="color:red"> %s</span>\r\n' % {unix.strerrno(errno)})
|
||||
Write('<span style="color:red"> %s</span>\r\n' % {EscapeHtml(tostring(errno))})
|
||||
Write('</h1>\r\n')
|
||||
Write([[
|
||||
<p>
|
||||
|
@ -63,7 +63,6 @@ local function main()
|
|||
unix.close(fd)
|
||||
return
|
||||
end
|
||||
|
||||
-- if pid is zero then we're the child
|
||||
-- turn into a daemon
|
||||
unix.umask(0)
|
||||
|
@ -106,34 +105,6 @@ local function main()
|
|||
unix.write(fd, 'became an autonomous daemon reparented on your init!\r\n')
|
||||
unix.write(fd, '</p>\r\n')
|
||||
|
||||
unix.write(fd, '<h2>listing of current directory</h2>\r\n')
|
||||
dir, err = unix.opendir('.')
|
||||
if dir then
|
||||
unix.write(fd, '<ul>\r\n')
|
||||
while true do
|
||||
name, errno, kind, ino, off = dir:read()
|
||||
if not name then
|
||||
break
|
||||
end
|
||||
unix.write(fd, '<li>')
|
||||
unix.write(fd, EscapeHtml(VisualizeControlCodes(name)))
|
||||
if kind == unix.DT_DIR then
|
||||
unix.write(fd, '/')
|
||||
else
|
||||
st, err = unix.stat(name)
|
||||
if st then
|
||||
unix.write(fd, ' (%d bytes)' % {st:size()})
|
||||
end
|
||||
end
|
||||
unix.write(fd, '\r\n')
|
||||
end
|
||||
unix.write(fd, '</ul>\r\n')
|
||||
else
|
||||
unix.write(fd, '<p>\r\n')
|
||||
unix.write(fd, 'failed: %s\r\n' % {EscapeHtml(VisualizeControlCodes(unix:strerror(err)))})
|
||||
unix.write(fd, '</p>\r\n')
|
||||
end
|
||||
|
||||
-- terminate
|
||||
unix.close(fd)
|
||||
unix.exit(0)
|
||||
|
|
|
@ -9,55 +9,48 @@ function main()
|
|||
end
|
||||
syscall = 'commandv'
|
||||
ls = assert(unix.commandv(cmd))
|
||||
if ls then
|
||||
syscall = 'pipe'
|
||||
reader, writer, errno = unix.pipe()
|
||||
if reader then
|
||||
-- oldint = assert(unix.sigaction(unix.SIGINT, unix.SIG_IGN))
|
||||
-- oldquit = assert(unix.sigaction(unix.SIGQUIT, unix.SIG_IGN))
|
||||
-- oldmask = assert(unix.sigprocmask(unix.SIG_BLOCK, (1 << (unix.SIGCHLD - 1))))
|
||||
syscall = 'fork'
|
||||
child, errno = unix.fork()
|
||||
if child then
|
||||
if child == 0 then
|
||||
unix.close(1)
|
||||
unix.dup(writer)
|
||||
unix.close(writer)
|
||||
unix.close(reader)
|
||||
-- unix.sigaction(unix.SIGINT, oldint)
|
||||
-- unix.sigaction(unix.SIGQUIT, oldquit)
|
||||
-- unix.sigprocmask(unix.SIG_SETMASK, oldmask)
|
||||
unix.execve(ls, {ls, '-Shal'})
|
||||
unix.exit(127)
|
||||
syscall = 'pipe'
|
||||
reader, writer = assert(unix.pipe(unix.O_CLOEXEC))
|
||||
oldint = assert(unix.sigaction(unix.SIGINT, unix.SIG_IGN))
|
||||
oldquit = assert(unix.sigaction(unix.SIGQUIT, unix.SIG_IGN))
|
||||
oldmask = assert(unix.sigprocmask(unix.SIG_BLOCK, unix.Sigset(unix.SIGCHLD)))
|
||||
syscall = 'fork'
|
||||
child = assert(unix.fork())
|
||||
if child == 0 then
|
||||
unix.close(0)
|
||||
unix.open("/dev/null", unix.O_RDONLY)
|
||||
unix.close(1)
|
||||
unix.dup(writer)
|
||||
unix.close(2)
|
||||
unix.open("/dev/null", unix.O_RDONLY)
|
||||
unix.sigaction(unix.SIGINT, oldint)
|
||||
unix.sigaction(unix.SIGQUIT, oldquit)
|
||||
unix.sigprocmask(unix.SIG_SETMASK, oldmask)
|
||||
unix.execve(ls, {ls, '-Shal'})
|
||||
unix.exit(127)
|
||||
else
|
||||
unix.close(writer)
|
||||
SetStatus(200)
|
||||
SetHeader('Content-Type', 'text/plain')
|
||||
while true do
|
||||
data, err = unix.read(reader)
|
||||
if data then
|
||||
if data ~= '' then
|
||||
Write(data)
|
||||
else
|
||||
unix.close(writer)
|
||||
SetStatus(200)
|
||||
SetHeader('Content-Type', 'text/plain')
|
||||
while true do
|
||||
data, errno = unix.read(reader)
|
||||
if data then
|
||||
if data ~= '' then
|
||||
Write(data)
|
||||
else
|
||||
break
|
||||
end
|
||||
elseif errno ~= unix.EINTR then
|
||||
Log(kLogWarn, 'read() failed: %s' % {unix.strerror(errno)})
|
||||
break
|
||||
end
|
||||
end
|
||||
unix.close(reader)
|
||||
unix.wait(-1)
|
||||
-- unix.sigaction(unix.SIGINT, oldint)
|
||||
-- unix.sigaction(unix.SIGQUIT, oldquit)
|
||||
-- unix.sigprocmask(unix.SIG_SETMASK, oldmask)
|
||||
return
|
||||
break
|
||||
end
|
||||
elseif err:errno() ~= unix.EINTR then
|
||||
Log(kLogWarn, 'read() failed: %s' % {tostring(err)})
|
||||
break
|
||||
end
|
||||
end
|
||||
unix.close(reader)
|
||||
unix.wait(-1)
|
||||
unix.sigaction(unix.SIGINT, oldint)
|
||||
unix.sigaction(unix.SIGQUIT, oldquit)
|
||||
unix.sigprocmask(unix.SIG_SETMASK, oldmask)
|
||||
return
|
||||
end
|
||||
SetStatus(200)
|
||||
SetHeader('Content-Type', 'text/plain')
|
||||
Write('error %s calling %s()' % {unix.strerrno(errno), syscall})
|
||||
end
|
||||
main()
|
||||
|
|
|
@ -45,7 +45,7 @@ function main()
|
|||
server = unix.socket()
|
||||
unix.bind(server, ifs[i].ip)
|
||||
unix.listen(server)
|
||||
ip, errno, port = unix.getsockname(server)
|
||||
ip, port = assert(unix.getsockname(server))
|
||||
addr = '%s:%d' % {FormatIp(ip), port}
|
||||
url = 'http://%s' % {addr}
|
||||
Log(kLogInfo, 'listening on %s' % {addr})
|
||||
|
@ -65,7 +65,7 @@ function main()
|
|||
if fd == mainfd then
|
||||
data, errno = unix.read(mainfd)
|
||||
if not data then
|
||||
Log(kLogInfo, 'got %s from parent client' % {unix.strerrno(errno)})
|
||||
Log(kLogInfo, 'got %s from parent client' % {tostring(errno)})
|
||||
-- prevent redbean core from writing a response
|
||||
unix.exit(1)
|
||||
end
|
||||
|
@ -79,8 +79,7 @@ function main()
|
|||
unix.write(mainfd, data)
|
||||
elseif servers[fd] then
|
||||
unix.write(mainfd, 'preparing to accept from %d<br>\r\n' % {fd})
|
||||
client, errno, clientip, clientport = unix.accept(fd)
|
||||
unix.write(mainfd, 'preparing to accept from %d<br>\r\n' % {fd})
|
||||
client, clientip, clientport = assert(unix.accept(fd))
|
||||
addr = '%s:%d' % {FormatIp(clientip), clientport}
|
||||
addrs[client] = addr
|
||||
unix.write(mainfd, 'got client %s<br>\r\n' % {addr})
|
||||
|
|
1828
tool/net/help.txt
1828
tool/net/help.txt
File diff suppressed because it is too large
Load diff
|
@ -33,6 +33,7 @@
|
|||
#include "libc/nexgen32e/rdtscp.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/rusage.h"
|
||||
|
@ -82,6 +83,11 @@ int LuaGetCpuCore(lua_State *L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int LuaGetCpuCount(lua_State *L) {
|
||||
lua_pushinteger(L, GetCpuCount());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaGetLogLevel(lua_State *L) {
|
||||
lua_pushinteger(L, __log_level);
|
||||
return 1;
|
||||
|
|
|
@ -35,6 +35,7 @@ int LuaEscapeUser(lua_State *);
|
|||
int LuaFormatHttpDateTime(lua_State *);
|
||||
int LuaFormatIp(lua_State *);
|
||||
int LuaGetCpuCore(lua_State *);
|
||||
int LuaGetCpuCount(lua_State *);
|
||||
int LuaGetCpuNode(lua_State *);
|
||||
int LuaGetCryptoHash(lua_State *);
|
||||
int LuaGetHostOs(lua_State *);
|
||||
|
|
1498
tool/net/lunix.c
1498
tool/net/lunix.c
File diff suppressed because it is too large
Load diff
|
@ -175,6 +175,7 @@ o/$(MODE)/tool/net/demo/sql.lua.zip.o \
|
|||
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-dir.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/hello.lua.zip.o \
|
||||
|
@ -221,6 +222,7 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \
|
|||
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-dir.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/hello.lua.zip.o \
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
@ -196,6 +197,8 @@ STATIC_YOINK("zip_uri_support");
|
|||
// puncts not used: !"#$%&'()*+,-./;<=>@[\]^_`{|}~
|
||||
#define GETOPTS "BSVZabdfghijkmsuvzA:C:D:F:G:H:K:L:M:P:R:T:U:c:e:l:p:r:t:"
|
||||
|
||||
extern unsigned long long __kbirth;
|
||||
|
||||
static const uint8_t kGzipHeader[] = {
|
||||
0x1F, // MAGNUM
|
||||
0x8B, // MAGNUM
|
||||
|
@ -4956,6 +4959,7 @@ static const luaL_Reg kLuaFuncs[] = {
|
|||
{"GetComment", LuaGetAssetComment}, //
|
||||
{"GetCookie", LuaGetCookie}, //
|
||||
{"GetCpuCore", LuaGetCpuCore}, //
|
||||
{"GetCpuCount", LuaGetCpuCount}, //
|
||||
{"GetCpuNode", LuaGetCpuNode}, //
|
||||
{"GetCryptoHash", LuaGetCryptoHash}, //
|
||||
{"GetDate", LuaGetDate}, //
|
||||
|
@ -5192,6 +5196,7 @@ static void LuaPrint(lua_State *L) {
|
|||
static void LuaInterpreter(lua_State *L) {
|
||||
int i, n, sig, status;
|
||||
const char *script;
|
||||
if (funtrace) ftrace_install();
|
||||
if (optind < __argc) {
|
||||
script = __argv[optind];
|
||||
if (!strcmp(script, "-")) script = 0;
|
||||
|
@ -5201,7 +5206,11 @@ static void LuaInterpreter(lua_State *L) {
|
|||
luaL_checkstack(L, n + 3, "too many script args");
|
||||
for (i = 1; i <= n; i++) lua_rawgeti(L, -i, i);
|
||||
lua_remove(L, -i); // remove arg table from stack
|
||||
if (funtrace) ++g_ftrace;
|
||||
if (systrace) ++__strace;
|
||||
status = lua_runchunk(L, n, LUA_MULTRET);
|
||||
if (systrace) --__strace;
|
||||
if (funtrace) --g_ftrace;
|
||||
}
|
||||
lua_report(L, status);
|
||||
} else {
|
||||
|
@ -5225,7 +5234,9 @@ static void LuaInterpreter(lua_State *L) {
|
|||
exit(1);
|
||||
}
|
||||
if (status == LUA_OK) {
|
||||
if (funtrace) ++g_ftrace;
|
||||
status = lua_runchunk(GL, 0, LUA_MULTRET);
|
||||
if (funtrace) --g_ftrace;
|
||||
}
|
||||
if (status == LUA_OK) {
|
||||
LuaPrint(GL);
|
||||
|
@ -6358,7 +6369,6 @@ static int HandleConnection(size_t i) {
|
|||
connectionclose = false;
|
||||
if (!IsTiny()) {
|
||||
if (systrace) {
|
||||
extern unsigned long long __kbirth;
|
||||
__strace = 1;
|
||||
__kbirth = rdtsc();
|
||||
}
|
||||
|
@ -6474,18 +6484,20 @@ static void RestoreApe(void) {
|
|||
if (endswith(zpath, ".com.dbg")) return;
|
||||
if ((a = GetAssetZip("/.ape", 5)) && (p = LoadAsset(a, &n))) {
|
||||
close(zfd);
|
||||
if ((zfd = OpenExecutable()) == -1 || WRITE(zfd, p, n) == -1)
|
||||
if ((zfd = OpenExecutable()) == -1 || WRITE(zfd, p, n) == -1) {
|
||||
WARNF("(srvr) can't restore .ape");
|
||||
}
|
||||
free(p);
|
||||
} else {
|
||||
INFOF("(srvr) /.ape not found");
|
||||
DEBUGF("(srvr) /.ape not found");
|
||||
}
|
||||
}
|
||||
|
||||
static int HandleReadline(void) {
|
||||
int status;
|
||||
lua_State *L = GL;
|
||||
for (;;) {
|
||||
status = lua_loadline(GL);
|
||||
status = lua_loadline(L);
|
||||
if (status < 0) {
|
||||
if (status == -1) {
|
||||
OnTerm(SIGHUP); // eof
|
||||
|
@ -6508,12 +6520,12 @@ static int HandleReadline(void) {
|
|||
linenoiseDisableRawMode();
|
||||
LUA_REPL_LOCK;
|
||||
if (status == LUA_OK) {
|
||||
status = lua_runchunk(GL, 0, LUA_MULTRET);
|
||||
status = lua_runchunk(L, 0, LUA_MULTRET);
|
||||
}
|
||||
if (status == LUA_OK) {
|
||||
LuaPrint(GL);
|
||||
LuaPrint(L);
|
||||
} else {
|
||||
lua_report(GL, status);
|
||||
lua_report(L, status);
|
||||
}
|
||||
LUA_REPL_UNLOCK;
|
||||
if (lua_repl_isterminal) {
|
||||
|
@ -6683,26 +6695,28 @@ static int EventLoop(int ms) {
|
|||
}
|
||||
|
||||
static void ReplEventLoop(void) {
|
||||
lua_State *L = GL;
|
||||
DEBUGF("ReplEventLoop()");
|
||||
polls[0].fd = 0;
|
||||
lua_repl_completions_callback = HandleCompletions;
|
||||
lua_initrepl(GL, "redbean");
|
||||
lua_initrepl(L, "redbean");
|
||||
if (lua_repl_isterminal) {
|
||||
linenoiseEnableRawMode(0);
|
||||
}
|
||||
EventLoop(100);
|
||||
linenoiseDisableRawMode();
|
||||
lua_freerepl();
|
||||
lua_settop(GL, 0); // clear stack
|
||||
lua_settop(L, 0); // clear stack
|
||||
polls[0].fd = -1;
|
||||
}
|
||||
|
||||
static uint32_t WindowsReplThread(void *arg) {
|
||||
int sig;
|
||||
lua_State *L = GL;
|
||||
DEBUGF("WindowsReplThread()");
|
||||
lua_repl_blocking = true;
|
||||
lua_repl_completions_callback = HandleCompletions;
|
||||
lua_initrepl(GL, "redbean");
|
||||
lua_initrepl(L, "redbean");
|
||||
if (lua_repl_isterminal) {
|
||||
linenoiseEnableRawMode(0);
|
||||
}
|
||||
|
@ -6714,7 +6728,7 @@ static uint32_t WindowsReplThread(void *arg) {
|
|||
linenoiseDisableRawMode();
|
||||
lua_freerepl();
|
||||
LUA_REPL_LOCK;
|
||||
lua_settop(GL, 0); // clear stack
|
||||
lua_settop(L, 0); // clear stack
|
||||
LUA_REPL_UNLOCK;
|
||||
if ((sig = linenoiseGetInterrupt())) {
|
||||
raise(sig);
|
||||
|
@ -6896,7 +6910,7 @@ void RedBean(int argc, char *argv[]) {
|
|||
(shared = mmap(NULL, ROUNDUP(sizeof(struct Shared), FRAMESIZE),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
|
||||
-1, 0)));
|
||||
zpath = program_executable_name;
|
||||
zpath = GetProgramExecutableName();
|
||||
CHECK_NE(-1, (zfd = open(zpath, O_RDONLY)));
|
||||
CHECK_NE(-1, fstat(zfd, &zst));
|
||||
OpenZip(true);
|
||||
|
|
Loading…
Reference in a new issue