mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-26 07:49:05 +00:00
Work towards improving signals and processes
This commit is contained in:
parent
de703b182c
commit
d7ac16a9ed
96 changed files with 1474 additions and 427 deletions
|
@ -3,8 +3,8 @@
|
||||||
Fast portable static native textmode executable containers.
|
Fast portable static native textmode executable containers.
|
||||||
|
|
||||||
For an introduction to this project, please read the <a
|
For an introduction to this project, please read the <a
|
||||||
href="https://justine.storage.googleapis.com/ape.html">αcτµαlly pδrταblε
|
href="https://justine.lol/ape.html">αcτµαlly pδrταblε εxεcµταblε</a>
|
||||||
εxεcµταblε</a> blog post and <a
|
blog post and <a
|
||||||
href="https://justine.lol/cosmopolitan/index.html">cosmopolitan libc</a>
|
href="https://justine.lol/cosmopolitan/index.html">cosmopolitan libc</a>
|
||||||
website. API documentation is available <a
|
website. API documentation is available <a
|
||||||
href="https://justine.lol/cosmopolitan/documentation.html">here</a>.
|
href="https://justine.lol/cosmopolitan/documentation.html">here</a>.
|
||||||
|
|
|
@ -425,6 +425,7 @@ SECTIONS {
|
||||||
*(.xlm)
|
*(.xlm)
|
||||||
. = ALIGN(0x1000);
|
. = ALIGN(0x1000);
|
||||||
|
|
||||||
|
. = ALIGN(0x10000); /* for brk()/sbrk() allocation */
|
||||||
HIDDEN(_end = .);
|
HIDDEN(_end = .);
|
||||||
PROVIDE_HIDDEN(end = .);
|
PROVIDE_HIDDEN(end = .);
|
||||||
} AT>SmallCode :Ram
|
} AT>SmallCode :Ram
|
||||||
|
|
Binary file not shown.
|
@ -185,6 +185,9 @@ DEFAULT_LDFLAGS = \
|
||||||
-z max-page-size=0x1000 \
|
-z max-page-size=0x1000 \
|
||||||
-Ttext-segment=$(IMAGE_BASE_VIRTUAL)
|
-Ttext-segment=$(IMAGE_BASE_VIRTUAL)
|
||||||
|
|
||||||
|
ZIPOBJ_FLAGS = \
|
||||||
|
-b$(IMAGE_BASE_VIRTUAL)
|
||||||
|
|
||||||
ASONLYFLAGS = \
|
ASONLYFLAGS = \
|
||||||
-g \
|
-g \
|
||||||
--debug-prefix-map="$(PWD)"=
|
--debug-prefix-map="$(PWD)"=
|
||||||
|
|
|
@ -34,7 +34,7 @@ o/%.pkg:; @build/package $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(f
|
||||||
o/%.h.ok: %.h; @ACTION=CHECK.h build/compile $(COMPILE.c) -x c -g0 -o $@ $<
|
o/%.h.ok: %.h; @ACTION=CHECK.h build/compile $(COMPILE.c) -x c -g0 -o $@ $<
|
||||||
o/%.h.okk: %.h; @ACTION=CHECK.h build/compile $(COMPILE.cxx) -x c++ -g0 -o $@ $<
|
o/%.h.okk: %.h; @ACTION=CHECK.h build/compile $(COMPILE.cxx) -x c++ -g0 -o $@ $<
|
||||||
o/%.greg.o: %.greg.c; @ACTION=OBJECTIFY.greg build/compile $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
|
o/%.greg.o: %.greg.c; @ACTION=OBJECTIFY.greg build/compile $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
|
||||||
o/%.zip.o: o/%; @build/zipobj $(OUTPUT_OPTION) $<
|
o/%.zip.o: o/%; @build/zipobj $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
o/$(MODE)/%.a:; @$(ARCHIVE) $@ $^
|
o/$(MODE)/%.a:; @$(ARCHIVE) $@ $^
|
||||||
o/$(MODE)/%: o/$(MODE)/%.dbg; @ACTION=OBJCOPY TARGET=$@ build/do $(OBJCOPY) -SO binary $< $@
|
o/$(MODE)/%: o/$(MODE)/%.dbg; @ACTION=OBJCOPY TARGET=$@ build/do $(OBJCOPY) -SO binary $< $@
|
||||||
|
@ -75,7 +75,7 @@ o/$(MODE)/%.ncabi.o: %.ncabi.c; @ACTION=OBJECTIFY.nc build/compile $(OBJECTIFY.n
|
||||||
o/$(MODE)/%.real.o: %.c; @ACTION=OBJECTIFY.real build/compile $(OBJECTIFY.real.c) $(OUTPUT_OPTION) $<
|
o/$(MODE)/%.real.o: %.c; @ACTION=OBJECTIFY.real build/compile $(OBJECTIFY.real.c) $(OUTPUT_OPTION) $<
|
||||||
o/$(MODE)/%.runs: o/$(MODE)/%; @ACTION=CHECK.runs TARGET=$< build/runcom $< $(TESTARGS) && touch $@
|
o/$(MODE)/%.runs: o/$(MODE)/%; @ACTION=CHECK.runs TARGET=$< build/runcom $< $(TESTARGS) && touch $@
|
||||||
o/$(MODE)/%.pkg:; @build/package $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^)
|
o/$(MODE)/%.pkg:; @build/package $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^)
|
||||||
o/$(MODE)/%.zip.o: %; @build/zipobj $(OUTPUT_OPTION) $<
|
o/$(MODE)/%.zip.o: %; @build/zipobj $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
o/$(MODE)/%-gcc.asm: %.c; @ACTION=OBJECTIFY.c build/compile $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
o/$(MODE)/%-gcc.asm: %.c; @ACTION=OBJECTIFY.c build/compile $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
||||||
o/$(MODE)/%-clang.asm: CC = $(CLANG)
|
o/$(MODE)/%-clang.asm: CC = $(CLANG)
|
||||||
|
|
|
@ -8,10 +8,12 @@
|
||||||
╚─────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
#endif
|
#endif
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/log/color.internal.h"
|
#include "libc/log/color.internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/nt/thread.h"
|
||||||
#include "libc/runtime/gc.h"
|
#include "libc/runtime/gc.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
@ -20,48 +22,41 @@
|
||||||
#include "libc/sysv/consts/fileno.h"
|
#include "libc/sysv/consts/fileno.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
|
||||||
#define kTutorialMessage "This echos stdio until Ctrl+C is pressed.\n"
|
volatile bool gotctrlc;
|
||||||
#define kVictoryMessage "\rGot Ctrl+C and longjmp() ran dtors (>'.')>\n"
|
|
||||||
|
|
||||||
jmp_buf jb;
|
|
||||||
|
|
||||||
void GotCtrlC(int sig) {
|
void GotCtrlC(int sig) {
|
||||||
gclongjmp(jb, 1);
|
gotctrlc = true;
|
||||||
unreachable;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HowManyBytesOfHeapMemoryAreAllocated(void) {
|
|
||||||
return mallinfo().uordblks;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReadAndPrintLinesLoop(void) {
|
|
||||||
ssize_t got;
|
|
||||||
unsigned char *buf;
|
|
||||||
buf = gc(malloc(BUFSIZ));
|
|
||||||
CHECK_NE(0, HowManyBytesOfHeapMemoryAreAllocated());
|
|
||||||
for (;;) {
|
|
||||||
CHECK_NE(-1, (got = read(STDIN_FILENO, buf, BUFSIZ)));
|
|
||||||
CHECK_EQ(got, write(STDOUT_FILENO, buf, got));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int rc;
|
ssize_t rc;
|
||||||
rc = 0;
|
size_t got, wrote;
|
||||||
showcrashreports();
|
unsigned char buf[512];
|
||||||
if (cancolor()) {
|
fprintf(stderr, "This echos stdio until Ctrl+C is pressed.\n");
|
||||||
CHECK_EQ(0 /* cosmo runtime doesn't link malloc */,
|
CHECK_NE(
|
||||||
HowManyBytesOfHeapMemoryAreAllocated());
|
-1, sigaction(SIGINT, &(struct sigaction){.sa_handler = GotCtrlC}, NULL));
|
||||||
puts("This echos stdio until Ctrl+C is pressed.");
|
for (;;) {
|
||||||
if (!(rc = setjmp(jb))) {
|
rc = read(0, buf, BUFSIZ);
|
||||||
CHECK_NE(SIG_ERR, signal(SIGINT, GotCtrlC));
|
if (rc != -1) {
|
||||||
ReadAndPrintLinesLoop();
|
got = rc;
|
||||||
unreachable;
|
|
||||||
} else {
|
} else {
|
||||||
--rc;
|
CHECK_EQ(EINTR, errno);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
CHECK_EQ(0, HowManyBytesOfHeapMemoryAreAllocated());
|
if (!got) break;
|
||||||
puts("\rGot Ctrl+C and longjmp() ran dtors (>'.')>");
|
rc = write(1, buf, got);
|
||||||
|
if (rc != -1) {
|
||||||
|
wrote = rc;
|
||||||
|
} else {
|
||||||
|
CHECK_EQ(EINTR, errno);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return rc;
|
CHECK_EQ(got, wrote);
|
||||||
|
}
|
||||||
|
if (gotctrlc) {
|
||||||
|
fprintf(stderr, "Got Ctrl+C\n");
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Got EOF\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ EXAMPLES_DIRECTDEPS = \
|
||||||
LIBC_LOG_ASAN \
|
LIBC_LOG_ASAN \
|
||||||
LIBC_MEM \
|
LIBC_MEM \
|
||||||
LIBC_NEXGEN32E \
|
LIBC_NEXGEN32E \
|
||||||
|
LIBC_NT_KERNEL32 \
|
||||||
LIBC_NT_NTDLL \
|
LIBC_NT_NTDLL \
|
||||||
LIBC_NT_USER32 \
|
LIBC_NT_USER32 \
|
||||||
LIBC_NT_WS2_32 \
|
LIBC_NT_WS2_32 \
|
||||||
|
|
61
examples/sleep.c
Normal file
61
examples/sleep.c
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#if 0
|
||||||
|
/*─────────────────────────────────────────────────────────────────╗
|
||||||
|
│ To the extent possible under law, Justine Tunney has waived │
|
||||||
|
│ all copyright and related or neighboring rights to this file, │
|
||||||
|
│ as it is written in the following disclaimers: │
|
||||||
|
│ • http://unlicense.org/ │
|
||||||
|
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||||
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
|
#endif
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/time/time.h"
|
||||||
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16kb sleep executable that runs on all operating systems.
|
||||||
|
* https://justine.lol/cosmopolitan/demos/sleep.c
|
||||||
|
* https://justine.lol/cosmopolitan/demos/sleep.com
|
||||||
|
* https://justine.lol/cosmopolitan/index.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define WRITE(s) write(2, s, strlen(s))
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
char *p;
|
||||||
|
long double x, y;
|
||||||
|
if (argc != 2) {
|
||||||
|
WRITE("Usage: ");
|
||||||
|
WRITE(argv[0]);
|
||||||
|
WRITE(" SECONDS\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
x = 0;
|
||||||
|
for (p = argv[1]; isdigit(*p); ++p) {
|
||||||
|
x *= 10;
|
||||||
|
x += *p - '0';
|
||||||
|
}
|
||||||
|
if (*p == '.') {
|
||||||
|
y = 1;
|
||||||
|
for (++p; isdigit(*p); ++p) {
|
||||||
|
x += (*p - '0') * (y /= 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (*p) {
|
||||||
|
case 'm':
|
||||||
|
x *= 60;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
x *= 60 * 60;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
x *= 60 * 60 * 24;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dsleep(x);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -617,7 +617,7 @@
|
||||||
|
|
||||||
#define setlocate(l, s) 0
|
#define setlocate(l, s) 0
|
||||||
#define equal(s1, s2) (strcmp(s1, s2) == 0)
|
#define equal(s1, s2) (strcmp(s1, s2) == 0)
|
||||||
#define getenv(p) bltinlookup((p), 0)
|
/* #define getenv(p) bltinlookup((p), 0) */
|
||||||
#define isodigit(c) ((c) >= '0' && (c) <= '7')
|
#define isodigit(c) ((c) >= '0' && (c) <= '7')
|
||||||
#define octtobin(c) ((c) - '0')
|
#define octtobin(c) ((c) - '0')
|
||||||
#define scopy(s1, s2) ((void)strcpy(s2, s1))
|
#define scopy(s1, s2) ((void)strcpy(s2, s1))
|
||||||
|
|
|
@ -16,12 +16,13 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/macros.h"
|
#include "libc/macros.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
static struct AtFork {
|
static struct AtFork {
|
||||||
size_t i;
|
volatile size_t i;
|
||||||
struct AtForkCallback {
|
struct AtForkCallback {
|
||||||
void (*fn)(void *);
|
void (*fn)(void *);
|
||||||
void *arg;
|
void *arg;
|
||||||
|
@ -33,17 +34,25 @@ static struct AtFork {
|
||||||
*
|
*
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
* @note vfork() won't invoke callbacks
|
* @note vfork() won't invoke callbacks
|
||||||
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
int atfork(void *fn, void *arg) {
|
int atfork(void *fn, void *arg) {
|
||||||
if (g_atfork.i == ARRAYLEN(g_atfork.p)) return enomem();
|
size_t i;
|
||||||
g_atfork.p[g_atfork.i++] = (struct AtForkCallback){.fn = fn, .arg = arg};
|
for (;;) {
|
||||||
|
i = g_atfork.i;
|
||||||
|
if (i == ARRAYLEN(g_atfork.p)) return enomem();
|
||||||
|
if (cmpxchg(&g_atfork.i, i, i + 1)) {
|
||||||
|
g_atfork.p[i] = (struct AtForkCallback){.fn = fn, .arg = arg};
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers callbacks registered by atfork().
|
* Triggers callbacks registered by atfork().
|
||||||
*
|
*
|
||||||
* @note only fork() should call this
|
* @note only fork() should call this
|
||||||
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
void __onfork(void) {
|
void __onfork(void) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/nt/enum/accessmask.h"
|
||||||
|
#include "libc/nt/enum/fileflagandattributes.h"
|
||||||
|
#include "libc/nt/enum/filesharemode.h"
|
||||||
#include "libc/nt/files.h"
|
#include "libc/nt/files.h"
|
||||||
#include "libc/sysv/consts/f.h"
|
#include "libc/sysv/consts/f.h"
|
||||||
#include "libc/sysv/consts/fd.h"
|
#include "libc/sysv/consts/fd.h"
|
||||||
|
@ -30,7 +33,22 @@ textwindows int fcntl$nt(int fd, int cmd, unsigned arg) {
|
||||||
case F_GETFL:
|
case F_GETFL:
|
||||||
return g_fds.p[fd].flags;
|
return g_fds.p[fd].flags;
|
||||||
case F_SETFL:
|
case F_SETFL:
|
||||||
|
if (ReOpenFile(
|
||||||
|
g_fds.p[fd].handle,
|
||||||
|
(arg & O_APPEND)
|
||||||
|
? kNtFileAppendData
|
||||||
|
: (arg & O_ACCMODE) == O_RDONLY
|
||||||
|
? kNtGenericExecute | kNtFileGenericRead
|
||||||
|
: kNtGenericExecute | kNtFileGenericRead |
|
||||||
|
kNtFileGenericWrite,
|
||||||
|
(arg & O_EXCL) == O_EXCL
|
||||||
|
? kNtFileShareExclusive
|
||||||
|
: kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
|
||||||
|
kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal)) {
|
||||||
return (g_fds.p[fd].flags = arg);
|
return (g_fds.p[fd].flags = arg);
|
||||||
|
} else {
|
||||||
|
return __winerr();
|
||||||
|
}
|
||||||
case F_GETFD:
|
case F_GETFD:
|
||||||
if (g_fds.p[fd].flags & O_CLOEXEC) {
|
if (g_fds.p[fd].flags & O_CLOEXEC) {
|
||||||
return FD_CLOEXEC;
|
return FD_CLOEXEC;
|
||||||
|
@ -38,7 +56,7 @@ textwindows int fcntl$nt(int fd, int cmd, unsigned arg) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case F_SETFD:
|
case F_SETFD:
|
||||||
if (arg & O_CLOEXEC) {
|
if (arg & FD_CLOEXEC) {
|
||||||
g_fds.p[fd].flags |= O_CLOEXEC;
|
g_fds.p[fd].flags |= O_CLOEXEC;
|
||||||
return FD_CLOEXEC;
|
return FD_CLOEXEC;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,15 +17,16 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/nt/process.h"
|
#include "libc/nt/process.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
static int g_pid;
|
static int __pid;
|
||||||
|
|
||||||
static int __get_pid(void) {
|
static int __getpid(void) {
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
return getpid$sysv();
|
return getpid$sysv();
|
||||||
} else {
|
} else {
|
||||||
|
@ -33,20 +34,25 @@ static int __get_pid(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __update_pid(void) {
|
static void __updatepid(void) {
|
||||||
g_pid = __get_pid();
|
__pid = __getpid();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns process id.
|
* Returns process id.
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
|
* @vforksafe
|
||||||
*/
|
*/
|
||||||
int getpid(void) {
|
int getpid(void) {
|
||||||
static bool once;
|
static bool once;
|
||||||
if (!once) {
|
if (__vforked) {
|
||||||
__update_pid();
|
return getpid$sysv();
|
||||||
atfork(__update_pid, NULL);
|
|
||||||
once = true;
|
|
||||||
}
|
}
|
||||||
return g_pid;
|
if (!once) {
|
||||||
|
__updatepid();
|
||||||
|
if (cmpxchg(&once, false, true)) {
|
||||||
|
atfork(__updatepid, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return __pid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
/ call read() safely but you can call pread(). Call _exit() but
|
/ call read() safely but you can call pread(). Call _exit() but
|
||||||
/ don't call exit(). Look for the vforksafe function annotation
|
/ don't call exit(). Look for the vforksafe function annotation
|
||||||
/
|
/
|
||||||
|
/ Do not make the assumption that the parent is suspended until
|
||||||
|
/ the child terminates since this impl calls fork() on Windows.
|
||||||
|
/
|
||||||
/ @return pid of child process or 0 if forked process
|
/ @return pid of child process or 0 if forked process
|
||||||
/ @returnstwice
|
/ @returnstwice
|
||||||
/ @vforksafe
|
/ @vforksafe
|
||||||
|
|
|
@ -70,8 +70,14 @@ hidden extern const struct NtSecurityAttributes kNtIsInheritable;
|
||||||
ssize_t __getemptyfd(void) hidden;
|
ssize_t __getemptyfd(void) hidden;
|
||||||
int __ensurefds(int) hidden;
|
int __ensurefds(int) hidden;
|
||||||
void __removefd(int) hidden;
|
void __removefd(int) hidden;
|
||||||
bool __isfdopen(int) hidden nosideeffect;
|
|
||||||
bool __isfdkind(int, enum FdKind) hidden nosideeffect;
|
forceinline bool __isfdopen(int fd) {
|
||||||
|
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline bool __isfdkind(int fd, enum FdKind kind) {
|
||||||
|
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind == kind;
|
||||||
|
}
|
||||||
|
|
||||||
forceinline size_t clampio(size_t size) {
|
forceinline size_t clampio(size_t size) {
|
||||||
if (!IsTrustworthy()) {
|
if (!IsTrustworthy()) {
|
||||||
|
@ -214,46 +220,46 @@ void xnutrampoline(void *, i32, i32, const struct __darwin_siginfo *,
|
||||||
│ cosmopolitan § syscalls » windows nt » veneers ─╬─│┼
|
│ cosmopolitan § syscalls » windows nt » veneers ─╬─│┼
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
|
||||||
int gettimeofday$nt(struct timeval *, struct timezone *) hidden;
|
|
||||||
bool32 isatty$nt(int) hidden;
|
bool32 isatty$nt(int) hidden;
|
||||||
char *getcwd$nt(char *, size_t) hidden;
|
char *getcwd$nt(char *, size_t) hidden;
|
||||||
int fork$nt(void) hidden;
|
i64 lseek$nt(int, i64, int) hidden;
|
||||||
int chdir$nt(const char *) hidden;
|
int chdir$nt(const char *) hidden;
|
||||||
int close$nt(int) hidden;
|
int close$nt(int) hidden;
|
||||||
int dup$nt(int, int, int) hidden;
|
int dup$nt(int, int, int) hidden;
|
||||||
|
int execve$nt(const char *, char *const[], char *const[]) hidden;
|
||||||
|
int faccessat$nt(int, const char *, int, uint32_t) hidden;
|
||||||
int fadvise$nt(int, u64, u64, int) hidden;
|
int fadvise$nt(int, u64, u64, int) hidden;
|
||||||
int fcntl$nt(int, int, unsigned) hidden;
|
int fcntl$nt(int, int, unsigned) hidden;
|
||||||
int getpriority$nt(int) hidden;
|
|
||||||
int setpriority$nt(int) hidden;
|
|
||||||
int fdatasync$nt(int) hidden;
|
int fdatasync$nt(int) hidden;
|
||||||
int flock$nt(int, int) hidden;
|
int flock$nt(int, int) hidden;
|
||||||
|
int fork$nt(void) hidden;
|
||||||
int fstat$nt(i64, struct stat *) hidden;
|
int fstat$nt(i64, struct stat *) hidden;
|
||||||
int ftruncate$nt(int, u64) hidden;
|
int ftruncate$nt(int, u64) hidden;
|
||||||
int kill$nt(i64, int) hidden;
|
int getpriority$nt(int) hidden;
|
||||||
|
int getrusage$nt(int, struct rusage *) hidden;
|
||||||
|
int gettimeofday$nt(struct timeval *, struct timezone *) hidden;
|
||||||
|
int kill$nt(int, int) hidden;
|
||||||
int link$nt(const char *, const char *) hidden;
|
int link$nt(const char *, const char *) hidden;
|
||||||
int lstat$nt(const char *, struct stat *) hidden;
|
int lstat$nt(const char *, struct stat *) hidden;
|
||||||
int madvise$nt(void *, size_t, int) hidden;
|
int madvise$nt(void *, size_t, int) hidden;
|
||||||
int msync$nt(void *, size_t, int) hidden;
|
int msync$nt(void *, size_t, int) hidden;
|
||||||
ssize_t open$nt(const char *, u32, i32) nodiscard hidden;
|
int nanosleep$nt(const struct timespec *, struct timespec *) hidden;
|
||||||
int pipe$nt(int[hasatleast 2], unsigned) hidden;
|
int pipe$nt(int[hasatleast 2], unsigned) hidden;
|
||||||
int rename$nt(const char *, const char *) hidden;
|
int rename$nt(const char *, const char *) hidden;
|
||||||
int rmdir$nt(const char *) hidden;
|
int rmdir$nt(const char *) hidden;
|
||||||
int sched_yield$nt(void) hidden;
|
int sched_yield$nt(void) hidden;
|
||||||
|
int setitimer$nt(int, const struct itimerval *, struct itimerval *) hidden;
|
||||||
|
int setpriority$nt(int) hidden;
|
||||||
int stat$nt(const char *, struct stat *) hidden;
|
int stat$nt(const char *, struct stat *) hidden;
|
||||||
int sync$nt(void) hidden;
|
|
||||||
int symlink$nt(const char *, const char *) hidden;
|
int symlink$nt(const char *, const char *) hidden;
|
||||||
|
int sync$nt(void) hidden;
|
||||||
int sysinfo$nt(struct sysinfo *) hidden;
|
int sysinfo$nt(struct sysinfo *) hidden;
|
||||||
int truncate$nt(const char *, u64) hidden;
|
int truncate$nt(const char *, u64) hidden;
|
||||||
int unlink$nt(const char *) hidden;
|
int unlink$nt(const char *) hidden;
|
||||||
i64 lseek$nt(int, i64, int) hidden;
|
int utimensat$nt(int, const char *, const struct timespec *, int) hidden;
|
||||||
|
ssize_t open$nt(const char *, u32, i32) nodiscard hidden;
|
||||||
ssize_t read$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
|
ssize_t read$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
|
||||||
ssize_t write$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
|
ssize_t write$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
|
||||||
int utimensat$nt(int, const char *, const struct timespec *, int) hidden;
|
|
||||||
int getrusage$nt(int, struct rusage *) hidden;
|
|
||||||
int setitimer$nt(int, const struct itimerval *, struct itimerval *) hidden;
|
|
||||||
int nanosleep$nt(const struct timespec *, struct timespec *) hidden;
|
|
||||||
int faccessat$nt(int, const char *, int, uint32_t) hidden;
|
|
||||||
int execve$nt(const char *, char *const[], char *const[]) hidden;
|
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § syscalls » windows nt » support ─╬─│┼
|
│ cosmopolitan § syscalls » windows nt » support ─╬─│┼
|
||||||
|
@ -266,7 +272,6 @@ int getsetpriority$nt(int, unsigned, int, int (*)(int));
|
||||||
void ntcontext2linux(struct ucontext *, const struct NtContext *) hidden;
|
void ntcontext2linux(struct ucontext *, const struct NtContext *) hidden;
|
||||||
struct NtOverlapped *offset2overlap(int64_t, struct NtOverlapped *) hidden;
|
struct NtOverlapped *offset2overlap(int64_t, struct NtOverlapped *) hidden;
|
||||||
bool32 ntsetprivilege(i64, const char16_t *, u32) hidden;
|
bool32 ntsetprivilege(i64, const char16_t *, u32) hidden;
|
||||||
bool32 onntconsoleevent$nt(u32) hidden;
|
|
||||||
void __winalarm(void *, uint32_t, uint32_t) hidden;
|
void __winalarm(void *, uint32_t, uint32_t) hidden;
|
||||||
int ntaccesscheck(const char16_t *, u32) paramsnonnull() hidden;
|
int ntaccesscheck(const char16_t *, u32) paramsnonnull() hidden;
|
||||||
int64_t __winerr(void) nocallback privileged;
|
int64_t __winerr(void) nocallback privileged;
|
||||||
|
|
56
libc/calls/kill-nt.c
Normal file
56
libc/calls/kill-nt.c
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*-*- 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/internal.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/macros.h"
|
||||||
|
#include "libc/nt/console.h"
|
||||||
|
#include "libc/nt/enum/ctrlevent.h"
|
||||||
|
#include "libc/nt/process.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
textwindows int kill$nt(int pid, int sig) {
|
||||||
|
int target;
|
||||||
|
uint32_t event;
|
||||||
|
if (!pid) return raise(sig);
|
||||||
|
if ((pid > 0 && __isfdkind(pid, kFdProcess)) ||
|
||||||
|
(pid < 0 && __isfdkind(-pid, kFdProcess))) {
|
||||||
|
target = GetProcessId(g_fds.p[ABS(pid)].handle);
|
||||||
|
} else {
|
||||||
|
target = pid;
|
||||||
|
}
|
||||||
|
if (target == GetCurrentProcessId()) {
|
||||||
|
return raise(sig);
|
||||||
|
} else {
|
||||||
|
switch (sig) {
|
||||||
|
case SIGINT:
|
||||||
|
event = kNtCtrlCEvent;
|
||||||
|
case SIGHUP:
|
||||||
|
event = kNtCtrlCloseEvent;
|
||||||
|
case SIGQUIT:
|
||||||
|
event = kNtCtrlBreakEvent;
|
||||||
|
default:
|
||||||
|
return einval();
|
||||||
|
}
|
||||||
|
if (GenerateConsoleCtrlEvent(event, target)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return __winerr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,6 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends signal to process.
|
* Sends signal to process.
|
||||||
|
@ -39,15 +38,9 @@
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
int kill(int pid, int sig) {
|
int kill(int pid, int sig) {
|
||||||
int me;
|
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
return kill$sysv(pid, sig, 1);
|
return kill$sysv(pid, sig, 1);
|
||||||
} else {
|
} else {
|
||||||
me = getpid();
|
return kill$nt(pid, sig);
|
||||||
if (!pid || pid == me || pid == -me) {
|
|
||||||
return raise(sig);
|
|
||||||
} else {
|
|
||||||
return enosys();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,8 @@ textwindows int ntspawn(
|
||||||
mkntenvblock(block->envvars, envp) != -1) {
|
mkntenvblock(block->envvars, envp) != -1) {
|
||||||
if (CreateProcess(NULL, block->cmdline, opt_lpProcessAttributes,
|
if (CreateProcess(NULL, block->cmdline, opt_lpProcessAttributes,
|
||||||
opt_lpThreadAttributes, bInheritHandles,
|
opt_lpThreadAttributes, bInheritHandles,
|
||||||
dwCreationFlags | kNtCreateUnicodeEnvironment,
|
dwCreationFlags | kNtCreateNewProcessGroup |
|
||||||
|
kNtCreateUnicodeEnvironment,
|
||||||
block->envvars, opt_lpCurrentDirectory, lpStartupInfo,
|
block->envvars, opt_lpCurrentDirectory, lpStartupInfo,
|
||||||
opt_out_lpProcessInformation)) {
|
opt_out_lpProcessInformation)) {
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
|
||||||
textwindows bool32 onntconsoleevent(uint32_t CtrlType) {
|
textwindows bool32 __onntconsoleevent(uint32_t CtrlType) {
|
||||||
int sig;
|
int sig;
|
||||||
siginfo_t info;
|
siginfo_t info;
|
||||||
switch (CtrlType) {
|
switch (CtrlType) {
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
.source __FILE__
|
.source __FILE__
|
||||||
|
|
||||||
.init.start 300,_init_onntconsoleevent
|
.init.start 300,_init_onntconsoleevent
|
||||||
ezlea onntconsoleevent$nt,cx
|
ezlea __onntconsoleevent$nt,cx
|
||||||
pushpop 1,%rdx
|
pushpop 1,%rdx
|
||||||
ntcall __imp_SetConsoleCtrlHandler
|
ntcall __imp_SetConsoleCtrlHandler
|
||||||
.init.end 300,_init_onntconsoleevent,globl,hidden
|
.init.end 300,_init_onntconsoleevent,globl,hidden
|
||||||
|
|
|
@ -45,7 +45,9 @@ static textwindows int64_t open$nt$impl(const char *file, uint32_t flags,
|
||||||
(flags & 0xf000000f) |
|
(flags & 0xf000000f) |
|
||||||
(/* this is needed if we mmap(rwx+cow)
|
(/* this is needed if we mmap(rwx+cow)
|
||||||
nt is choosy about open() access */
|
nt is choosy about open() access */
|
||||||
(flags & O_ACCMODE) == O_RDONLY
|
(flags & O_APPEND)
|
||||||
|
? kNtFileAppendData
|
||||||
|
: (flags & O_ACCMODE) == O_RDONLY
|
||||||
? kNtGenericExecute | kNtFileGenericRead
|
? kNtGenericExecute | kNtFileGenericRead
|
||||||
: kNtGenericExecute | kNtFileGenericRead |
|
: kNtGenericExecute | kNtFileGenericRead |
|
||||||
kNtFileGenericWrite),
|
kNtFileGenericWrite),
|
||||||
|
|
|
@ -25,15 +25,18 @@
|
||||||
/**
|
/**
|
||||||
* Waits for signal.
|
* Waits for signal.
|
||||||
*
|
*
|
||||||
* @return should be -1 w/ EINTR
|
* This suspends execution until an unmasked signal is delivered
|
||||||
|
* and its callback function has been called. It's a better idea
|
||||||
|
* to use sigsuspend() w/ sigprocmask() to avoid race conditions
|
||||||
|
*
|
||||||
|
* @return should always be -1 w/ EINTR
|
||||||
* @see sigsuspend()
|
* @see sigsuspend()
|
||||||
*/
|
*/
|
||||||
int pause(void) {
|
int pause(void) {
|
||||||
int rc, olderr;
|
int rc, olderr;
|
||||||
sigset_t oldmask;
|
sigset_t oldmask;
|
||||||
olderr = errno;
|
olderr = errno;
|
||||||
rc = pause$sysv();
|
if ((rc = pause$sysv()) == -1 && errno == ENOSYS) {
|
||||||
if (rc == -1 && errno == ENOSYS) {
|
|
||||||
errno = olderr;
|
errno = olderr;
|
||||||
if (sigprocmask(SIG_BLOCK, NULL, &oldmask) == -1) return -1;
|
if (sigprocmask(SIG_BLOCK, NULL, &oldmask) == -1) return -1;
|
||||||
rc = sigsuspend(&oldmask);
|
rc = sigsuspend(&oldmask);
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
|
||||||
static uint32_t GetCtrlEvent(int sig) {
|
static textwindows uint32_t GetCtrlEvent(int sig) {
|
||||||
switch (sig) {
|
switch (sig) {
|
||||||
case SIGINT:
|
case SIGINT:
|
||||||
return kNtCtrlCEvent;
|
return kNtCtrlCEvent;
|
||||||
|
|
|
@ -34,11 +34,12 @@
|
||||||
* @param oldset will receive the old mask (optional) and can't overlap
|
* @param oldset will receive the old mask (optional) and can't overlap
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
|
* @vforksafe
|
||||||
*/
|
*/
|
||||||
int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
|
int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
return sigprocmask$sysv(how, opt_set, opt_out_oldset, 8);
|
return sigprocmask$sysv(how, opt_set, opt_out_oldset, 8);
|
||||||
} else {
|
} else {
|
||||||
return enosys(); /* TODO(jart): Implement me! */
|
return 0; /* TODO(jart): Implement me! */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,14 +25,14 @@
|
||||||
/**
|
/**
|
||||||
* Blocks until SIG ∉ MASK is delivered to process.
|
* Blocks until SIG ∉ MASK is delivered to process.
|
||||||
*
|
*
|
||||||
* @param mask is a bitset of signals to block temporarily
|
* @param ignore is a bitset of signals to block temporarily
|
||||||
* @return -1 w/ EINTR
|
* @return -1 w/ EINTR
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
int sigsuspend(const sigset_t *mask) {
|
int sigsuspend(const sigset_t *ignore) {
|
||||||
if (!mask) return efault();
|
if (!ignore) return efault();
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
return sigsuspend$sysv(mask, 8);
|
return sigsuspend$sysv(ignore, 8);
|
||||||
} else {
|
} else {
|
||||||
return enosys(); /* TODO(jart): Implement me! */
|
return enosys(); /* TODO(jart): Implement me! */
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
.text.windows
|
.text.windows
|
||||||
.source __FILE__
|
.source __FILE__
|
||||||
|
|
||||||
onntconsoleevent$nt:
|
__onntconsoleevent$nt:
|
||||||
ezlea onntconsoleevent,ax
|
ezlea __onntconsoleevent,ax
|
||||||
jmp __nt2sysv
|
jmp __nt2sysv
|
||||||
.endfn onntconsoleevent$nt,globl,hidden
|
.endfn __onntconsoleevent$nt,globl,hidden
|
||||||
|
|
|
@ -17,9 +17,6 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
|
||||||
#include "libc/calls/wait4.h"
|
|
||||||
#include "libc/dce.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for status to change on process.
|
* Waits for status to change on process.
|
||||||
|
@ -33,9 +30,5 @@
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
int waitpid(int pid, int *opt_out_wstatus, int options) {
|
int waitpid(int pid, int *opt_out_wstatus, int options) {
|
||||||
if (!IsWindows()) {
|
return wait4(pid, opt_out_wstatus, options, NULL);
|
||||||
return wait4$sysv(pid, opt_out_wstatus, options, NULL);
|
|
||||||
} else {
|
|
||||||
return wait4$nt(pid, opt_out_wstatus, options, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ textwindows ssize_t write$nt(struct Fd *fd, const struct iovec *iov,
|
||||||
if (WriteFile(fd->handle, iovlen ? iov[0].iov_base : NULL,
|
if (WriteFile(fd->handle, iovlen ? iov[0].iov_base : NULL,
|
||||||
iovlen ? clampio(iov[0].iov_len) : 0, &wrote,
|
iovlen ? clampio(iov[0].iov_len) : 0, &wrote,
|
||||||
offset2overlap(opt_offset, &overlap))) {
|
offset2overlap(opt_offset, &overlap))) {
|
||||||
if (!wrote) assert(SumIovecLen(iov, iovlen) > 0);
|
if (!wrote) assert(!SumIovecLen(iov, iovlen));
|
||||||
FlushFileBuffers(fd->handle);
|
FlushFileBuffers(fd->handle);
|
||||||
return wrote;
|
return wrote;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/log/backtrace.internal.h"
|
#include "libc/log/backtrace.internal.h"
|
||||||
|
@ -40,7 +41,7 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
||||||
ssize_t got;
|
ssize_t got;
|
||||||
intptr_t addr;
|
intptr_t addr;
|
||||||
size_t i, j, gi;
|
size_t i, j, gi;
|
||||||
int rc, pid, pipefds[2];
|
int ws, pid, pipefds[2];
|
||||||
struct Garbages *garbage;
|
struct Garbages *garbage;
|
||||||
const struct StackFrame *frame;
|
const struct StackFrame *frame;
|
||||||
const char *debugbin, *p1, *p2, *p3, *addr2line;
|
const char *debugbin, *p1, *p2, *p3, *addr2line;
|
||||||
|
@ -73,7 +74,7 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
||||||
close(pipefds[0]);
|
close(pipefds[0]);
|
||||||
close(pipefds[1]);
|
close(pipefds[1]);
|
||||||
execvp(addr2line, argv);
|
execvp(addr2line, argv);
|
||||||
abort();
|
_exit(127);
|
||||||
}
|
}
|
||||||
close(pipefds[1]);
|
close(pipefds[1]);
|
||||||
while ((got = read(pipefds[0], buf, kBacktraceBufSize)) > 0) {
|
while ((got = read(pipefds[0], buf, kBacktraceBufSize)) > 0) {
|
||||||
|
@ -99,9 +100,15 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(pipefds[0]);
|
close(pipefds[0]);
|
||||||
if (waitpid(pid, &rc, 0) == -1) return -1;
|
while (waitpid(pid, &ws, 0) == -1) {
|
||||||
if (WEXITSTATUS(rc) != 0) return -1;
|
if (errno == EINTR) continue;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (WIFEXITED(ws) && !WEXITSTATUS(ws)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PrintBacktrace(int fd, const struct StackFrame *bp) {
|
static int PrintBacktrace(int fd, const struct StackFrame *bp) {
|
||||||
|
|
|
@ -50,7 +50,6 @@ int PrintBacktraceUsingSymbols(int fd, const struct StackFrame *bp,
|
||||||
char buf[256], ibuf[21];
|
char buf[256], ibuf[21];
|
||||||
const struct Symbol *symbol;
|
const struct Symbol *symbol;
|
||||||
const struct StackFrame *frame;
|
const struct StackFrame *frame;
|
||||||
if (!st) return -1;
|
|
||||||
if (!bp) bp = __builtin_frame_address(0);
|
if (!bp) bp = __builtin_frame_address(0);
|
||||||
garbage = weaken(__garbage);
|
garbage = weaken(__garbage);
|
||||||
gi = garbage ? garbage->i : 0;
|
gi = garbage ? garbage->i : 0;
|
||||||
|
@ -66,7 +65,8 @@ int PrintBacktraceUsingSymbols(int fd, const struct StackFrame *bp,
|
||||||
*p++ = ' ';
|
*p++ = ' ';
|
||||||
p = mempcpy(p, ibuf, uint64toarray_fixed16(addr, ibuf, 48));
|
p = mempcpy(p, ibuf, uint64toarray_fixed16(addr, ibuf, 48));
|
||||||
*p++ = ' ';
|
*p++ = ' ';
|
||||||
if (st->count && ((intptr_t)addr >= (intptr_t)&_base &&
|
if (st && st->count &&
|
||||||
|
((intptr_t)addr >= (intptr_t)&_base &&
|
||||||
(intptr_t)addr <= (intptr_t)&_end)) {
|
(intptr_t)addr <= (intptr_t)&_end)) {
|
||||||
symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
|
symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
|
||||||
st->count, addr - st->addr_base - 1)];
|
st->count, addr - st->addr_base - 1)];
|
||||||
|
|
|
@ -56,10 +56,10 @@ relegated void __check_fail(const char *suffix, const char *opstr,
|
||||||
gethostname(hostname, sizeof(hostname));
|
gethostname(hostname, sizeof(hostname));
|
||||||
|
|
||||||
(dprintf)(STDERR_FILENO,
|
(dprintf)(STDERR_FILENO,
|
||||||
"check failed on %s pid %d\r\n"
|
"check failed on %s pid %d\n"
|
||||||
"\tCHECK_%s(%s, %s);\r\n"
|
"\tCHECK_%s(%s, %s);\n"
|
||||||
"\t\t → %#lx (%s)\r\n"
|
"\t\t → %#lx (%s)\n"
|
||||||
"\t\t%s %#lx (%s)\r\n",
|
"\t\t%s %#lx (%s)\n",
|
||||||
hostname, getpid(), sufbuf, wantstr, gotstr, want, wantstr, opstr,
|
hostname, getpid(), sufbuf, wantstr, gotstr, want, wantstr, opstr,
|
||||||
got, gotstr);
|
got, gotstr);
|
||||||
|
|
||||||
|
@ -68,19 +68,19 @@ relegated void __check_fail(const char *suffix, const char *opstr,
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
(vdprintf)(STDERR_FILENO, fmt, va);
|
(vdprintf)(STDERR_FILENO, fmt, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
(dprintf)(STDERR_FILENO, "\r\n");
|
(dprintf)(STDERR_FILENO, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
(dprintf)(STDERR_FILENO, "\t%s\r\n\t%s%s%s%s\r\n", strerror(lasterr), SUBTLE,
|
(dprintf)(STDERR_FILENO, "\t%s\n\t%s%s%s%s\n", strerror(lasterr), SUBTLE,
|
||||||
getauxval(AT_EXECFN), g_argc > 1 ? " \\" : "", RESET);
|
getauxval(AT_EXECFN), g_argc > 1 ? " \\" : "", RESET);
|
||||||
|
|
||||||
for (i = 1; i < g_argc; ++i) {
|
for (i = 1; i < g_argc; ++i) {
|
||||||
(dprintf)(STDERR_FILENO, "\t\t%s%s\r\n", g_argv[i],
|
(dprintf)(STDERR_FILENO, "\t\t%s%s\n", g_argv[i],
|
||||||
i < g_argc - 1 ? " \\" : "");
|
i < g_argc - 1 ? " \\" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsTiny() && lasterr == ENOMEM) {
|
if (!IsTiny() && lasterr == ENOMEM) {
|
||||||
(dprintf)(STDERR_FILENO, "\r\n");
|
(dprintf)(STDERR_FILENO, "\n");
|
||||||
PrintMemoryIntervals(STDERR_FILENO, &_mmi);
|
PrintMemoryIntervals(STDERR_FILENO, &_mmi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,5 +46,5 @@ relegated void ___check_fail_ndebug(uint64_t want, uint64_t got,
|
||||||
__print(bx, uint64toarray_radix16(got, bx));
|
__print(bx, uint64toarray_radix16(got, bx));
|
||||||
__print_string(" (");
|
__print_string(" (");
|
||||||
__print(bx, int64toarray_radix10(lasterr, bx));
|
__print(bx, int64toarray_radix10(lasterr, bx));
|
||||||
__print_string(")\r\n");
|
__print_string(")\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,13 +18,21 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/log/color.internal.h"
|
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes error messages to standard error.
|
||||||
|
*/
|
||||||
void perror(const char *message) {
|
void perror(const char *message) {
|
||||||
fprintf(stderr, "%s%s%s: %s: %s: %s\r\n", RED2, "error", RESET,
|
int err;
|
||||||
program_invocation_name, strerror(errno), message);
|
err = errno;
|
||||||
|
if (message && *message) {
|
||||||
|
fputs(message, stderr);
|
||||||
|
fputs(": ", stderr);
|
||||||
|
}
|
||||||
|
fputs(strerror(err), stderr);
|
||||||
|
fputc('\n', stderr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,9 @@ STATIC_YOINK("ntoa");
|
||||||
STATIC_YOINK("stoa");
|
STATIC_YOINK("stoa");
|
||||||
STATIC_YOINK("ftoa");
|
STATIC_YOINK("ftoa");
|
||||||
|
|
||||||
static int loglevel2char(unsigned level) {
|
static struct timespec vflogf_ts;
|
||||||
|
|
||||||
|
static int vflogf_loglevel2char(unsigned level) {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case kLogInfo:
|
case kLogInfo:
|
||||||
return 'I';
|
return 'I';
|
||||||
|
@ -78,34 +80,46 @@ void vflogf_onfail(FILE *f) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes formatted message w/ timestamp to log.
|
* Writes formatted message w/ timestamp to log.
|
||||||
|
*
|
||||||
|
* Timestamps are hyphenated out when multiple events happen within the
|
||||||
|
* same second in the same process. When timestamps are crossed out, it
|
||||||
|
* will display microseconsd as a delta elapsed time. This is useful if
|
||||||
|
* you do something like:
|
||||||
|
*
|
||||||
|
* LOGF("connecting to foo");
|
||||||
|
* connect(...)
|
||||||
|
* LOGF("connected to foo");
|
||||||
|
*
|
||||||
|
* In that case, the second log entry will always display the amount of
|
||||||
|
* time that it took to connect. This is great in forking applications.
|
||||||
*/
|
*/
|
||||||
void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
||||||
const char *fmt, va_list va) {
|
const char *fmt, va_list va) {
|
||||||
static struct timespec ts;
|
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
long double t2;
|
long double t2;
|
||||||
const char *prog;
|
const char *prog;
|
||||||
int64_t secs, nsec, dots;
|
bool issamesecond;
|
||||||
char buf32[32], *buf32p;
|
char buf32[32], *buf32p;
|
||||||
|
int64_t secs, nsec, dots;
|
||||||
if (!f) f = g_logfile;
|
if (!f) f = g_logfile;
|
||||||
if (fileno(f) == -1) return;
|
if (fileno(f) == -1) return;
|
||||||
t2 = nowl();
|
t2 = nowl();
|
||||||
secs = t2;
|
secs = t2;
|
||||||
nsec = rem1000000000int64(t2 * 1e9L);
|
nsec = (t2 - secs) * 1e9L;
|
||||||
if (secs > ts.tv_sec) {
|
issamesecond = secs == vflogf_ts.tv_sec;
|
||||||
|
dots = issamesecond ? nsec - vflogf_ts.tv_nsec : nsec;
|
||||||
|
vflogf_ts.tv_sec = secs;
|
||||||
|
vflogf_ts.tv_nsec = nsec;
|
||||||
|
if (!issamesecond) {
|
||||||
localtime_r(&secs, &tm);
|
localtime_r(&secs, &tm);
|
||||||
strftime(buf32, sizeof(buf32), "%Y-%m-%dT%H:%M:%S.", &tm);
|
strftime(buf32, sizeof(buf32), "%Y-%m-%dT%H:%M:%S.", &tm);
|
||||||
buf32p = buf32;
|
buf32p = buf32;
|
||||||
dots = nsec;
|
|
||||||
} else {
|
} else {
|
||||||
buf32p = "--------------------";
|
buf32p = "--------------------";
|
||||||
dots = nsec - ts.tv_nsec;
|
|
||||||
}
|
}
|
||||||
ts.tv_sec = secs;
|
|
||||||
ts.tv_nsec = nsec;
|
|
||||||
prog = basename(program_invocation_name);
|
prog = basename(program_invocation_name);
|
||||||
if ((fprintf)(f, "%c%s%06ld:%s:%d:%.*s:%d] ", loglevel2char(level), buf32p,
|
if ((fprintf)(f, "%c%s%06ld:%s:%d:%.*s:%d] ", vflogf_loglevel2char(level),
|
||||||
rem1000000int64(div1000int64(dots)), file, line,
|
buf32p, rem1000000int64(div1000int64(dots)), file, line,
|
||||||
strchrnul(prog, '.') - prog, prog, getpid()) <= 0) {
|
strchrnul(prog, '.') - prog, prog, getpid()) <= 0) {
|
||||||
vflogf_onfail(f);
|
vflogf_onfail(f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_NT_PRIVILEGE_H_
|
#ifndef COSMOPOLITAN_LIBC_NT_PRIVILEGE_H_
|
||||||
#define COSMOPOLITAN_LIBC_NT_PRIVILEGE_H_
|
#define COSMOPOLITAN_LIBC_NT_PRIVILEGE_H_
|
||||||
#include "libc/nt/struct/luid.h"
|
#include "libc/nt/struct/luid.h"
|
||||||
|
#include "libc/nt/struct/tokenprivileges.h"
|
||||||
/* ░░░░
|
/* ░░░░
|
||||||
▒▒▒░░░▒▒▒▒▒▒▒▓▓▓░
|
▒▒▒░░░▒▒▒▒▒▒▒▓▓▓░
|
||||||
▒▒▒▒░░░▒▒▒▒▒▒▓▓▓▓▓▓░
|
▒▒▒▒░░░▒▒▒▒▒▒▓▓▓▓▓▓░
|
||||||
|
@ -34,9 +35,6 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
struct NtLuid;
|
|
||||||
struct NtTokenPrivileges;
|
|
||||||
|
|
||||||
bool32 LookupPrivilegeValue(const char16_t *opt_lpSystemName,
|
bool32 LookupPrivilegeValue(const char16_t *opt_lpSystemName,
|
||||||
const char16_t *lpName, struct NtLuid *out_lpLuid);
|
const char16_t *lpName, struct NtLuid *out_lpLuid);
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,8 @@ bool32 CreateProcess(const char16_t *opt_lpApplicationName,
|
||||||
struct NtProcessInformation *opt_out_lpProcessInformation)
|
struct NtProcessInformation *opt_out_lpProcessInformation)
|
||||||
paramsnonnull((2, 9));
|
paramsnonnull((2, 9));
|
||||||
|
|
||||||
uint32_t GetThreadId(int64_t Thread); /* cf. NT_TID */
|
uint32_t GetThreadId(int64_t hThread); /* cf. NT_TID */
|
||||||
uint32_t GetProcessId(int64_t Process); /* cf. NT_PID */
|
uint32_t GetProcessId(int64_t hProcess); /* cf. NT_PID */
|
||||||
void SetLastError(uint32_t dwErrCode);
|
void SetLastError(uint32_t dwErrCode);
|
||||||
uint32_t FormatMessage(uint32_t dwFlags, const void *lpSource,
|
uint32_t FormatMessage(uint32_t dwFlags, const void *lpSource,
|
||||||
uint32_t dwMessageId, uint32_t dwLanguageId,
|
uint32_t dwMessageId, uint32_t dwLanguageId,
|
||||||
|
|
32
libc/runtime/abort-nt.c
Normal file
32
libc/runtime/abort-nt.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 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/pushpop.h"
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/struct/siginfo.h"
|
||||||
|
#include "libc/nt/enum/ctrlevent.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
|
||||||
|
textwindows wontreturn void abort$nt(void) {
|
||||||
|
siginfo_t info;
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
info.si_signo = SIGABRT;
|
||||||
|
__sigenter(SIGABRT, &info, NULL);
|
||||||
|
_Exit(128 + SIGABRT);
|
||||||
|
}
|
|
@ -56,6 +56,5 @@ abort: push %rbp
|
||||||
mov SIGABRT,%esi
|
mov SIGABRT,%esi
|
||||||
mov __NR_kill,%eax
|
mov __NR_kill,%eax
|
||||||
syscall # avoid hook and less bt noise
|
syscall # avoid hook and less bt noise
|
||||||
2: mov $134,%edi # exit(128+SIGABRT) [bash-ism]
|
2: call abort$nt
|
||||||
call _Exit
|
|
||||||
.endfn abort,globl,protected
|
.endfn abort,globl,protected
|
||||||
|
|
77
libc/runtime/brk.c
Normal file
77
libc/runtime/brk.c
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*-*- 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/calls/calls.h"
|
||||||
|
#include "libc/macros.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/sysv/consts/map.h"
|
||||||
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
uintptr_t __break;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets end of data section.
|
||||||
|
*
|
||||||
|
* This can be used to allocate and deallocate memory. It won't
|
||||||
|
* conflict with malloc() and mmap(NULL, ...) allocations since
|
||||||
|
* APE binaries load the image at 0x400000 and does allocations
|
||||||
|
* starting at 0x100080000000. You should consult _end, or call
|
||||||
|
* sbrk(NULL), to figure out where the existing break is first.
|
||||||
|
*
|
||||||
|
* @return 0 on success or -1 w/ errno
|
||||||
|
* @see mmap(), sbrk(), _end
|
||||||
|
*/
|
||||||
|
int brk(void *end) {
|
||||||
|
int rc;
|
||||||
|
uintptr_t x;
|
||||||
|
if (!__break) __break = (uintptr_t)_end;
|
||||||
|
x = (uintptr_t)end;
|
||||||
|
if (x < (uintptr_t)_end) x = (uintptr_t)_end;
|
||||||
|
x = ROUNDUP(x, FRAMESIZE);
|
||||||
|
if (x == __break) return 0;
|
||||||
|
/* allocate one frame at a time due to nt pickiness */
|
||||||
|
for (; x > __break; __break += FRAMESIZE) {
|
||||||
|
if (mmap((void *)__break, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == MAP_FAILED) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (rc = 0; x < __break; __break -= FRAMESIZE) {
|
||||||
|
rc |= munmap((void *)(__break - FRAMESIZE), FRAMESIZE);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts end of data section.
|
||||||
|
*
|
||||||
|
* This shrinks or increases the program break by delta bytes. On
|
||||||
|
* success, the previous program break is returned. It's possible
|
||||||
|
* to pass zero to this function to get the current program break
|
||||||
|
*
|
||||||
|
* @return old break on success or -1 w/ errno
|
||||||
|
* @see mmap(), brk(), _end
|
||||||
|
*/
|
||||||
|
void *sbrk(intptr_t delta) {
|
||||||
|
uintptr_t oldbreak;
|
||||||
|
if (!__break) __break = (uintptr_t)_end;
|
||||||
|
oldbreak = __break;
|
||||||
|
return (void *)(brk((void *)(__break + delta)) != -1 ? oldbreak : -1);
|
||||||
|
}
|
40
libc/runtime/ldso.c
Normal file
40
libc/runtime/ldso.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 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/runtime/runtime.h"
|
||||||
|
|
||||||
|
char *dlerror(void) {
|
||||||
|
return "cosmopolitan doesn't support dsos";
|
||||||
|
}
|
||||||
|
|
||||||
|
void *dlopen(const char *file, int mode) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *dlsym(void *handle, const char *name) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dlclose(void *handle) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dl_iterate_phdr(int callback(void *info, size_t size, void *data),
|
||||||
|
void *data) {
|
||||||
|
return -1;
|
||||||
|
}
|
50
libc/runtime/pthread.c
Normal file
50
libc/runtime/pthread.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 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/bits/bits.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
|
typedef void *pthread_t;
|
||||||
|
typedef bool pthread_once_t;
|
||||||
|
typedef int pthread_mutex_t;
|
||||||
|
|
||||||
|
int pthread_once(pthread_once_t *once, void init(void)) {
|
||||||
|
if (lockcmpxchg(once, 0, 1)) init();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_mutex_lock(pthread_mutex_t *mutex) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_mutex_trylock(pthread_mutex_t *mutex) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_mutex_unlock(pthread_mutex_t *mutex) {
|
||||||
|
return EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_cancel(pthread_t thread) {
|
||||||
|
return ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *__tls_get_addr(size_t v[2]) {
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ extern unsigned char _base[] forcealign(PAGESIZE); /* αpε */
|
||||||
extern unsigned char _ehead[] forcealign(PAGESIZE); /* αpε */
|
extern unsigned char _ehead[] forcealign(PAGESIZE); /* αpε */
|
||||||
extern unsigned char _etext[] forcealign(PAGESIZE); /* αpε */
|
extern unsigned char _etext[] forcealign(PAGESIZE); /* αpε */
|
||||||
extern unsigned char _edata[] forcealign(PAGESIZE); /* αpε */
|
extern unsigned char _edata[] forcealign(PAGESIZE); /* αpε */
|
||||||
extern unsigned char _end[] forcealign(PAGESIZE); /* αpε */
|
extern unsigned char _end[] forcealign(FRAMESIZE); /* αpε */
|
||||||
extern unsigned char _ereal; /* αpε */
|
extern unsigned char _ereal; /* αpε */
|
||||||
extern unsigned char __privileged_start; /* αpε */
|
extern unsigned char __privileged_start; /* αpε */
|
||||||
extern unsigned char __test_start; /* αpε */
|
extern unsigned char __test_start; /* αpε */
|
||||||
|
@ -70,6 +70,8 @@ int msync(void *, size_t, int);
|
||||||
void __print(const void *, size_t);
|
void __print(const void *, size_t);
|
||||||
void __print_string(const char *);
|
void __print_string(const char *);
|
||||||
void __fast_math(void);
|
void __fast_math(void);
|
||||||
|
void *sbrk(intptr_t);
|
||||||
|
int brk(void *);
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § runtime » optimizations ─╬─│┼
|
│ cosmopolitan § runtime » optimizations ─╬─│┼
|
||||||
|
|
|
@ -23,16 +23,6 @@
|
||||||
#include "libc/sock/yoink.inc"
|
#include "libc/sock/yoink.inc"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* Assigns local address and port number to socket.
|
|
||||||
*
|
|
||||||
* @param fd is the file descriptor returned by socket()
|
|
||||||
* @param addr is usually the binary-encoded ip:port on which to listen
|
|
||||||
* @param addrsize is the byte-length of addr's true polymorphic form
|
|
||||||
* @return socket file descriptor or -1 w/ errno
|
|
||||||
* @error ENETDOWN, EPFNOSUPPORT, etc.
|
|
||||||
* @asyncsignalsafe
|
|
||||||
*/
|
|
||||||
textwindows int bind$nt(struct Fd *fd, const void *addr, uint32_t addrsize) {
|
textwindows int bind$nt(struct Fd *fd, const void *addr, uint32_t addrsize) {
|
||||||
assert(fd->kind == kFdSocket);
|
assert(fd->kind == kFdSocket);
|
||||||
if (__bind$nt(fd->handle, addr, addrsize) != -1) {
|
if (__bind$nt(fd->handle, addr, addrsize) != -1) {
|
||||||
|
|
|
@ -58,8 +58,6 @@ int32_t __socket$sysv(int32_t, int32_t, int32_t) hidden;
|
||||||
int32_t __getsockname$sysv(int32_t, void *, uint32_t *) hidden;
|
int32_t __getsockname$sysv(int32_t, void *, uint32_t *) hidden;
|
||||||
int32_t __getpeername$sysv(int32_t, void *, uint32_t *) hidden;
|
int32_t __getpeername$sysv(int32_t, void *, uint32_t *) hidden;
|
||||||
|
|
||||||
int32_t setsockopt$sysv(int32_t, int32_t, int32_t, const void *,
|
|
||||||
uint32_t) hidden;
|
|
||||||
int32_t accept4$sysv(int32_t, void *, uint32_t *, int) nodiscard hidden;
|
int32_t accept4$sysv(int32_t, void *, uint32_t *, int) nodiscard hidden;
|
||||||
int32_t accept$sysv(int32_t, void *, uint32_t *) hidden;
|
int32_t accept$sysv(int32_t, void *, uint32_t *) hidden;
|
||||||
int32_t bind$sysv(int32_t, const void *, uint32_t) hidden;
|
int32_t bind$sysv(int32_t, const void *, uint32_t) hidden;
|
||||||
|
@ -78,6 +76,7 @@ ssize_t sendto$sysv(int, const void *, size_t, int, const void *,
|
||||||
uint32_t) hidden;
|
uint32_t) hidden;
|
||||||
int32_t select$sysv(int32_t, fd_set *, fd_set *, fd_set *,
|
int32_t select$sysv(int32_t, fd_set *, fd_set *, fd_set *,
|
||||||
struct timeval *) hidden;
|
struct timeval *) hidden;
|
||||||
|
int setsockopt$sysv(int, int, int, const void *, uint32_t) hidden;
|
||||||
int32_t epoll_create$sysv(int32_t) hidden;
|
int32_t epoll_create$sysv(int32_t) hidden;
|
||||||
int32_t epoll_ctl$sysv(int32_t, int32_t, int32_t, void *) hidden;
|
int32_t epoll_ctl$sysv(int32_t, int32_t, int32_t, void *) hidden;
|
||||||
int32_t epoll_wait$sysv(int32_t, void *, int32_t, int32_t) hidden;
|
int32_t epoll_wait$sysv(int32_t, void *, int32_t, int32_t) hidden;
|
||||||
|
@ -93,6 +92,7 @@ int accept$nt(struct Fd *, void *, uint32_t *, int) hidden;
|
||||||
int closesocket$nt(int) hidden;
|
int closesocket$nt(int) hidden;
|
||||||
int socket$nt(int, int, int) hidden;
|
int socket$nt(int, int, int) hidden;
|
||||||
int select$nt(int, fd_set *, fd_set *, fd_set *, struct timeval *) hidden;
|
int select$nt(int, fd_set *, fd_set *, fd_set *, struct timeval *) hidden;
|
||||||
|
int shutdown$nt(struct Fd *, int) hidden;
|
||||||
|
|
||||||
size_t iovec2nt(struct NtIovec[hasatleast 16], const struct iovec *,
|
size_t iovec2nt(struct NtIovec[hasatleast 16], const struct iovec *,
|
||||||
size_t) hidden;
|
size_t) hidden;
|
||||||
|
|
29
libc/sock/shutdown-nt.c
Normal file
29
libc/sock/shutdown-nt.c
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*-*- 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/internal.h"
|
||||||
|
#include "libc/nt/winsock.h"
|
||||||
|
#include "libc/sock/internal.h"
|
||||||
|
|
||||||
|
textwindows int shutdown$nt(struct Fd *fd, int how) {
|
||||||
|
if (__shutdown$nt(fd->handle, how) != -1) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return __winsockerr();
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,19 +18,10 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/nt/winsock.h"
|
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
#include "libc/sock/sock.h"
|
#include "libc/sock/sock.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
static int shutdown$nt(struct Fd *fd, int how) {
|
|
||||||
if (__shutdown$nt(fd->handle, how) != -1) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return __winsockerr();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disables sends or receives on a socket, without closing.
|
* Disables sends or receives on a socket, without closing.
|
||||||
*
|
*
|
||||||
|
@ -41,12 +32,7 @@ static int shutdown$nt(struct Fd *fd, int how) {
|
||||||
*/
|
*/
|
||||||
int shutdown(int fd, int how) {
|
int shutdown(int fd, int how) {
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
if (!IsXnu()) {
|
|
||||||
return shutdown$sysv(fd, how);
|
return shutdown$sysv(fd, how);
|
||||||
} else {
|
|
||||||
/* TODO(jart): What's wrong with XNU shutdown()? */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else if (__isfdkind(fd, kFdSocket)) {
|
} else if (__isfdkind(fd, kFdSocket)) {
|
||||||
return shutdown$nt(&g_fds.p[fd], how);
|
return shutdown$nt(&g_fds.p[fd], how);
|
||||||
} else {
|
} else {
|
||||||
|
|
27
libc/stdio/fbufsize.c
Normal file
27
libc/stdio/fbufsize.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*-*- 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/stdio/stdio_ext.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns capacity of stdio stream buffer.
|
||||||
|
*/
|
||||||
|
size_t __fbufsize(FILE *f) {
|
||||||
|
return f->size;
|
||||||
|
}
|
|
@ -23,22 +23,11 @@
|
||||||
#include "libc/macros.h"
|
#include "libc/macros.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/fflush.internal.h"
|
||||||
#include "libc/stdio/internal.h"
|
#include "libc/stdio/internal.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
struct StdioFlushHandles {
|
|
||||||
size_t i, n;
|
|
||||||
FILE **p;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StdioFlush {
|
|
||||||
struct StdioFlushHandles handles;
|
|
||||||
FILE *handles_initmem[8];
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct StdioFlush g_fflush;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocks until data from stream buffer is written out.
|
* Blocks until data from stream buffer is written out.
|
||||||
*
|
*
|
||||||
|
|
21
libc/stdio/fflush.internal.h
Normal file
21
libc/stdio/fflush.internal.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_STDIO_FFLUSH_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_STDIO_FFLUSH_H_
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
struct StdioFlushHandles {
|
||||||
|
size_t i, n;
|
||||||
|
FILE **p;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StdioFlush {
|
||||||
|
struct StdioFlushHandles handles;
|
||||||
|
FILE *handles_initmem[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct StdioFlush g_fflush;
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_STDIO_FFLUSH_H_ */
|
27
libc/stdio/flbf.c
Normal file
27
libc/stdio/flbf.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*-*- 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/stdio/stdio_ext.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns nonzero if stream is line buffered.
|
||||||
|
*/
|
||||||
|
int __flbf(FILE *f) {
|
||||||
|
return f->bufmode == _IOLBF;
|
||||||
|
}
|
33
libc/stdio/flushlbf.c
Normal file
33
libc/stdio/flushlbf.c
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*-*- 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/stdio/fflush.internal.h"
|
||||||
|
#include "libc/stdio/stdio_ext.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes all line-buffered streams.
|
||||||
|
*/
|
||||||
|
void _flushlbf(void) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < g_fflush.handles.i; ++i) {
|
||||||
|
if (g_fflush.handles.p[i]->bufmode == _IOLBF) {
|
||||||
|
fflush(g_fflush.handles.p[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
libc/stdio/fpending.c
Normal file
26
libc/stdio/fpending.c
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*-*- 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/stdio/stdio_ext.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns number of pending output bytes.
|
||||||
|
*/
|
||||||
|
size_t __fpending(FILE *f) {
|
||||||
|
return f->end - f->beg;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
/*-*- 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│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,8 +16,11 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/stdio/stdio_ext.h"
|
||||||
|
|
||||||
bool __isfdkind(int fd, enum FdKind kind) {
|
/**
|
||||||
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind == kind;
|
* Discards contents of stream buffer.
|
||||||
|
*/
|
||||||
|
void __fpurge(FILE *f) {
|
||||||
|
f->beg = f->end = 0;
|
||||||
}
|
}
|
28
libc/stdio/freadable.c
Normal file
28
libc/stdio/freadable.c
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*-*- 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/stdio/stdio_ext.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns nonzero if stream allows reading.
|
||||||
|
*/
|
||||||
|
int __freadable(FILE *f) {
|
||||||
|
return (f->iomode & O_ACCMODE) == O_RDONLY ||
|
||||||
|
(f->iomode & O_ACCMODE) == O_RDWR;
|
||||||
|
}
|
27
libc/stdio/freading.c
Normal file
27
libc/stdio/freading.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*-*- 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/stdio/stdio_ext.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns nonzero if stream is read only.
|
||||||
|
*/
|
||||||
|
int __freading(FILE *f) {
|
||||||
|
return (f->iomode & O_ACCMODE) == O_RDONLY;
|
||||||
|
}
|
|
@ -17,18 +17,9 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
|
||||||
#include "libc/dce.h"
|
|
||||||
#include "libc/errno.h"
|
|
||||||
#include "libc/nt/enum/accessmask.h"
|
|
||||||
#include "libc/nt/enum/fileflagandattributes.h"
|
|
||||||
#include "libc/nt/enum/filesharemode.h"
|
|
||||||
#include "libc/nt/files.h"
|
|
||||||
#include "libc/nt/runtime.h"
|
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/consts/f.h"
|
#include "libc/sysv/consts/f.h"
|
||||||
#include "libc/sysv/consts/fd.h"
|
#include "libc/sysv/consts/fd.h"
|
||||||
#include "libc/sysv/consts/fileno.h"
|
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,42 +43,16 @@ FILE *freopen(const char *pathname, const char *mode, FILE *stream) {
|
||||||
if (pathname) {
|
if (pathname) {
|
||||||
/* open new stream, overwriting existing alloc */
|
/* open new stream, overwriting existing alloc */
|
||||||
if ((fd = open(pathname, flags, 0666)) != -1) {
|
if ((fd = open(pathname, flags, 0666)) != -1) {
|
||||||
if (!IsWindows()) {
|
dup3(fd, stream->fd, flags & O_CLOEXEC);
|
||||||
dup3(fd, stream->fd, (flags & O_CLOEXEC));
|
|
||||||
close(fd);
|
close(fd);
|
||||||
} else {
|
|
||||||
g_fds.p[stream->fd].handle = g_fds.p[fd].handle;
|
|
||||||
g_fds.p[fd].kind = kFdEmpty;
|
|
||||||
}
|
|
||||||
stream->iomode = flags;
|
stream->iomode = flags;
|
||||||
return stream;
|
return stream;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* change mode of open file */
|
fcntl(stream->fd, F_SETFD, !!(flags & O_CLOEXEC));
|
||||||
if (!IsWindows()) {
|
fcntl(stream->fd, F_SETFL, flags & ~O_CLOEXEC);
|
||||||
if (flags & O_CLOEXEC) {
|
|
||||||
if (fcntl$sysv(stream->fd, F_SETFD, FD_CLOEXEC) == -1) return NULL;
|
|
||||||
flags &= ~O_CLOEXEC;
|
|
||||||
}
|
|
||||||
if (flags) {
|
|
||||||
if (fcntl$sysv(stream->fd, F_SETFL, flags) == -1) return NULL;
|
|
||||||
}
|
|
||||||
return stream;
|
return stream;
|
||||||
} else {
|
|
||||||
if (ReOpenFile(
|
|
||||||
stream->fd,
|
|
||||||
(flags & O_RDWR) == O_RDWR ? kNtGenericWrite : kNtGenericRead,
|
|
||||||
(flags & O_EXCL) == O_EXCL
|
|
||||||
? kNtFileShareExclusive
|
|
||||||
: kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
|
|
||||||
kNtFileAttributeNormal)) {
|
|
||||||
return stream;
|
|
||||||
} else {
|
|
||||||
__winerr();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
26
libc/stdio/fsetlocking.c
Normal file
26
libc/stdio/fsetlocking.c
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*-*- 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/stdio/stdio_ext.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing and returns `FSETLOCKING_BYCALLER`.
|
||||||
|
*/
|
||||||
|
int __fsetlocking(FILE *f, int type) {
|
||||||
|
return FSETLOCKING_BYCALLER;
|
||||||
|
}
|
28
libc/stdio/fwritable.c
Normal file
28
libc/stdio/fwritable.c
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*-*- 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/stdio/stdio_ext.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns nonzero if stream allows reading.
|
||||||
|
*/
|
||||||
|
int __fwritable(FILE *f) {
|
||||||
|
return (f->iomode & O_ACCMODE) == O_WRONLY ||
|
||||||
|
(f->iomode & O_ACCMODE) == O_RDWR;
|
||||||
|
}
|
27
libc/stdio/fwriting.c
Normal file
27
libc/stdio/fwriting.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*-*- 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/stdio/stdio_ext.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns nonzero if stream is write only.
|
||||||
|
*/
|
||||||
|
int __fwriting(FILE *f) {
|
||||||
|
return (f->iomode & O_ACCMODE) == O_WRONLY;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
/*-*- 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│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,8 +16,6 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/stdio/fflush.internal.h"
|
||||||
|
|
||||||
bool __isfdopen(int fd) {
|
struct StdioFlush g_fflush;
|
||||||
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty;
|
|
||||||
}
|
|
|
@ -17,6 +17,7 @@ int __fwritebuf(FILE *) hidden;
|
||||||
long __fseteof(FILE *) hidden;
|
long __fseteof(FILE *) hidden;
|
||||||
long __fseterrno(FILE *) hidden;
|
long __fseterrno(FILE *) hidden;
|
||||||
long __fseterr(FILE *, int) hidden;
|
long __fseterr(FILE *, int) hidden;
|
||||||
|
void __fclosepid(FILE *) hidden;
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
43
libc/stdio/pclose.c
Normal file
43
libc/stdio/pclose.c
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*-*- 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/calls/calls.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes stream created by popen().
|
||||||
|
* @return termination status of subprocess, or -1 w/ ECHILD
|
||||||
|
*/
|
||||||
|
int pclose(FILE *f) {
|
||||||
|
int ws, pid;
|
||||||
|
pid = f->pid;
|
||||||
|
fclose(f);
|
||||||
|
assert(pid);
|
||||||
|
if (!pid) return 0;
|
||||||
|
TryAgain:
|
||||||
|
if (wait4(pid, &ws, 0, 0) != -1) {
|
||||||
|
return ws;
|
||||||
|
} else if (errno == EINTR) {
|
||||||
|
goto TryAgain;
|
||||||
|
} else {
|
||||||
|
return echild();
|
||||||
|
}
|
||||||
|
}
|
57
libc/stdio/popen.c
Normal file
57
libc/stdio/popen.c
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/*-*- 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/errno.h"
|
||||||
|
#include "libc/paths.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/internal.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/sysv/consts/f.h"
|
||||||
|
#include "libc/sysv/consts/fd.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spawns subprocess and returns pipe stream.
|
||||||
|
* @see pclose()
|
||||||
|
*/
|
||||||
|
FILE *popen(const char *cmdline, const char *mode) {
|
||||||
|
FILE *f;
|
||||||
|
int dir, flags, pipefds[2];
|
||||||
|
flags = fopenflags(mode);
|
||||||
|
if ((flags & O_ACCMODE) == O_RDONLY) {
|
||||||
|
dir = 0;
|
||||||
|
} else if ((flags & O_ACCMODE) == O_WRONLY) {
|
||||||
|
dir = 1;
|
||||||
|
} else {
|
||||||
|
errno = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (pipe(pipefds) == -1) return NULL;
|
||||||
|
fcntl(pipefds[dir], F_SETFD, FD_CLOEXEC);
|
||||||
|
if (!(f = fdopen(pipefds[dir], mode))) abort();
|
||||||
|
if ((f->pid = vfork()) == -1) abort();
|
||||||
|
if (!f->pid) {
|
||||||
|
dup2(pipefds[!dir], !dir);
|
||||||
|
systemexec(cmdline);
|
||||||
|
_exit(127);
|
||||||
|
}
|
||||||
|
close(pipefds[!dir]);
|
||||||
|
return f;
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ typedef struct FILE {
|
||||||
uint32_t nofree; // 0x24
|
uint32_t nofree; // 0x24
|
||||||
int (*reader)(struct FILE *); // 0x28
|
int (*reader)(struct FILE *); // 0x28
|
||||||
int (*writer)(struct FILE *); // 0x30
|
int (*writer)(struct FILE *); // 0x30
|
||||||
|
int pid; // 0x34
|
||||||
} FILE;
|
} FILE;
|
||||||
|
|
||||||
extern FILE *stdin;
|
extern FILE *stdin;
|
||||||
|
@ -69,6 +70,8 @@ unsigned favail(FILE *);
|
||||||
void setbuf(FILE *, char *);
|
void setbuf(FILE *, char *);
|
||||||
void setbuffer(FILE *, char *, size_t);
|
void setbuffer(FILE *, char *, size_t);
|
||||||
int setvbuf(FILE *, char *, int, size_t);
|
int setvbuf(FILE *, char *, int, size_t);
|
||||||
|
FILE *popen(const char *, const char *);
|
||||||
|
int pclose(FILE *);
|
||||||
|
|
||||||
typedef uint64_t fpos_t;
|
typedef uint64_t fpos_t;
|
||||||
compatfn char *gets(char *) paramsnonnull();
|
compatfn char *gets(char *) paramsnonnull();
|
||||||
|
@ -78,6 +81,7 @@ compatfn int64_t fseeko(FILE *, long, int) paramsnonnull();
|
||||||
compatfn int64_t ftello(FILE *) paramsnonnull();
|
compatfn int64_t ftello(FILE *) paramsnonnull();
|
||||||
|
|
||||||
int system(const char *);
|
int system(const char *);
|
||||||
|
int systemexec(const char *);
|
||||||
int systemecho(const char *);
|
int systemecho(const char *);
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
|
|
25
libc/stdio/stdio_ext.h
Normal file
25
libc/stdio/stdio_ext.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_STDIO_STDIO_EXT_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_STDIO_STDIO_EXT_H_
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
|
#define FSETLOCKING_QUERY 0
|
||||||
|
#define FSETLOCKING_INTERNAL 1
|
||||||
|
#define FSETLOCKING_BYCALLER 2
|
||||||
|
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
size_t __fbufsize(FILE *);
|
||||||
|
size_t __fpending(FILE *);
|
||||||
|
int __flbf(FILE *);
|
||||||
|
int __freadable(FILE *);
|
||||||
|
int __fwritable(FILE *);
|
||||||
|
int __freading(FILE *);
|
||||||
|
int __fwriting(FILE *);
|
||||||
|
int __fsetlocking(FILE *, int);
|
||||||
|
void _flushlbf(void);
|
||||||
|
void __fpurge(FILE *);
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_STDIO_STDIO_EXT_H_ */
|
|
@ -18,12 +18,15 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/sigbits.h"
|
||||||
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/paths.h"
|
#include "libc/paths.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launches program with system command interpreter.
|
* Launches program with system command interpreter.
|
||||||
|
@ -34,26 +37,36 @@
|
||||||
*/
|
*/
|
||||||
int system(const char *cmdline) {
|
int system(const char *cmdline) {
|
||||||
int pid, wstatus;
|
int pid, wstatus;
|
||||||
char comspec[128];
|
sigset_t chldmask, savemask;
|
||||||
const char *prog, *arg;
|
struct sigaction ignore, saveint, savequit;
|
||||||
if (weaken(fflush)) weaken(fflush)(NULL);
|
if (!cmdline) return 1;
|
||||||
if (cmdline) {
|
ignore.sa_flags = 0;
|
||||||
if ((pid = vfork()) == -1) return -1;
|
ignore.sa_handler = SIG_IGN;
|
||||||
|
sigemptyset(&ignore.sa_mask);
|
||||||
|
sigaction(SIGINT, &ignore, &saveint);
|
||||||
|
sigaction(SIGQUIT, &ignore, &savequit);
|
||||||
|
sigemptyset(&chldmask);
|
||||||
|
sigaddset(&chldmask, SIGCHLD);
|
||||||
|
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
||||||
|
pid = fork();
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
strcpy(comspec, kNtSystemDirectory);
|
sigaction(SIGINT, &saveint, NULL);
|
||||||
strcat(comspec, "cmd.exe");
|
sigaction(SIGQUIT, &savequit, NULL);
|
||||||
prog = !IsWindows() ? _PATH_BSHELL : comspec;
|
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||||
arg = !IsWindows() ? "-c" : "/C";
|
systemexec(cmdline);
|
||||||
execv(prog, (char *const[]){prog, arg, cmdline, NULL});
|
_exit(127);
|
||||||
_exit(errno);
|
} else if (pid != -1) {
|
||||||
} else if (wait4(pid, &wstatus, 0, NULL) != -1) {
|
while (wait4(pid, &wstatus, 0, NULL) == -1) {
|
||||||
|
if (errno != EINTR) {
|
||||||
|
wstatus = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wstatus = -1;
|
||||||
|
}
|
||||||
|
sigaction(SIGINT, &saveint, NULL);
|
||||||
|
sigaction(SIGQUIT, &savequit, NULL);
|
||||||
|
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||||
return wstatus;
|
return wstatus;
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else if (IsWindows()) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return fileexists(_PATH_BSHELL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
38
libc/stdio/systemexec.c
Normal file
38
libc/stdio/systemexec.c
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*-*- 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/dce.h"
|
||||||
|
#include "libc/paths.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes system command replacing current process.
|
||||||
|
* @vforksafe
|
||||||
|
*/
|
||||||
|
int systemexec(const char *cmdline) {
|
||||||
|
char comspec[128];
|
||||||
|
const char *prog, *arg;
|
||||||
|
strcpy(comspec, kNtSystemDirectory);
|
||||||
|
strcat(comspec, "cmd.exe");
|
||||||
|
prog = !IsWindows() ? _PATH_BSHELL : comspec;
|
||||||
|
arg = !IsWindows() ? "-c" : "/C";
|
||||||
|
return execv(prog, (char *const[]){prog, arg, cmdline, NULL});
|
||||||
|
}
|
33
libc/str/iconv.c
Normal file
33
libc/str/iconv.c
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*-*- 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/str/str.h"
|
||||||
|
|
||||||
|
typedef void *iconv_t;
|
||||||
|
|
||||||
|
iconv_t iconv_open(const char *to, const char *from) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iconv_close(iconv_t cd) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t iconv(iconv_t cd, char **in, size_t *inb, char **out, size_t *outb) {
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -169,6 +169,7 @@ bool endswith(const char *, const char *) strlenesque;
|
||||||
bool endswith16(const char16_t *, const char16_t *) strlenesque;
|
bool endswith16(const char16_t *, const char16_t *) strlenesque;
|
||||||
bool wcsendswith(const wchar_t *, const wchar_t *) strlenesque;
|
bool wcsendswith(const wchar_t *, const wchar_t *) strlenesque;
|
||||||
const char *IndexDoubleNulString(const char *, unsigned) strlenesque;
|
const char *IndexDoubleNulString(const char *, unsigned) strlenesque;
|
||||||
|
int strverscmp(const char *, const char *);
|
||||||
wchar_t *wmemset(wchar_t *, wchar_t, size_t) memcpyesque;
|
wchar_t *wmemset(wchar_t *, wchar_t, size_t) memcpyesque;
|
||||||
char16_t *memset16(char16_t *, char16_t, size_t) memcpyesque;
|
char16_t *memset16(char16_t *, char16_t, size_t) memcpyesque;
|
||||||
compatfn wchar_t *wmemcpy(wchar_t *, const wchar_t *, size_t) memcpyesque;
|
compatfn wchar_t *wmemcpy(wchar_t *, const wchar_t *, size_t) memcpyesque;
|
||||||
|
|
71
libc/str/strverscmp.c
Normal file
71
libc/str/strverscmp.c
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/*-*- 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│
|
||||||
|
╚──────────────────────────────────────────────────────────────────────────────╝
|
||||||
|
│ │
|
||||||
|
│ Musl Libc │
|
||||||
|
│ Copyright © 2005-2014 Rich Felker, et al. │
|
||||||
|
│ │
|
||||||
|
│ Permission is hereby granted, free of charge, to any person obtaining │
|
||||||
|
│ a copy of this software and associated documentation files (the │
|
||||||
|
│ "Software"), to deal in the Software without restriction, including │
|
||||||
|
│ without limitation the rights to use, copy, modify, merge, publish, │
|
||||||
|
│ distribute, sublicense, and/or sell copies of the Software, and to │
|
||||||
|
│ permit persons to whom the Software is furnished to do so, subject to │
|
||||||
|
│ the following conditions: │
|
||||||
|
│ │
|
||||||
|
│ The above copyright notice and this permission notice shall be │
|
||||||
|
│ included in all copies or substantial portions of the Software. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||||
|
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||||
|
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||||
|
│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │
|
||||||
|
│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │
|
||||||
|
│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │
|
||||||
|
│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
|
||||||
|
│ │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
asm(".ident\t\"\\n\\n\
|
||||||
|
Musl libc (MIT License)\\n\
|
||||||
|
Copyright 2005-2014 Rich Felker, et. al.\"");
|
||||||
|
asm(".include \"libc/disclaimer.inc\"");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two version strings.
|
||||||
|
*/
|
||||||
|
int strverscmp(const char *l0, const char *r0) {
|
||||||
|
const unsigned char *l = (const void *)l0;
|
||||||
|
const unsigned char *r = (const void *)r0;
|
||||||
|
size_t i, dp, j;
|
||||||
|
int z = 1;
|
||||||
|
/* Find maximal matching prefix and track its maximal digit
|
||||||
|
* suffix and whether those digits are all zeros. */
|
||||||
|
for (dp = i = 0; l[i] == r[i]; i++) {
|
||||||
|
int c = l[i];
|
||||||
|
if (!c) return 0;
|
||||||
|
if (!isdigit(c)) {
|
||||||
|
dp = i + 1, z = 1;
|
||||||
|
} else if (c != '0') {
|
||||||
|
z = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (l[dp] != '0' && r[dp] != '0') {
|
||||||
|
/* If we're not looking at a digit sequence that began
|
||||||
|
* with a zero, longest digit string is greater. */
|
||||||
|
for (j = i; isdigit(l[j]); j++) {
|
||||||
|
if (!isdigit(r[j])) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isdigit(r[j])) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (z && dp < i && (isdigit(l[i]) || isdigit(r[i]))) {
|
||||||
|
/* Otherwise, if common prefix of digit sequence is
|
||||||
|
* all zeros, digits order less than non-digits. */
|
||||||
|
return (unsigned char)(l[i] - '0') - (unsigned char)(r[i] - '0');
|
||||||
|
}
|
||||||
|
return l[i] - r[i];
|
||||||
|
}
|
|
@ -180,21 +180,21 @@ syscon sig SIGXFSZ 25 25 25 25 25 # unix consensus & faked on nt
|
||||||
syscon sig SIGVTALRM 26 26 26 26 26 # unix consensus & faked on nt
|
syscon sig SIGVTALRM 26 26 26 26 26 # unix consensus & faked on nt
|
||||||
syscon sig SIGPROF 27 27 27 27 27 # unix consensus & faked on nt
|
syscon sig SIGPROF 27 27 27 27 27 # unix consensus & faked on nt
|
||||||
syscon sig SIGWINCH 28 28 28 28 28 # unix consensus & faked on nt
|
syscon sig SIGWINCH 28 28 28 28 28 # unix consensus & faked on nt
|
||||||
syscon sig SIGBUS 7 10 10 10 0 # bsd consensus
|
syscon sig SIGBUS 7 10 10 10 7 # bsd consensus
|
||||||
syscon sig SIGUSR1 10 30 30 30 0 # bsd consensus
|
syscon sig SIGUSR1 10 30 30 30 10 # bsd consensus
|
||||||
syscon sig SIGCHLD 17 20 20 20 0 # bsd consensus
|
syscon sig SIGCHLD 17 20 20 20 17 # bsd consensus
|
||||||
syscon sig SIGCONT 18 19 19 19 0 # bsd consensus
|
syscon sig SIGCONT 18 19 19 19 18 # bsd consensus
|
||||||
syscon sig SIGIO 29 23 23 23 0 # bsd consensus
|
syscon sig SIGIO 29 23 23 23 29 # bsd consensus
|
||||||
syscon sig SIGSTOP 19 17 17 17 0 # bsd consensus
|
syscon sig SIGSTOP 19 17 17 17 19 # bsd consensus
|
||||||
syscon sig SIGSYS 31 12 12 12 0 # bsd consensus
|
syscon sig SIGSYS 31 12 12 12 31 # bsd consensus
|
||||||
syscon sig SIGTSTP 20 18 18 18 0 # bsd consensus
|
syscon sig SIGTSTP 20 18 18 18 20 # bsd consensus
|
||||||
syscon sig SIGURG 23 0x10 0x10 0x10 0 # bsd consensus
|
syscon sig SIGURG 23 0x10 0x10 0x10 23 # bsd consensus
|
||||||
syscon sig SIGUSR2 12 31 31 31 0 # bsd consensus
|
syscon sig SIGUSR2 12 31 31 31 12 # bsd consensus
|
||||||
syscon sig SIGSTKSZ 0x2000 0x020000 0x8800 0x7000 0
|
syscon sig SIGSTKSZ 0x2000 0x020000 0x8800 0x7000 0x2000
|
||||||
syscon sig SIGPOLL 29 0 0 0 0
|
syscon sig SIGPOLL 29 0 0 0 29
|
||||||
syscon sig SIGPWR 30 0 0 0 0
|
syscon sig SIGPWR 30 0 0 0 30
|
||||||
syscon sig SIGSTKFLT 0x10 0 0 0 0
|
syscon sig SIGSTKFLT 0x10 0 0 0 0x10
|
||||||
syscon sig SIGUNUSED 31 0 0 0 0
|
syscon sig SIGUNUSED 31 0 0 0 31
|
||||||
syscon sig SIGRTMAX 0 0 126 0 0
|
syscon sig SIGRTMAX 0 0 126 0 0
|
||||||
syscon sig SIGRTMIN 0 0 65 0 0
|
syscon sig SIGRTMIN 0 0 65 0 0
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGBUS 7 10 10 10 0
|
.syscon sig SIGBUS 7 10 10 10 7
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGCHLD 17 20 20 20 0
|
.syscon sig SIGCHLD 17 20 20 20 17
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGCONT 18 19 19 19 0
|
.syscon sig SIGCONT 18 19 19 19 18
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGIO 29 23 23 23 0
|
.syscon sig SIGIO 29 23 23 23 29
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGPOLL 29 0 0 0 0
|
.syscon sig SIGPOLL 29 0 0 0 29
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGPWR 30 0 0 0 0
|
.syscon sig SIGPWR 30 0 0 0 30
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGSTKFLT 0x10 0 0 0 0
|
.syscon sig SIGSTKFLT 0x10 0 0 0 0x10
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGSTKSZ 0x2000 0x020000 0x8800 0x7000 0
|
.syscon sig SIGSTKSZ 0x2000 0x020000 0x8800 0x7000 0x2000
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGSTOP 19 17 17 17 0
|
.syscon sig SIGSTOP 19 17 17 17 19
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGSYS 31 12 12 12 0
|
.syscon sig SIGSYS 31 12 12 12 31
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGTSTP 20 18 18 18 0
|
.syscon sig SIGTSTP 20 18 18 18 20
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGUNUSED 31 0 0 0 0
|
.syscon sig SIGUNUSED 31 0 0 0 31
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGURG 23 0x10 0x10 0x10 0
|
.syscon sig SIGURG 23 0x10 0x10 0x10 23
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGUSR1 10 30 30 30 0
|
.syscon sig SIGUSR1 10 30 30 30 10
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon sig SIGUSR2 12 31 31 31 0
|
.syscon sig SIGUSR2 12 31 31 31 12
|
||||||
|
|
|
@ -30,8 +30,6 @@
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
STATIC_YOINK("__isfdkind");
|
|
||||||
|
|
||||||
const char *testlib_showerror_errno;
|
const char *testlib_showerror_errno;
|
||||||
const char *testlib_showerror_file;
|
const char *testlib_showerror_file;
|
||||||
const char *testlib_showerror_func;
|
const char *testlib_showerror_func;
|
||||||
|
@ -85,9 +83,10 @@ testonly void testlib_showerror_(int line, const char *wantcode,
|
||||||
strcpy(hostname, "unknown");
|
strcpy(hostname, "unknown");
|
||||||
gethostname(hostname, sizeof(hostname));
|
gethostname(hostname, sizeof(hostname));
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"\t%s%s\n"
|
"\t%s%s%s\n"
|
||||||
"\t%s @ %s%s\n",
|
"\t%s%s @ %s%s\n",
|
||||||
SUBTLE, strerror(err), program_invocation_name, hostname, RESET);
|
SUBTLE, strerror(err), RESET, SUBTLE, program_invocation_name,
|
||||||
|
hostname, RESET);
|
||||||
|
|
||||||
free_s(&FREED_want);
|
free_s(&FREED_want);
|
||||||
free_s(&FREED_got);
|
free_s(&FREED_got);
|
||||||
|
|
|
@ -20,4 +20,12 @@
|
||||||
|
|
||||||
static char g_asctime_buf[64];
|
static char g_asctime_buf[64];
|
||||||
|
|
||||||
char *asctime(const struct tm *date) { return asctime_r(date, g_asctime_buf); }
|
/**
|
||||||
|
* Converts date time to string.
|
||||||
|
*
|
||||||
|
* @return date time string in statically allocated buffer
|
||||||
|
* @see asctime_r for reentrant version
|
||||||
|
*/
|
||||||
|
char *asctime(const struct tm *date) {
|
||||||
|
return asctime_r(date, g_asctime_buf);
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,13 @@ static unsigned clip(unsigned index, unsigned count) {
|
||||||
return index < count ? index : 0;
|
return index < count ? index : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts date time to string.
|
||||||
|
*
|
||||||
|
* @param buf needs to have 64 bytes
|
||||||
|
* @return pointer to buf
|
||||||
|
* @see asctime_r for reentrant version
|
||||||
|
*/
|
||||||
char *asctime_r(const struct tm *date, char buf[hasatleast 64]) {
|
char *asctime_r(const struct tm *date, char buf[hasatleast 64]) {
|
||||||
(snprintf)(buf, 64, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
|
(snprintf)(buf, 64, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
|
||||||
kWeekdayNameShort[clip(date->tm_wday, 7)],
|
kWeekdayNameShort[clip(date->tm_wday, 7)],
|
||||||
|
|
|
@ -33,14 +33,18 @@ TEST(vfork, test) {
|
||||||
ASSERT_NE(-1, lseek(fd, 0, SEEK_SET));
|
ASSERT_NE(-1, lseek(fd, 0, SEEK_SET));
|
||||||
if (!vfork()) {
|
if (!vfork()) {
|
||||||
EXPECT_EQ(5, pread(fd, buf, 5, 0));
|
EXPECT_EQ(5, pread(fd, buf, 5, 0));
|
||||||
|
/*
|
||||||
|
* TODO(jart): DOES PREAD IN CHILD REALLY CHANGE PARENT HANDLE POSITION?
|
||||||
|
*/
|
||||||
|
ASSERT_NE(-1, lseek(fd, 0, SEEK_SET));
|
||||||
EXPECT_STREQ("hello", buf);
|
EXPECT_STREQ("hello", buf);
|
||||||
EXPECT_NE(-1, close(fd));
|
EXPECT_NE(-1, close(fd));
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
EXPECT_EQ(0, __vforked);
|
EXPECT_EQ(0, __vforked);
|
||||||
|
EXPECT_NE(-1, wait(0));
|
||||||
EXPECT_EQ(5, read(fd, buf, 5));
|
EXPECT_EQ(5, read(fd, buf, 5));
|
||||||
EXPECT_STREQ("hello", buf);
|
EXPECT_STREQ("hello", buf);
|
||||||
EXPECT_NE(-1, close(fd));
|
EXPECT_NE(-1, close(fd));
|
||||||
EXPECT_NE(-1, wait(0));
|
|
||||||
unlink(PATH);
|
unlink(PATH);
|
||||||
}
|
}
|
||||||
|
|
63
test/libc/calls/sigaction_test.c
Normal file
63
test/libc/calls/sigaction_test.c
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*-*- 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/sigbits.h"
|
||||||
|
#include "libc/calls/struct/sigaction.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/sysv/consts/sa.h"
|
||||||
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
|
bool gotsigint;
|
||||||
|
|
||||||
|
void OnSigInt(int sig) {
|
||||||
|
gotsigint = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(sigaction, test) {
|
||||||
|
/* TODO(jart): Why does RHEL5 behave differently? */
|
||||||
|
/* TODO(jart): Windows needs huge signal overhaul */
|
||||||
|
if (IsWindows()) return;
|
||||||
|
int pid, status;
|
||||||
|
sigset_t block, ignore, oldmask;
|
||||||
|
struct sigaction saint = {.sa_handler = OnSigInt};
|
||||||
|
sigemptyset(&block);
|
||||||
|
sigaddset(&block, SIGINT);
|
||||||
|
EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &block, &oldmask));
|
||||||
|
sigfillset(&ignore);
|
||||||
|
sigdelset(&ignore, SIGINT);
|
||||||
|
EXPECT_NE(-1, sigaction(SIGINT, &saint, NULL));
|
||||||
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
|
if (!pid) {
|
||||||
|
EXPECT_NE(-1, kill(getppid(), SIGINT));
|
||||||
|
EXPECT_EQ(-1, sigsuspend(&ignore));
|
||||||
|
EXPECT_EQ(EINTR, errno);
|
||||||
|
EXPECT_TRUE(gotsigint);
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
EXPECT_EQ(-1, sigsuspend(&ignore));
|
||||||
|
EXPECT_NE(-1, kill(pid, SIGINT));
|
||||||
|
EXPECT_NE(-1, waitpid(pid, &status, 0));
|
||||||
|
EXPECT_EQ(1, WIFEXITED(status));
|
||||||
|
EXPECT_EQ(0, WEXITSTATUS(status));
|
||||||
|
EXPECT_EQ(0, WTERMSIG(status));
|
||||||
|
EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &oldmask, NULL));
|
||||||
|
}
|
34
test/libc/stdio/popen_test.c
Normal file
34
test/libc/stdio/popen_test.c
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*-*- 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/log/check.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
|
TEST(popen, test) {
|
||||||
|
int ws;
|
||||||
|
FILE *f;
|
||||||
|
f = popen("echo hi", "r");
|
||||||
|
ASSERT_NE(NULL, f);
|
||||||
|
EXPECT_EQ('h', fgetc(f));
|
||||||
|
EXPECT_EQ('i', fgetc(f));
|
||||||
|
ws = pclose(f);
|
||||||
|
EXPECT_NE(-1, ws);
|
||||||
|
EXPECT_TRUE(WIFEXITED(ws));
|
||||||
|
EXPECT_EQ(0, WEXITSTATUS(ws));
|
||||||
|
}
|
3
third_party/chibicc/chibicc.c
vendored
3
third_party/chibicc/chibicc.c
vendored
|
@ -1,5 +1,6 @@
|
||||||
#include "libc/calls/struct/siginfo.h"
|
#include "libc/calls/struct/siginfo.h"
|
||||||
#include "libc/calls/ucontext.h"
|
#include "libc/calls/ucontext.h"
|
||||||
|
#include "libc/x/x.h"
|
||||||
#include "third_party/chibicc/chibicc.h"
|
#include "third_party/chibicc/chibicc.h"
|
||||||
|
|
||||||
asm(".ident\t\"\\n\\n\
|
asm(".ident\t\"\\n\\n\
|
||||||
|
@ -606,7 +607,7 @@ static void run_linker(StringArray *inputs, char *output) {
|
||||||
strarray_push(&arr, "--gc-sections");
|
strarray_push(&arr, "--gc-sections");
|
||||||
strarray_push(&arr, "--build-id=none");
|
strarray_push(&arr, "--build-id=none");
|
||||||
strarray_push(&arr, "--no-dynamic-linker");
|
strarray_push(&arr, "--no-dynamic-linker");
|
||||||
strarray_push(&arr, "-Ttext-segment=0x400000");
|
strarray_push(&arr, xasprintf("-Ttext-segment=%#x", IMAGE_BASE_VIRTUAL));
|
||||||
strarray_push(&arr, "-T");
|
strarray_push(&arr, "-T");
|
||||||
strarray_push(&arr, LDS);
|
strarray_push(&arr, LDS);
|
||||||
strarray_push(&arr, APE);
|
strarray_push(&arr, APE);
|
||||||
|
|
3
third_party/chibicc/chibicc.mk
vendored
3
third_party/chibicc/chibicc.mk
vendored
|
@ -14,7 +14,8 @@ CHIBICC = o/$(MODE)/third_party/chibicc/chibicc.com.dbg
|
||||||
CHIBICC2 = o/$(MODE)/third_party/chibicc/chibicc2.com.dbg
|
CHIBICC2 = o/$(MODE)/third_party/chibicc/chibicc2.com.dbg
|
||||||
CHIBICC_FLAGS = \
|
CHIBICC_FLAGS = \
|
||||||
-fno-common \
|
-fno-common \
|
||||||
-include libc/integral/normalize.inc
|
-include libc/integral/normalize.inc \
|
||||||
|
-DIMAGE_BASE_VIRTUAL=$(IMAGE_BASE_VIRTUAL)
|
||||||
|
|
||||||
PKGS += THIRD_PARTY_CHIBICC
|
PKGS += THIRD_PARTY_CHIBICC
|
||||||
THIRD_PARTY_CHIBICC_ARTIFACTS += THIRD_PARTY_CHIBICC_A
|
THIRD_PARTY_CHIBICC_ARTIFACTS += THIRD_PARTY_CHIBICC_A
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/bits/safemacros.h"
|
#include "libc/bits/safemacros.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/calls/struct/flock.h"
|
#include "libc/calls/struct/flock.h"
|
||||||
#include "libc/calls/struct/itimerval.h"
|
#include "libc/calls/struct/itimerval.h"
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
|
@ -119,7 +120,7 @@ char g_hostname[128];
|
||||||
uint16_t g_runitdport;
|
uint16_t g_runitdport;
|
||||||
volatile bool alarmed;
|
volatile bool alarmed;
|
||||||
|
|
||||||
static void OnAlarm(void) {
|
static void OnAlarm(int sig) {
|
||||||
alarmed = true;
|
alarmed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +171,9 @@ void DeployEphemeralRunItDaemonRemotelyViaSsh(struct addrinfo *ai) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char linebuf[32];
|
char linebuf[32];
|
||||||
struct timeval now, then;
|
struct timeval now, then;
|
||||||
|
sigset_t chldmask, savemask;
|
||||||
int sshpid, wstatus, binfd, pipefds[2][2];
|
int sshpid, wstatus, binfd, pipefds[2][2];
|
||||||
|
struct sigaction ignore, saveint, savequit;
|
||||||
mkdir("o", 0755);
|
mkdir("o", 0755);
|
||||||
CHECK_NE(-1, (lock = open(gc(xasprintf("o/lock.%s", g_hostname)),
|
CHECK_NE(-1, (lock = open(gc(xasprintf("o/lock.%s", g_hostname)),
|
||||||
O_RDWR | O_CREAT, 0644)));
|
O_RDWR | O_CREAT, 0644)));
|
||||||
|
@ -179,7 +182,7 @@ void DeployEphemeralRunItDaemonRemotelyViaSsh(struct addrinfo *ai) {
|
||||||
if (!read(lock, &then, 16) || ((now.tv_sec * 1000 + now.tv_usec / 1000) -
|
if (!read(lock, &then, 16) || ((now.tv_sec * 1000 + now.tv_usec / 1000) -
|
||||||
(then.tv_sec * 1000 + then.tv_usec / 1000)) >=
|
(then.tv_sec * 1000 + then.tv_usec / 1000)) >=
|
||||||
(RUNITD_TIMEOUT_MS >> 1)) {
|
(RUNITD_TIMEOUT_MS >> 1)) {
|
||||||
DEBUGF("spawning %s on %s:%hu", g_runitd, g_hostname, g_runitdport);
|
DEBUGF("ssh %s:%hu to spawn %s", g_hostname, g_runitdport, g_runitd);
|
||||||
CHECK_NE(-1, (binfd = open(g_runitd, O_RDONLY | O_CLOEXEC)));
|
CHECK_NE(-1, (binfd = open(g_runitd, O_RDONLY | O_CLOEXEC)));
|
||||||
CHECK_NE(-1, fstat(binfd, &st));
|
CHECK_NE(-1, fstat(binfd, &st));
|
||||||
args[0] = "ssh";
|
args[0] = "ssh";
|
||||||
|
@ -189,16 +192,28 @@ void DeployEphemeralRunItDaemonRemotelyViaSsh(struct addrinfo *ai) {
|
||||||
args[4] = g_hostname;
|
args[4] = g_hostname;
|
||||||
args[5] = gc(MakeDeployScript(ai, st.st_size));
|
args[5] = gc(MakeDeployScript(ai, st.st_size));
|
||||||
args[6] = NULL;
|
args[6] = NULL;
|
||||||
|
ignore.sa_flags = 0;
|
||||||
|
ignore.sa_handler = SIG_IGN;
|
||||||
|
LOGIFNEG1(sigemptyset(&ignore.sa_mask));
|
||||||
|
LOGIFNEG1(sigaction(SIGINT, &ignore, &saveint));
|
||||||
|
LOGIFNEG1(sigaction(SIGQUIT, &ignore, &savequit));
|
||||||
|
LOGIFNEG1(sigemptyset(&chldmask));
|
||||||
|
LOGIFNEG1(sigaddset(&chldmask, SIGCHLD));
|
||||||
|
LOGIFNEG1(sigprocmask(SIG_BLOCK, &chldmask, &savemask));
|
||||||
CHECK_NE(-1, pipe2(pipefds[0], O_CLOEXEC));
|
CHECK_NE(-1, pipe2(pipefds[0], O_CLOEXEC));
|
||||||
CHECK_NE(-1, pipe2(pipefds[1], O_CLOEXEC));
|
CHECK_NE(-1, pipe2(pipefds[1], O_CLOEXEC));
|
||||||
if (!(sshpid = vfork())) {
|
CHECK_NE(-1, (sshpid = fork()));
|
||||||
|
if (!sshpid) {
|
||||||
|
sigaction(SIGINT, &saveint, NULL);
|
||||||
|
sigaction(SIGQUIT, &savequit, NULL);
|
||||||
|
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||||
dup2(pipefds[0][0], 0);
|
dup2(pipefds[0][0], 0);
|
||||||
dup2(pipefds[1][1], 1);
|
dup2(pipefds[1][1], 1);
|
||||||
execv(g_ssh, args);
|
execv(g_ssh, args);
|
||||||
abort();
|
_exit(127);
|
||||||
}
|
}
|
||||||
close(pipefds[0][0]);
|
LOGIFNEG1(close(pipefds[0][0]));
|
||||||
close(pipefds[1][1]);
|
LOGIFNEG1(close(pipefds[1][1]));
|
||||||
Upload(pipefds[0][1], binfd, &st);
|
Upload(pipefds[0][1], binfd, &st);
|
||||||
LOGIFNEG1(close(pipefds[0][1]));
|
LOGIFNEG1(close(pipefds[0][1]));
|
||||||
CHECK_NE(-1, (got = read(pipefds[1][0], linebuf, sizeof(linebuf))));
|
CHECK_NE(-1, (got = read(pipefds[1][0], linebuf, sizeof(linebuf))));
|
||||||
|
@ -212,7 +227,16 @@ void DeployEphemeralRunItDaemonRemotelyViaSsh(struct addrinfo *ai) {
|
||||||
g_runitdport = (uint16_t)atoi(&linebuf[6]);
|
g_runitdport = (uint16_t)atoi(&linebuf[6]);
|
||||||
LOGIFNEG1(close(pipefds[1][0]));
|
LOGIFNEG1(close(pipefds[1][0]));
|
||||||
CHECK_NE(-1, waitpid(sshpid, &wstatus, 0));
|
CHECK_NE(-1, waitpid(sshpid, &wstatus, 0));
|
||||||
CHECK_EQ(0, WEXITSTATUS(wstatus));
|
LOGIFNEG1(sigaction(SIGINT, &saveint, NULL));
|
||||||
|
LOGIFNEG1(sigaction(SIGQUIT, &savequit, NULL));
|
||||||
|
LOGIFNEG1(sigprocmask(SIG_SETMASK, &savemask, NULL));
|
||||||
|
if (WIFEXITED(wstatus)) {
|
||||||
|
DEBUGF("ssh %s exited with %d", g_hostname, WEXITSTATUS(wstatus));
|
||||||
|
} else {
|
||||||
|
DEBUGF("ssh %s terminated with %s", g_hostname,
|
||||||
|
strsignal(WTERMSIG(wstatus)));
|
||||||
|
}
|
||||||
|
CHECK(WIFEXITED(wstatus) && !WEXITSTATUS(wstatus), "wstatus=%#x", wstatus);
|
||||||
CHECK_NE(-1, gettimeofday(&now, 0));
|
CHECK_NE(-1, gettimeofday(&now, 0));
|
||||||
CHECK_NE(-1, lseek(lock, 0, SEEK_SET));
|
CHECK_NE(-1, lseek(lock, 0, SEEK_SET));
|
||||||
CHECK_NE(-1, write(lock, &now, 16));
|
CHECK_NE(-1, write(lock, &now, 16));
|
||||||
|
@ -223,7 +247,11 @@ void DeployEphemeralRunItDaemonRemotelyViaSsh(struct addrinfo *ai) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDeadline(int micros) {
|
void SetDeadline(int micros) {
|
||||||
setitimer(ITIMER_REAL, &(const struct itimerval){{0, 0}, {0, micros}}, NULL);
|
alarmed = false;
|
||||||
|
LOGIFNEG1(
|
||||||
|
sigaction(SIGALRM, &(struct sigaction){.sa_handler = OnAlarm}, NULL));
|
||||||
|
LOGIFNEG1(setitimer(ITIMER_REAL,
|
||||||
|
&(const struct itimerval){{0, 0}, {0, micros}}, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connect(void) {
|
void Connect(void) {
|
||||||
|
@ -242,28 +270,32 @@ void Connect(void) {
|
||||||
g_hostname, ip4[0], ip4[1], ip4[2], ip4[3]);
|
g_hostname, ip4[0], ip4[1], ip4[2], ip4[3]);
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
DEBUGF("connecting to %s (%hhu.%hhu.%hhu.%hhu) to run %s", g_hostname, ip4[0],
|
|
||||||
ip4[1], ip4[2], ip4[3], g_prog);
|
|
||||||
CHECK_NE(-1,
|
CHECK_NE(-1,
|
||||||
(g_sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)));
|
(g_sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)));
|
||||||
expo = 1;
|
expo = 1;
|
||||||
TryAgain:
|
Reconnect:
|
||||||
alarmed = false;
|
DEBUGF("connecting to %s (%hhu.%hhu.%hhu.%hhu) to run %s", g_hostname, ip4[0],
|
||||||
|
ip4[1], ip4[2], ip4[3], g_prog);
|
||||||
SetDeadline(100000);
|
SetDeadline(100000);
|
||||||
|
TryAgain:
|
||||||
rc = connect(g_sock, ai->ai_addr, ai->ai_addrlen);
|
rc = connect(g_sock, ai->ai_addr, ai->ai_addrlen);
|
||||||
err = errno;
|
err = errno;
|
||||||
SetDeadline(0);
|
SetDeadline(0);
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
if ((err == ECONNREFUSED || err == EHOSTUNREACH || err == ECONNRESET ||
|
if (err == EINTR) goto TryAgain;
|
||||||
err == EINTR)) {
|
if (err == ECONNREFUSED || err == EHOSTUNREACH || err == ECONNRESET) {
|
||||||
|
DEBUGF("got %s from %s (%hhu.%hhu.%hhu.%hhu)", strerror(err), g_hostname,
|
||||||
|
ip4[0], ip4[1], ip4[2], ip4[3]);
|
||||||
usleep((expo *= 2));
|
usleep((expo *= 2));
|
||||||
DeployEphemeralRunItDaemonRemotelyViaSsh(ai);
|
DeployEphemeralRunItDaemonRemotelyViaSsh(ai);
|
||||||
goto TryAgain;
|
goto Reconnect;
|
||||||
} else {
|
} else {
|
||||||
FATALF("%s(%s:%hu): %s", "connect", g_hostname, g_runitdport,
|
FATALF("%s(%s:%hu): %s", "connect", g_hostname, g_runitdport,
|
||||||
strerror(err));
|
strerror(err));
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
DEBUGF("connected to %s", g_hostname);
|
||||||
}
|
}
|
||||||
freeaddrinfo(ai);
|
freeaddrinfo(ai);
|
||||||
}
|
}
|
||||||
|
@ -275,6 +307,7 @@ void SendRequest(void) {
|
||||||
const char *name;
|
const char *name;
|
||||||
unsigned char *hdr;
|
unsigned char *hdr;
|
||||||
size_t progsize, namesize, hdrsize;
|
size_t progsize, namesize, hdrsize;
|
||||||
|
DEBUGF("running %s on %s", g_prog, g_hostname);
|
||||||
CHECK_NE(-1, (fd = open(g_prog, O_RDONLY)));
|
CHECK_NE(-1, (fd = open(g_prog, O_RDONLY)));
|
||||||
CHECK_NE(-1, fstat(fd, &st));
|
CHECK_NE(-1, fstat(fd, &st));
|
||||||
CHECK_LE((namesize = strlen((name = basename(g_prog)))), PATH_MAX);
|
CHECK_LE((namesize = strlen((name = basename(g_prog)))), PATH_MAX);
|
||||||
|
@ -370,8 +403,7 @@ int RunOnHost(char *spec) {
|
||||||
do {
|
do {
|
||||||
Connect();
|
Connect();
|
||||||
SendRequest();
|
SendRequest();
|
||||||
rc = ReadResponse();
|
} while ((rc = ReadResponse()) == -1);
|
||||||
} while (rc == -1);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,59 +416,56 @@ bool ShouldRunInParralel(void) {
|
||||||
return !IsWindows() && IsParallelBuild();
|
return !IsWindows() && IsParallelBuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
int RunRemoteTestsInSerial(char *hosts[], int count) {
|
|
||||||
int i, exitcode;
|
|
||||||
for (i = 0; i < count; ++i) {
|
|
||||||
if ((exitcode = RunOnHost(hosts[i]))) {
|
|
||||||
return exitcode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnInterrupt(int sig) {
|
|
||||||
static bool once;
|
|
||||||
if (!once) {
|
|
||||||
once = true;
|
|
||||||
gclongjmp(g_jmpbuf, 128 + sig);
|
|
||||||
} else {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int RunRemoteTestsInParallel(char *hosts[], int count) {
|
int RunRemoteTestsInParallel(char *hosts[], int count) {
|
||||||
const struct sigaction onsigterm = {.sa_handler = (void *)OnInterrupt};
|
sigset_t chldmask, savemask;
|
||||||
struct sigaction onsigint = {.sa_handler = (void *)OnInterrupt};
|
int i, rc, ws, pid, *pids, exitcode;
|
||||||
int i, rc, exitcode;
|
struct sigaction ignore, saveint, savequit;
|
||||||
int64_t leader, *pids;
|
pids = calloc(count, sizeof(char *));
|
||||||
leader = getpid();
|
ignore.sa_flags = 0;
|
||||||
pids = gc(xcalloc(count, sizeof(char *)));
|
ignore.sa_handler = SIG_IGN;
|
||||||
if (!(exitcode = setjmp(g_jmpbuf))) {
|
LOGIFNEG1(sigemptyset(&ignore.sa_mask));
|
||||||
sigaction(SIGINT, &onsigint, NULL);
|
LOGIFNEG1(sigaction(SIGINT, &ignore, &saveint));
|
||||||
sigaction(SIGTERM, &onsigterm, NULL);
|
LOGIFNEG1(sigaction(SIGQUIT, &ignore, &savequit));
|
||||||
|
LOGIFNEG1(sigemptyset(&chldmask));
|
||||||
|
LOGIFNEG1(sigaddset(&chldmask, SIGCHLD));
|
||||||
|
LOGIFNEG1(sigprocmask(SIG_BLOCK, &chldmask, &savemask));
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
CHECK_NE(-1, (pids[i] = fork()));
|
CHECK_NE(-1, (pids[i] = fork()));
|
||||||
if (!pids[i]) {
|
if (!pids[i]) {
|
||||||
return RunOnHost(hosts[i]);
|
sigaction(SIGINT, &saveint, NULL);
|
||||||
|
sigaction(SIGQUIT, &savequit, NULL);
|
||||||
|
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||||
|
_exit(RunOnHost(hosts[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (exitcode = 0;;) {
|
||||||
|
if ((pid = wait(&ws)) == -1) {
|
||||||
|
if (errno == EINTR) continue;
|
||||||
|
if (errno == ECHILD) break;
|
||||||
|
FATALF("wait failed");
|
||||||
|
}
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
CHECK_NE(-1, waitpid(pids[i], &rc, 0));
|
if (pids[i] != pid) continue;
|
||||||
exitcode |= WEXITSTATUS(rc);
|
if (WIFEXITED(ws)) {
|
||||||
|
DEBUGF("%s exited with %d", hosts[i], WEXITSTATUS(ws));
|
||||||
|
if (!exitcode) exitcode = WEXITSTATUS(ws);
|
||||||
|
} else {
|
||||||
|
DEBUGF("%s terminated with %s", hosts[i], strsignal(WTERMSIG(ws)));
|
||||||
|
if (!exitcode) exitcode = 128 + WTERMSIG(ws);
|
||||||
}
|
}
|
||||||
} else if (getpid() == leader) {
|
break;
|
||||||
onsigint.sa_handler = SIG_IGN;
|
|
||||||
sigaction(SIGINT, &onsigint, NULL);
|
|
||||||
kill(0, SIGINT);
|
|
||||||
while (waitpid(-1, NULL, 0) > 0) donothing;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
LOGIFNEG1(sigaction(SIGINT, &saveint, NULL));
|
||||||
|
LOGIFNEG1(sigaction(SIGQUIT, &savequit, NULL));
|
||||||
|
LOGIFNEG1(sigprocmask(SIG_SETMASK, &savemask, NULL));
|
||||||
|
free(pids);
|
||||||
return exitcode;
|
return exitcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
showcrashreports();
|
showcrashreports();
|
||||||
/* g_loglevel = kLogDebug; */
|
/* g_loglevel = kLogDebug; */
|
||||||
const struct sigaction onsigalrm = {.sa_handler = (void *)OnAlarm};
|
|
||||||
if (argc > 1 &&
|
if (argc > 1 &&
|
||||||
(strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
|
(strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
|
||||||
ShowUsage(stdout, 0);
|
ShowUsage(stdout, 0);
|
||||||
|
@ -447,9 +476,7 @@ int main(int argc, char *argv[]) {
|
||||||
CheckExists((g_runitd = argv[1]));
|
CheckExists((g_runitd = argv[1]));
|
||||||
CheckExists((g_prog = argv[2]));
|
CheckExists((g_prog = argv[2]));
|
||||||
if (argc == 1 + 2) return 0; /* hosts list empty */
|
if (argc == 1 + 2) return 0; /* hosts list empty */
|
||||||
sigaction(SIGALRM, &onsigalrm, NULL);
|
|
||||||
g_sshport = 22;
|
g_sshport = 22;
|
||||||
g_runitdport = RUNITD_PORT;
|
g_runitdport = RUNITD_PORT;
|
||||||
return (ShouldRunInParralel() ? RunRemoteTestsInParallel
|
return RunRemoteTestsInParallel(&argv[3], argc - 3);
|
||||||
: RunRemoteTestsInSerial)(&argv[3], argc - 3);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/bits/safemacros.h"
|
#include "libc/bits/safemacros.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
@ -96,32 +97,30 @@
|
||||||
#define kLogFile "o/runitd.log"
|
#define kLogFile "o/runitd.log"
|
||||||
#define kLogMaxBytes (2 * 1000 * 1000)
|
#define kLogMaxBytes (2 * 1000 * 1000)
|
||||||
|
|
||||||
jmp_buf g_jb;
|
|
||||||
char *g_exepath;
|
char *g_exepath;
|
||||||
volatile bool g_childterm;
|
|
||||||
volatile int g_childstatus;
|
|
||||||
struct sockaddr_in g_servaddr;
|
struct sockaddr_in g_servaddr;
|
||||||
unsigned char g_buf[PAGESIZE];
|
unsigned char g_buf[PAGESIZE];
|
||||||
bool g_daemonize, g_sendready;
|
bool g_daemonize, g_sendready;
|
||||||
int g_timeout, g_devnullfd, g_servfd, g_clifd, g_exefd;
|
int g_timeout, g_devnullfd, g_servfd, g_clifd, g_exefd;
|
||||||
|
|
||||||
void OnInterrupt(int sig) {
|
void OnChildTerminated(int sig) {
|
||||||
static bool once;
|
int ws, pid;
|
||||||
if (once) abort();
|
|
||||||
once = true;
|
|
||||||
kill(0, sig);
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (waitpid(-1, NULL, 0) == -1) {
|
if ((pid = waitpid(-1, &ws, WNOHANG)) != -1) {
|
||||||
|
if (pid) {
|
||||||
|
if (WIFEXITED(ws)) {
|
||||||
|
DEBUGF("worker %d exited with %d", pid, WEXITSTATUS(ws));
|
||||||
|
} else {
|
||||||
|
DEBUGF("worker %d terminated with %s", pid, strsignal(WTERMSIG(ws)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (errno == EINTR) continue;
|
||||||
|
if (errno == ECHILD) break;
|
||||||
|
FATALF("waitpid failed in sigchld");
|
||||||
}
|
}
|
||||||
gclongjmp(g_jb, sig);
|
|
||||||
unreachable;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnChildTerminated(int sig) {
|
|
||||||
while (waitpid(-1, &g_childstatus, WNOHANG) > 0) {
|
|
||||||
g_childterm = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,14 +189,14 @@ void StartTcpServer(void) {
|
||||||
CHECK_NE(-1, listen(g_servfd, 10));
|
CHECK_NE(-1, listen(g_servfd, 10));
|
||||||
asize = sizeof(g_servaddr);
|
asize = sizeof(g_servaddr);
|
||||||
CHECK_NE(-1, getsockname(g_servfd, &g_servaddr, &asize));
|
CHECK_NE(-1, getsockname(g_servfd, &g_servaddr, &asize));
|
||||||
|
CHECK_NE(-1, fcntl(g_servfd, F_SETFD, FD_CLOEXEC));
|
||||||
|
LOGF("%s:%s", "listening on tcp", gc(DescribeAddress(&g_servaddr)));
|
||||||
if (g_sendready) {
|
if (g_sendready) {
|
||||||
printf("ready %hu\n", ntohs(g_servaddr.sin_port));
|
printf("ready %hu\n", ntohs(g_servaddr.sin_port));
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
fclose(stdout);
|
fclose(stdout);
|
||||||
stdout->fd = g_devnullfd;
|
dup2(g_devnullfd, stdout->fd);
|
||||||
}
|
}
|
||||||
CHECK_NE(-1, fcntl(g_servfd, F_SETFD, FD_CLOEXEC));
|
|
||||||
LOGF("%s:%s", "listening on tcp", gc(DescribeAddress(&g_servaddr)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendExitMessage(int sock, int rc) {
|
void SendExitMessage(int sock, int rc) {
|
||||||
|
@ -242,7 +241,9 @@ void HandleClient(void) {
|
||||||
ssize_t got, wrote;
|
ssize_t got, wrote;
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
char *addrstr, *exename;
|
char *addrstr, *exename;
|
||||||
int rc, wstatus, child, pipefds[2];
|
sigset_t chldmask, savemask;
|
||||||
|
int exitcode, wstatus, child, pipefds[2];
|
||||||
|
struct sigaction ignore, saveint, savequit;
|
||||||
uint32_t addrsize, namesize, filesize, remaining;
|
uint32_t addrsize, namesize, filesize, remaining;
|
||||||
|
|
||||||
/* read request to run program */
|
/* read request to run program */
|
||||||
|
@ -252,7 +253,6 @@ void HandleClient(void) {
|
||||||
close(g_clifd);
|
close(g_clifd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
g_childterm = false;
|
|
||||||
addrstr = gc(DescribeAddress(&addr));
|
addrstr = gc(DescribeAddress(&addr));
|
||||||
DEBUGF("%s %s %s", gc(DescribeAddress(&g_servaddr)), "accepted", addrstr);
|
DEBUGF("%s %s %s", gc(DescribeAddress(&g_servaddr)), "accepted", addrstr);
|
||||||
got = recv(g_clifd, (p = &g_buf[0]), sizeof(g_buf), 0);
|
got = recv(g_clifd, (p = &g_buf[0]), sizeof(g_buf), 0);
|
||||||
|
@ -303,13 +303,25 @@ void HandleClient(void) {
|
||||||
|
|
||||||
/* run program, tee'ing stderr to both log and client */
|
/* run program, tee'ing stderr to both log and client */
|
||||||
DEBUGF("spawning %s", exename);
|
DEBUGF("spawning %s", exename);
|
||||||
|
ignore.sa_flags = 0;
|
||||||
|
ignore.sa_handler = SIG_IGN;
|
||||||
|
LOGIFNEG1(sigemptyset(&ignore.sa_mask));
|
||||||
|
LOGIFNEG1(sigaction(SIGINT, &ignore, &saveint));
|
||||||
|
LOGIFNEG1(sigaction(SIGQUIT, &ignore, &savequit));
|
||||||
|
LOGIFNEG1(sigemptyset(&chldmask));
|
||||||
|
LOGIFNEG1(sigaddset(&chldmask, SIGCHLD));
|
||||||
|
LOGIFNEG1(sigprocmask(SIG_BLOCK, &chldmask, &savemask));
|
||||||
CHECK_NE(-1, pipe2(pipefds, O_CLOEXEC));
|
CHECK_NE(-1, pipe2(pipefds, O_CLOEXEC));
|
||||||
if (!(child = vfork())) {
|
CHECK_NE(-1, (child = fork()));
|
||||||
|
if (!child) {
|
||||||
|
sigaction(SIGINT, &saveint, NULL);
|
||||||
|
sigaction(SIGQUIT, &savequit, NULL);
|
||||||
|
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||||
dup2(pipefds[1], 2);
|
dup2(pipefds[1], 2);
|
||||||
execv(g_exepath, (char *const[]){g_exepath, NULL});
|
execv(g_exepath, (char *const[]){g_exepath, NULL});
|
||||||
abort();
|
_exit(127);
|
||||||
}
|
}
|
||||||
close(pipefds[1]);
|
LOGIFNEG1(close(pipefds[1]));
|
||||||
DEBUGF("communicating %s[%d]", exename, child);
|
DEBUGF("communicating %s[%d]", exename, child);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
CHECK_NE(-1, (got = read(pipefds[0], g_buf, sizeof(g_buf))));
|
CHECK_NE(-1, (got = read(pipefds[0], g_buf, sizeof(g_buf))));
|
||||||
|
@ -320,23 +332,24 @@ void HandleClient(void) {
|
||||||
fwrite(g_buf, got, 1, stderr);
|
fwrite(g_buf, got, 1, stderr);
|
||||||
SendOutputFragmentMessage(g_clifd, kRunitStderr, g_buf, got);
|
SendOutputFragmentMessage(g_clifd, kRunitStderr, g_buf, got);
|
||||||
}
|
}
|
||||||
|
while (waitpid(child, &wstatus, 0) == -1) {
|
||||||
if ((rc = waitpid(child, &wstatus, 0)) != -1) {
|
if (errno == EINTR) continue;
|
||||||
g_childstatus = wstatus;
|
FATALF("waitpid failed");
|
||||||
} else {
|
|
||||||
CHECK_EQ(ECHILD, errno);
|
|
||||||
CHECK(g_childterm);
|
|
||||||
}
|
}
|
||||||
if (WIFSIGNALED(g_childstatus)) {
|
if (WIFEXITED(wstatus)) {
|
||||||
rc = 128 + WTERMSIG(g_childstatus);
|
DEBUGF("%s exited with %d", exename, WEXITSTATUS(wstatus));
|
||||||
|
exitcode = WEXITSTATUS(wstatus);
|
||||||
} else {
|
} else {
|
||||||
rc = WEXITSTATUS(g_childstatus);
|
DEBUGF("%s terminated with %s", exename, strsignal(WTERMSIG(wstatus)));
|
||||||
|
exitcode = 128 + WTERMSIG(wstatus);
|
||||||
}
|
}
|
||||||
DEBUGF("exited %s[%d] -> %d", exename, child, rc);
|
LOGIFNEG1(sigaction(SIGINT, &saveint, NULL));
|
||||||
|
LOGIFNEG1(sigaction(SIGQUIT, &savequit, NULL));
|
||||||
|
LOGIFNEG1(sigprocmask(SIG_SETMASK, &savemask, NULL));
|
||||||
|
|
||||||
/* let client know how it went */
|
/* let client know how it went */
|
||||||
LOGIFNEG1(unlink(g_exepath));
|
LOGIFNEG1(unlink(g_exepath));
|
||||||
SendExitMessage(g_clifd, rc);
|
SendExitMessage(g_clifd, exitcode);
|
||||||
LOGIFNEG1(shutdown(g_clifd, SHUT_RDWR));
|
LOGIFNEG1(shutdown(g_clifd, SHUT_RDWR));
|
||||||
LOGIFNEG1(close(g_clifd));
|
LOGIFNEG1(close(g_clifd));
|
||||||
_exit(0);
|
_exit(0);
|
||||||
|
@ -363,29 +376,17 @@ TryAgain:
|
||||||
}
|
}
|
||||||
|
|
||||||
int Serve(void) {
|
int Serve(void) {
|
||||||
int rc;
|
|
||||||
const struct sigaction onsigint = {.sa_handler = (void *)OnInterrupt,
|
|
||||||
.sa_flags = SA_NODEFER};
|
|
||||||
const struct sigaction onsigterm = {.sa_handler = (void *)OnInterrupt,
|
|
||||||
.sa_flags = SA_NODEFER};
|
|
||||||
const struct sigaction onsigchld = {.sa_handler = (void *)OnChildTerminated,
|
|
||||||
.sa_flags = SA_RESTART};
|
|
||||||
StartTcpServer();
|
StartTcpServer();
|
||||||
defer(close_s, &g_servfd);
|
sigaction(SIGCHLD,
|
||||||
if (!(rc = setjmp(g_jb))) {
|
(&(struct sigaction){.sa_handler = (void *)OnChildTerminated,
|
||||||
sigaction(SIGINT, &onsigint, NULL);
|
.sa_flags = SA_RESTART}),
|
||||||
sigaction(SIGTERM, &onsigterm, NULL);
|
NULL);
|
||||||
sigaction(SIGCHLD, &onsigchld, NULL);
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!Poll() && !g_timeout) break;
|
if (!Poll() && !g_timeout) break;
|
||||||
}
|
}
|
||||||
|
close(g_servfd);
|
||||||
LOGF("timeout expired, shutting down");
|
LOGF("timeout expired, shutting down");
|
||||||
} else {
|
return 0;
|
||||||
if (isatty(fileno(stderr))) fputc('\r', stderr);
|
|
||||||
LOGF("got %s, shutting down", strsignal(rc));
|
|
||||||
rc += 128;
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Daemonize(void) {
|
void Daemonize(void) {
|
||||||
|
@ -393,15 +394,17 @@ void Daemonize(void) {
|
||||||
if (fork() > 0) _exit(0);
|
if (fork() > 0) _exit(0);
|
||||||
setsid();
|
setsid();
|
||||||
if (fork() > 0) _exit(0);
|
if (fork() > 0) _exit(0);
|
||||||
stdin->fd = g_devnullfd;
|
dup2(g_devnullfd, stdin->fd);
|
||||||
if (!g_sendready) stdout->fd = g_devnullfd;
|
if (!g_sendready) dup2(g_devnullfd, stdout->fd);
|
||||||
if (stat(kLogFile, &st) != -1 && st.st_size > kLogMaxBytes) unlink(kLogFile);
|
freopen(kLogFile, "ae", stderr);
|
||||||
freopen(kLogFile, "a", stderr);
|
if (fstat(fileno(stderr), &st) != -1 && st.st_size > kLogMaxBytes) {
|
||||||
|
ftruncate(fileno(stderr), 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
showcrashreports();
|
showcrashreports();
|
||||||
g_loglevel = kLogDebug;
|
/* g_loglevel = kLogDebug; */
|
||||||
GetOpts(argc, argv);
|
GetOpts(argc, argv);
|
||||||
CHECK_NE(-1, (g_devnullfd = open("/dev/null", O_RDWR)));
|
CHECK_NE(-1, (g_devnullfd = open("/dev/null", O_RDWR)));
|
||||||
defer(close_s, &g_devnullfd);
|
defer(close_s, &g_devnullfd);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
#include "libc/calls/struct/timespec.h"
|
#include "libc/calls/struct/timespec.h"
|
||||||
#include "libc/elf/def.h"
|
#include "libc/elf/def.h"
|
||||||
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
|
@ -68,6 +69,7 @@
|
||||||
char *symbol_;
|
char *symbol_;
|
||||||
char *outpath_;
|
char *outpath_;
|
||||||
char *yoink_;
|
char *yoink_;
|
||||||
|
int64_t image_base_;
|
||||||
|
|
||||||
const size_t kMinCompressSize = 32;
|
const size_t kMinCompressSize = 32;
|
||||||
const char kNoCompressExts[][8] = {".gz", ".xz", ".jpg", ".png",
|
const char kNoCompressExts[][8] = {".gz", ".xz", ".jpg", ".png",
|
||||||
|
@ -83,7 +85,8 @@ wontreturn void PrintUsage(int rc, FILE *f) {
|
||||||
void GetOpts(int *argc, char ***argv) {
|
void GetOpts(int *argc, char ***argv) {
|
||||||
int opt;
|
int opt;
|
||||||
yoink_ = "__zip_start";
|
yoink_ = "__zip_start";
|
||||||
while ((opt = getopt(*argc, *argv, "?ho:s:y:")) != -1) {
|
image_base_ = IMAGE_BASE_VIRTUAL;
|
||||||
|
while ((opt = getopt(*argc, *argv, "?ho:s:y:b:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'o':
|
case 'o':
|
||||||
outpath_ = optarg;
|
outpath_ = optarg;
|
||||||
|
@ -94,6 +97,9 @@ void GetOpts(int *argc, char ***argv) {
|
||||||
case 'y':
|
case 'y':
|
||||||
yoink_ = optarg;
|
yoink_ = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'b':
|
||||||
|
image_base_ = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
case 'h':
|
case 'h':
|
||||||
PrintUsage(EXIT_SUCCESS, stdout);
|
PrintUsage(EXIT_SUCCESS, stdout);
|
||||||
|
@ -261,7 +267,7 @@ void EmitZip(struct ElfWriter *elf, const char *name, size_t namesize,
|
||||||
ELF64_ST_INFO(STB_LOCAL, STT_OBJECT), STV_DEFAULT, 0,
|
ELF64_ST_INFO(STB_LOCAL, STT_OBJECT), STV_DEFAULT, 0,
|
||||||
kZipCdirHdrLinkableSize);
|
kZipCdirHdrLinkableSize);
|
||||||
elfwriter_appendrela(elf, kZipCfileOffsetOffset, lfilesym, R_X86_64_32,
|
elfwriter_appendrela(elf, kZipCfileOffsetOffset, lfilesym, R_X86_64_32,
|
||||||
-IMAGE_BASE_VIRTUAL);
|
-image_base_);
|
||||||
elfwriter_commit(elf, kZipCdirHdrLinkableSize);
|
elfwriter_commit(elf, kZipCdirHdrLinkableSize);
|
||||||
elfwriter_finishsection(elf);
|
elfwriter_finishsection(elf);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue