mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +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.
|
||||
|
||||
For an introduction to this project, please read the <a
|
||||
href="https://justine.storage.googleapis.com/ape.html">αcτµαlly pδrταblε
|
||||
εxεcµταblε</a> blog post and <a
|
||||
href="https://justine.lol/ape.html">αcτµαlly pδrταblε εxεcµταblε</a>
|
||||
blog post and <a
|
||||
href="https://justine.lol/cosmopolitan/index.html">cosmopolitan libc</a>
|
||||
website. API documentation is available <a
|
||||
href="https://justine.lol/cosmopolitan/documentation.html">here</a>.
|
||||
|
|
|
@ -425,6 +425,7 @@ SECTIONS {
|
|||
*(.xlm)
|
||||
. = ALIGN(0x1000);
|
||||
|
||||
. = ALIGN(0x10000); /* for brk()/sbrk() allocation */
|
||||
HIDDEN(_end = .);
|
||||
PROVIDE_HIDDEN(end = .);
|
||||
} AT>SmallCode :Ram
|
||||
|
|
Binary file not shown.
|
@ -185,6 +185,9 @@ DEFAULT_LDFLAGS = \
|
|||
-z max-page-size=0x1000 \
|
||||
-Ttext-segment=$(IMAGE_BASE_VIRTUAL)
|
||||
|
||||
ZIPOBJ_FLAGS = \
|
||||
-b$(IMAGE_BASE_VIRTUAL)
|
||||
|
||||
ASONLYFLAGS = \
|
||||
-g \
|
||||
--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.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/%.zip.o: o/%; @build/zipobj $(OUTPUT_OPTION) $<
|
||||
o/%.zip.o: o/%; @build/zipobj $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%.a:; @$(ARCHIVE) $@ $^
|
||||
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)/%.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)/%.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)/%-clang.asm: CC = $(CLANG)
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
@ -20,48 +22,41 @@
|
|||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
#define kTutorialMessage "This echos stdio until Ctrl+C is pressed.\n"
|
||||
#define kVictoryMessage "\rGot Ctrl+C and longjmp() ran dtors (>'.')>\n"
|
||||
|
||||
jmp_buf jb;
|
||||
volatile bool gotctrlc;
|
||||
|
||||
void GotCtrlC(int sig) {
|
||||
gclongjmp(jb, 1);
|
||||
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));
|
||||
}
|
||||
gotctrlc = true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int rc;
|
||||
rc = 0;
|
||||
showcrashreports();
|
||||
if (cancolor()) {
|
||||
CHECK_EQ(0 /* cosmo runtime doesn't link malloc */,
|
||||
HowManyBytesOfHeapMemoryAreAllocated());
|
||||
puts("This echos stdio until Ctrl+C is pressed.");
|
||||
if (!(rc = setjmp(jb))) {
|
||||
CHECK_NE(SIG_ERR, signal(SIGINT, GotCtrlC));
|
||||
ReadAndPrintLinesLoop();
|
||||
unreachable;
|
||||
ssize_t rc;
|
||||
size_t got, wrote;
|
||||
unsigned char buf[512];
|
||||
fprintf(stderr, "This echos stdio until Ctrl+C is pressed.\n");
|
||||
CHECK_NE(
|
||||
-1, sigaction(SIGINT, &(struct sigaction){.sa_handler = GotCtrlC}, NULL));
|
||||
for (;;) {
|
||||
rc = read(0, buf, BUFSIZ);
|
||||
if (rc != -1) {
|
||||
got = rc;
|
||||
} else {
|
||||
--rc;
|
||||
CHECK_EQ(EINTR, errno);
|
||||
break;
|
||||
}
|
||||
CHECK_EQ(0, HowManyBytesOfHeapMemoryAreAllocated());
|
||||
puts("\rGot Ctrl+C and longjmp() ran dtors (>'.')>");
|
||||
if (!got) break;
|
||||
rc = write(1, buf, got);
|
||||
if (rc != -1) {
|
||||
wrote = rc;
|
||||
} else {
|
||||
CHECK_EQ(EINTR, errno);
|
||||
break;
|
||||
}
|
||||
CHECK_EQ(got, wrote);
|
||||
}
|
||||
return rc;
|
||||
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_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_USER32 \
|
||||
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,10 +617,10 @@
|
|||
|
||||
#define setlocate(l, s) 0
|
||||
#define equal(s1, s2) (strcmp(s1, s2) == 0)
|
||||
#define getenv(p) bltinlookup((p), 0)
|
||||
#define isodigit(c) ((c) >= '0' && (c) <= '7')
|
||||
#define octtobin(c) ((c) - '0')
|
||||
#define scopy(s1, s2) ((void)strcpy(s2, s1))
|
||||
/* #define getenv(p) bltinlookup((p), 0) */
|
||||
#define isodigit(c) ((c) >= '0' && (c) <= '7')
|
||||
#define octtobin(c) ((c) - '0')
|
||||
#define scopy(s1, s2) ((void)strcpy(s2, s1))
|
||||
|
||||
#define TRACE(param)
|
||||
/* #define TRACE(param) \ */
|
||||
|
|
|
@ -16,12 +16,13 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static struct AtFork {
|
||||
size_t i;
|
||||
volatile size_t i;
|
||||
struct AtForkCallback {
|
||||
void (*fn)(void *);
|
||||
void *arg;
|
||||
|
@ -33,17 +34,25 @@ static struct AtFork {
|
|||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @note vfork() won't invoke callbacks
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int atfork(void *fn, void *arg) {
|
||||
if (g_atfork.i == ARRAYLEN(g_atfork.p)) return enomem();
|
||||
g_atfork.p[g_atfork.i++] = (struct AtForkCallback){.fn = fn, .arg = arg};
|
||||
return 0;
|
||||
size_t i;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers callbacks registered by atfork().
|
||||
*
|
||||
* @note only fork() should call this
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
void __onfork(void) {
|
||||
size_t i;
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#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/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
|
@ -30,7 +33,22 @@ textwindows int fcntl$nt(int fd, int cmd, unsigned arg) {
|
|||
case F_GETFL:
|
||||
return g_fds.p[fd].flags;
|
||||
case F_SETFL:
|
||||
return (g_fds.p[fd].flags = arg);
|
||||
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);
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
case F_GETFD:
|
||||
if (g_fds.p[fd].flags & O_CLOEXEC) {
|
||||
return FD_CLOEXEC;
|
||||
|
@ -38,7 +56,7 @@ textwindows int fcntl$nt(int fd, int cmd, unsigned arg) {
|
|||
return 0;
|
||||
}
|
||||
case F_SETFD:
|
||||
if (arg & O_CLOEXEC) {
|
||||
if (arg & FD_CLOEXEC) {
|
||||
g_fds.p[fd].flags |= O_CLOEXEC;
|
||||
return FD_CLOEXEC;
|
||||
} else {
|
||||
|
|
|
@ -17,15 +17,16 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
static int g_pid;
|
||||
static int __pid;
|
||||
|
||||
static int __get_pid(void) {
|
||||
static int __getpid(void) {
|
||||
if (!IsWindows()) {
|
||||
return getpid$sysv();
|
||||
} else {
|
||||
|
@ -33,20 +34,25 @@ static int __get_pid(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void __update_pid(void) {
|
||||
g_pid = __get_pid();
|
||||
static void __updatepid(void) {
|
||||
__pid = __getpid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns process id.
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int getpid(void) {
|
||||
static bool once;
|
||||
if (!once) {
|
||||
__update_pid();
|
||||
atfork(__update_pid, NULL);
|
||||
once = true;
|
||||
if (__vforked) {
|
||||
return getpid$sysv();
|
||||
}
|
||||
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
|
||||
/ 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
|
||||
/ @returnstwice
|
||||
/ @vforksafe
|
||||
|
|
|
@ -70,8 +70,14 @@ hidden extern const struct NtSecurityAttributes kNtIsInheritable;
|
|||
ssize_t __getemptyfd(void) hidden;
|
||||
int __ensurefds(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) {
|
||||
if (!IsTrustworthy()) {
|
||||
|
@ -214,46 +220,46 @@ void xnutrampoline(void *, i32, i32, const struct __darwin_siginfo *,
|
|||
│ cosmopolitan § syscalls » windows nt » veneers ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
int gettimeofday$nt(struct timeval *, struct timezone *) hidden;
|
||||
bool32 isatty$nt(int) 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 close$nt(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 fcntl$nt(int, int, unsigned) hidden;
|
||||
int getpriority$nt(int) hidden;
|
||||
int setpriority$nt(int) hidden;
|
||||
int fdatasync$nt(int) hidden;
|
||||
int flock$nt(int, int) hidden;
|
||||
int fork$nt(void) hidden;
|
||||
int fstat$nt(i64, struct stat *) 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 lstat$nt(const char *, struct stat *) hidden;
|
||||
int madvise$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 rename$nt(const char *, const char *) hidden;
|
||||
int rmdir$nt(const char *) 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 sync$nt(void) hidden;
|
||||
int symlink$nt(const char *, const char *) hidden;
|
||||
int sync$nt(void) hidden;
|
||||
int sysinfo$nt(struct sysinfo *) hidden;
|
||||
int truncate$nt(const char *, u64) 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 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 ─╬─│┼
|
||||
|
@ -266,7 +272,6 @@ int getsetpriority$nt(int, unsigned, int, int (*)(int));
|
|||
void ntcontext2linux(struct ucontext *, const struct NtContext *) hidden;
|
||||
struct NtOverlapped *offset2overlap(int64_t, struct NtOverlapped *) hidden;
|
||||
bool32 ntsetprivilege(i64, const char16_t *, u32) hidden;
|
||||
bool32 onntconsoleevent$nt(u32) hidden;
|
||||
void __winalarm(void *, uint32_t, uint32_t) hidden;
|
||||
int ntaccesscheck(const char16_t *, u32) paramsnonnull() hidden;
|
||||
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/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Sends signal to process.
|
||||
|
@ -39,15 +38,9 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int kill(int pid, int sig) {
|
||||
int me;
|
||||
if (!IsWindows()) {
|
||||
return kill$sysv(pid, sig, 1);
|
||||
} else {
|
||||
me = getpid();
|
||||
if (!pid || pid == me || pid == -me) {
|
||||
return raise(sig);
|
||||
} else {
|
||||
return enosys();
|
||||
}
|
||||
return kill$nt(pid, sig);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,8 @@ textwindows int ntspawn(
|
|||
mkntenvblock(block->envvars, envp) != -1) {
|
||||
if (CreateProcess(NULL, block->cmdline, opt_lpProcessAttributes,
|
||||
opt_lpThreadAttributes, bInheritHandles,
|
||||
dwCreationFlags | kNtCreateUnicodeEnvironment,
|
||||
dwCreationFlags | kNtCreateNewProcessGroup |
|
||||
kNtCreateUnicodeEnvironment,
|
||||
block->envvars, opt_lpCurrentDirectory, lpStartupInfo,
|
||||
opt_out_lpProcessInformation)) {
|
||||
rc = 0;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
textwindows bool32 onntconsoleevent(uint32_t CtrlType) {
|
||||
textwindows bool32 __onntconsoleevent(uint32_t CtrlType) {
|
||||
int sig;
|
||||
siginfo_t info;
|
||||
switch (CtrlType) {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
.source __FILE__
|
||||
|
||||
.init.start 300,_init_onntconsoleevent
|
||||
ezlea onntconsoleevent$nt,cx
|
||||
ezlea __onntconsoleevent$nt,cx
|
||||
pushpop 1,%rdx
|
||||
ntcall __imp_SetConsoleCtrlHandler
|
||||
.init.end 300,_init_onntconsoleevent,globl,hidden
|
||||
|
|
|
@ -45,10 +45,12 @@ static textwindows int64_t open$nt$impl(const char *file, uint32_t flags,
|
|||
(flags & 0xf000000f) |
|
||||
(/* this is needed if we mmap(rwx+cow)
|
||||
nt is choosy about open() access */
|
||||
(flags & O_ACCMODE) == O_RDONLY
|
||||
? kNtGenericExecute | kNtFileGenericRead
|
||||
: kNtGenericExecute | kNtFileGenericRead |
|
||||
kNtFileGenericWrite),
|
||||
(flags & O_APPEND)
|
||||
? kNtFileAppendData
|
||||
: (flags & O_ACCMODE) == O_RDONLY
|
||||
? kNtGenericExecute | kNtFileGenericRead
|
||||
: kNtGenericExecute | kNtFileGenericRead |
|
||||
kNtFileGenericWrite),
|
||||
(flags & O_EXCL)
|
||||
? kNtFileShareExclusive
|
||||
: kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
|
||||
|
|
|
@ -25,15 +25,18 @@
|
|||
/**
|
||||
* 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()
|
||||
*/
|
||||
int pause(void) {
|
||||
int rc, olderr;
|
||||
sigset_t oldmask;
|
||||
olderr = errno;
|
||||
rc = pause$sysv();
|
||||
if (rc == -1 && errno == ENOSYS) {
|
||||
if ((rc = pause$sysv()) == -1 && errno == ENOSYS) {
|
||||
errno = olderr;
|
||||
if (sigprocmask(SIG_BLOCK, NULL, &oldmask) == -1) return -1;
|
||||
rc = sigsuspend(&oldmask);
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
static uint32_t GetCtrlEvent(int sig) {
|
||||
static textwindows uint32_t GetCtrlEvent(int sig) {
|
||||
switch (sig) {
|
||||
case SIGINT:
|
||||
return kNtCtrlCEvent;
|
||||
|
|
|
@ -34,11 +34,12 @@
|
|||
* @param oldset will receive the old mask (optional) and can't overlap
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
|
||||
if (!IsWindows()) {
|
||||
return sigprocmask$sysv(how, opt_set, opt_out_oldset, 8);
|
||||
} 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.
|
||||
*
|
||||
* @param mask is a bitset of signals to block temporarily
|
||||
* @param ignore is a bitset of signals to block temporarily
|
||||
* @return -1 w/ EINTR
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigsuspend(const sigset_t *mask) {
|
||||
if (!mask) return efault();
|
||||
int sigsuspend(const sigset_t *ignore) {
|
||||
if (!ignore) return efault();
|
||||
if (!IsWindows()) {
|
||||
return sigsuspend$sysv(mask, 8);
|
||||
return sigsuspend$sysv(ignore, 8);
|
||||
} else {
|
||||
return enosys(); /* TODO(jart): Implement me! */
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
.text.windows
|
||||
.source __FILE__
|
||||
|
||||
onntconsoleevent$nt:
|
||||
ezlea onntconsoleevent,ax
|
||||
__onntconsoleevent$nt:
|
||||
ezlea __onntconsoleevent,ax
|
||||
jmp __nt2sysv
|
||||
.endfn onntconsoleevent$nt,globl,hidden
|
||||
.endfn __onntconsoleevent$nt,globl,hidden
|
||||
|
|
|
@ -17,9 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#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.
|
||||
|
@ -33,9 +30,5 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int waitpid(int pid, int *opt_out_wstatus, int options) {
|
||||
if (!IsWindows()) {
|
||||
return wait4$sysv(pid, opt_out_wstatus, options, NULL);
|
||||
} else {
|
||||
return wait4$nt(pid, opt_out_wstatus, options, NULL);
|
||||
}
|
||||
return wait4(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,
|
||||
iovlen ? clampio(iov[0].iov_len) : 0, &wrote,
|
||||
offset2overlap(opt_offset, &overlap))) {
|
||||
if (!wrote) assert(SumIovecLen(iov, iovlen) > 0);
|
||||
if (!wrote) assert(!SumIovecLen(iov, iovlen));
|
||||
FlushFileBuffers(fd->handle);
|
||||
return wrote;
|
||||
} else {
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
|
@ -40,7 +41,7 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
ssize_t got;
|
||||
intptr_t addr;
|
||||
size_t i, j, gi;
|
||||
int rc, pid, pipefds[2];
|
||||
int ws, pid, pipefds[2];
|
||||
struct Garbages *garbage;
|
||||
const struct StackFrame *frame;
|
||||
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[1]);
|
||||
execvp(addr2line, argv);
|
||||
abort();
|
||||
_exit(127);
|
||||
}
|
||||
close(pipefds[1]);
|
||||
while ((got = read(pipefds[0], buf, kBacktraceBufSize)) > 0) {
|
||||
|
@ -99,9 +100,15 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
}
|
||||
}
|
||||
close(pipefds[0]);
|
||||
if (waitpid(pid, &rc, 0) == -1) return -1;
|
||||
if (WEXITSTATUS(rc) != 0) return -1;
|
||||
return 0;
|
||||
while (waitpid(pid, &ws, 0) == -1) {
|
||||
if (errno == EINTR) continue;
|
||||
return -1;
|
||||
}
|
||||
if (WIFEXITED(ws) && !WEXITSTATUS(ws)) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
const struct Symbol *symbol;
|
||||
const struct StackFrame *frame;
|
||||
if (!st) return -1;
|
||||
if (!bp) bp = __builtin_frame_address(0);
|
||||
garbage = weaken(__garbage);
|
||||
gi = garbage ? garbage->i : 0;
|
||||
|
@ -66,8 +65,9 @@ int PrintBacktraceUsingSymbols(int fd, const struct StackFrame *bp,
|
|||
*p++ = ' ';
|
||||
p = mempcpy(p, ibuf, uint64toarray_fixed16(addr, ibuf, 48));
|
||||
*p++ = ' ';
|
||||
if (st->count && ((intptr_t)addr >= (intptr_t)&_base &&
|
||||
(intptr_t)addr <= (intptr_t)&_end)) {
|
||||
if (st && st->count &&
|
||||
((intptr_t)addr >= (intptr_t)&_base &&
|
||||
(intptr_t)addr <= (intptr_t)&_end)) {
|
||||
symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
|
||||
st->count, addr - st->addr_base - 1)];
|
||||
p = stpcpy(p, &st->name_base[symbol->name_rva]);
|
||||
|
|
|
@ -56,10 +56,10 @@ relegated void __check_fail(const char *suffix, const char *opstr,
|
|||
gethostname(hostname, sizeof(hostname));
|
||||
|
||||
(dprintf)(STDERR_FILENO,
|
||||
"check failed on %s pid %d\r\n"
|
||||
"\tCHECK_%s(%s, %s);\r\n"
|
||||
"\t\t → %#lx (%s)\r\n"
|
||||
"\t\t%s %#lx (%s)\r\n",
|
||||
"check failed on %s pid %d\n"
|
||||
"\tCHECK_%s(%s, %s);\n"
|
||||
"\t\t → %#lx (%s)\n"
|
||||
"\t\t%s %#lx (%s)\n",
|
||||
hostname, getpid(), sufbuf, wantstr, gotstr, want, wantstr, opstr,
|
||||
got, gotstr);
|
||||
|
||||
|
@ -68,19 +68,19 @@ relegated void __check_fail(const char *suffix, const char *opstr,
|
|||
va_start(va, fmt);
|
||||
(vdprintf)(STDERR_FILENO, fmt, 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);
|
||||
|
||||
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 ? " \\" : "");
|
||||
}
|
||||
|
||||
if (!IsTiny() && lasterr == ENOMEM) {
|
||||
(dprintf)(STDERR_FILENO, "\r\n");
|
||||
(dprintf)(STDERR_FILENO, "\n");
|
||||
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_string(" (");
|
||||
__print(bx, int64toarray_radix10(lasterr, bx));
|
||||
__print_string(")\r\n");
|
||||
__print_string(")\n");
|
||||
}
|
||||
|
|
|
@ -18,13 +18,21 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* Writes error messages to standard error.
|
||||
*/
|
||||
void perror(const char *message) {
|
||||
fprintf(stderr, "%s%s%s: %s: %s: %s\r\n", RED2, "error", RESET,
|
||||
program_invocation_name, strerror(errno), message);
|
||||
int err;
|
||||
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("ftoa");
|
||||
|
||||
static int loglevel2char(unsigned level) {
|
||||
static struct timespec vflogf_ts;
|
||||
|
||||
static int vflogf_loglevel2char(unsigned level) {
|
||||
switch (level) {
|
||||
case kLogInfo:
|
||||
return 'I';
|
||||
|
@ -78,34 +80,46 @@ void vflogf_onfail(FILE *f) {
|
|||
|
||||
/**
|
||||
* 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,
|
||||
const char *fmt, va_list va) {
|
||||
static struct timespec ts;
|
||||
struct tm tm;
|
||||
long double t2;
|
||||
const char *prog;
|
||||
int64_t secs, nsec, dots;
|
||||
bool issamesecond;
|
||||
char buf32[32], *buf32p;
|
||||
int64_t secs, nsec, dots;
|
||||
if (!f) f = g_logfile;
|
||||
if (fileno(f) == -1) return;
|
||||
t2 = nowl();
|
||||
secs = t2;
|
||||
nsec = rem1000000000int64(t2 * 1e9L);
|
||||
if (secs > ts.tv_sec) {
|
||||
nsec = (t2 - secs) * 1e9L;
|
||||
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);
|
||||
strftime(buf32, sizeof(buf32), "%Y-%m-%dT%H:%M:%S.", &tm);
|
||||
buf32p = buf32;
|
||||
dots = nsec;
|
||||
} else {
|
||||
buf32p = "--------------------";
|
||||
dots = nsec - ts.tv_nsec;
|
||||
}
|
||||
ts.tv_sec = secs;
|
||||
ts.tv_nsec = nsec;
|
||||
prog = basename(program_invocation_name);
|
||||
if ((fprintf)(f, "%c%s%06ld:%s:%d:%.*s:%d] ", loglevel2char(level), buf32p,
|
||||
rem1000000int64(div1000int64(dots)), file, line,
|
||||
if ((fprintf)(f, "%c%s%06ld:%s:%d:%.*s:%d] ", vflogf_loglevel2char(level),
|
||||
buf32p, rem1000000int64(div1000int64(dots)), file, line,
|
||||
strchrnul(prog, '.') - prog, prog, getpid()) <= 0) {
|
||||
vflogf_onfail(f);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_NT_PRIVILEGE_H_
|
||||
#define COSMOPOLITAN_LIBC_NT_PRIVILEGE_H_
|
||||
#include "libc/nt/struct/luid.h"
|
||||
#include "libc/nt/struct/tokenprivileges.h"
|
||||
/* ░░░░
|
||||
▒▒▒░░░▒▒▒▒▒▒▒▓▓▓░
|
||||
▒▒▒▒░░░▒▒▒▒▒▒▓▓▓▓▓▓░
|
||||
|
@ -34,9 +35,6 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct NtLuid;
|
||||
struct NtTokenPrivileges;
|
||||
|
||||
bool32 LookupPrivilegeValue(const char16_t *opt_lpSystemName,
|
||||
const char16_t *lpName, struct NtLuid *out_lpLuid);
|
||||
|
||||
|
|
|
@ -43,8 +43,8 @@ bool32 CreateProcess(const char16_t *opt_lpApplicationName,
|
|||
struct NtProcessInformation *opt_out_lpProcessInformation)
|
||||
paramsnonnull((2, 9));
|
||||
|
||||
uint32_t GetThreadId(int64_t Thread); /* cf. NT_TID */
|
||||
uint32_t GetProcessId(int64_t Process); /* cf. NT_PID */
|
||||
uint32_t GetThreadId(int64_t hThread); /* cf. NT_TID */
|
||||
uint32_t GetProcessId(int64_t hProcess); /* cf. NT_PID */
|
||||
void SetLastError(uint32_t dwErrCode);
|
||||
uint32_t FormatMessage(uint32_t dwFlags, const void *lpSource,
|
||||
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 __NR_kill,%eax
|
||||
syscall # avoid hook and less bt noise
|
||||
2: mov $134,%edi # exit(128+SIGABRT) [bash-ism]
|
||||
call _Exit
|
||||
2: call abort$nt
|
||||
.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 _etext[] 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 __privileged_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_string(const char *);
|
||||
void __fast_math(void);
|
||||
void *sbrk(intptr_t);
|
||||
int brk(void *);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § runtime » optimizations ─╬─│┼
|
||||
|
|
|
@ -23,16 +23,6 @@
|
|||
#include "libc/sock/yoink.inc"
|
||||
#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) {
|
||||
assert(fd->kind == kFdSocket);
|
||||
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 __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 accept$sysv(int32_t, 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;
|
||||
int32_t select$sysv(int32_t, fd_set *, fd_set *, fd_set *,
|
||||
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_ctl$sysv(int32_t, int32_t, int32_t, void *) 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 socket$nt(int, int, int) 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) 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/dce.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/sock.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.
|
||||
*
|
||||
|
@ -41,12 +32,7 @@ static int shutdown$nt(struct Fd *fd, int how) {
|
|||
*/
|
||||
int shutdown(int fd, int how) {
|
||||
if (!IsWindows()) {
|
||||
if (!IsXnu()) {
|
||||
return shutdown$sysv(fd, how);
|
||||
} else {
|
||||
/* TODO(jart): What's wrong with XNU shutdown()? */
|
||||
return 0;
|
||||
}
|
||||
return shutdown$sysv(fd, how);
|
||||
} else if (__isfdkind(fd, kFdSocket)) {
|
||||
return shutdown$nt(&g_fds.p[fd], how);
|
||||
} 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/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/fflush.internal.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.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.
|
||||
*
|
||||
|
|
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 -*-│
|
||||
│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 │
|
||||
│ 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 │
|
||||
│ 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#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/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
|
@ -52,42 +43,16 @@ FILE *freopen(const char *pathname, const char *mode, FILE *stream) {
|
|||
if (pathname) {
|
||||
/* open new stream, overwriting existing alloc */
|
||||
if ((fd = open(pathname, flags, 0666)) != -1) {
|
||||
if (!IsWindows()) {
|
||||
dup3(fd, stream->fd, (flags & O_CLOEXEC));
|
||||
close(fd);
|
||||
} else {
|
||||
g_fds.p[stream->fd].handle = g_fds.p[fd].handle;
|
||||
g_fds.p[fd].kind = kFdEmpty;
|
||||
}
|
||||
dup3(fd, stream->fd, flags & O_CLOEXEC);
|
||||
close(fd);
|
||||
stream->iomode = flags;
|
||||
return stream;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/* change mode of open file */
|
||||
if (!IsWindows()) {
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
fcntl(stream->fd, F_SETFD, !!(flags & O_CLOEXEC));
|
||||
fcntl(stream->fd, F_SETFL, flags & ~O_CLOEXEC);
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
|
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 -*-│
|
||||
│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 │
|
||||
│ 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 │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/stdio/fflush.internal.h"
|
||||
|
||||
bool __isfdopen(int fd) {
|
||||
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty;
|
||||
}
|
||||
struct StdioFlush g_fflush;
|
|
@ -17,6 +17,7 @@ int __fwritebuf(FILE *) hidden;
|
|||
long __fseteof(FILE *) hidden;
|
||||
long __fseterrno(FILE *) hidden;
|
||||
long __fseterr(FILE *, int) hidden;
|
||||
void __fclosepid(FILE *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#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
|
||||
int (*reader)(struct FILE *); // 0x28
|
||||
int (*writer)(struct FILE *); // 0x30
|
||||
int pid; // 0x34
|
||||
} FILE;
|
||||
|
||||
extern FILE *stdin;
|
||||
|
@ -69,6 +70,8 @@ unsigned favail(FILE *);
|
|||
void setbuf(FILE *, char *);
|
||||
void setbuffer(FILE *, char *, size_t);
|
||||
int setvbuf(FILE *, char *, int, size_t);
|
||||
FILE *popen(const char *, const char *);
|
||||
int pclose(FILE *);
|
||||
|
||||
typedef uint64_t fpos_t;
|
||||
compatfn char *gets(char *) paramsnonnull();
|
||||
|
@ -78,6 +81,7 @@ compatfn int64_t fseeko(FILE *, long, int) paramsnonnull();
|
|||
compatfn int64_t ftello(FILE *) paramsnonnull();
|
||||
|
||||
int system(const char *);
|
||||
int systemexec(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/calls/calls.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
/**
|
||||
* Launches program with system command interpreter.
|
||||
|
@ -34,26 +37,36 @@
|
|||
*/
|
||||
int system(const char *cmdline) {
|
||||
int pid, wstatus;
|
||||
char comspec[128];
|
||||
const char *prog, *arg;
|
||||
if (weaken(fflush)) weaken(fflush)(NULL);
|
||||
if (cmdline) {
|
||||
if ((pid = vfork()) == -1) return -1;
|
||||
if (!pid) {
|
||||
strcpy(comspec, kNtSystemDirectory);
|
||||
strcat(comspec, "cmd.exe");
|
||||
prog = !IsWindows() ? _PATH_BSHELL : comspec;
|
||||
arg = !IsWindows() ? "-c" : "/C";
|
||||
execv(prog, (char *const[]){prog, arg, cmdline, NULL});
|
||||
_exit(errno);
|
||||
} else if (wait4(pid, &wstatus, 0, NULL) != -1) {
|
||||
return wstatus;
|
||||
} else {
|
||||
return -1;
|
||||
sigset_t chldmask, savemask;
|
||||
struct sigaction ignore, saveint, savequit;
|
||||
if (!cmdline) return 1;
|
||||
ignore.sa_flags = 0;
|
||||
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) {
|
||||
sigaction(SIGINT, &saveint, NULL);
|
||||
sigaction(SIGQUIT, &savequit, NULL);
|
||||
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||
systemexec(cmdline);
|
||||
_exit(127);
|
||||
} else if (pid != -1) {
|
||||
while (wait4(pid, &wstatus, 0, NULL) == -1) {
|
||||
if (errno != EINTR) {
|
||||
wstatus = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (IsWindows()) {
|
||||
return true;
|
||||
} else {
|
||||
return fileexists(_PATH_BSHELL);
|
||||
wstatus = -1;
|
||||
}
|
||||
sigaction(SIGINT, &saveint, NULL);
|
||||
sigaction(SIGQUIT, &savequit, NULL);
|
||||
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||
return wstatus;
|
||||
}
|
||||
|
|
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 wcsendswith(const wchar_t *, const wchar_t *) strlenesque;
|
||||
const char *IndexDoubleNulString(const char *, unsigned) strlenesque;
|
||||
int strverscmp(const char *, const char *);
|
||||
wchar_t *wmemset(wchar_t *, wchar_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;
|
||||
|
|
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 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 SIGBUS 7 10 10 10 0 # bsd consensus
|
||||
syscon sig SIGUSR1 10 30 30 30 0 # bsd consensus
|
||||
syscon sig SIGCHLD 17 20 20 20 0 # bsd consensus
|
||||
syscon sig SIGCONT 18 19 19 19 0 # bsd consensus
|
||||
syscon sig SIGIO 29 23 23 23 0 # bsd consensus
|
||||
syscon sig SIGSTOP 19 17 17 17 0 # bsd consensus
|
||||
syscon sig SIGSYS 31 12 12 12 0 # bsd consensus
|
||||
syscon sig SIGTSTP 20 18 18 18 0 # bsd consensus
|
||||
syscon sig SIGURG 23 0x10 0x10 0x10 0 # bsd consensus
|
||||
syscon sig SIGUSR2 12 31 31 31 0 # bsd consensus
|
||||
syscon sig SIGSTKSZ 0x2000 0x020000 0x8800 0x7000 0
|
||||
syscon sig SIGPOLL 29 0 0 0 0
|
||||
syscon sig SIGPWR 30 0 0 0 0
|
||||
syscon sig SIGSTKFLT 0x10 0 0 0 0
|
||||
syscon sig SIGUNUSED 31 0 0 0 0
|
||||
syscon sig SIGBUS 7 10 10 10 7 # bsd consensus
|
||||
syscon sig SIGUSR1 10 30 30 30 10 # bsd consensus
|
||||
syscon sig SIGCHLD 17 20 20 20 17 # bsd consensus
|
||||
syscon sig SIGCONT 18 19 19 19 18 # bsd consensus
|
||||
syscon sig SIGIO 29 23 23 23 29 # bsd consensus
|
||||
syscon sig SIGSTOP 19 17 17 17 19 # bsd consensus
|
||||
syscon sig SIGSYS 31 12 12 12 31 # bsd consensus
|
||||
syscon sig SIGTSTP 20 18 18 18 20 # bsd consensus
|
||||
syscon sig SIGURG 23 0x10 0x10 0x10 23 # bsd consensus
|
||||
syscon sig SIGUSR2 12 31 31 31 12 # bsd consensus
|
||||
syscon sig SIGSTKSZ 0x2000 0x020000 0x8800 0x7000 0x2000
|
||||
syscon sig SIGPOLL 29 0 0 0 29
|
||||
syscon sig SIGPWR 30 0 0 0 30
|
||||
syscon sig SIGSTKFLT 0x10 0 0 0 0x10
|
||||
syscon sig SIGUNUSED 31 0 0 0 31
|
||||
syscon sig SIGRTMAX 0 0 126 0 0
|
||||
syscon sig SIGRTMIN 0 0 65 0 0
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.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"
|
||||
.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"
|
||||
.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"
|
||||
.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"
|
||||
.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"
|
||||
.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"
|
||||
.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"
|
||||
.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"
|
||||
.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"
|
||||
.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"
|
||||
.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"
|
||||
.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"
|
||||
.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"
|
||||
.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"
|
||||
.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/testlib/testlib.h"
|
||||
|
||||
STATIC_YOINK("__isfdkind");
|
||||
|
||||
const char *testlib_showerror_errno;
|
||||
const char *testlib_showerror_file;
|
||||
const char *testlib_showerror_func;
|
||||
|
@ -85,9 +83,10 @@ testonly void testlib_showerror_(int line, const char *wantcode,
|
|||
strcpy(hostname, "unknown");
|
||||
gethostname(hostname, sizeof(hostname));
|
||||
fprintf(stderr,
|
||||
"\t%s%s\n"
|
||||
"\t%s @ %s%s\n",
|
||||
SUBTLE, strerror(err), program_invocation_name, hostname, RESET);
|
||||
"\t%s%s%s\n"
|
||||
"\t%s%s @ %s%s\n",
|
||||
SUBTLE, strerror(err), RESET, SUBTLE, program_invocation_name,
|
||||
hostname, RESET);
|
||||
|
||||
free_s(&FREED_want);
|
||||
free_s(&FREED_got);
|
||||
|
|
|
@ -20,4 +20,12 @@
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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]) {
|
||||
(snprintf)(buf, 64, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
|
||||
kWeekdayNameShort[clip(date->tm_wday, 7)],
|
||||
|
|
|
@ -33,14 +33,18 @@ TEST(vfork, test) {
|
|||
ASSERT_NE(-1, lseek(fd, 0, SEEK_SET));
|
||||
if (!vfork()) {
|
||||
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_NE(-1, close(fd));
|
||||
_exit(0);
|
||||
}
|
||||
EXPECT_EQ(0, __vforked);
|
||||
EXPECT_NE(-1, wait(0));
|
||||
EXPECT_EQ(5, read(fd, buf, 5));
|
||||
EXPECT_STREQ("hello", buf);
|
||||
EXPECT_NE(-1, close(fd));
|
||||
EXPECT_NE(-1, wait(0));
|
||||
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/ucontext.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
|
||||
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, "--build-id=none");
|
||||
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, LDS);
|
||||
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
|
||||
CHIBICC_FLAGS = \
|
||||
-fno-common \
|
||||
-include libc/integral/normalize.inc
|
||||
-include libc/integral/normalize.inc \
|
||||
-DIMAGE_BASE_VIRTUAL=$(IMAGE_BASE_VIRTUAL)
|
||||
|
||||
PKGS += THIRD_PARTY_CHIBICC
|
||||
THIRD_PARTY_CHIBICC_ARTIFACTS += THIRD_PARTY_CHIBICC_A
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/flock.h"
|
||||
#include "libc/calls/struct/itimerval.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
|
@ -119,7 +120,7 @@ char g_hostname[128];
|
|||
uint16_t g_runitdport;
|
||||
volatile bool alarmed;
|
||||
|
||||
static void OnAlarm(void) {
|
||||
static void OnAlarm(int sig) {
|
||||
alarmed = true;
|
||||
}
|
||||
|
||||
|
@ -170,7 +171,9 @@ void DeployEphemeralRunItDaemonRemotelyViaSsh(struct addrinfo *ai) {
|
|||
struct stat st;
|
||||
char linebuf[32];
|
||||
struct timeval now, then;
|
||||
sigset_t chldmask, savemask;
|
||||
int sshpid, wstatus, binfd, pipefds[2][2];
|
||||
struct sigaction ignore, saveint, savequit;
|
||||
mkdir("o", 0755);
|
||||
CHECK_NE(-1, (lock = open(gc(xasprintf("o/lock.%s", g_hostname)),
|
||||
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) -
|
||||
(then.tv_sec * 1000 + then.tv_usec / 1000)) >=
|
||||
(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, fstat(binfd, &st));
|
||||
args[0] = "ssh";
|
||||
|
@ -189,16 +192,28 @@ void DeployEphemeralRunItDaemonRemotelyViaSsh(struct addrinfo *ai) {
|
|||
args[4] = g_hostname;
|
||||
args[5] = gc(MakeDeployScript(ai, st.st_size));
|
||||
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[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[1][1], 1);
|
||||
execv(g_ssh, args);
|
||||
abort();
|
||||
_exit(127);
|
||||
}
|
||||
close(pipefds[0][0]);
|
||||
close(pipefds[1][1]);
|
||||
LOGIFNEG1(close(pipefds[0][0]));
|
||||
LOGIFNEG1(close(pipefds[1][1]));
|
||||
Upload(pipefds[0][1], binfd, &st);
|
||||
LOGIFNEG1(close(pipefds[0][1]));
|
||||
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]);
|
||||
LOGIFNEG1(close(pipefds[1][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, lseek(lock, 0, SEEK_SET));
|
||||
CHECK_NE(-1, write(lock, &now, 16));
|
||||
|
@ -223,7 +247,11 @@ void DeployEphemeralRunItDaemonRemotelyViaSsh(struct addrinfo *ai) {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -242,28 +270,32 @@ void Connect(void) {
|
|||
g_hostname, ip4[0], ip4[1], ip4[2], ip4[3]);
|
||||
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,
|
||||
(g_sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)));
|
||||
expo = 1;
|
||||
TryAgain:
|
||||
alarmed = false;
|
||||
Reconnect:
|
||||
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);
|
||||
TryAgain:
|
||||
rc = connect(g_sock, ai->ai_addr, ai->ai_addrlen);
|
||||
err = errno;
|
||||
SetDeadline(0);
|
||||
if (rc == -1) {
|
||||
if ((err == ECONNREFUSED || err == EHOSTUNREACH || err == ECONNRESET ||
|
||||
err == EINTR)) {
|
||||
if (err == EINTR) goto TryAgain;
|
||||
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));
|
||||
DeployEphemeralRunItDaemonRemotelyViaSsh(ai);
|
||||
goto TryAgain;
|
||||
goto Reconnect;
|
||||
} else {
|
||||
FATALF("%s(%s:%hu): %s", "connect", g_hostname, g_runitdport,
|
||||
strerror(err));
|
||||
unreachable;
|
||||
}
|
||||
} else {
|
||||
DEBUGF("connected to %s", g_hostname);
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
|
@ -275,6 +307,7 @@ void SendRequest(void) {
|
|||
const char *name;
|
||||
unsigned char *hdr;
|
||||
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, fstat(fd, &st));
|
||||
CHECK_LE((namesize = strlen((name = basename(g_prog)))), PATH_MAX);
|
||||
|
@ -370,8 +403,7 @@ int RunOnHost(char *spec) {
|
|||
do {
|
||||
Connect();
|
||||
SendRequest();
|
||||
rc = ReadResponse();
|
||||
} while (rc == -1);
|
||||
} while ((rc = ReadResponse()) == -1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -384,59 +416,56 @@ bool ShouldRunInParralel(void) {
|
|||
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) {
|
||||
const struct sigaction onsigterm = {.sa_handler = (void *)OnInterrupt};
|
||||
struct sigaction onsigint = {.sa_handler = (void *)OnInterrupt};
|
||||
int i, rc, exitcode;
|
||||
int64_t leader, *pids;
|
||||
leader = getpid();
|
||||
pids = gc(xcalloc(count, sizeof(char *)));
|
||||
if (!(exitcode = setjmp(g_jmpbuf))) {
|
||||
sigaction(SIGINT, &onsigint, NULL);
|
||||
sigaction(SIGTERM, &onsigterm, NULL);
|
||||
for (i = 0; i < count; ++i) {
|
||||
CHECK_NE(-1, (pids[i] = fork()));
|
||||
if (!pids[i]) {
|
||||
return RunOnHost(hosts[i]);
|
||||
}
|
||||
sigset_t chldmask, savemask;
|
||||
int i, rc, ws, pid, *pids, exitcode;
|
||||
struct sigaction ignore, saveint, savequit;
|
||||
pids = calloc(count, sizeof(char *));
|
||||
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));
|
||||
for (i = 0; i < count; ++i) {
|
||||
CHECK_NE(-1, (pids[i] = fork()));
|
||||
if (!pids[i]) {
|
||||
sigaction(SIGINT, &saveint, NULL);
|
||||
sigaction(SIGQUIT, &savequit, NULL);
|
||||
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||
_exit(RunOnHost(hosts[i]));
|
||||
}
|
||||
for (i = 0; i < count; ++i) {
|
||||
CHECK_NE(-1, waitpid(pids[i], &rc, 0));
|
||||
exitcode |= WEXITSTATUS(rc);
|
||||
}
|
||||
} else if (getpid() == leader) {
|
||||
onsigint.sa_handler = SIG_IGN;
|
||||
sigaction(SIGINT, &onsigint, NULL);
|
||||
kill(0, SIGINT);
|
||||
while (waitpid(-1, NULL, 0) > 0) donothing;
|
||||
}
|
||||
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) {
|
||||
if (pids[i] != pid) continue;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOGIFNEG1(sigaction(SIGINT, &saveint, NULL));
|
||||
LOGIFNEG1(sigaction(SIGQUIT, &savequit, NULL));
|
||||
LOGIFNEG1(sigprocmask(SIG_SETMASK, &savemask, NULL));
|
||||
free(pids);
|
||||
return exitcode;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
showcrashreports();
|
||||
/* g_loglevel = kLogDebug; */
|
||||
const struct sigaction onsigalrm = {.sa_handler = (void *)OnAlarm};
|
||||
if (argc > 1 &&
|
||||
(strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
|
||||
ShowUsage(stdout, 0);
|
||||
|
@ -447,9 +476,7 @@ int main(int argc, char *argv[]) {
|
|||
CheckExists((g_runitd = argv[1]));
|
||||
CheckExists((g_prog = argv[2]));
|
||||
if (argc == 1 + 2) return 0; /* hosts list empty */
|
||||
sigaction(SIGALRM, &onsigalrm, NULL);
|
||||
g_sshport = 22;
|
||||
g_runitdport = RUNITD_PORT;
|
||||
return (ShouldRunInParralel() ? RunRemoteTestsInParallel
|
||||
: RunRemoteTestsInSerial)(&argv[3], argc - 3);
|
||||
return RunRemoteTestsInParallel(&argv[3], argc - 3);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -96,32 +97,30 @@
|
|||
#define kLogFile "o/runitd.log"
|
||||
#define kLogMaxBytes (2 * 1000 * 1000)
|
||||
|
||||
jmp_buf g_jb;
|
||||
char *g_exepath;
|
||||
volatile bool g_childterm;
|
||||
volatile int g_childstatus;
|
||||
struct sockaddr_in g_servaddr;
|
||||
unsigned char g_buf[PAGESIZE];
|
||||
bool g_daemonize, g_sendready;
|
||||
int g_timeout, g_devnullfd, g_servfd, g_clifd, g_exefd;
|
||||
|
||||
void OnInterrupt(int sig) {
|
||||
static bool once;
|
||||
if (once) abort();
|
||||
once = true;
|
||||
kill(0, sig);
|
||||
for (;;) {
|
||||
if (waitpid(-1, NULL, 0) == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
gclongjmp(g_jb, sig);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
void OnChildTerminated(int sig) {
|
||||
while (waitpid(-1, &g_childstatus, WNOHANG) > 0) {
|
||||
g_childterm = true;
|
||||
int ws, pid;
|
||||
for (;;) {
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
if (errno == EINTR) continue;
|
||||
if (errno == ECHILD) break;
|
||||
FATALF("waitpid failed in sigchld");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,14 +189,14 @@ void StartTcpServer(void) {
|
|||
CHECK_NE(-1, listen(g_servfd, 10));
|
||||
asize = sizeof(g_servaddr);
|
||||
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) {
|
||||
printf("ready %hu\n", ntohs(g_servaddr.sin_port));
|
||||
fflush(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) {
|
||||
|
@ -242,7 +241,9 @@ void HandleClient(void) {
|
|||
ssize_t got, wrote;
|
||||
struct sockaddr_in addr;
|
||||
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;
|
||||
|
||||
/* read request to run program */
|
||||
|
@ -252,7 +253,6 @@ void HandleClient(void) {
|
|||
close(g_clifd);
|
||||
return;
|
||||
}
|
||||
g_childterm = false;
|
||||
addrstr = gc(DescribeAddress(&addr));
|
||||
DEBUGF("%s %s %s", gc(DescribeAddress(&g_servaddr)), "accepted", addrstr);
|
||||
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 */
|
||||
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));
|
||||
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);
|
||||
execv(g_exepath, (char *const[]){g_exepath, NULL});
|
||||
abort();
|
||||
_exit(127);
|
||||
}
|
||||
close(pipefds[1]);
|
||||
LOGIFNEG1(close(pipefds[1]));
|
||||
DEBUGF("communicating %s[%d]", exename, child);
|
||||
for (;;) {
|
||||
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);
|
||||
SendOutputFragmentMessage(g_clifd, kRunitStderr, g_buf, got);
|
||||
}
|
||||
|
||||
if ((rc = waitpid(child, &wstatus, 0)) != -1) {
|
||||
g_childstatus = wstatus;
|
||||
} else {
|
||||
CHECK_EQ(ECHILD, errno);
|
||||
CHECK(g_childterm);
|
||||
while (waitpid(child, &wstatus, 0) == -1) {
|
||||
if (errno == EINTR) continue;
|
||||
FATALF("waitpid failed");
|
||||
}
|
||||
if (WIFSIGNALED(g_childstatus)) {
|
||||
rc = 128 + WTERMSIG(g_childstatus);
|
||||
if (WIFEXITED(wstatus)) {
|
||||
DEBUGF("%s exited with %d", exename, WEXITSTATUS(wstatus));
|
||||
exitcode = WEXITSTATUS(wstatus);
|
||||
} 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 */
|
||||
LOGIFNEG1(unlink(g_exepath));
|
||||
SendExitMessage(g_clifd, rc);
|
||||
SendExitMessage(g_clifd, exitcode);
|
||||
LOGIFNEG1(shutdown(g_clifd, SHUT_RDWR));
|
||||
LOGIFNEG1(close(g_clifd));
|
||||
_exit(0);
|
||||
|
@ -363,29 +376,17 @@ TryAgain:
|
|||
}
|
||||
|
||||
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();
|
||||
defer(close_s, &g_servfd);
|
||||
if (!(rc = setjmp(g_jb))) {
|
||||
sigaction(SIGINT, &onsigint, NULL);
|
||||
sigaction(SIGTERM, &onsigterm, NULL);
|
||||
sigaction(SIGCHLD, &onsigchld, NULL);
|
||||
for (;;) {
|
||||
if (!Poll() && !g_timeout) break;
|
||||
}
|
||||
LOGF("timeout expired, shutting down");
|
||||
} else {
|
||||
if (isatty(fileno(stderr))) fputc('\r', stderr);
|
||||
LOGF("got %s, shutting down", strsignal(rc));
|
||||
rc += 128;
|
||||
sigaction(SIGCHLD,
|
||||
(&(struct sigaction){.sa_handler = (void *)OnChildTerminated,
|
||||
.sa_flags = SA_RESTART}),
|
||||
NULL);
|
||||
for (;;) {
|
||||
if (!Poll() && !g_timeout) break;
|
||||
}
|
||||
return rc;
|
||||
close(g_servfd);
|
||||
LOGF("timeout expired, shutting down");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Daemonize(void) {
|
||||
|
@ -393,15 +394,17 @@ void Daemonize(void) {
|
|||
if (fork() > 0) _exit(0);
|
||||
setsid();
|
||||
if (fork() > 0) _exit(0);
|
||||
stdin->fd = g_devnullfd;
|
||||
if (!g_sendready) stdout->fd = g_devnullfd;
|
||||
if (stat(kLogFile, &st) != -1 && st.st_size > kLogMaxBytes) unlink(kLogFile);
|
||||
freopen(kLogFile, "a", stderr);
|
||||
dup2(g_devnullfd, stdin->fd);
|
||||
if (!g_sendready) dup2(g_devnullfd, stdout->fd);
|
||||
freopen(kLogFile, "ae", stderr);
|
||||
if (fstat(fileno(stderr), &st) != -1 && st.st_size > kLogMaxBytes) {
|
||||
ftruncate(fileno(stderr), 0);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
showcrashreports();
|
||||
g_loglevel = kLogDebug;
|
||||
/* g_loglevel = kLogDebug; */
|
||||
GetOpts(argc, argv);
|
||||
CHECK_NE(-1, (g_devnullfd = open("/dev/null", O_RDWR)));
|
||||
defer(close_s, &g_devnullfd);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
|
@ -68,6 +69,7 @@
|
|||
char *symbol_;
|
||||
char *outpath_;
|
||||
char *yoink_;
|
||||
int64_t image_base_;
|
||||
|
||||
const size_t kMinCompressSize = 32;
|
||||
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) {
|
||||
int opt;
|
||||
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) {
|
||||
case 'o':
|
||||
outpath_ = optarg;
|
||||
|
@ -94,6 +97,9 @@ void GetOpts(int *argc, char ***argv) {
|
|||
case 'y':
|
||||
yoink_ = optarg;
|
||||
break;
|
||||
case 'b':
|
||||
image_base_ = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
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,
|
||||
kZipCdirHdrLinkableSize);
|
||||
elfwriter_appendrela(elf, kZipCfileOffsetOffset, lfilesym, R_X86_64_32,
|
||||
-IMAGE_BASE_VIRTUAL);
|
||||
-image_base_);
|
||||
elfwriter_commit(elf, kZipCdirHdrLinkableSize);
|
||||
elfwriter_finishsection(elf);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue