mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Make improvements for Actually Portable Emacs
- Get SIGWINCH working again on the New Technology - Correctly handle O_NOFOLLOW in open() on Windows - Implement synthetic umask() functionality on Windows - Do a better job managing file execute access on Windows - Fill in `st_uid` and `st_gid` with username hash on Windows - Munge UNICODE control pictures into control codes on Windows - Do a better job ensuring Windows console settings are restored - Introduce KPRINTF_LOG environment variable to log kprintf to a file
This commit is contained in:
parent
9c7b81ee0f
commit
965516e313
108 changed files with 1126 additions and 807 deletions
|
@ -55,10 +55,10 @@ int rawmode(void) {
|
|||
static bool once;
|
||||
struct termios t;
|
||||
if (!once) {
|
||||
if (tcgetattr(1, &oldterm) != -1) {
|
||||
if (tcgetattr(1, &oldterm)) {
|
||||
atexit(restoretty);
|
||||
} else {
|
||||
return -1;
|
||||
perror("tcgetattr");
|
||||
}
|
||||
once = true;
|
||||
}
|
||||
|
@ -82,7 +82,10 @@ int rawmode(void) {
|
|||
t.c_cflag |= CS8;
|
||||
t.c_iflag |= IUTF8;
|
||||
|
||||
tcsetattr(1, TCSANOW, &t);
|
||||
if (tcsetattr(1, TCSANOW, &t)) {
|
||||
perror("tcsetattr");
|
||||
}
|
||||
|
||||
WRITE(1, ENABLE_SAFE_PASTE);
|
||||
WRITE(1, ENABLE_MOUSE_TRACKING);
|
||||
WRITE(1, PROBE_DISPLAY_SIZE);
|
||||
|
@ -94,7 +97,7 @@ void getsize(void) {
|
|||
printf("termios says terminal size is %hu×%hu\r\n", wsize.ws_col,
|
||||
wsize.ws_row);
|
||||
} else {
|
||||
printf("%s\n", strerror(errno));
|
||||
perror("tcgetwinsize");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,12 +160,13 @@ int main(int argc, char *argv[]) {
|
|||
getsize();
|
||||
resized = false;
|
||||
}
|
||||
bzero(code, sizeof(code));
|
||||
if ((n = readansi(0, code, sizeof(code))) == -1) {
|
||||
if (errno == EINTR) continue;
|
||||
printf("ERROR: READ: %s\r\n", strerror(errno));
|
||||
perror("read");
|
||||
exit(1);
|
||||
}
|
||||
printf("%`'.*s ", n, code);
|
||||
printf("%`'.*s (got %d) ", n, code, n);
|
||||
if (iscntrl(code[0]) && !code[1]) {
|
||||
printf("is CTRL-%c a.k.a. ^%c\r\n", CTRL(code[0]), CTRL(code[0]));
|
||||
if (code[0] == CTRL('C') || code[0] == CTRL('D')) break;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
|
@ -35,6 +36,7 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
/**
|
||||
|
@ -179,8 +181,16 @@ textwindows bool __sig_handle(int sigops, int sig, int si_code,
|
|||
switch (__sighandrvas[sig]) {
|
||||
case (intptr_t)SIG_DFL:
|
||||
if (__sig_is_fatal(sig)) {
|
||||
STRACE("terminating on %G", sig);
|
||||
_restorewintty();
|
||||
size_t len;
|
||||
char name[16];
|
||||
strsignal_r(sig, name);
|
||||
len = strlen(name);
|
||||
name[len++] = '\n';
|
||||
WriteFile(GetStdHandle(kNtStdErrorHandle), name, len, 0, 0);
|
||||
STRACE("terminating on %s", name);
|
||||
if (_weaken(__restore_console_win32)) {
|
||||
_weaken(__restore_console_win32)();
|
||||
}
|
||||
ExitProcess(sig);
|
||||
}
|
||||
// fallthrough
|
||||
|
|
|
@ -34,7 +34,7 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
|
|||
for (;;) {
|
||||
if (sys_clock_gettime_nt(clock, &now)) return -1;
|
||||
if (timespec_cmp(now, abs) >= 0) return 0;
|
||||
if (_check_interrupts(0, g_fds.p)) return -1;
|
||||
if (_check_interrupts(0)) return -1;
|
||||
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
|
||||
timespec_tomillis(timespec_sub(abs, now))),
|
||||
false);
|
||||
|
@ -45,7 +45,7 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
|
|||
for (;;) {
|
||||
sys_clock_gettime_nt(clock, &now);
|
||||
if (timespec_cmp(now, abs) >= 0) return 0;
|
||||
if (_check_interrupts(0, g_fds.p)) {
|
||||
if (_check_interrupts(0)) {
|
||||
if (rem) *rem = timespec_sub(abs, now);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -23,11 +23,12 @@
|
|||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Closes file descriptor.
|
||||
|
@ -59,6 +60,8 @@ int close(int fd) {
|
|||
if (fd < 0) {
|
||||
rc = ebadf();
|
||||
} else {
|
||||
// helps guarantee stderr log gets duplicated before user closes
|
||||
if (_weaken(kloghandle)) _weaken(kloghandle)();
|
||||
// for performance reasons we want to avoid holding __fds_lock()
|
||||
// while sys_close() is happening. this leaves the kernel / libc
|
||||
// having a temporarily inconsistent state. routines that obtain
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/filesharemode.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
// code size optimization
|
||||
// <sync libc/sysv/consts.sh>
|
||||
|
@ -34,69 +35,113 @@
|
|||
#define _O_DIRECTORY 0x00010000 // kNtFileFlagBackupSemantics
|
||||
#define _O_TMPFILE 0x00410000 // AttributeTemporary|FlagDeleteOnClose
|
||||
#define _O_DIRECT 0x00004000 // kNtFileFlagNoBuffering
|
||||
#define _O_NDELAY 0x00000800 // kNtFileFlagWriteThrough
|
||||
#define _O_NONBLOCK 0x00000800 // kNtFileFlagWriteThrough
|
||||
#define _O_RANDOM 0x80000000 // kNtFileFlagRandomAccess
|
||||
#define _O_SEQUENTIAL 0x40000000 // kNtFileFlagSequentialScan
|
||||
#define _O_COMPRESSED 0x20000000 // kNtFileAttributeCompressed
|
||||
#define _O_INDEXED 0x10000000 // !kNtFileAttributeNotContentIndexed
|
||||
#define _O_NONBLOCK 0x00000800
|
||||
#define _O_CLOEXEC 0x00080000
|
||||
// </sync libc/sysv/consts.sh>
|
||||
|
||||
textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
|
||||
uint32_t *out_share, uint32_t *out_disp,
|
||||
uint32_t *out_attr) {
|
||||
bool is_creating_file;
|
||||
uint32_t perm, share, disp, attr;
|
||||
|
||||
if (flags &
|
||||
~(O_ACCMODE | _O_APPEND | _O_CREAT | _O_EXCL | _O_TRUNC | _O_DIRECTORY |
|
||||
_O_TMPFILE | _O_NONBLOCK | _O_RANDOM | _O_SEQUENTIAL | _O_COMPRESSED |
|
||||
_O_INDEXED | _O_CLOEXEC | _O_DIRECT)) {
|
||||
return einval();
|
||||
}
|
||||
|
||||
switch (flags & O_ACCMODE) {
|
||||
case O_RDONLY:
|
||||
perm = kNtFileGenericRead | kNtGenericExecute;
|
||||
perm = kNtFileGenericRead;
|
||||
break;
|
||||
case O_WRONLY:
|
||||
perm = kNtFileGenericWrite | kNtGenericExecute;
|
||||
perm = kNtFileGenericWrite;
|
||||
break;
|
||||
case O_RDWR:
|
||||
perm = kNtFileGenericRead | kNtFileGenericWrite | kNtGenericExecute;
|
||||
perm = kNtFileGenericRead | kNtFileGenericWrite;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
return einval();
|
||||
}
|
||||
if (flags & _O_APPEND) {
|
||||
perm = kNtFileAppendData;
|
||||
perm = kNtFileAppendData; // todo: this is part of generic write above
|
||||
}
|
||||
|
||||
attr = 0;
|
||||
is_creating_file = (flags & _O_CREAT) || (flags & _O_TMPFILE) == _O_TMPFILE;
|
||||
|
||||
// POSIX O_EXEC doesn't mean the same thing as kNtGenericExecute. We
|
||||
// request execute access when we can determine it from mode's bits.
|
||||
// When opening existing files we greedily request execute access so
|
||||
// mmap() won't fail. If it causes CreateFile() to fail, our wrapper
|
||||
// will try calling CreateFile a second time without execute access.
|
||||
if (is_creating_file) {
|
||||
if (mode & 0111) {
|
||||
perm |= kNtGenericExecute;
|
||||
}
|
||||
if (~mode & 0200) {
|
||||
attr |= kNtFileAttributeReadonly; // not sure why anyone would
|
||||
}
|
||||
} else {
|
||||
perm |= kNtGenericExecute;
|
||||
}
|
||||
|
||||
// Be as generous as possible in sharing file access. Not doing this
|
||||
// you'll quickly find yourself no longer able to administer Windows
|
||||
if (flags & _O_EXCL) {
|
||||
share = kNtFileShareExclusive;
|
||||
} else {
|
||||
share = kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete;
|
||||
}
|
||||
|
||||
if ((flags & _O_CREAT) && (flags & _O_EXCL)) {
|
||||
disp = kNtCreateNew;
|
||||
} else if ((flags & _O_CREAT) && (flags & _O_TRUNC)) {
|
||||
disp = kNtCreateAlways;
|
||||
} else if (flags & _O_CREAT) {
|
||||
disp = kNtOpenAlways;
|
||||
// These POSIX to WIN32 mappings are relatively straightforward.
|
||||
if (flags & _O_EXCL) {
|
||||
if (is_creating_file) {
|
||||
disp = kNtCreateNew;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
} else if (is_creating_file) {
|
||||
if (flags & _O_TRUNC) {
|
||||
disp = kNtCreateAlways;
|
||||
} else {
|
||||
disp = kNtOpenAlways;
|
||||
}
|
||||
} else if (flags & _O_TRUNC) {
|
||||
disp = kNtTruncateExisting;
|
||||
} else {
|
||||
disp = kNtOpenExisting;
|
||||
}
|
||||
|
||||
// Please use tmpfd() or tmpfile() instead of O_TMPFILE.
|
||||
if ((flags & _O_TMPFILE) == _O_TMPFILE) {
|
||||
attr = kNtFileAttributeTemporary | kNtFileFlagDeleteOnClose;
|
||||
attr |= kNtFileAttributeTemporary | kNtFileFlagDeleteOnClose;
|
||||
} else {
|
||||
attr = kNtFileAttributeNormal;
|
||||
attr |= kNtFileAttributeNormal;
|
||||
if (flags & _O_DIRECTORY) {
|
||||
attr |= kNtFileFlagBackupSemantics;
|
||||
}
|
||||
if (~mode & 0200) {
|
||||
attr |= kNtFileAttributeReadonly;
|
||||
}
|
||||
}
|
||||
|
||||
if (~flags & _O_INDEXED) attr |= kNtFileAttributeNotContentIndexed;
|
||||
if (flags & _O_COMPRESSED) attr |= kNtFileAttributeCompressed;
|
||||
// The Windows content indexing service ravages performance similar to
|
||||
// Windows Defender. Please pass O_INDEXED to openat() to enable this.
|
||||
if (~flags & _O_INDEXED) {
|
||||
attr |= kNtFileAttributeNotContentIndexed;
|
||||
}
|
||||
|
||||
// Windows' transparent filesystem compression is really cool, as such
|
||||
// we've introduced a nonstandard O_COMPRESSED flag to help you use it
|
||||
if (flags & _O_COMPRESSED) {
|
||||
attr |= kNtFileAttributeCompressed;
|
||||
}
|
||||
|
||||
// Not certain yet what benefit these flags offer.
|
||||
if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan;
|
||||
if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess;
|
||||
if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering;
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
@ -60,6 +62,8 @@
|
|||
*/
|
||||
int dup2(int oldfd, int newfd) {
|
||||
int rc;
|
||||
// helps guarantee stderr log gets duplicated before user closes
|
||||
if (_weaken(kloghandle)) _weaken(kloghandle)();
|
||||
if (__isfdkind(oldfd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
#ifdef __aarch64__
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
@ -59,6 +61,8 @@
|
|||
*/
|
||||
int dup3(int oldfd, int newfd, int flags) {
|
||||
int rc;
|
||||
// helps guarantee stderr log gets duplicated before user closes
|
||||
if (_weaken(kloghandle)) _weaken(kloghandle)();
|
||||
if (oldfd == newfd || (flags & ~O_CLOEXEC)) {
|
||||
rc = einval(); // NetBSD doesn't do this
|
||||
} else if (oldfd < 0 || newfd < 0) {
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
extern long __klog_handle;
|
||||
|
||||
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
|
||||
__msabi extern typeof(WaitForSingleObject) *const __imp_WaitForSingleObject;
|
||||
__msabi extern typeof(GetExitCodeProcess) *const __imp_GetExitCodeProcess;
|
||||
|
@ -115,6 +117,12 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
|
|||
startinfo.hStdOutput = g_fds.p[1].handle;
|
||||
startinfo.hStdError = g_fds.p[2].handle;
|
||||
|
||||
if (_weaken(__klog_handle) && //
|
||||
*_weaken(__klog_handle) != 0 && //
|
||||
*_weaken(__klog_handle) != -1) {
|
||||
__imp_CloseHandle(*_weaken(__klog_handle));
|
||||
}
|
||||
|
||||
// spawn the process
|
||||
rc = ntspawn(program, argv, envp, v, 0, 0, true, 0, 0, &startinfo, &procinfo);
|
||||
if (rc == -1) {
|
||||
|
|
|
@ -23,6 +23,6 @@
|
|||
textwindows int sys_fdatasync_nt(int fd) {
|
||||
// TODO(jart): what should we do with worker pipes?
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (_check_interrupts(0, 0)) return -1;
|
||||
if (_check_interrupts(0)) return -1;
|
||||
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
|
||||
}
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/bsr.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -70,25 +72,27 @@ static textwindows uint32_t GetSizeOfReparsePoint(int64_t fh) {
|
|||
|
||||
textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
|
||||
int filetype;
|
||||
uint32_t umask;
|
||||
uint64_t actualsize;
|
||||
struct NtFileCompressionInfo fci;
|
||||
struct NtByHandleFileInformation wst;
|
||||
if (!st) return efault();
|
||||
if ((filetype = GetFileType(handle))) {
|
||||
bzero(st, sizeof(*st));
|
||||
umask = atomic_load_explicit(&__umask, memory_order_acquire);
|
||||
switch (filetype) {
|
||||
case kNtFileTypeChar:
|
||||
st->st_mode = S_IFCHR | 0644;
|
||||
st->st_mode = S_IFCHR | (0666 & ~umask);
|
||||
break;
|
||||
case kNtFileTypePipe:
|
||||
st->st_mode = S_IFIFO | 0644;
|
||||
st->st_mode = S_IFIFO | (0666 & ~umask);
|
||||
break;
|
||||
case kNtFileTypeDisk:
|
||||
if (GetFileInformationByHandle(handle, &wst)) {
|
||||
st->st_mode = 0555;
|
||||
st->st_mode = 0555 & ~umask;
|
||||
st->st_flags = wst.dwFileAttributes;
|
||||
if (!(wst.dwFileAttributes & kNtFileAttributeReadonly)) {
|
||||
st->st_mode |= 0200;
|
||||
st->st_mode |= 0222 & ~umask;
|
||||
}
|
||||
if (wst.dwFileAttributes & kNtFileAttributeDirectory) {
|
||||
st->st_mode |= S_IFDIR;
|
||||
|
@ -101,6 +105,7 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
|
|||
st->st_mtim = FileTimeToTimeSpec(wst.ftLastWriteFileTime);
|
||||
st->st_ctim = FileTimeToTimeSpec(wst.ftCreationFileTime);
|
||||
st->st_birthtim = st->st_ctim;
|
||||
st->st_gid = st->st_uid = __synthesize_uid();
|
||||
st->st_size = (uint64_t)wst.nFileSizeHigh << 32 | wst.nFileSizeLow;
|
||||
st->st_blksize = 4096;
|
||||
st->st_dev = wst.dwVolumeSerialNumber;
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
/**
|
||||
* Returns information about file, via open()'d descriptor.
|
||||
*
|
||||
* On Windows, this implementation always sets `st_uid` and `st_gid` to
|
||||
* `getuid()` and `getgid()`. The `st_mode` field is generated based on
|
||||
* the current umask().
|
||||
*
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @raise EBADF if `fd` isn't a valid file descriptor
|
||||
* @raise EIO if an i/o error happens while reading from file system
|
||||
|
@ -43,14 +47,14 @@ int fstat(int fd, struct stat *st) {
|
|||
} else if (__isfdkind(fd, kFdZip)) {
|
||||
rc = _weaken(__zipos_fstat)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, st);
|
||||
} else if (!IsWindows() && !IsMetal()) {
|
||||
} else if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
|
||||
rc = sys_fstat(fd, st);
|
||||
} else if (IsMetal()) {
|
||||
rc = sys_fstat_metal(fd, st);
|
||||
} else if (!__isfdkind(fd, kFdFile)) {
|
||||
rc = ebadf();
|
||||
} else {
|
||||
} else if (IsWindows()) {
|
||||
rc = sys_fstat_nt(__getfdhandleactual(fd), st);
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
STRACE("fstat(%d, [%s]) → %d% m", fd, DescribeStat(rc, st), rc);
|
||||
return rc;
|
||||
|
|
|
@ -43,10 +43,26 @@ static inline const char *__strace_fstatat_flags(char buf[12], int flags) {
|
|||
/**
|
||||
* Returns information about thing.
|
||||
*
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* file is a relative path, then file becomes relative to dirfd
|
||||
* On Windows, this implementation always sets `st_uid` and `st_gid` to
|
||||
* `getuid()` and `getgid()`. Anyone who relies upon the information to
|
||||
* secure a multi-tenant personal computer should consider improving it
|
||||
* and further note that the `st_mode` group / other bits will be clear
|
||||
*
|
||||
* @param dirfd is normally `AT_FDCWD` but if it's an open directory and
|
||||
* file is a relative path, then `path` becomes relative to `dirfd`
|
||||
* @param st is where the result is stored
|
||||
* @param flags can have `AT_SYMLINK_NOFOLLOW`
|
||||
* @param st is where result is stored
|
||||
* @param flags can have AT_SYMLINK_NOFOLLOW
|
||||
* @raise EACCES if denied access to component in path prefix
|
||||
* @raise EIO if i/o error occurred while reading from filesystem
|
||||
* @raise ELOOP if a symbolic link loop exists in `path`
|
||||
* @raise ENAMETOOLONG if a component in `path` exceeds `NAME_MAX`
|
||||
* @raise ENOENT on empty string or if component in path doesn't exist
|
||||
* @raise ENOTDIR if a parent component existed that wasn't a directory
|
||||
* @raise ENOTDIR if `path` is relative and `dirfd` isn't an open directory
|
||||
* @raise EOVERFLOW shouldn't be possible on 64-bit systems
|
||||
* @raise ELOOP may ahappen if `SYMLOOP_MAX` symlinks were dereferenced
|
||||
* @raise ENAMETOOLONG may happen if `path` exceeded `PATH_MAX`
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see S_ISDIR(st.st_mode), S_ISREG()
|
||||
* @asyncsignalsafe
|
||||
|
@ -70,10 +86,12 @@ int fstatat(int dirfd, const char *path, struct stat *st, int flags) {
|
|||
} else {
|
||||
rc = enotsup();
|
||||
}
|
||||
} else if (!IsWindows()) {
|
||||
} else if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
|
||||
rc = sys_fstatat(dirfd, path, st, flags);
|
||||
} else {
|
||||
} else if (IsWindows()) {
|
||||
rc = sys_fstatat_nt(dirfd, path, st, flags);
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
STRACE("fstatat(%s, %#s, [%s], %s) → %d% m", DescribeDirfd(dirfd), path,
|
||||
DescribeStat(rc, st), __strace_fstatat_flags(alloca(12), flags), rc);
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -27,7 +29,7 @@
|
|||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
static uint32_t KnuthMultiplicativeHash32(const void *buf, size_t size) {
|
||||
static uint32_t __kmp32(const void *buf, size_t size) {
|
||||
size_t i;
|
||||
uint32_t h;
|
||||
const uint32_t kPhiPrime = 0x9e3779b1;
|
||||
|
@ -36,18 +38,24 @@ static uint32_t KnuthMultiplicativeHash32(const void *buf, size_t size) {
|
|||
return h;
|
||||
}
|
||||
|
||||
static textwindows dontinline uint32_t GetUserNameHash(void) {
|
||||
textwindows uint32_t __synthesize_uid(void) {
|
||||
char16_t buf[257];
|
||||
uint32_t size = ARRAYLEN(buf);
|
||||
GetUserName(&buf, &size);
|
||||
return KnuthMultiplicativeHash32(buf, size >> 1) & INT_MAX;
|
||||
static atomic_uint uid;
|
||||
uint32_t tmp, size = ARRAYLEN(buf);
|
||||
if (!(tmp = atomic_load_explicit(&uid, memory_order_acquire))) {
|
||||
GetUserName(&buf, &size);
|
||||
tmp = __kmp32(buf, size >> 1) & INT_MAX;
|
||||
if (!tmp) ++tmp;
|
||||
atomic_store_explicit(&uid, tmp, memory_order_release);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns real user id of process.
|
||||
*
|
||||
* This never fails. On Windows, which doesn't really have this concept,
|
||||
* we return a deterministic value that's likely to work.
|
||||
* we return a hash of the username.
|
||||
*
|
||||
* @return user id (always successful)
|
||||
* @asyncsignalsafe
|
||||
|
@ -61,7 +69,7 @@ uint32_t getuid(void) {
|
|||
} else if (!IsWindows()) {
|
||||
rc = sys_getuid();
|
||||
} else {
|
||||
rc = GetUserNameHash();
|
||||
rc = __synthesize_uid();
|
||||
}
|
||||
npassert(rc >= 0);
|
||||
STRACE("%s() → %d", "getuid", rc);
|
||||
|
@ -72,7 +80,7 @@ uint32_t getuid(void) {
|
|||
* Returns real group id of process.
|
||||
*
|
||||
* This never fails. On Windows, which doesn't really have this concept,
|
||||
* we return a deterministic value that's likely to work.
|
||||
* we return a hash of the username.
|
||||
*
|
||||
* @return group id (always successful)
|
||||
* @asyncsignalsafe
|
||||
|
@ -86,7 +94,7 @@ uint32_t getgid(void) {
|
|||
} else if (!IsWindows()) {
|
||||
rc = sys_getgid();
|
||||
} else {
|
||||
rc = GetUserNameHash();
|
||||
rc = __synthesize_uid();
|
||||
}
|
||||
npassert(rc >= 0);
|
||||
STRACE("%s() → %d", "getgid", rc);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/sigval.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -16,6 +17,7 @@ COSMOPOLITAN_C_START_
|
|||
#define kIoMotion ((const int8_t[3]){1, 0, 0})
|
||||
|
||||
extern struct Fds g_fds;
|
||||
extern atomic_int __umask;
|
||||
extern const struct Fd kEmptyFd;
|
||||
|
||||
int __reservefd(int);
|
||||
|
@ -24,6 +26,7 @@ void __releasefd(int);
|
|||
int __ensurefds(int);
|
||||
int __ensurefds_unlocked(int);
|
||||
void __printfds(void);
|
||||
uint32_t __synthesize_uid(void);
|
||||
|
||||
forceinline int64_t __getfdhandleactual(int fd) {
|
||||
return g_fds.p[fd].handle;
|
||||
|
@ -37,8 +40,8 @@ forceinline bool __isfdkind(int fd, int kind) {
|
|||
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind == kind;
|
||||
}
|
||||
|
||||
int _check_interrupts(int);
|
||||
int sys_close_nt(struct Fd *, int);
|
||||
int _check_interrupts(int, struct Fd *);
|
||||
int sys_openat_metal(int, const char *, int, unsigned);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
textwindows int _check_interrupts(int sigops, struct Fd *fd) {
|
||||
int e, rc;
|
||||
textwindows int _check_interrupts(int sigops) {
|
||||
int e, rc, flags = 0;
|
||||
e = errno;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
|
@ -42,21 +42,22 @@ textwindows int _check_interrupts(int sigops, struct Fd *fd) {
|
|||
return -1;
|
||||
}
|
||||
if (__tls_enabled) {
|
||||
flags = __get_tls()->tib_flags;
|
||||
__get_tls()->tib_flags |= TIB_FLAG_TIME_CRITICAL;
|
||||
}
|
||||
if (_weaken(_check_sigalrm)) {
|
||||
_weaken(_check_sigalrm)();
|
||||
}
|
||||
if (__tls_enabled) {
|
||||
__get_tls()->tib_flags &= ~TIB_FLAG_TIME_CRITICAL;
|
||||
__get_tls()->tib_flags = flags;
|
||||
}
|
||||
if (_weaken(_check_sigwinch)) {
|
||||
_weaken(_check_sigwinch)();
|
||||
}
|
||||
if (!__tls_enabled || !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
if (!(sigops & kSigOpNochld) && _weaken(_check_sigchld)) {
|
||||
_weaken(_check_sigchld)();
|
||||
}
|
||||
if (fd && _weaken(_check_sigwinch)) {
|
||||
_weaken(_check_sigwinch)(fd);
|
||||
}
|
||||
}
|
||||
if (_weaken(__sig_check) && _weaken(__sig_check)(sigops)) {
|
||||
return eintr();
|
||||
|
|
|
@ -672,9 +672,9 @@ int ioctl(int fd, unsigned long request, ...) {
|
|||
if (request == FIONREAD) {
|
||||
rc = ioctl_fionread(fd, arg);
|
||||
} else if (request == TIOCGWINSZ) {
|
||||
rc = tcgetwinsize(fd, arg);
|
||||
return tcgetwinsize(fd, arg);
|
||||
} else if (request == TIOCSWINSZ) {
|
||||
rc = tcsetwinsize(fd, arg);
|
||||
return tcsetwinsize(fd, arg);
|
||||
} else if (request == SIOCGIFCONF) {
|
||||
rc = ioctl_siocgifconf(fd, arg);
|
||||
} else if (request == SIOCGIFADDR) {
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
int64_t lseek(int fd, int64_t offset, int whence) {
|
||||
int64_t rc;
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = _weaken(__zipos_lseek)(
|
||||
rc = _weaken(__zipos_seek)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, offset, whence);
|
||||
} else if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd()) {
|
||||
rc = sys_lseek(fd, offset, whence, 0);
|
||||
|
|
|
@ -92,20 +92,24 @@ TryAgain:
|
|||
if (result || flags == F_OK) {
|
||||
rc = 0;
|
||||
} else {
|
||||
NTTRACE("ntaccesscheck finale failed %d %x", result, flags);
|
||||
NTTRACE("ntaccesscheck finale failed: result=%d flags=%x", result,
|
||||
flags);
|
||||
rc = eacces();
|
||||
}
|
||||
} else {
|
||||
rc = __winerr();
|
||||
NTTRACE("%s(%#hs) failed: %m", "AccessCheck", pathname);
|
||||
NTTRACE("%s(%#hs) failed: %s", "AccessCheck", pathname,
|
||||
strerror(errno));
|
||||
}
|
||||
} else {
|
||||
rc = __winerr();
|
||||
NTTRACE("%s(%#hs) failed: %m", "DuplicateToken", pathname);
|
||||
NTTRACE("%s(%#hs) failed: %s", "DuplicateToken", pathname,
|
||||
strerror(errno));
|
||||
}
|
||||
} else {
|
||||
rc = __winerr();
|
||||
NTTRACE("%s(%#hs) failed: %m", "OpenProcessToken", pathname);
|
||||
NTTRACE("%s(%#hs) failed: %s", "OpenProcessToken", pathname,
|
||||
strerror(errno));
|
||||
}
|
||||
} else {
|
||||
e = GetLastError();
|
||||
|
@ -115,11 +119,13 @@ TryAgain:
|
|||
goto TryAgain;
|
||||
} else {
|
||||
rc = enomem();
|
||||
NTTRACE("%s(%#hs) failed: %m", "GetFileSecurity", pathname);
|
||||
NTTRACE("%s(%#hs) failed: %s", "GetFileSecurity", pathname,
|
||||
strerror(errno));
|
||||
}
|
||||
} else {
|
||||
errno = e;
|
||||
NTTRACE("%s(%#hs) failed: %m", "GetFileSecurity", pathname);
|
||||
NTTRACE("%s(%#hs) failed: %s", "GetFileSecurity", pathname,
|
||||
strerror(errno));
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,13 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
|
|||
if (__mkntpathat(dirfd, path, flags, path16) == -1) {
|
||||
return kNtInvalidHandleValue;
|
||||
}
|
||||
if (flags & O_NOFOLLOW) {
|
||||
if ((attr = GetFileAttributes(path16)) != -1u && //
|
||||
(attr & kNtFileAttributeReparsePoint)) {
|
||||
return eloop();
|
||||
}
|
||||
flags &= ~O_NOFOLLOW;
|
||||
}
|
||||
if (GetNtOpenFlags(flags, mode, &perm, &share, &disp, &attr) == -1) {
|
||||
return kNtInvalidHandleValue;
|
||||
}
|
||||
|
@ -57,7 +64,9 @@ static textwindows int sys_open_nt_console(int dirfd,
|
|||
// this is an ugly hack that works for observed usage patterns
|
||||
g_fds.p[fd].handle = g_fds.p[STDIN_FILENO].handle;
|
||||
g_fds.p[fd].extra = g_fds.p[STDOUT_FILENO].handle;
|
||||
g_fds.p[fd].dontclose = true; // don't call CloseHandle() upon close()
|
||||
g_fds.p[STDOUT_FILENO].dontclose = true;
|
||||
g_fds.p[STDIN_FILENO].dontclose = true;
|
||||
g_fds.p[fd].dontclose = true;
|
||||
} else if ((g_fds.p[fd].handle = sys_open_nt_impl(
|
||||
dirfd, mp->conin, (flags & ~O_ACCMODE) | O_RDONLY, mode,
|
||||
kNtFileFlagOverlapped)) != -1) {
|
||||
|
|
|
@ -61,6 +61,19 @@
|
|||
* // run `zip program.com hi.txt` beforehand
|
||||
* openat(AT_FDCWD, "/zip/hi.txt", O_RDONLY);
|
||||
*
|
||||
* Cosmopolitan's general approach on Windows to path translation is to
|
||||
*
|
||||
* - replace `/' with `\`
|
||||
* - translate utf-8 into utf-16
|
||||
* - turn `"\X\foo"` into `"\\?\X:\foo"`
|
||||
* - turn `"\X"` into `"\\?\X:\"`
|
||||
* - turn `"X:\foo"` into `"\\?\X:\foo"`
|
||||
*
|
||||
* On Windows, opening files in `/tmp` will open them in GetTempPath(),
|
||||
* which is a secure per-user directory. Opening `/dev/tty` will open a
|
||||
* special console file descriptor holding both `CONIN$` and `CONOUT$`,
|
||||
* which can't be fully closed. Opening `/dev/null` will open up `NUL`.
|
||||
*
|
||||
* @param dirfd is normally `AT_FDCWD` but if it's an open directory and
|
||||
* `file` names a relative path then it's opened relative to `dirfd`
|
||||
* @param file is a UTF-8 string naming filesystem entity, e.g. `foo/bar.txt`,
|
||||
|
@ -81,12 +94,12 @@
|
|||
* - `O_CLOEXEC` automatic close() upon execve()
|
||||
* - `O_EXCL` exclusive access (see below)
|
||||
* - `O_APPEND` open file for appending only
|
||||
* - `O_NOFOLLOW` fail with ELOOP if it's a symlink
|
||||
* - `O_NONBLOCK` asks read/write to fail with `EAGAIN` rather than block
|
||||
* - `O_EXEC` open file for execution only; see fexecve()
|
||||
* - `O_NOCTTY` prevents `file` possibly becoming controlling terminal
|
||||
* - `O_NONBLOCK` asks read/write to fail with `EAGAIN` rather than block
|
||||
* - `O_DIRECT` it's complicated (not supported on Apple and OpenBSD)
|
||||
* - `O_DIRECTORY` useful for stat'ing (hint on UNIX but required on NT)
|
||||
* - `O_NOFOLLOW` fail if it's a symlink (zero on Windows)
|
||||
* - `O_DSYNC` it's complicated (zero on non-Linux/Apple)
|
||||
* - `O_RSYNC` it's complicated (zero on non-Linux/Apple)
|
||||
* - `O_VERIFY` it's complicated (zero on non-FreeBSD)
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
textwindows int sys_pause_nt(void) {
|
||||
for (;;) {
|
||||
|
||||
if (_check_interrupts(0, g_fds.p)) {
|
||||
if (_check_interrupts(0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
|||
if (sigmask) {
|
||||
__sig_mask(SIG_SETMASK, sigmask, &oldmask);
|
||||
}
|
||||
if ((rc = _check_interrupts(0, g_fds.p))) {
|
||||
if ((rc = _check_interrupts(0))) {
|
||||
goto ReturnPath;
|
||||
}
|
||||
|
||||
|
@ -194,7 +194,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
|||
}
|
||||
// otherwise loop limitlessly for timeout to elapse while
|
||||
// checking for signal delivery interrupts, along the way
|
||||
if ((rc = _check_interrupts(0, g_fds.p))) {
|
||||
if ((rc = _check_interrupts(0))) {
|
||||
goto ReturnPath;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,10 +27,6 @@
|
|||
#include "libc/thread/tls.h"
|
||||
#include "libc/thread/xnu.internal.h"
|
||||
|
||||
static textwindows inline bool HasWorkingConsole(void) {
|
||||
return !!(__ntconsolemode[0] | __ntconsolemode[1] | __ntconsolemode[2]);
|
||||
}
|
||||
|
||||
static dontubsan void RaiseSigFpe(void) {
|
||||
volatile int x = 0;
|
||||
x = 1 / x;
|
||||
|
|
|
@ -26,9 +26,12 @@
|
|||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/wincrash.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/enum/wait.h"
|
||||
#include "libc/nt/errors.h"
|
||||
|
@ -48,83 +51,12 @@
|
|||
|
||||
#ifdef __x86_64__
|
||||
|
||||
enum Action {
|
||||
DO_NOTHING,
|
||||
DO_RESTART,
|
||||
DO_EINTR,
|
||||
};
|
||||
|
||||
static textwindows void sys_read_nt_abort(int64_t handle,
|
||||
struct NtOverlapped *overlapped) {
|
||||
unassert(CancelIoEx(handle, overlapped) ||
|
||||
GetLastError() == kNtErrorNotFound);
|
||||
}
|
||||
|
||||
static textwindows int MungeTerminalInput(char *p, uint32_t *n) {
|
||||
size_t i, j;
|
||||
if (!(__ttymagic & kFdTtyNoCr2Nl)) {
|
||||
for (i = 0; i < *n; ++i) {
|
||||
if (p[i] == '\r') {
|
||||
p[i] = '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(__ttymagic & kFdTtyNoIsigs)) {
|
||||
bool delivered = false;
|
||||
bool got_vintr = false;
|
||||
bool got_vquit = false;
|
||||
for (j = i = 0; i < *n; ++i) {
|
||||
if (__vintr != _POSIX_VDISABLE && p[i] == __vintr) {
|
||||
got_vintr = true;
|
||||
} else if (__vquit != _POSIX_VDISABLE && p[i] == __vquit) {
|
||||
got_vquit = true;
|
||||
} else {
|
||||
p[j++] = p[i];
|
||||
}
|
||||
}
|
||||
if (got_vintr) {
|
||||
delivered |= __sig_handle(0, SIGINT, SI_KERNEL, 0);
|
||||
}
|
||||
if (got_vquit) {
|
||||
delivered |= __sig_handle(0, SIGQUIT, SI_KERNEL, 0);
|
||||
}
|
||||
if (*n && !j) {
|
||||
if (delivered) {
|
||||
return DO_EINTR;
|
||||
} else {
|
||||
return DO_RESTART;
|
||||
}
|
||||
}
|
||||
*n = j;
|
||||
}
|
||||
return DO_NOTHING;
|
||||
}
|
||||
|
||||
// Manual CMD.EXE echoing for when !ICANON && ECHO is the case.
|
||||
static textwindows void EchoTerminalInput(struct Fd *fd, char *p, size_t n) {
|
||||
int64_t hOutput;
|
||||
if (fd->kind == kFdConsole) {
|
||||
hOutput = fd->extra;
|
||||
} else {
|
||||
hOutput = g_fds.p[1].handle;
|
||||
}
|
||||
if (__ttymagic & kFdTtyEchoRaw) {
|
||||
WriteFile(hOutput, p, n, 0, 0);
|
||||
} else {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (isascii(p[i]) && iscntrl(p[i]) && p[i] != '\n' && p[i] != '\t') {
|
||||
char ctl[2];
|
||||
ctl[0] = '^';
|
||||
ctl[1] = p[i] ^ 0100;
|
||||
WriteFile(hOutput, ctl, 2, 0, 0);
|
||||
} else {
|
||||
WriteFile(hOutput, p + i, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
|
||||
size_t size, int64_t offset) {
|
||||
|
||||
|
@ -133,11 +65,38 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
|
|||
uint32_t got;
|
||||
int filetype;
|
||||
int64_t handle;
|
||||
uint32_t remain;
|
||||
uint32_t conmode;
|
||||
char *targetdata;
|
||||
uint32_t targetsize;
|
||||
bool is_console_input;
|
||||
int abort_errno = EAGAIN;
|
||||
StartOver:
|
||||
size = MIN(size, 0x7ffff000);
|
||||
handle = __resolve_stdin_handle(fd->handle);
|
||||
filetype = GetFileType(handle);
|
||||
is_console_input = g_fds.stdin.handle ? fd->handle == g_fds.stdin.handle
|
||||
: fd->handle == g_fds.p[0].handle;
|
||||
|
||||
// the caller might be reading a single byte at a time. but we need to
|
||||
// be able to munge three bytes into just 1 e.g. "\342\220\200" → "\0"
|
||||
if (size && fd->buflen) {
|
||||
ReturnDataFromBuffer:
|
||||
got = MIN(size, fd->buflen);
|
||||
remain = fd->buflen - got;
|
||||
if (got) memcpy(data, fd->buf, got);
|
||||
if (remain) memmove(fd->buf, fd->buf + got, remain);
|
||||
fd->buflen = remain;
|
||||
return got;
|
||||
}
|
||||
if (is_console_input && size && size < 3 && (__ttymagic & kFdTtyMunging)) {
|
||||
targetdata = fd->buf;
|
||||
targetsize = sizeof(fd->buf);
|
||||
} else {
|
||||
targetdata = data;
|
||||
targetsize = size;
|
||||
}
|
||||
|
||||
if (filetype == kNtFileTypeChar || filetype == kNtFileTypePipe) {
|
||||
struct NtOverlapped overlap = {0};
|
||||
if (offset != -1) {
|
||||
|
@ -147,7 +106,7 @@ StartOver:
|
|||
if ((overlap.hEvent = CreateEvent(0, 0, 0, 0))) {
|
||||
// the win32 manual says it's important to *not* put &got here
|
||||
// since for overlapped i/o, we always use GetOverlappedResult
|
||||
ok = ReadFile(handle, data, size, 0, &overlap);
|
||||
ok = ReadFile(handle, targetdata, targetsize, 0, &overlap);
|
||||
if (!ok && GetLastError() == kNtErrorIoPending) {
|
||||
// the i/o operation is in flight; blocking is unavoidable
|
||||
// if we're in a non-blocking mode, then immediately abort
|
||||
|
@ -155,7 +114,7 @@ StartOver:
|
|||
// otherwise wait for i/o periodically checking interrupts
|
||||
if (fd->flags & O_NONBLOCK) {
|
||||
sys_read_nt_abort(handle, &overlap);
|
||||
} else if (_check_interrupts(kSigOpRestartable, g_fds.p)) {
|
||||
} else if (_check_interrupts(kSigOpRestartable)) {
|
||||
Interrupted:
|
||||
abort_errno = errno;
|
||||
sys_read_nt_abort(handle, &overlap);
|
||||
|
@ -164,7 +123,7 @@ StartOver:
|
|||
uint32_t i;
|
||||
i = WaitForSingleObject(overlap.hEvent, __SIG_POLLING_INTERVAL_MS);
|
||||
if (i == kNtWaitTimeout) {
|
||||
if (_check_interrupts(kSigOpRestartable, g_fds.p)) {
|
||||
if (_check_interrupts(kSigOpRestartable)) {
|
||||
goto Interrupted;
|
||||
}
|
||||
} else {
|
||||
|
@ -186,7 +145,7 @@ StartOver:
|
|||
}
|
||||
} else if (offset == -1) {
|
||||
// perform simple blocking file read
|
||||
ok = ReadFile(handle, data, size, &got, 0);
|
||||
ok = ReadFile(handle, targetdata, targetsize, &got, 0);
|
||||
} else {
|
||||
// perform pread()-style file read at particular file offset
|
||||
int64_t position;
|
||||
|
@ -196,17 +155,17 @@ StartOver:
|
|||
}
|
||||
struct NtOverlapped overlap = {0};
|
||||
overlap.Pointer = (void *)(uintptr_t)offset;
|
||||
ok = ReadFile(handle, data, size, 0, &overlap);
|
||||
ok = ReadFile(handle, targetdata, targetsize, 0, &overlap);
|
||||
if (!ok && GetLastError() == kNtErrorIoPending) ok = true;
|
||||
if (ok) ok = GetOverlappedResult(handle, &overlap, &got, true);
|
||||
// restore file pointer which windows clobbers, even on error
|
||||
unassert(SetFilePointerEx(handle, position, 0, SEEK_SET));
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
if (g_fds.stdin.handle ? fd->handle == g_fds.stdin.handle
|
||||
: fd->handle == g_fds.p[0].handle) {
|
||||
if (is_console_input) {
|
||||
if (__ttymagic & kFdTtyMunging) {
|
||||
switch (MungeTerminalInput(data, &got)) {
|
||||
switch (_weaken(__munge_terminal_input)(targetdata, &got)) {
|
||||
case DO_NOTHING:
|
||||
break;
|
||||
case DO_RESTART:
|
||||
|
@ -218,9 +177,13 @@ StartOver:
|
|||
}
|
||||
}
|
||||
if (__ttymagic & kFdTtyEchoing) {
|
||||
EchoTerminalInput(fd, data, got);
|
||||
_weaken(__echo_terminal_input)(fd, targetdata, got);
|
||||
}
|
||||
}
|
||||
if (targetdata != data) {
|
||||
fd->buflen = got;
|
||||
goto ReturnDataFromBuffer;
|
||||
}
|
||||
return got;
|
||||
}
|
||||
|
||||
|
@ -245,7 +208,7 @@ textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov,
|
|||
uint32_t size;
|
||||
size_t i, total;
|
||||
if (opt_offset < -1) return einval();
|
||||
if (_check_interrupts(kSigOpRestartable, fd)) return -1;
|
||||
if (_check_interrupts(kSigOpRestartable)) return -1;
|
||||
while (iovlen && !iov[0].iov_len) iov++, iovlen--;
|
||||
if (iovlen) {
|
||||
for (total = i = 0; i < iovlen; ++i) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "libc/calls/ucontext.h"
|
||||
|
||||
#define __SIG_QUEUE_LENGTH 32
|
||||
#define __SIG_POLLING_INTERVAL_MS 50
|
||||
#define __SIG_POLLING_INTERVAL_MS 20
|
||||
#define __SIG_LOGGING_INTERVAL_MS 1700
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
|
|
@ -77,7 +77,7 @@ int sigsuspend(const sigset_t *ignore) {
|
|||
long totoms = 0;
|
||||
#endif
|
||||
do {
|
||||
if ((rc = _check_interrupts(0, g_fds.p))) {
|
||||
if ((rc = _check_interrupts(0))) {
|
||||
break;
|
||||
}
|
||||
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
|
||||
|
|
|
@ -16,48 +16,57 @@
|
|||
│ 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/atomic.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/calls/struct/winsize.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/struct/consolescreenbufferinfoex.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
static struct winsize __ws;
|
||||
static atomic_uint __win_winsize;
|
||||
|
||||
textwindows void _check_sigwinch(struct Fd *fd) {
|
||||
int e;
|
||||
siginfo_t si;
|
||||
struct winsize ws, old;
|
||||
struct NtConsoleScreenBufferInfoEx sbinfo;
|
||||
if (__tls_enabled && __threaded != gettid()) return;
|
||||
old = __ws;
|
||||
e = errno;
|
||||
if (old.ws_row != 0xffff) {
|
||||
if (tcgetwinsize_nt(fd, &ws) != -1) {
|
||||
if (old.ws_col != ws.ws_col || old.ws_row != ws.ws_row) {
|
||||
__ws = ws;
|
||||
if (old.ws_col | old.ws_row) {
|
||||
__sig_add(0, SIGWINCH, SI_KERNEL);
|
||||
}
|
||||
}
|
||||
static textwindows unsigned __get_console_size(void) {
|
||||
for (int fd = 1; fd < 10; ++fd) {
|
||||
intptr_t hConsoleOutput;
|
||||
if (g_fds.p[fd].kind == kFdConsole) {
|
||||
hConsoleOutput = g_fds.p[fd].extra;
|
||||
} else {
|
||||
if (!old.ws_row && !old.ws_col) {
|
||||
__ws.ws_row = 0xffff;
|
||||
}
|
||||
hConsoleOutput = g_fds.p[fd].handle;
|
||||
}
|
||||
struct NtConsoleScreenBufferInfoEx sr = {.cbSize = sizeof(sr)};
|
||||
if (GetConsoleScreenBufferInfoEx(hConsoleOutput, &sr)) {
|
||||
unsigned short yn = sr.srWindow.Bottom - sr.srWindow.Top + 1;
|
||||
unsigned short xn = sr.srWindow.Right - sr.srWindow.Left + 1;
|
||||
return (unsigned)yn << 16 | xn;
|
||||
}
|
||||
}
|
||||
errno = e;
|
||||
return -1u;
|
||||
}
|
||||
|
||||
textwindows void _check_sigwinch(void) {
|
||||
unsigned old = atomic_load_explicit(&__win_winsize, memory_order_acquire);
|
||||
if (old == -1u) return;
|
||||
unsigned neu = __get_console_size();
|
||||
old = atomic_exchange(&__win_winsize, neu);
|
||||
if (neu != old) {
|
||||
__sig_add(0, SIGWINCH, SI_KERNEL);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void sigwinch_init(void) {
|
||||
if (!IsWindows()) return;
|
||||
unsigned ws = __get_console_size();
|
||||
atomic_store_explicit(&__win_winsize, ws, memory_order_release);
|
||||
STRACE("sigwinch_init() → %08x", ws);
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
|
|
@ -20,19 +20,14 @@
|
|||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
/**
|
||||
* Returns information about thing.
|
||||
* Returns information about file.
|
||||
*
|
||||
* @param st is where result is stored
|
||||
* @see S_ISDIR(st.st_mode), S_ISREG(), etc.
|
||||
* @raise EACCES if denied access to component in path prefix
|
||||
* @raise EIO if i/o error occurred while reading from filesystem
|
||||
* @raise ELOOP if a symbolic link loop exists in `path`
|
||||
* @raise ENAMETOOLONG if a component in `path` exceeds `NAME_MAX`
|
||||
* @raise ENOENT on empty string or if component in path doesn't exist
|
||||
* @raise ENOTDIR if a parent component existed that wasn't a directory
|
||||
* @raise EOVERFLOW shouldn't be possible on 64-bit systems
|
||||
* @raise ELOOP may ahappen if `SYMLOOP_MAX` symlinks were dereferenced
|
||||
* @raise ENAMETOOLONG may happen if `path` exceeded `PATH_MAX`
|
||||
* This function is equivalent to:
|
||||
*
|
||||
* struct stat st;
|
||||
* fstatat(AT_FDCWD, path, &st, 0);
|
||||
*
|
||||
* @see fstatat() for further documentation
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int stat(const char *path, struct stat *st) {
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define DO_NOTHING 0
|
||||
#define DO_RESTART 1
|
||||
#define DO_EINTR 2
|
||||
|
||||
#define kFdEmpty 0
|
||||
#define kFdFile 1
|
||||
#define kFdSocket 2
|
||||
|
@ -23,6 +27,8 @@ struct Fd {
|
|||
char kind;
|
||||
bool zombie;
|
||||
bool dontclose;
|
||||
char buflen;
|
||||
char buf[4];
|
||||
unsigned flags;
|
||||
unsigned mode;
|
||||
int64_t handle;
|
||||
|
@ -44,8 +50,10 @@ struct Fds {
|
|||
struct StdinRelay stdin;
|
||||
};
|
||||
|
||||
int64_t __resolve_stdin_handle(int64_t);
|
||||
void WinMainStdin(void);
|
||||
int64_t __resolve_stdin_handle(int64_t);
|
||||
int __munge_terminal_input(char *, uint32_t *);
|
||||
void __echo_terminal_input(struct Fd *, char *, size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -65,7 +65,7 @@ const char *DescribeSigaction(char[256], int, const struct sigaction *);
|
|||
|
||||
void _init_onntconsoleevent(void);
|
||||
void _init_wincrash(void);
|
||||
void _check_sigwinch();
|
||||
void _check_sigwinch(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int tcgetwinsize_nt(struct Fd *, struct winsize *);
|
||||
int tcgetwinsize_nt(int, struct winsize *);
|
||||
const char *DescribeWinsize(char[64], int, struct winsize *);
|
||||
#define DescribeWinsize(rc, ws) DescribeWinsize(alloca(64), rc, ws)
|
||||
|
||||
|
|
|
@ -33,8 +33,9 @@
|
|||
|
||||
static dontinline textwindows int sys_tcdrain_nt(int fd) {
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
if (_check_interrupts(0, g_fds.p)) return -1;
|
||||
if (!FlushFileBuffers(g_fds.p[fd].handle)) return __winerr();
|
||||
if (_check_interrupts(0)) return -1;
|
||||
// Tried FlushFileBuffers but it made Emacs hang when run in cmd.exe
|
||||
// "Console output is not buffered." -Quoth MSDN on FlushFileBuffers
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,67 +17,45 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/calls/struct/winsize.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/enum/startf.h"
|
||||
#include "libc/nt/startupinfo.h"
|
||||
#include "libc/nt/struct/consolescreenbufferinfoex.h"
|
||||
#include "libc/nt/struct/startupinfo.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int tcgetwinsize_nt(struct Fd *fd, struct winsize *ws) {
|
||||
int i, e, rc;
|
||||
uint32_t mode;
|
||||
struct Fd *fds[3];
|
||||
struct NtStartupInfo startinfo;
|
||||
struct NtConsoleScreenBufferInfoEx sbinfo;
|
||||
rc = -1;
|
||||
e = errno;
|
||||
if (ws) {
|
||||
__fds_lock();
|
||||
fds[0] = fd, fds[1] = g_fds.p + 1, fds[2] = g_fds.p + 0;
|
||||
GetStartupInfo(&startinfo);
|
||||
for (i = 0; i < ARRAYLEN(fds); ++i) {
|
||||
if (fds[i]->kind == kFdFile || fds[i]->kind == kFdConsole) {
|
||||
if (GetConsoleMode(__getfdhandleactual(i), &mode)) {
|
||||
bzero(&sbinfo, sizeof(sbinfo));
|
||||
sbinfo.cbSize = sizeof(sbinfo);
|
||||
if (GetConsoleScreenBufferInfoEx(__getfdhandleactual(i), &sbinfo)) {
|
||||
ws->ws_col = sbinfo.srWindow.Right - sbinfo.srWindow.Left + 1;
|
||||
ws->ws_row = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top + 1;
|
||||
ws->ws_xpixel = 0;
|
||||
ws->ws_ypixel = 0;
|
||||
errno = e;
|
||||
rc = 0;
|
||||
break;
|
||||
} else if (startinfo.dwFlags & kNtStartfUsecountchars) {
|
||||
ws->ws_col = startinfo.dwXCountChars;
|
||||
ws->ws_row = startinfo.dwYCountChars;
|
||||
ws->ws_xpixel = 0;
|
||||
ws->ws_ypixel = 0;
|
||||
errno = e;
|
||||
rc = 0;
|
||||
break;
|
||||
} else {
|
||||
__winerr();
|
||||
}
|
||||
} else {
|
||||
enotty();
|
||||
}
|
||||
} else {
|
||||
ebadf();
|
||||
}
|
||||
}
|
||||
__fds_unlock();
|
||||
} else {
|
||||
efault();
|
||||
textwindows int tcgetwinsize_nt(int fd, struct winsize *ws) {
|
||||
|
||||
// The Linux man page doesn't list EBADF as an errno for this.
|
||||
if (!__isfdopen(fd)) {
|
||||
return enotty();
|
||||
}
|
||||
|
||||
// Unlike _check_sigwinch() this is an API so be stricter.
|
||||
intptr_t hConsoleOutput;
|
||||
if (fd == STDIN_FILENO) {
|
||||
uint32_t dwMode;
|
||||
// WIN32 doesn't allow GetConsoleScreenBufferInfoEx(stdin)
|
||||
if (GetConsoleMode(g_fds.p[STDIN_FILENO].handle, &dwMode)) {
|
||||
hConsoleOutput = g_fds.p[STDOUT_FILENO].handle;
|
||||
if (GetConsoleMode(hConsoleOutput, &dwMode)) {
|
||||
hConsoleOutput = g_fds.p[STDERR_FILENO].handle;
|
||||
}
|
||||
} else {
|
||||
return enotty();
|
||||
}
|
||||
} else if (g_fds.p[fd].kind == kFdConsole) {
|
||||
hConsoleOutput = g_fds.p[fd].extra;
|
||||
} else {
|
||||
hConsoleOutput = g_fds.p[fd].handle;
|
||||
}
|
||||
|
||||
// Query the console.
|
||||
struct NtConsoleScreenBufferInfoEx sr = {.cbSize = sizeof(sr)};
|
||||
if (GetConsoleScreenBufferInfoEx(hConsoleOutput, &sr)) {
|
||||
ws->ws_col = sr.srWindow.Right - sr.srWindow.Left + 1;
|
||||
ws->ws_row = sr.srWindow.Bottom - sr.srWindow.Top + 1;
|
||||
return 0;
|
||||
} else {
|
||||
return enotty();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ int tcgetwinsize(int fd, struct winsize *ws) {
|
|||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = enotty();
|
||||
} else if (IsWindows()) {
|
||||
rc = tcgetwinsize_nt(g_fds.p + fd, ws);
|
||||
rc = tcgetwinsize_nt(fd, ws);
|
||||
} else {
|
||||
rc = sys_ioctl(fd, TIOCGWINSZ, ws);
|
||||
}
|
||||
|
|
|
@ -17,20 +17,151 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/metatermios.internal.h"
|
||||
#include "libc/calls/termios.internal.h"
|
||||
#include "libc/calls/ttydefaults.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/enum/consolemodeflags.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/version.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
textwindows int __munge_terminal_input(char *p, uint32_t *n) {
|
||||
size_t i, j;
|
||||
if (!(__ttymagic & kFdTtyNoCr2Nl)) {
|
||||
for (i = 0; i < *n; ++i) {
|
||||
if (p[i] == '\r') {
|
||||
p[i] = '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
bool delivered = false;
|
||||
bool got_vintr = false;
|
||||
bool got_vquit = false;
|
||||
for (j = i = 0; i < *n; ++i) {
|
||||
/*
|
||||
It's not possible to type Ctrl+Space (aka ^@) into the CMD.EXE
|
||||
console. Ctrl+Z is also problematic, since the Windows Console
|
||||
processes that keystroke into an EOF event, even when we don't
|
||||
enable input processing. These control codes are important for
|
||||
Emacs users. One solution is to install the "Windows Terminal"
|
||||
application from Microsoft Store, type Ctrl+Shift+, to get its
|
||||
settings.json file opened, and add this code to its "actions":
|
||||
|
||||
"actions": [
|
||||
{
|
||||
"command": {
|
||||
"action": "sendInput",
|
||||
"input": "␀"
|
||||
},
|
||||
"keys": "ctrl+space"
|
||||
},
|
||||
{
|
||||
"command": {
|
||||
"action": "sendInput",
|
||||
"input": "␚"
|
||||
},
|
||||
"keys": "ctrl+z"
|
||||
},
|
||||
{
|
||||
"command": {
|
||||
"action": "sendInput",
|
||||
"input": "\u001f"
|
||||
},
|
||||
"keys": "ctrl+-"
|
||||
}
|
||||
],
|
||||
|
||||
Its not possible to configure Windows Terminal to output our
|
||||
control codes. The workaround is to encode control sequences
|
||||
using the "Control Pictures" UNICODE plane, which we'll then
|
||||
translate back from UTF-8 glyphs, into actual control codes.
|
||||
|
||||
Another option Windows users can consider, particularly when
|
||||
using CMD.EXE is installing Microsoft PowerTools whech makes
|
||||
it possible to remap keys then configure ncurses to use them
|
||||
|
||||
https://github.com/microsoft/terminal/issues/2865
|
||||
*/
|
||||
int c;
|
||||
if (i + 3 <= *n && // control pictures ascii nul ␀
|
||||
(p[i + 0] & 255) == 0xe2 && // becomes ^@ a.k.a. ctrl-space
|
||||
(p[i + 1] & 255) == 0x90 && // map the entire unicode plane
|
||||
((p[i + 2] & 255) >= 0x80 && //
|
||||
(p[i + 2] & 255) <= 0x9F)) {
|
||||
c = (p[i + 2] & 255) - 0x80;
|
||||
i += 2;
|
||||
} else {
|
||||
c = p[i] & 255;
|
||||
}
|
||||
if (!(__ttymagic & kFdTtyNoIsigs) && //
|
||||
__vintr != _POSIX_VDISABLE && //
|
||||
c == __vintr) {
|
||||
got_vintr = true;
|
||||
} else if (!(__ttymagic & kFdTtyNoIsigs) && //
|
||||
__vquit != _POSIX_VDISABLE && //
|
||||
c == __vquit) {
|
||||
got_vquit = true;
|
||||
} else {
|
||||
p[j++] = c;
|
||||
}
|
||||
}
|
||||
if (got_vintr) {
|
||||
delivered |= __sig_handle(0, SIGINT, SI_KERNEL, 0);
|
||||
}
|
||||
if (got_vquit) {
|
||||
delivered |= __sig_handle(0, SIGQUIT, SI_KERNEL, 0);
|
||||
}
|
||||
if (*n && !j) {
|
||||
if (delivered) {
|
||||
return DO_EINTR;
|
||||
} else {
|
||||
return DO_RESTART;
|
||||
}
|
||||
}
|
||||
*n = j;
|
||||
return DO_NOTHING;
|
||||
}
|
||||
|
||||
// Manual CMD.EXE echoing for when !ICANON && ECHO is the case.
|
||||
textwindows void __echo_terminal_input(struct Fd *fd, char *p, size_t n) {
|
||||
int64_t hOutput;
|
||||
if (fd->kind == kFdConsole) {
|
||||
hOutput = fd->extra;
|
||||
} else {
|
||||
hOutput = g_fds.p[1].handle;
|
||||
}
|
||||
if (__ttymagic & kFdTtyEchoRaw) {
|
||||
WriteFile(hOutput, p, n, 0, 0);
|
||||
} else {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (isascii(p[i]) && iscntrl(p[i]) && p[i] != '\n' && p[i] != '\t') {
|
||||
char ctl[2];
|
||||
ctl[0] = '^';
|
||||
ctl[1] = p[i] ^ 0100;
|
||||
WriteFile(hOutput, ctl, 2, 0, 0);
|
||||
} else {
|
||||
WriteFile(hOutput, p + i, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) {
|
||||
bool32 ok;
|
||||
int infd;
|
||||
|
@ -122,3 +253,11 @@ textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) {
|
|||
return enotty();
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void tcsetattr_nt_init(void) {
|
||||
if (!getenv("TERM")) {
|
||||
setenv("TERM", "xterm-256color", true);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
|
|
@ -17,14 +17,22 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
|
||||
/**
|
||||
* Sets file mode creation mask.
|
||||
*
|
||||
* On Windows, the value of umask() determines how Cosmopolitan goes
|
||||
* about creating synthetic `st_mode` bits. The default umask is 077
|
||||
* which is based on the assumption that Windows is being used for a
|
||||
* single user. Don't assume that Cosmopolitan Libc will help you to
|
||||
* secure a multitenant Windows computer.
|
||||
*
|
||||
* @return previous mask
|
||||
* @note always succeeds
|
||||
*/
|
||||
|
@ -33,8 +41,7 @@ unsigned umask(unsigned newmask) {
|
|||
if (!IsWindows()) {
|
||||
oldmask = sys_umask(newmask);
|
||||
} else {
|
||||
// TODO(jart): what should we do with this?
|
||||
oldmask = newmask;
|
||||
oldmask = atomic_exchange(&__umask, newmask);
|
||||
}
|
||||
STRACE("umask(%#o) → %#o", oldmask);
|
||||
return oldmask;
|
||||
|
|
|
@ -155,7 +155,7 @@ textwindows int sys_wait4_nt(int pid, int *opt_out_wstatus, int options,
|
|||
sigaddset(&mask, SIGCHLD);
|
||||
__sig_mask(SIG_BLOCK, &mask, &oldmask);
|
||||
do {
|
||||
rc = _check_interrupts(kSigOpRestartable | kSigOpNochld, 0);
|
||||
rc = _check_interrupts(kSigOpRestartable | kSigOpNochld);
|
||||
if (rc == -1) break;
|
||||
__fds_lock();
|
||||
rc = sys_wait4_nt_impl(&pid, opt_out_wstatus, options, opt_out_rusage);
|
||||
|
|
|
@ -66,6 +66,7 @@ _start:
|
|||
lea 8(%rsp),%rsi // argv
|
||||
lea 16(%rsp,%rbx,8),%rdx // envp
|
||||
mov %rsp,__oldstack(%rip)
|
||||
mov %rdx,__envp(%rip)
|
||||
|
||||
// setup backtraces
|
||||
xor %ebp,%ebp
|
||||
|
@ -77,7 +78,8 @@ _start:
|
|||
// make win32 imps noop
|
||||
.weak ape_idata_iat
|
||||
.weak ape_idata_iatend
|
||||
ezlea __win32_oops,ax
|
||||
.weak __oops_win32
|
||||
ezlea __oops_win32,ax
|
||||
ezlea ape_idata_iat,di
|
||||
ezlea ape_idata_iatend,cx
|
||||
sub %rdi,%rcx
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#define ToUpper(c) \
|
||||
(IsWindows() && (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
|
||||
dontasan struct Env __getenv(char **p, const char *k) {
|
||||
dontasan privileged struct Env __getenv(char **p, const char *k) {
|
||||
char *t;
|
||||
int i, j;
|
||||
for (i = 0; (t = p[i]); ++i) {
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 sw=8 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/macros.internal.h"
|
||||
#include "libc/notice.inc"
|
||||
|
||||
// __pid_exec is __pid that isn't updated on fork()
|
||||
|
||||
.initbss 301,_init__pid_exec
|
||||
__pid_exec:
|
||||
.quad 0
|
||||
.endobj __pid_exec,globl
|
||||
.previous
|
||||
|
||||
.init.start 301,_init__pid_exec
|
||||
mov __pid(%rip),%rax
|
||||
stosq
|
||||
.init.end 301,_init__pid_exec
|
|
@ -344,7 +344,7 @@ static void __asan_exit(void) {
|
|||
kprintf("your asan runtime needs\n"
|
||||
"\t__static_yoink(\"__die\");\n"
|
||||
"in order to show you backtraces\n");
|
||||
_Exitr(99);
|
||||
_Exit(99);
|
||||
}
|
||||
|
||||
dontdiscard static __asan_die_f *__asan_die(void) {
|
||||
|
@ -1483,7 +1483,7 @@ void __asan_init(int argc, char **argv, char **envp, intptr_t *auxv) {
|
|||
if (!_cmpxchg(&once, false, true)) return;
|
||||
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
|
||||
__write_str("error: asan binaries require windows10\r\n");
|
||||
_Exitr(0); /* So `make MODE=dbg test` passes w/ Windows7 */
|
||||
_Exit(0); /* So `make MODE=dbg test` passes w/ Windows7 */
|
||||
}
|
||||
REQUIRE(_mmi);
|
||||
REQUIRE(sys_mmap);
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
|
@ -33,30 +35,50 @@ __msabi extern typeof(Sleep) *const __imp_Sleep;
|
|||
/**
|
||||
* Opens file on the New Technology.
|
||||
*
|
||||
* @return handle, or -1 on failure
|
||||
* @return handle, or -1 on failure w/ `errno` set appropriately
|
||||
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
|
||||
*/
|
||||
textwindows int64_t CreateFile(
|
||||
const char16_t *lpFileName, uint32_t dwDesiredAccess, uint32_t dwShareMode,
|
||||
struct NtSecurityAttributes *opt_lpSecurityAttributes,
|
||||
int dwCreationDisposition, uint32_t dwFlagsAndAttributes,
|
||||
int64_t opt_hTemplateFile) {
|
||||
textwindows int64_t CreateFile(const char16_t *lpFileName, //
|
||||
uint32_t dwDesiredAccess, //
|
||||
uint32_t dwShareMode, //
|
||||
struct NtSecurityAttributes *opt_lpSecurity, //
|
||||
int dwCreationDisposition, //
|
||||
uint32_t dwFlagsAndAttributes, //
|
||||
int64_t opt_hTemplateFile) {
|
||||
int64_t hHandle;
|
||||
uint32_t micros = 1;
|
||||
TryAgain:
|
||||
hHandle = __imp_CreateFileW(lpFileName, dwDesiredAccess, dwShareMode,
|
||||
opt_lpSecurityAttributes, dwCreationDisposition,
|
||||
opt_lpSecurity, dwCreationDisposition,
|
||||
dwFlagsAndAttributes, opt_hTemplateFile);
|
||||
if (hHandle == -1 && __imp_GetLastError() == kNtErrorPipeBusy) {
|
||||
if (micros >= 1024) __imp_Sleep(micros / 1024);
|
||||
if (micros / 1024 < __SIG_POLLING_INTERVAL_MS) micros <<= 1;
|
||||
goto TryAgain;
|
||||
if (hHandle == -1) {
|
||||
switch (__imp_GetLastError()) {
|
||||
case kNtErrorPipeBusy:
|
||||
if (micros >= 1024) __imp_Sleep(micros / 1024);
|
||||
if (micros / 1024 < __SIG_POLLING_INTERVAL_MS) micros <<= 1;
|
||||
goto TryAgain;
|
||||
case kNtErrorAccessDenied:
|
||||
// GetNtOpenFlags() always greedily requests execute permissions
|
||||
// because the POSIX flag O_EXEC doesn't mean the same thing. It
|
||||
// seems however this causes the opening of certain files to not
|
||||
// work, possibly due to Windows Defender or some security thing
|
||||
// In that case, we'll cross our fingers the file isn't a binary
|
||||
if ((dwDesiredAccess & kNtGenericExecute) &&
|
||||
(dwCreationDisposition == kNtOpenExisting ||
|
||||
dwCreationDisposition == kNtTruncateExisting)) {
|
||||
dwDesiredAccess &= ~kNtGenericExecute;
|
||||
goto TryAgain;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
__winerr();
|
||||
}
|
||||
if (hHandle == -1) __winerr();
|
||||
NTTRACE("CreateFile(%#hs, %s, %s, %s, %s, %s, %ld) → %ld% m", lpFileName,
|
||||
DescribeNtFileAccessFlags(dwDesiredAccess),
|
||||
DescribeNtFileShareFlags(dwShareMode),
|
||||
DescribeNtSecurityAttributes(opt_lpSecurityAttributes),
|
||||
DescribeNtSecurityAttributes(opt_lpSecurity),
|
||||
DescribeNtCreationDisposition(dwCreationDisposition),
|
||||
DescribeNtFileFlagAttr(dwFlagsAndAttributes), opt_hTemplateFile,
|
||||
hHandle);
|
||||
|
|
|
@ -43,10 +43,12 @@ textwindows int64_t CreateFileMapping(
|
|||
flProtect, dwMaximumSizeHigh,
|
||||
dwMaximumSizeLow, opt_lpName);
|
||||
if (!hHandle) __winerr();
|
||||
#if 1
|
||||
NTTRACE("CreateFileMapping(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile,
|
||||
DescribeNtSecurityAttributes(opt_lpFileMappingAttributes),
|
||||
DescribeNtPageFlags(flProtect),
|
||||
(uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName,
|
||||
hHandle);
|
||||
#endif
|
||||
return hHandle;
|
||||
}
|
||||
|
|
|
@ -120,10 +120,6 @@ const char *(DescribeTermios)(char buf[N], ssize_t rc, struct termios *tio) {
|
|||
append(", .c_lflag=%s",
|
||||
DescribeFlags(b128, 128, kLocal, ARRAYLEN(kLocal), "", tio->c_lflag));
|
||||
|
||||
append(", c_cc[VINTR]=%#o", tio->c_cc[VINTR]);
|
||||
append(", c_cc[VERASE]=%#o", tio->c_cc[VERASE]);
|
||||
append(", c_cc[VWERASE]=%#o", tio->c_cc[VWERASE]);
|
||||
|
||||
append("}");
|
||||
|
||||
return buf;
|
||||
|
|
|
@ -19,31 +19,30 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/directmap.internal.h"
|
||||
#include "libc/nt/enum/filemapflags.h"
|
||||
#include "libc/nt/enum/pageflags.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/processmemorycounters.h"
|
||||
#include "libc/nt/struct/securityattributes.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
|
||||
int flags, int fd, int64_t off) {
|
||||
int iscow;
|
||||
int64_t handle;
|
||||
uint32_t oldprot;
|
||||
struct DirectMap dm;
|
||||
struct ProtectNt fl;
|
||||
const struct NtSecurityAttributes *sec;
|
||||
|
||||
int64_t handle;
|
||||
if (flags & MAP_ANONYMOUS) {
|
||||
handle = kNtInvalidHandleValue;
|
||||
} else {
|
||||
handle = g_fds.p[fd].handle;
|
||||
}
|
||||
|
||||
const struct NtSecurityAttributes *sec;
|
||||
if ((flags & MAP_TYPE) != MAP_SHARED) {
|
||||
sec = 0; // MAP_PRIVATE isn't inherited across fork()
|
||||
} else {
|
||||
|
@ -54,7 +53,8 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
|
|||
// later using mprotect(). the workaround is to always request execute
|
||||
// and then virtualprotect() it away until we actually need it. please
|
||||
// note that open-nt.c always requests an kNtGenericExecute accessmask
|
||||
iscow = false;
|
||||
int iscow = false;
|
||||
struct ProtectNt fl;
|
||||
if (handle != -1) {
|
||||
if ((flags & MAP_TYPE) != MAP_SHARED) {
|
||||
// windows has cow pages but they can't propagate across fork()
|
||||
|
@ -77,16 +77,43 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
|
|||
kNtFileMapWrite | kNtFileMapExecute};
|
||||
}
|
||||
|
||||
int e = errno;
|
||||
struct DirectMap dm;
|
||||
TryAgain:
|
||||
if ((dm.maphandle = CreateFileMapping(handle, sec, fl.flags1,
|
||||
(size + off) >> 32, (size + off), 0))) {
|
||||
if ((dm.addr = MapViewOfFileEx(dm.maphandle, fl.flags2, off >> 32, off,
|
||||
size, addr))) {
|
||||
uint32_t oldprot;
|
||||
if (VirtualProtect(addr, size, __prot2nt(prot, iscow), &oldprot)) {
|
||||
return dm;
|
||||
}
|
||||
UnmapViewOfFile(dm.addr);
|
||||
}
|
||||
CloseHandle(dm.maphandle);
|
||||
} else if (!(prot & PROT_EXEC) && //
|
||||
(fl.flags2 & kNtFileMapExecute) && //
|
||||
GetLastError() == kNtErrorAccessDenied) {
|
||||
// your file needs to have been O_CREAT'd with exec `mode` bits in
|
||||
// order to be mapped with executable permission. we always try to
|
||||
// get execute permission if the kernel will give it to us because
|
||||
// win32 would otherwise forbid mprotect() from elevating later on
|
||||
fl.flags2 &= ~kNtFileMapExecute;
|
||||
switch (fl.flags1) {
|
||||
case kNtPageExecuteWritecopy:
|
||||
fl.flags1 = kNtPageWritecopy;
|
||||
break;
|
||||
case kNtPageExecuteReadwrite:
|
||||
fl.flags1 = kNtPageReadwrite;
|
||||
break;
|
||||
case kNtPageExecuteRead:
|
||||
fl.flags1 = kNtPageReadonly;
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
errno = e;
|
||||
goto TryAgain;
|
||||
}
|
||||
|
||||
dm.maphandle = kNtInvalidHandleValue;
|
||||
|
|
|
@ -19,29 +19,30 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/intrin/promises.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/nexgen32e/vendor.internal.h"
|
||||
#include "libc/nt/enum/status.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
|
||||
/**
|
||||
* Terminates process, ignoring destructors and atexit() handlers.
|
||||
*
|
||||
* When running on bare metal, this function will reboot your computer
|
||||
* by hosing the interrupt descriptors and triple faulting the system.
|
||||
*
|
||||
* Exit codes are narrowed to an unsigned char on most platforms. The
|
||||
* exceptions would be Windows, NetBSD, and OpenBSD, which should let
|
||||
* you have larger exit codes.
|
||||
*
|
||||
* When running on bare metal, this function will reboot your computer
|
||||
* by hosing the interrupt descriptors and triple faulting the system.
|
||||
*
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
* @noreturn
|
||||
*/
|
||||
wontreturn void _Exit(int exitcode) {
|
||||
int i;
|
||||
STRACE("_Exit(%d)", exitcode);
|
||||
if (!IsWindows() && !IsMetal()) {
|
||||
// On Linux _Exit1 (exit) must be called in pledge("") mode. If we
|
||||
|
@ -84,19 +85,24 @@ wontreturn void _Exit(int exitcode) {
|
|||
#endif
|
||||
} else if (IsWindows()) {
|
||||
uint32_t waitstatus;
|
||||
// Restoring the CMD.EXE program to its original state is critical.
|
||||
if (_weaken(__restore_console_win32)) {
|
||||
_weaken(__restore_console_win32)();
|
||||
}
|
||||
// What Microsoft calls an exit code, POSIX calls a status code. See
|
||||
// also the WEXITSTATUS() and WIFEXITED() macros that POSIX defines.
|
||||
waitstatus = exitcode;
|
||||
waitstatus <<= 8;
|
||||
// "The GetExitCodeProcess function returns a valid error code
|
||||
// defined by the application only after the thread terminates.
|
||||
// Therefore, an application should not use kNtStillActive (259) as
|
||||
// an error code (kNtStillActive is a macro for kNtStatusPending).
|
||||
// If a thread returns kNtStillActive (259) as an error code, then
|
||||
// applications that test for that value could interpret it to mean
|
||||
// that the thread is still running, and continue to test for the
|
||||
// completion of the thread after the thread has terminated, which
|
||||
// could put the application into an infinite loop." -Quoth MSDN
|
||||
if (waitstatus == kNtStillActive) {
|
||||
// The GetExitCodeProcess function returns a valid error code
|
||||
// defined by the application only after the thread terminates.
|
||||
// Therefore, an application should not use STILL_ACTIVE (259) as
|
||||
// an error code (STILL_ACTIVE is a macro for STATUS_PENDING
|
||||
// (minwinbase.h)). If a thread returns STILL_ACTIVE (259) as an
|
||||
// error code, then applications that test for that value could
|
||||
// interpret it to mean that the thread is still running, and
|
||||
// continue to test for the completion of the thread after the
|
||||
// thread has terminated, which could put the application into an
|
||||
// infinite loop. -Quoth MSDN (see also libc/calls/wait4-nt.c)
|
||||
waitstatus = 0xc9af3d51u;
|
||||
}
|
||||
ExitProcess(waitstatus);
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
wontreturn void _Exitr(int exitcode) {
|
||||
#if SupportsWindows()
|
||||
_restorewintty();
|
||||
#endif
|
||||
_Exit(exitcode);
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ShouldUseMsabiAttribute() 1
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
|
@ -30,20 +29,29 @@
|
|||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/asancodes.h"
|
||||
#include "libc/intrin/asmflag.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/getenv.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/uart.internal.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/filesharemode.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
|
@ -57,8 +65,13 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/str/tab.internal.h"
|
||||
#include "libc/str/utf16.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/thread/tls2.h"
|
||||
|
@ -107,6 +120,17 @@
|
|||
break; \
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
__msabi extern typeof(CreateFile) *const __imp_CreateFileW;
|
||||
__msabi extern typeof(DuplicateHandle) *const __imp_DuplicateHandle;
|
||||
__msabi extern typeof(GetCurrentProcess) *const __imp_GetCurrentProcess;
|
||||
__msabi extern typeof(GetEnvironmentVariable) *const __imp_GetEnvironmentVariableW;
|
||||
__msabi extern typeof(GetLastError) *const __imp_GetLastError;
|
||||
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
|
||||
__msabi extern typeof(SetLastError) *const __imp_SetLastError;
|
||||
__msabi extern typeof(WriteFile) *const __imp_WriteFile;
|
||||
// clang-format on
|
||||
|
||||
long __klog_handle;
|
||||
extern struct SymbolTable *__symtab;
|
||||
|
||||
|
@ -188,24 +212,180 @@ privileged bool kisdangerous(const void *p) {
|
|||
if (IsStackFrame(frame)) return false;
|
||||
if (kismapped(frame)) return false;
|
||||
}
|
||||
if (GetStackAddr() + 16384 <= (uintptr_t)p &&
|
||||
if (GetStackAddr() + GetGuardSize() <= (uintptr_t)p &&
|
||||
(uintptr_t)p < GetStackAddr() + GetStackSize()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
privileged static long kloghandle(void) {
|
||||
if (__klog_handle) {
|
||||
return __klog_handle;
|
||||
} else if (!IsWindows()) {
|
||||
return 2;
|
||||
} else {
|
||||
return __imp_GetStdHandle(kNtStdErrorHandle);
|
||||
}
|
||||
privileged static void klogclose(long fd) {
|
||||
#ifdef __x86_64__
|
||||
long ax = __NR_close;
|
||||
asm volatile("syscall"
|
||||
: "+a"(ax), "+D"(fd)
|
||||
: /* inputs already specified */
|
||||
: "rsi", "rdx", "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
#elif defined(__aarch64__)
|
||||
register long x0 asm("x0") = fd;
|
||||
register int x8 asm("x8") = __NR_close;
|
||||
register int x16 asm("x16") = __NR_close;
|
||||
asm volatile("svc\t0" : "+r"(x0) : "r"(x8), "r"(x16) : "x9", "memory");
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
}
|
||||
|
||||
privileged void _klog(const char *b, size_t n) {
|
||||
privileged static long klogfcntl(long fd, long cmd, long arg) {
|
||||
#ifdef __x86_64__
|
||||
char cf;
|
||||
long ax = __NR_fcntl;
|
||||
asm volatile("clc\n\tsyscall"
|
||||
: CFLAG_CONSTRAINT(cf), "+a"(ax), "+D"(fd), "+S"(cmd), "+d"(arg)
|
||||
: /* inputs already specified */
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||
if (cf) ax = -ax;
|
||||
return ax;
|
||||
#elif defined(__aarch64__)
|
||||
register long x0 asm("x0") = fd;
|
||||
register long x1 asm("x1") = cmd;
|
||||
register long x2 asm("x2") = arg;
|
||||
register int x8 asm("x8") = __NR_fcntl;
|
||||
register int x16 asm("x16") = __NR_fcntl;
|
||||
asm volatile("mov\tx9,0\n\t" // clear carry flag
|
||||
"adds\tx9,x9,0\n\t" // clear carry flag
|
||||
"svc\t0\n\t"
|
||||
"bcs\t1f\n\t"
|
||||
"b\t2f\n1:\t"
|
||||
"neg\tx0,x0\n2:"
|
||||
: "+r"(x0)
|
||||
: "r"(x1), "r"(x2), "r"(x8), "r"(x16)
|
||||
: "x9", "memory");
|
||||
return x0;
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
}
|
||||
|
||||
privileged static long klogopen(const char *path) {
|
||||
long dirfd = AT_FDCWD;
|
||||
long flags = O_WRONLY | O_CREAT | O_APPEND;
|
||||
long mode = 0600;
|
||||
#ifdef __x86_64__
|
||||
char cf;
|
||||
long ax = __NR_openat;
|
||||
register long r10 asm("r10") = mode;
|
||||
asm volatile(CFLAG_ASM("clc\n\tsyscall")
|
||||
: CFLAG_CONSTRAINT(cf), "+a"(ax), "+D"(dirfd), "+S"(path),
|
||||
"+d"(flags), "+r"(r10)
|
||||
: /* inputs already specified */
|
||||
: "rcx", "r8", "r9", "r11", "memory");
|
||||
if (cf) ax = -ax;
|
||||
return ax;
|
||||
#elif defined(__aarch64__)
|
||||
register long x0 asm("x0") = dirfd;
|
||||
register long x1 asm("x1") = (long)path;
|
||||
register long x2 asm("x2") = flags;
|
||||
register long x3 asm("x3") = mode;
|
||||
register int x8 asm("x8") = __NR_openat;
|
||||
register int x16 asm("x16") = __NR_openat;
|
||||
asm volatile("mov\tx9,0\n\t" // clear carry flag
|
||||
"adds\tx9,x9,0\n\t" // clear carry flag
|
||||
"svc\t0\n\t"
|
||||
"bcs\t1f\n\t"
|
||||
"b\t2f\n1:\t"
|
||||
"neg\tx0,x0\n2:"
|
||||
: "+r"(x0)
|
||||
: "r"(x1), "r"(x2), "r"(x3), "r"(x8), "r"(x16)
|
||||
: "x9", "memory");
|
||||
return x0;
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
}
|
||||
|
||||
// returns log handle or -1 if logging shouldn't happen
|
||||
privileged long kloghandle(void) {
|
||||
// kprintf() needs to own a file descriptor in case apps closes stderr
|
||||
// our close() and dup() implementations will trigger this initializer
|
||||
// to minimize a chance that the user accidentally closes their logger
|
||||
// while at the same time, avoiding a mandatory initialization syscall
|
||||
if (!__klog_handle) {
|
||||
long hand;
|
||||
// setting KPRINTF_LOG="/tmp/foo.log" will override stderr
|
||||
// setting KPRINTF_LOG="INTEGER" logs to a file descriptor
|
||||
// setting KPRINTF_LOG="" shall disable kprintf altogether
|
||||
if (IsMetal()) {
|
||||
hand = STDERR_FILENO;
|
||||
} else if (IsWindows()) {
|
||||
uint32_t e, n;
|
||||
const char16_t path[512];
|
||||
e = __imp_GetLastError();
|
||||
n = __imp_GetEnvironmentVariableW(u"KPRINTF_LOG", path, 512);
|
||||
if (!n && __imp_GetLastError() == kNtErrorEnvvarNotFound) {
|
||||
long proc;
|
||||
proc = __imp_GetCurrentProcess();
|
||||
hand = __imp_GetStdHandle(kNtStdErrorHandle);
|
||||
__imp_DuplicateHandle(proc, hand, proc, &hand, 0, true,
|
||||
kNtDuplicateSameAccess);
|
||||
} else if (n && n < 512) {
|
||||
hand = __imp_CreateFileW(
|
||||
path, kNtGenericWrite | kNtFileAppendData,
|
||||
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
|
||||
&kNtIsInheritable, kNtOpenAlways, kNtFileAttributeNormal, 0);
|
||||
} else {
|
||||
hand = -1; // KPRINTF_LOG was empty string or too long
|
||||
}
|
||||
__imp_SetLastError(e);
|
||||
} else {
|
||||
long fd, fd2;
|
||||
bool closefd;
|
||||
const char *path;
|
||||
if (!__NR_write || !__envp) {
|
||||
// it's too early in the initialization process for kprintf
|
||||
return -1;
|
||||
}
|
||||
path = __getenv(__envp, "KPRINTF_LOG").s;
|
||||
closefd = false;
|
||||
if (!path) {
|
||||
fd = STDERR_FILENO;
|
||||
} else if (*path) {
|
||||
const char *p;
|
||||
for (fd = 0, p = path; *p; ++p) {
|
||||
if ('0' <= *p && *p <= '9') {
|
||||
fd *= 10;
|
||||
fd += *p - '0';
|
||||
} else {
|
||||
fd = klogopen(path);
|
||||
closefd = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fd = -1;
|
||||
}
|
||||
if (fd >= 0) {
|
||||
// avoid interfering with hard-coded assumptions about fds
|
||||
if ((fd2 = klogfcntl(fd, F_DUPFD, 100)) >= 0) {
|
||||
klogfcntl(fd2, F_SETFD, FD_CLOEXEC);
|
||||
if (closefd) {
|
||||
klogclose(fd);
|
||||
}
|
||||
} else {
|
||||
// RLIMIT_NOFILE was probably too low for safe duplicate
|
||||
fd2 = fd;
|
||||
}
|
||||
} else {
|
||||
fd2 = -1;
|
||||
}
|
||||
hand = fd2;
|
||||
}
|
||||
__klog_handle = hand;
|
||||
}
|
||||
return __klog_handle;
|
||||
}
|
||||
|
||||
privileged void klog(const char *b, size_t n) {
|
||||
#ifdef __x86_64__
|
||||
int e;
|
||||
long h;
|
||||
|
@ -215,7 +395,9 @@ privileged void _klog(const char *b, size_t n) {
|
|||
uint32_t wrote;
|
||||
unsigned char al;
|
||||
long rax, rdi, rsi, rdx;
|
||||
h = kloghandle();
|
||||
if ((h = kloghandle()) == -1) {
|
||||
return;
|
||||
}
|
||||
if (IsWindows()) {
|
||||
e = __imp_GetLastError();
|
||||
__imp_WriteFile(h, b, n, &wrote, 0);
|
||||
|
@ -243,7 +425,7 @@ privileged void _klog(const char *b, size_t n) {
|
|||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
register long r0 asm("x0") = (long)kloghandle();
|
||||
register long r0 asm("x0") = kloghandle();
|
||||
register long r1 asm("x1") = (long)b;
|
||||
register long r2 asm("x2") = (long)n;
|
||||
register long r8 asm("x8") = (long)__NR_write;
|
||||
|
@ -262,7 +444,6 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
|
|||
va_list va) {
|
||||
int si, y;
|
||||
wint_t t, u;
|
||||
char errnum[12];
|
||||
const char *abet;
|
||||
signed char type;
|
||||
const char *s, *f;
|
||||
|
@ -545,11 +726,16 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
|
|||
break;
|
||||
} else {
|
||||
type = 0;
|
||||
#if defined(SYSDEBUG) && _NTTRACE
|
||||
strerror_r(e, z, sizeof(z));
|
||||
s = z;
|
||||
#else
|
||||
s = _strerrno(e);
|
||||
if (!s) {
|
||||
FormatInt32(errnum, e);
|
||||
s = errnum;
|
||||
FormatInt32(z, e);
|
||||
s = z;
|
||||
}
|
||||
#endif
|
||||
goto FormatString;
|
||||
}
|
||||
}
|
||||
|
@ -851,7 +1037,7 @@ privileged void kvprintf(const char *fmt, va_list v) {
|
|||
size_t n;
|
||||
char b[4000];
|
||||
n = kformat(b, sizeof(b), fmt, v);
|
||||
_klog(b, MIN(n, sizeof(b) - 1));
|
||||
klog(b, MIN(n, sizeof(b) - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -926,9 +1112,9 @@ privileged void kvprintf(const char *fmt, va_list v) {
|
|||
* @vforksafe
|
||||
*/
|
||||
privileged void kprintf(const char *fmt, ...) {
|
||||
/* system call support runtime depends on this function */
|
||||
/* function tracing runtime depends on this function */
|
||||
/* asan runtime depends on this function */
|
||||
// system call support runtime depends on this function
|
||||
// function tracing runtime depends on this function
|
||||
// asan runtime depends on this function
|
||||
va_list v;
|
||||
va_start(v, fmt);
|
||||
kvprintf(fmt, v);
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
#define COSMOPOLITAN_LIBC_INTRIN_KPRINTF_H_
|
||||
#ifdef _COSMO_SOURCE
|
||||
|
||||
#define klog __klog
|
||||
#define kprintf __kprintf
|
||||
#define ksnprintf __ksnprintf
|
||||
#define kvprintf __kvprintf
|
||||
#define kvsnprintf __kvsnprintf
|
||||
#define kloghandle __kloghandle
|
||||
#define kisdangerous __kisdangerous
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
@ -21,8 +23,10 @@ void kprintf(const char *, ...);
|
|||
size_t ksnprintf(char *, size_t, const char *, ...);
|
||||
void kvprintf(const char *, va_list);
|
||||
size_t kvsnprintf(char *, size_t, const char *, va_list);
|
||||
|
||||
bool kisdangerous(const void *);
|
||||
void _klog(const char *, size_t);
|
||||
void klog(const char *, size_t);
|
||||
long kloghandle(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
wontreturn void quick_exit(int exitcode) {
|
||||
const uintptr_t *p;
|
||||
STRACE("quick_exit(%d)", exitcode);
|
||||
_restorewintty();
|
||||
if (_weaken(fflush)) {
|
||||
_weaken(fflush)(0);
|
||||
}
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
|
||||
__msabi extern typeof(GetCurrentProcessId) *const __imp_GetCurrentProcessId;
|
||||
__msabi extern typeof(SetConsoleMode) *const __imp_SetConsoleMode;
|
||||
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
|
||||
|
||||
extern uint32_t __pid_exec;
|
||||
|
||||
const signed char kNtConsoleHandles[3] = {
|
||||
(signed char)kNtStdInputHandle,
|
||||
(signed char)kNtStdOutputHandle,
|
||||
(signed char)kNtStdErrorHandle,
|
||||
};
|
||||
|
||||
// Puts cmd.exe gui back the way it was.
|
||||
void _restorewintty(void) {
|
||||
int i;
|
||||
if (!IsWindows()) return;
|
||||
if (__imp_GetCurrentProcessId() != __pid_exec) return;
|
||||
for (i = 0; i < 3; ++i) {
|
||||
__imp_SetConsoleMode(__imp_GetStdHandle(kNtConsoleHandles[i]),
|
||||
__ntconsolemode[i]);
|
||||
}
|
||||
}
|
|
@ -16,9 +16,17 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ShouldUseMsabiAttribute() 1
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/str/str.h"
|
||||
// clang-format off
|
||||
|
||||
#if defined(SYSDEBUG) && _NTTRACE
|
||||
dontasan dontubsan privileged
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Converts errno value to string.
|
||||
|
@ -27,6 +35,6 @@
|
|||
* @return 0 on success, or error code
|
||||
*/
|
||||
int strerror_r(int err, char *buf, size_t size) {
|
||||
int winerr = IsWindows() ? GetLastError() : 0;
|
||||
int winerr = IsWindows() ? __imp_GetLastError() : 0;
|
||||
return strerror_wr(err, winerr, buf, size);
|
||||
}
|
||||
|
|
|
@ -21,11 +21,17 @@
|
|||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/formatmessageflags.h"
|
||||
#include "libc/nt/enum/lang.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/str/str.h"
|
||||
// clang-format off
|
||||
|
||||
#if defined(SYSDEBUG) && _NTTRACE
|
||||
dontasan dontubsan privileged
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Converts errno value to string with explicit windows errno too.
|
||||
|
@ -53,7 +59,7 @@ int strerror_wr(int err, uint32_t winerr, char *buf, size_t size) {
|
|||
for (; (c = *sym++); --size)
|
||||
if (size > 1) *buf++ = c;
|
||||
if (size) *buf = 0;
|
||||
} else if (!IsWindows() || ((err == winerr || !winerr) && !wanting)) {
|
||||
} else if (!IsWindows() /* || ((err == winerr || !winerr) && !wanting) */) {
|
||||
ksnprintf(buf, size, "%s/%d/%s", sym, err, msg);
|
||||
} else {
|
||||
if ((n = __imp_FormatMessageW(
|
||||
|
|
|
@ -206,7 +206,7 @@ static void __ubsan_exit(void) {
|
|||
kprintf("your ubsan runtime needs\n"
|
||||
"\t__static_yoink(\"__die\");\n"
|
||||
"in order to show you backtraces\n");
|
||||
_Exitr(99);
|
||||
_Exit(99);
|
||||
}
|
||||
|
||||
static char *__ubsan_stpcpy(char *d, const char *s) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2023 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,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/internal.h"
|
||||
|
||||
uint32_t __ntconsolemode[3];
|
||||
atomic_int __umask;
|
|
@ -148,11 +148,11 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
strlen(" (discriminator ") - 1)) &&
|
||||
(p3 = memchr(p2, '\n', got - (p2 - p1)))) {
|
||||
if (p3 > p2 && p3[-1] == '\r') --p3;
|
||||
_klog(p1, p2 - p1);
|
||||
klog(p1, p2 - p1);
|
||||
got -= p3 - p1;
|
||||
p1 += p3 - p1;
|
||||
} else {
|
||||
_klog(p1, got);
|
||||
klog(p1, got);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ static relegated wontreturn void __check_fail_ndebug(uint64_t want, //
|
|||
}
|
||||
kprintf("\n");
|
||||
if (_weaken(__die)) _weaken(__die)();
|
||||
_Exitr(68);
|
||||
_Exit(68);
|
||||
}
|
||||
|
||||
void __check_fail_eq(uint64_t want, uint64_t got, const char *file, int line,
|
||||
|
|
|
@ -55,10 +55,10 @@ relegated wontreturn void __die(void) {
|
|||
DebugBreak();
|
||||
}
|
||||
ShowBacktrace(2, __builtin_frame_address(0));
|
||||
_Exitr(77);
|
||||
_Exit(77);
|
||||
} else if (owner == me) {
|
||||
kprintf("die failed while dying\n");
|
||||
_Exitr(79);
|
||||
_Exit(79);
|
||||
} else {
|
||||
_Exit1(79);
|
||||
}
|
||||
|
|
|
@ -115,6 +115,6 @@ dontasan void CheckForMemoryLeaks(void) {
|
|||
/* __print_maps(); */
|
||||
/* PrintSystemMappings(2); */
|
||||
/* PrintGarbage(); */
|
||||
_Exitr(78);
|
||||
_Exit(78);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,6 @@ void _meminfo(int); /* shows malloc statistics &c. */
|
|||
void _memsummary(int); /* light version of same thing */
|
||||
bool IsTerminalInarticulate(void) nosideeffect;
|
||||
const char *commandvenv(const char *, const char *);
|
||||
int LogKprintfToFile(const char *);
|
||||
const char *GetAddr2linePath(void);
|
||||
const char *GetGdbPath(void);
|
||||
bool32 IsDebuggerPresent(bool);
|
||||
|
|
|
@ -20,5 +20,5 @@
|
|||
#include "libc/runtime/runtime.h"
|
||||
|
||||
wontreturn void _log_exit(int exitcode) {
|
||||
_Exitr(exitcode);
|
||||
_Exit(exitcode);
|
||||
}
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
static int __klog_fd;
|
||||
extern long __klog_handle;
|
||||
|
||||
/**
|
||||
* Redirects kprintf(), `--strace`, etc. output to file.
|
||||
*
|
||||
* @param path is filename to append to; if null is specified then
|
||||
* this file logging facility will be disabled; when the empty
|
||||
* string is specified, then the default path shall be used
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int LogKprintfToFile(const char *path) {
|
||||
int fd, dd;
|
||||
if (!path) {
|
||||
if (__klog_fd) {
|
||||
__klog_handle = 0;
|
||||
close(__klog_fd);
|
||||
__klog_fd = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (!*path) path = "/tmp/kprintf.log";
|
||||
fd = open(path, O_WRONLY | O_APPEND | O_CREAT, 0644);
|
||||
if (fd == -1) return -1;
|
||||
dd = fcntl(fd, F_DUPFD_CLOEXEC, 100);
|
||||
close(fd);
|
||||
if (dd == -1) return -1;
|
||||
if (__klog_fd) close(__klog_fd);
|
||||
__klog_fd = dd;
|
||||
__klog_handle = IsWindows() ? g_fds.p[dd].handle : dd;
|
||||
return 0;
|
||||
}
|
|
@ -239,11 +239,11 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
|
|||
p = ShowGeneralRegisters(p, ctx);
|
||||
p = ShowSseRegisters(p, ctx);
|
||||
*p++ = '\n';
|
||||
_klog(buf, p - buf);
|
||||
klog(buf, p - buf);
|
||||
ShowFunctionCalls(ctx);
|
||||
} else {
|
||||
*p++ = '\n';
|
||||
_klog(buf, p - buf);
|
||||
klog(buf, p - buf);
|
||||
}
|
||||
kprintf("\n");
|
||||
if (!IsWindows()) __print_maps();
|
||||
|
@ -275,7 +275,7 @@ static wontreturn relegated dontinstrument void __minicrash(int sig,
|
|||
kind, sig, __argv[0], ctx ? ctx->uc_mcontext.rip : 0,
|
||||
ctx ? ctx->uc_mcontext.rsp : 0, ctx ? ctx->uc_mcontext.rbp : 0, __pid,
|
||||
__tls_enabled ? __get_tls()->tib_tid : sys_gettid());
|
||||
_Exitr(119);
|
||||
_Exit(119);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -334,7 +334,7 @@ relegated void __oncrash_amd64(int sig, struct siginfo *si, void *arg) {
|
|||
if (!(gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT))) {
|
||||
__restore_tty();
|
||||
ShowCrashReport(err, sig, si, ctx);
|
||||
_Exitr(128 + sig);
|
||||
_Exit(128 + sig);
|
||||
}
|
||||
atomic_store_explicit(&once, 0, memory_order_relaxed);
|
||||
} else {
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 sw=8 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/macros.internal.h"
|
||||
#include "libc/notice.inc"
|
||||
|
||||
.initbss 300,_init_envp
|
||||
// Global variable holding _start(envp) parameter.
|
||||
__envp: .quad 0
|
||||
.endobj __envp,globl
|
||||
.previous
|
||||
|
||||
.init.start 300,_init_envp
|
||||
mov %r14,%rax
|
||||
stosq
|
||||
.init.end 300,_init_envp
|
|
@ -17,8 +17,5 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/runtime.h"
|
||||
#ifndef __x86_64__
|
||||
|
||||
char **__envp;
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -39,13 +39,13 @@ $(LIBC_NEXGEN32E_A).pkg: \
|
|||
$(LIBC_NEXGEN32E_A_OBJS) \
|
||||
$(foreach x,$(LIBC_NEXGEN32E_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/libc/nexgen32e/envp.o \
|
||||
o/$(MODE)/libc/nexgen32e/argc2.o \
|
||||
o/$(MODE)/libc/nexgen32e/argv2.o \
|
||||
o/$(MODE)/libc/nexgen32e/auxv2.o \
|
||||
o/$(MODE)/libc/nexgen32e/cescapec.o \
|
||||
o/$(MODE)/libc/nexgen32e/crc32init.o \
|
||||
o/$(MODE)/libc/nexgen32e/environ2.o \
|
||||
o/$(MODE)/libc/nexgen32e/envp2.o \
|
||||
o/$(MODE)/libc/nexgen32e/kbase36.o \
|
||||
o/$(MODE)/libc/nexgen32e/ktens.o \
|
||||
o/$(MODE)/libc/nexgen32e/ktolower.o \
|
||||
|
|
|
@ -77,8 +77,8 @@ bool32 SetNamedPipeHandleState(int64_t hNamedPipe, uint32_t *lpMode,
|
|||
uint32_t *lpCollectDataTimeout);
|
||||
|
||||
bool32 PeekNamedPipe(int64_t hNamedPipe, void *lpBuffer, uint32_t nBufferSize,
|
||||
uint32_t *lpBytesRead, uint32_t *lpTotalBytesAvail,
|
||||
uint32_t *lpBytesLeftThisMessage);
|
||||
uint32_t *opt_lpBytesRead, uint32_t *opt_lpTotalBytesAvail,
|
||||
uint32_t *opt_lpBytesLeftThisMessage);
|
||||
|
||||
bool32 TransactNamedPipe(int64_t hNamedPipe, void *lpInBuffer,
|
||||
uint32_t nInBufferSize, void *lpOutBuffer,
|
||||
|
|
2
libc/nt/kernel32/CreateFileA.S
Normal file
2
libc/nt/kernel32/CreateFileA.S
Normal file
|
@ -0,0 +1,2 @@
|
|||
#include "libc/nt/codegen.h"
|
||||
.imp kernel32,__imp_CreateFileA,CreateFileA
|
|
@ -13,6 +13,7 @@ imp '' CloseHandle kernel32 1
|
|||
imp '' CreateDirectoryW kernel32 2
|
||||
imp '' CreateFileMappingNumaW kernel32 7
|
||||
imp '' CreateFileMappingW kernel32 6
|
||||
imp '' CreateFileA kernel32 7
|
||||
imp '' CreateFileW kernel32 7
|
||||
imp '' CreateNamedPipeW kernel32 8
|
||||
imp '' CreatePipe kernel32 4
|
||||
|
|
|
@ -67,11 +67,6 @@ extern char ape_stack_prot[] __attribute__((__weak__));
|
|||
extern pthread_mutex_t __mmi_lock_obj;
|
||||
extern int hostos asm("__hostos");
|
||||
|
||||
void cosmo2(int, char **, char **, unsigned long *) wontreturn;
|
||||
void __switch_stacks(int, char **, char **, unsigned long *,
|
||||
void (*)(int, char **, char **, unsigned long *),
|
||||
void *) wontreturn;
|
||||
|
||||
static const char *DecodeMagnum(const char *p, long *r) {
|
||||
int k = 0;
|
||||
unsigned long c, x = 0;
|
||||
|
@ -96,6 +91,15 @@ wontreturn textstartup void cosmo(long *sp, struct Syslib *m1) {
|
|||
unsigned long *auxv = (unsigned long *)(sp + 1 + argc + 1);
|
||||
while (*auxv++) donothing;
|
||||
|
||||
// set helpful globals
|
||||
__argc = argc;
|
||||
__argv = argv;
|
||||
__envp = envp;
|
||||
__auxv = auxv;
|
||||
environ = envp;
|
||||
program_invocation_name = argv[0];
|
||||
__oldstack = (intptr_t)sp;
|
||||
|
||||
// detect apple m1 environment
|
||||
char *magnums;
|
||||
if (SupportsXnu() && (__syslib = m1)) {
|
||||
|
@ -134,16 +138,7 @@ wontreturn textstartup void cosmo(long *sp, struct Syslib *m1) {
|
|||
sys_sigaction(SIGSYS, act, 0, 8, 0);
|
||||
}
|
||||
|
||||
// set helpful globals
|
||||
__argc = argc;
|
||||
__argv = argv;
|
||||
__envp = envp;
|
||||
__auxv = auxv;
|
||||
environ = envp;
|
||||
program_invocation_name = argv[0];
|
||||
|
||||
// needed by kisdangerous()
|
||||
__oldstack = (intptr_t)sp;
|
||||
__pid = sys_getpid().ax;
|
||||
|
||||
// initialize memory manager
|
||||
|
|
|
@ -16,11 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
* Exits process with grace.
|
||||
|
@ -45,9 +43,5 @@ wontreturn void exit(int exitcode) {
|
|||
for (p = __fini_array_end; p > __fini_array_start;) {
|
||||
((void (*)(void))(*--p))();
|
||||
}
|
||||
#if SupportsWindows()
|
||||
_Exitr(exitcode);
|
||||
#else
|
||||
_Exit(exitcode);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "libc/nt/enum/pageflags.h"
|
||||
#include "libc/nt/enum/processcreationflags.h"
|
||||
#include "libc/nt/enum/startf.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/ipc.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/process.h"
|
||||
|
@ -145,18 +146,38 @@ static textwindows dontinline void ReadOrDie(int64_t h, void *buf, size_t n) {
|
|||
|
||||
static textwindows int64_t MapOrDie(uint32_t prot, uint64_t size) {
|
||||
int64_t h;
|
||||
if ((h = CreateFileMapping(-1, 0, prot, size >> 32, size, 0))) {
|
||||
return h;
|
||||
} else {
|
||||
for (;;) {
|
||||
if ((h = CreateFileMapping(-1, 0, prot, size >> 32, size, 0))) {
|
||||
return h;
|
||||
}
|
||||
if (GetLastError() == kNtErrorAccessDenied) {
|
||||
switch (prot) {
|
||||
case kNtPageExecuteWritecopy:
|
||||
prot = kNtPageWritecopy;
|
||||
continue;
|
||||
case kNtPageExecuteReadwrite:
|
||||
prot = kNtPageReadwrite;
|
||||
continue;
|
||||
case kNtPageExecuteRead:
|
||||
prot = kNtPageReadonly;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
AbortFork("MapOrDie");
|
||||
}
|
||||
}
|
||||
|
||||
static textwindows void ViewOrDie(int64_t h, uint32_t access, size_t pos,
|
||||
size_t size, void *base) {
|
||||
void *got;
|
||||
got = MapViewOfFileEx(h, access, pos >> 32, pos, size, base);
|
||||
if (!got || (base && got != base)) {
|
||||
TryAgain:
|
||||
if (!MapViewOfFileEx(h, access, pos >> 32, pos, size, base)) {
|
||||
if ((access & kNtFileMapExecute) &&
|
||||
GetLastError() == kNtErrorAccessDenied) {
|
||||
access &= ~kNtFileMapExecute;
|
||||
goto TryAgain;
|
||||
}
|
||||
AbortFork("ViewOrDie");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ COSMOPOLITAN_C_START_
|
|||
extern int __pid;
|
||||
extern char __runlevel;
|
||||
extern int ftrace_stackdigs;
|
||||
extern uint32_t __ntconsolemode[3];
|
||||
extern const char v_ntsubsystem[] __attribute__((__weak__));
|
||||
extern const uintptr_t __fini_array_end[] __attribute__((__weak__));
|
||||
extern const uintptr_t __fini_array_start[] __attribute__((__weak__));
|
||||
|
@ -38,6 +37,7 @@ void __morph_tls(void);
|
|||
void __enable_tls(void);
|
||||
void __enable_threads(void);
|
||||
void *__cxa_finalize(void *);
|
||||
void __restore_console_win32(void);
|
||||
void __stack_chk_fail(void) wontreturn relegated;
|
||||
void __stack_chk_fail_local(void) wontreturn relegated;
|
||||
void __asan_init(int, char **, char **, intptr_t *);
|
||||
|
|
|
@ -74,7 +74,7 @@ static inline pureconst unsigned long __rounddown2pow(unsigned long x) {
|
|||
static wontreturn void __mmap_die(const char *s) {
|
||||
if (_weaken(__die)) _weaken(__die)();
|
||||
STRACE("%s %m", s);
|
||||
_Exitr(199);
|
||||
_Exit(199);
|
||||
}
|
||||
|
||||
static dontasan inline bool __overlaps_existing_mapping(char *p, size_t n) {
|
||||
|
|
|
@ -480,13 +480,15 @@ dontasan textstartup void __printargs(const char *prologue) {
|
|||
} else {
|
||||
PRINT(" - stderr");
|
||||
}
|
||||
kprintf(prologue);
|
||||
errno = 0;
|
||||
kprintf(" isatty = %d% m\n", isatty(i));
|
||||
PRINT(" isatty = %d% m", isatty(i));
|
||||
if (!tcgetwinsize(i, &ws)) {
|
||||
kprintf(" ws_row = %d\n", ws.ws_row);
|
||||
kprintf(" ws_col = %d\n", ws.ws_col);
|
||||
PRINT(" ws_row = %d", ws.ws_row);
|
||||
PRINT(" ws_col = %d", ws.ws_col);
|
||||
} else {
|
||||
PRINT(" tcgetwinsize = %s", strerror(errno));
|
||||
}
|
||||
kprintf(prologue);
|
||||
kprintf(" c_iflag =");
|
||||
if (termios.c_iflag & IGNBRK) kprintf(" IGNBRK");
|
||||
if (termios.c_iflag & BRKINT) kprintf(" BRKINT");
|
||||
|
|
|
@ -110,9 +110,7 @@ axdx_t setlongerjmp(jmp_buf)
|
|||
libcesque returnstwice paramsnonnull();
|
||||
void longerjmp(jmp_buf, intptr_t) libcesque wontreturn paramsnonnull();
|
||||
void __warn_if_powersave(void);
|
||||
void _Exitr(int) libcesque wontreturn;
|
||||
void _Exit1(int) libcesque wontreturn;
|
||||
void _restorewintty(void);
|
||||
void __paginate(int, const char *);
|
||||
/* memory management */
|
||||
void _weakfree(void *);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/getenv.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -59,6 +60,7 @@
|
|||
// clang-format off
|
||||
__msabi extern typeof(CreateFileMapping) *const __imp_CreateFileMappingW;
|
||||
__msabi extern typeof(DuplicateHandle) *const __imp_DuplicateHandle;
|
||||
__msabi extern typeof(ExitProcess) *const __imp_ExitProcess;
|
||||
__msabi extern typeof(FreeEnvironmentStrings) *const __imp_FreeEnvironmentStringsW;
|
||||
__msabi extern typeof(GetConsoleMode) *const __imp_GetConsoleMode;
|
||||
__msabi extern typeof(GetCurrentProcess) *const __imp_GetCurrentProcess;
|
||||
|
@ -71,11 +73,17 @@ __msabi extern typeof(SetConsoleMode) *const __imp_SetConsoleMode;
|
|||
__msabi extern typeof(SetConsoleOutputCP) *const __imp_SetConsoleOutputCP;
|
||||
__msabi extern typeof(SetStdHandle) *const __imp_SetStdHandle;
|
||||
__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect;
|
||||
__msabi extern typeof(WriteFile) *const __imp_WriteFile;
|
||||
// clang-format on
|
||||
|
||||
extern const signed char kNtConsoleHandles[3];
|
||||
extern void cosmo(int, char **, char **, long (*)[2]) wontreturn;
|
||||
|
||||
static const signed char kNtStdio[3] = {
|
||||
(signed char)kNtStdInputHandle,
|
||||
(signed char)kNtStdOutputHandle,
|
||||
(signed char)kNtStdErrorHandle,
|
||||
};
|
||||
|
||||
static const short kConsoleModes[3] = {
|
||||
kNtEnableProcessedInput | kNtEnableLineInput | kNtEnableEchoInput |
|
||||
kNtEnableMouseInput | kNtEnableQuickEditMode | kNtEnableExtendedFlags |
|
||||
|
@ -87,12 +95,25 @@ static const short kConsoleModes[3] = {
|
|||
kNtEnableVirtualTerminalProcessing,
|
||||
};
|
||||
|
||||
static uint32_t __init_pid;
|
||||
static uint32_t __console_mode[3];
|
||||
|
||||
// implements all win32 apis on non-windows hosts
|
||||
__msabi long __win32_oops(void) {
|
||||
__msabi long __oops_win32(void) {
|
||||
assert(!"win32 api called on non-windows host");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// called by _exit to undo our config changes to cmd.exe
|
||||
// it must never ever be called from forked subprocesses
|
||||
void __restore_console_win32(void) {
|
||||
if (__imp_GetCurrentProcessId() == __init_pid) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
__imp_SetConsoleMode(__imp_GetStdHandle(kNtStdio[i]), __console_mode[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://nullprogram.com/blog/2022/02/18/
|
||||
__msabi static inline char16_t *MyCommandLine(void) {
|
||||
void *cmd;
|
||||
|
@ -106,14 +127,14 @@ __msabi static inline char16_t *MyCommandLine(void) {
|
|||
// this ensures close(1) won't accidentally close(2) for example
|
||||
__msabi static textwindows void DeduplicateStdioHandles(void) {
|
||||
for (long i = 0; i < 3; ++i) {
|
||||
int64_t h1 = __imp_GetStdHandle(kNtConsoleHandles[i]);
|
||||
int64_t h1 = __imp_GetStdHandle(kNtStdio[i]);
|
||||
for (long j = i + 1; j < 3; ++j) {
|
||||
int64_t h2 = __imp_GetStdHandle(kNtConsoleHandles[j]);
|
||||
int64_t h2 = __imp_GetStdHandle(kNtStdio[j]);
|
||||
if (h1 == h2) {
|
||||
int64_t h3, proc = __imp_GetCurrentProcess();
|
||||
__imp_DuplicateHandle(proc, h2, proc, &h3, 0, true,
|
||||
kNtDuplicateSameAccess);
|
||||
__imp_SetStdHandle(kNtConsoleHandles[j], h3);
|
||||
__imp_SetStdHandle(kNtStdio[j], h3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,14 +144,15 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
|||
size_t stacksize;
|
||||
struct WinArgs *wa;
|
||||
uintptr_t stackaddr;
|
||||
__init_pid = __pid;
|
||||
__oldstack = (intptr_t)__builtin_frame_address(0);
|
||||
if (NtGetPeb()->OSMajorVersion >= 10 &&
|
||||
(intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui) {
|
||||
__imp_SetConsoleCP(kNtCpUtf8);
|
||||
__imp_SetConsoleOutputCP(kNtCpUtf8);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
int64_t hand = __imp_GetStdHandle(kNtConsoleHandles[i]);
|
||||
__imp_GetConsoleMode(hand, __ntconsolemode + i);
|
||||
int64_t hand = __imp_GetStdHandle(kNtStdio[i]);
|
||||
__imp_GetConsoleMode(hand, __console_mode + i);
|
||||
__imp_SetConsoleMode(hand, kConsoleModes[i]);
|
||||
}
|
||||
}
|
||||
|
@ -167,6 +189,7 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
|||
GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp,
|
||||
ARRAYLEN(wa->envp) - 1);
|
||||
__imp_FreeEnvironmentStringsW(env16);
|
||||
__envp = &wa->envp[0];
|
||||
_jmpstack((char *)(stackaddr + (stacksize - sizeof(struct WinArgs))), cosmo,
|
||||
count, wa->argv, wa->envp, wa->auxv);
|
||||
}
|
||||
|
@ -175,8 +198,9 @@ __msabi textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
|||
const char *lpCmdLine, int64_t nCmdShow) {
|
||||
const char16_t *cmdline;
|
||||
extern char os asm("__hostos");
|
||||
os = _HOSTWINDOWS; /* madness https://news.ycombinator.com/item?id=21019722 */
|
||||
os = _HOSTWINDOWS; // madness https://news.ycombinator.com/item?id=21019722
|
||||
kStartTsc = rdtsc();
|
||||
__umask = 077;
|
||||
__pid = __imp_GetCurrentProcessId();
|
||||
DeduplicateStdioHandles();
|
||||
if (_weaken(WinMainStdin)) {
|
||||
|
@ -184,7 +208,7 @@ __msabi textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
|||
}
|
||||
cmdline = MyCommandLine();
|
||||
#ifdef SYSDEBUG
|
||||
/* sloppy flag-only check for early initialization */
|
||||
// sloppy flag-only check for early initialization
|
||||
if (__strstr16(cmdline, u"--strace")) ++__strace;
|
||||
#endif
|
||||
if (_weaken(WinSockInit)) {
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/metalfile.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/cosmo.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/kmalloc.h"
|
||||
|
@ -28,9 +30,11 @@
|
|||
#include "libc/mem/alg.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/posix.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
@ -39,23 +43,33 @@
|
|||
__static_yoink(APE_COM_NAME);
|
||||
#endif
|
||||
|
||||
static uint64_t __zipos_get_min_offset(const uint8_t *map,
|
||||
const uint8_t *cdir) {
|
||||
uint64_t i, n, c, r, o;
|
||||
static struct Zipos __zipos;
|
||||
static atomic_uint __zipos_once;
|
||||
|
||||
static void __zipos_dismiss(const uint8_t *map, const uint8_t *cdir, long pg) {
|
||||
uint64_t i, n, c, ef, lf, mo, lo, hi;
|
||||
|
||||
// determine the byte range of zip file content (excluding central dir)
|
||||
c = GetZipCdirOffset(cdir);
|
||||
n = GetZipCdirRecords(cdir);
|
||||
for (r = c, i = 0; i < n; ++i, c += ZIP_CFILE_HDRSIZE(map + c)) {
|
||||
o = GetZipCfileOffset(map + c);
|
||||
if (o < r) r = o;
|
||||
for (lo = c, hi = i = 0; i < n; ++i, c += ZIP_CFILE_HDRSIZE(map + c)) {
|
||||
lf = GetZipCfileOffset(map + c);
|
||||
if (lf < lo) lo = lf;
|
||||
ef = lf + ZIP_LFILE_HDRSIZE(map + lf) + GetZipLfileCompressedSize(map + lf);
|
||||
if (ef > hi) hi = ef;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __zipos_munmap_unneeded(const uint8_t *map, const uint8_t *cdir) {
|
||||
uint64_t n;
|
||||
n = __zipos_get_min_offset(map, cdir);
|
||||
n = ROUNDDOWN(n, FRAMESIZE);
|
||||
if (n) munmap(map, n);
|
||||
// unmap the executable portion beneath the local files
|
||||
mo = ROUNDDOWN(lo, FRAMESIZE);
|
||||
if (mo) munmap(map, mo);
|
||||
|
||||
// this is supposed to reduce our rss usage but does it
|
||||
pg = getauxval(AT_PAGESZ);
|
||||
lo = ROUNDDOWN(lo, pg);
|
||||
hi = MIN(ROUNDUP(hi, pg), ROUNDDOWN(c, pg));
|
||||
if (hi > lo) {
|
||||
posix_madvise(map + lo, hi - lo, POSIX_MADV_DONTNEED);
|
||||
}
|
||||
}
|
||||
|
||||
static int __zipos_compare_names(const void *a, const void *b, void *c) {
|
||||
|
@ -88,75 +102,67 @@ static void __zipos_generate_index(struct Zipos *zipos) {
|
|||
__zipos_compare_names, zipos);
|
||||
}
|
||||
|
||||
static void __zipos_init(void) {
|
||||
char *endptr;
|
||||
const char *s;
|
||||
struct stat st;
|
||||
int x, fd, err, msg;
|
||||
uint8_t *map, *cdir;
|
||||
const char *progpath;
|
||||
if (!(s = getenv("COSMOPOLITAN_DISABLE_ZIPOS"))) {
|
||||
// this environment variable may be a filename or file descriptor
|
||||
if ((progpath = getenv("COSMOPOLITAN_INIT_ZIPOS")) &&
|
||||
(x = strtol(progpath, &endptr, 10)) >= 0 && !*endptr) {
|
||||
fd = x;
|
||||
} else {
|
||||
fd = -1;
|
||||
}
|
||||
if (fd != -1 || PLEDGED(RPATH)) {
|
||||
if (fd == -1) {
|
||||
if (!progpath) {
|
||||
progpath = GetProgramExecutableName();
|
||||
}
|
||||
fd = open(progpath, O_RDONLY);
|
||||
}
|
||||
if (fd != -1) {
|
||||
if (!fstat(fd, &st) && (map = mmap(0, st.st_size, PROT_READ, MAP_SHARED,
|
||||
fd, 0)) != MAP_FAILED) {
|
||||
if ((cdir = GetZipEocd(map, st.st_size, &err))) {
|
||||
long pagesz = getauxval(AT_PAGESZ);
|
||||
__zipos_dismiss(map, cdir, pagesz);
|
||||
__zipos.map = map;
|
||||
__zipos.cdir = cdir;
|
||||
__zipos.dev = st.st_ino;
|
||||
__zipos.pagesz = pagesz;
|
||||
__zipos_generate_index(&__zipos);
|
||||
msg = kZipOk;
|
||||
} else {
|
||||
munmap(map, st.st_size);
|
||||
msg = !cdir ? err : kZipErrorRaceCondition;
|
||||
}
|
||||
} else {
|
||||
msg = kZipErrorMapFailed;
|
||||
}
|
||||
close(fd);
|
||||
} else {
|
||||
msg = kZipErrorOpenFailed;
|
||||
}
|
||||
} else {
|
||||
msg = -666;
|
||||
}
|
||||
} else {
|
||||
progpath = 0;
|
||||
msg = -777;
|
||||
}
|
||||
STRACE("__zipos_get(%#s) → %d% m", progpath, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns pointer to zip central directory of current executable.
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
struct Zipos *__zipos_get(void) {
|
||||
char *endptr;
|
||||
const char *s;
|
||||
struct stat st;
|
||||
static bool once;
|
||||
struct Zipos *res;
|
||||
int x, fd, err, msg;
|
||||
uint8_t *map, *cdir;
|
||||
const char *progpath;
|
||||
static struct Zipos zipos;
|
||||
__zipos_lock();
|
||||
if (!once) {
|
||||
if (!(s = getenv("COSMOPOLITAN_DISABLE_ZIPOS"))) {
|
||||
// this environment variable may be a filename or file descriptor
|
||||
if ((progpath = getenv("COSMOPOLITAN_INIT_ZIPOS")) &&
|
||||
(x = strtol(progpath, &endptr, 10)) >= 0 && !*endptr) {
|
||||
fd = x;
|
||||
} else {
|
||||
fd = -1;
|
||||
}
|
||||
if (fd != -1 || PLEDGED(RPATH)) {
|
||||
if (fd == -1) {
|
||||
if (!progpath) {
|
||||
progpath = GetProgramExecutableName();
|
||||
}
|
||||
fd = open(progpath, O_RDONLY);
|
||||
}
|
||||
if (fd != -1) {
|
||||
if (!fstat(fd, &st) &&
|
||||
(map = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) !=
|
||||
MAP_FAILED) {
|
||||
if ((cdir = GetZipEocd(map, st.st_size, &err))) {
|
||||
__zipos_munmap_unneeded(map, cdir);
|
||||
zipos.map = map;
|
||||
zipos.cdir = cdir;
|
||||
zipos.dev = st.st_ino;
|
||||
__zipos_generate_index(&zipos);
|
||||
msg = kZipOk;
|
||||
} else {
|
||||
munmap(map, st.st_size);
|
||||
msg = !cdir ? err : kZipErrorRaceCondition;
|
||||
}
|
||||
} else {
|
||||
msg = kZipErrorMapFailed;
|
||||
}
|
||||
close(fd);
|
||||
} else {
|
||||
msg = kZipErrorOpenFailed;
|
||||
}
|
||||
} else {
|
||||
msg = -666;
|
||||
}
|
||||
} else {
|
||||
progpath = 0;
|
||||
msg = -777;
|
||||
}
|
||||
STRACE("__zipos_get(%#s) → %d% m", progpath, msg);
|
||||
once = true;
|
||||
}
|
||||
__zipos_unlock();
|
||||
if (zipos.cdir) {
|
||||
res = &zipos;
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
return res;
|
||||
cosmo_once(&__zipos_once, __zipos_init);
|
||||
return __zipos.cdir ? &__zipos : 0;
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
static pthread_mutex_t __zipos_lock_obj;
|
||||
|
||||
void(__zipos_lock)(void) {
|
||||
pthread_mutex_lock(&__zipos_lock_obj);
|
||||
}
|
||||
|
||||
void(__zipos_unlock)(void) {
|
||||
pthread_mutex_unlock(&__zipos_lock_obj);
|
||||
}
|
||||
|
||||
void __zipos_funlock(void) {
|
||||
pthread_mutex_init(&__zipos_lock_obj, 0);
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void __zipos_init(void) {
|
||||
__zipos_funlock();
|
||||
pthread_atfork(__zipos_lock, __zipos_unlock, __zipos_funlock);
|
||||
}
|
|
@ -45,21 +45,39 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
||||
static char *mapend;
|
||||
static size_t maptotal;
|
||||
static char *__zipos_mapend;
|
||||
static size_t __zipos_maptotal;
|
||||
static pthread_mutex_t __zipos_lock_obj;
|
||||
|
||||
static void __zipos_lock(void) {
|
||||
if (__threaded) {
|
||||
pthread_mutex_lock(&__zipos_lock_obj);
|
||||
}
|
||||
}
|
||||
|
||||
static void __zipos_unlock(void) {
|
||||
if (__threaded) {
|
||||
pthread_mutex_unlock(&__zipos_lock_obj);
|
||||
}
|
||||
}
|
||||
|
||||
static void __zipos_funlock(void) {
|
||||
pthread_mutex_init(&__zipos_lock_obj, 0);
|
||||
}
|
||||
|
||||
static void *__zipos_mmap_space(size_t mapsize) {
|
||||
char *start;
|
||||
size_t offset;
|
||||
unassert(mapsize);
|
||||
offset = maptotal;
|
||||
maptotal += mapsize;
|
||||
offset = __zipos_maptotal;
|
||||
__zipos_maptotal += mapsize;
|
||||
start = (char *)kMemtrackZiposStart;
|
||||
if (!mapend) mapend = start;
|
||||
mapend = _extend(start, maptotal, mapend, MAP_PRIVATE,
|
||||
kMemtrackZiposStart + kMemtrackZiposSize);
|
||||
if (!__zipos_mapend) __zipos_mapend = start;
|
||||
__zipos_mapend = _extend(start, __zipos_maptotal, __zipos_mapend, MAP_PRIVATE,
|
||||
kMemtrackZiposStart + kMemtrackZiposSize);
|
||||
return start + offset;
|
||||
}
|
||||
|
||||
|
@ -68,7 +86,6 @@ void __zipos_free(struct ZiposHandle *h) {
|
|||
__asan_poison((char *)h + sizeof(struct ZiposHandle),
|
||||
h->mapsize - sizeof(struct ZiposHandle), kAsanHeapFree);
|
||||
}
|
||||
pthread_mutex_destroy(&h->lock);
|
||||
__zipos_lock();
|
||||
do h->next = h->zipos->freelist;
|
||||
while (!_cmpxchg(&h->zipos->freelist, h->next, h));
|
||||
|
@ -105,7 +122,6 @@ StartOver:
|
|||
h->size = size;
|
||||
h->zipos = zipos;
|
||||
h->mapsize = mapsize;
|
||||
pthread_mutex_init(&h->lock, 0);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
@ -197,16 +213,40 @@ static int __zipos_load(struct Zipos *zipos, size_t cf, int flags,
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int __zipos_open_impl(struct ZiposUri *name, int flags) {
|
||||
struct Zipos *zipos;
|
||||
/**
|
||||
* Loads compressed file from αcτµαlly pδrταblε εxεcµταblε object store.
|
||||
*
|
||||
* @param uri is obtained via __zipos_parseuri()
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
int __zipos_open(struct ZiposUri *name, int flags) {
|
||||
|
||||
// check if this thread is cancelled
|
||||
int rc;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// validate api usage
|
||||
if ((flags & O_CREAT) || //
|
||||
(flags & O_TRUNC) || //
|
||||
(flags & O_ACCMODE) != O_RDONLY) {
|
||||
return erofs();
|
||||
}
|
||||
|
||||
// get the zipos global singleton
|
||||
struct Zipos *zipos;
|
||||
if (!(zipos = __zipos_get())) {
|
||||
return enoexec();
|
||||
}
|
||||
|
||||
// most open() calls are due to languages path searching assets. the
|
||||
// majority of these calls will return ENOENT or ENOTDIR. we need to
|
||||
// perform two extremely costly sigprocmask() calls below. thanks to
|
||||
// zipos being a read-only filesystem, we can avoid it in many cases
|
||||
ssize_t cf;
|
||||
if ((cf = __zipos_find(zipos, name)) == -1) {
|
||||
return -1;
|
||||
|
@ -223,25 +263,14 @@ static int __zipos_open_impl(struct ZiposUri *name, int flags) {
|
|||
return eacces();
|
||||
}
|
||||
}
|
||||
return __zipos_load(zipos, cf, flags, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads compressed file from αcτµαlly pδrταblε εxεcµταblε object store.
|
||||
*
|
||||
* @param uri is obtained via __zipos_parseuri()
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
int __zipos_open(struct ZiposUri *name, int flags) {
|
||||
int rc;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
// now do the heavy lifting
|
||||
BLOCK_SIGNALS;
|
||||
rc = __zipos_open_impl(name, flags);
|
||||
rc = __zipos_load(zipos, cf, flags, name);
|
||||
ALLOW_SIGNALS;
|
||||
return rc;
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void __zipos_ctor(void) {
|
||||
pthread_atfork(__zipos_lock, __zipos_unlock, __zipos_funlock);
|
||||
}
|
||||
|
|
|
@ -21,14 +21,9 @@
|
|||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
||||
static size_t GetIovSize(const struct iovec *iov, size_t iovlen) {
|
||||
size_t i, r;
|
||||
for (r = i = 0; i < iovlen; ++i) r += iov[i].iov_len;
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t __zipos_read_impl(struct ZiposHandle *h, const struct iovec *iov,
|
||||
size_t iovlen, ssize_t opt_offset) {
|
||||
int i;
|
||||
|
@ -61,10 +56,6 @@ static ssize_t __zipos_read_impl(struct ZiposHandle *h, const struct iovec *iov,
|
|||
*/
|
||||
ssize_t __zipos_read(struct ZiposHandle *h, const struct iovec *iov,
|
||||
size_t iovlen, ssize_t opt_offset) {
|
||||
ssize_t rc;
|
||||
unassert(opt_offset >= 0 || opt_offset == -1);
|
||||
pthread_mutex_lock(&h->lock);
|
||||
rc = __zipos_read_impl(h, iov, iovlen, opt_offset);
|
||||
pthread_mutex_unlock(&h->lock);
|
||||
return rc;
|
||||
return __zipos_read_impl(h, iov, iovlen, opt_offset);
|
||||
}
|
||||
|
|
|
@ -22,10 +22,11 @@
|
|||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
||||
static int64_t __zipos_lseek_impl(struct ZiposHandle *h, int64_t offset,
|
||||
unsigned whence) {
|
||||
static int64_t __zipos_seek_impl(struct ZiposHandle *h, int64_t offset,
|
||||
unsigned whence) {
|
||||
int64_t pos;
|
||||
if (h->cfile == ZIPOS_SYNTHETIC_DIRECTORY ||
|
||||
S_ISDIR(GetZipCfileMode(h->zipos->map + h->cfile))) {
|
||||
|
@ -71,12 +72,10 @@ static int64_t __zipos_lseek_impl(struct ZiposHandle *h, int64_t offset,
|
|||
* @return new position relative to beginning, or -1 on error
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int64_t __zipos_lseek(struct ZiposHandle *h, int64_t offset, unsigned whence) {
|
||||
int64_t __zipos_seek(struct ZiposHandle *h, int64_t offset, unsigned whence) {
|
||||
int64_t pos;
|
||||
pthread_mutex_lock(&h->lock);
|
||||
if ((pos = __zipos_lseek_impl(h, offset, whence)) != -1) {
|
||||
if ((pos = __zipos_seek_impl(h, offset, whence)) != -1) {
|
||||
h->pos = pos;
|
||||
}
|
||||
pthread_mutex_unlock(&h->lock);
|
||||
return pos;
|
||||
}
|
|
@ -16,7 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -30,7 +32,8 @@ int __zipos_stat_impl(struct Zipos *zipos, size_t cf, struct stat *st) {
|
|||
st->st_dev = zipos->dev;
|
||||
st->st_blksize = FRAMESIZE;
|
||||
if (cf == ZIPOS_SYNTHETIC_DIRECTORY) {
|
||||
st->st_mode = S_IFDIR | 0555;
|
||||
st->st_mode = S_IFDIR | (0555 & ~atomic_load_explicit(
|
||||
&__umask, memory_order_acquire));
|
||||
} else {
|
||||
lf = GetZipCfileOffset(zipos->map + cf);
|
||||
st->st_mode = GetZipCfileMode(zipos->map + cf);
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
.yoink __zipos_fcntl
|
||||
.yoink __zipos_fstat
|
||||
.yoink __zipos_access
|
||||
.yoink __zipos_lseek
|
||||
.yoink __zipos_seek
|
||||
.yoink __zipos_open
|
||||
.yoink __zipos_parseuri
|
||||
.yoink __zipos_read
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ZIPOS_ZIPOS_H_
|
||||
#define COSMOPOLITAN_LIBC_ZIPOS_ZIPOS_H_
|
||||
#include "libc/intrin/nopl.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
@ -21,7 +18,6 @@ struct ZiposUri {
|
|||
|
||||
struct ZiposHandle {
|
||||
struct ZiposHandle *next;
|
||||
pthread_mutex_t lock;
|
||||
struct Zipos *zipos;
|
||||
size_t size;
|
||||
size_t mapsize;
|
||||
|
@ -32,6 +28,7 @@ struct ZiposHandle {
|
|||
};
|
||||
|
||||
struct Zipos {
|
||||
long pagesz;
|
||||
uint8_t *map;
|
||||
uint8_t *cdir;
|
||||
uint64_t dev;
|
||||
|
@ -41,8 +38,6 @@ struct Zipos {
|
|||
};
|
||||
|
||||
int __zipos_close(int);
|
||||
void __zipos_lock(void);
|
||||
void __zipos_unlock(void);
|
||||
void __zipos_free(struct ZiposHandle *);
|
||||
struct Zipos *__zipos_get(void) pureconst;
|
||||
size_t __zipos_normpath(char *, const char *, size_t);
|
||||
|
@ -57,20 +52,12 @@ int __zipos_fstat(struct ZiposHandle *, struct stat *);
|
|||
int __zipos_stat_impl(struct Zipos *, size_t, struct stat *);
|
||||
ssize_t __zipos_read(struct ZiposHandle *, const struct iovec *, size_t,
|
||||
ssize_t);
|
||||
int64_t __zipos_lseek(struct ZiposHandle *, int64_t, unsigned);
|
||||
int64_t __zipos_seek(struct ZiposHandle *, int64_t, unsigned);
|
||||
int __zipos_fcntl(int, int, uintptr_t);
|
||||
int __zipos_notat(int, const char *);
|
||||
void *__zipos_mmap(void *, uint64_t, int32_t, int32_t, struct ZiposHandle *,
|
||||
int64_t) dontasan;
|
||||
|
||||
#ifdef _NOPL0
|
||||
#define __zipos_lock() _NOPL0("__threadcalls", __zipos_lock)
|
||||
#define __zipos_unlock() _NOPL0("__threadcalls", __zipos_unlock)
|
||||
#else
|
||||
#define __zipos_lock() (__threaded ? __zipos_lock() : 0)
|
||||
#define __zipos_unlock() (__threaded ? __zipos_unlock() : 0)
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ZIPOS_ZIPOS_H_ */
|
||||
|
|
|
@ -57,7 +57,7 @@ static textwindows int SendfileBlock(int64_t handle,
|
|||
NTTRACE("WSAWaitForMultipleEvents failed %lm");
|
||||
return __winsockerr();
|
||||
} else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) {
|
||||
if (_check_interrupts(kSigOpRestartable, g_fds.p)) return -1;
|
||||
if (_check_interrupts(kSigOpRestartable)) return -1;
|
||||
#if _NTTRACE
|
||||
POLLTRACE("WSAWaitForMultipleEvents...");
|
||||
#endif
|
||||
|
|
|
@ -53,7 +53,7 @@ textwindows int __wsablock(struct Fd *fd, struct NtOverlapped *overlapped,
|
|||
abort_errno = EAGAIN;
|
||||
if (fd->flags & O_NONBLOCK) {
|
||||
__wsablock_abort(fd->handle, overlapped);
|
||||
} else if (_check_interrupts(sigops, g_fds.p)) {
|
||||
} else if (_check_interrupts(sigops)) {
|
||||
Interrupted:
|
||||
abort_errno = errno; // EINTR or ECANCELED
|
||||
__wsablock_abort(fd->handle, overlapped);
|
||||
|
@ -62,7 +62,7 @@ textwindows int __wsablock(struct Fd *fd, struct NtOverlapped *overlapped,
|
|||
i = WSAWaitForMultipleEvents(1, &overlapped->hEvent, true,
|
||||
__SIG_POLLING_INTERVAL_MS, true);
|
||||
if (i == kNtWaitFailed || i == kNtWaitTimeout) {
|
||||
if (_check_interrupts(sigops, g_fds.p)) {
|
||||
if (_check_interrupts(sigops)) {
|
||||
goto Interrupted;
|
||||
}
|
||||
if (i == kNtWaitFailed) {
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
||||
/**
|
||||
|
|
|
@ -176,7 +176,7 @@ static ssize_t GetDevUrandom(char *p, size_t n) {
|
|||
ssize_t __getrandom(void *p, size_t n, unsigned f) {
|
||||
ssize_t rc;
|
||||
if (IsWindows()) {
|
||||
if (_check_interrupts(kSigOpRestartable, 0)) {
|
||||
if (_check_interrupts(kSigOpRestartable)) {
|
||||
return -1;
|
||||
}
|
||||
rc = RtlGenRandom(p, n) ? n : __winerr();
|
||||
|
|
|
@ -245,20 +245,20 @@ syscon compat MAP_32BIT 0x00000040 0x00000040 0 0x00008000 0x00080000 0
|
|||
#
|
||||
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||
syscon madv MADV_NORMAL 0 0 0 0 0 0 0 0 # consensus
|
||||
syscon compat POSIX_FADV_NORMAL 0 0 0 0 0 0 0 0 # consensus
|
||||
syscon compat POSIX_MADV_NORMAL 0 0 0 0 0 0 0 0 # consensus
|
||||
syscon madv POSIX_FADV_NORMAL 0 0 0 0 0 0 0 0 # consensus
|
||||
syscon madv POSIX_MADV_NORMAL 0 0 0 0 0 0 0 0 # consensus
|
||||
syscon madv MADV_DONTNEED 4 4 4 4 4 4 4 127 # TODO(jart): weird nt decommit thing?
|
||||
syscon compat POSIX_MADV_DONTNEED 4 4 4 4 4 4 4 127 # unix consensus
|
||||
syscon compat POSIX_FADV_DONTNEED 4 4 127 127 4 4 4 127 # unix consensus
|
||||
syscon madv POSIX_MADV_DONTNEED 4 4 4 4 4 4 4 127 # unix consensus
|
||||
syscon madv POSIX_FADV_DONTNEED 4 4 127 127 4 4 4 127 # unix consensus
|
||||
syscon madv MADV_RANDOM 1 1 1 1 1 1 1 1 # unix consensus
|
||||
syscon compat POSIX_MADV_RANDOM 1 1 1 1 1 1 1 1 # unix consensus
|
||||
syscon compat POSIX_FADV_RANDOM 1 1 127 127 1 1 1 1 # unix consensus
|
||||
syscon madv POSIX_MADV_RANDOM 1 1 1 1 1 1 1 1 # unix consensus
|
||||
syscon madv POSIX_FADV_RANDOM 1 1 127 127 1 1 1 1 # unix consensus
|
||||
syscon madv MADV_SEQUENTIAL 2 2 2 2 2 2 2 2 # unix consensus
|
||||
syscon compat POSIX_MADV_SEQUENTIAL 2 2 2 2 2 2 2 2 # unix consensus
|
||||
syscon compat POSIX_FADV_SEQUENTIAL 2 2 127 127 2 2 2 2 # TODO(jart): double check xnu
|
||||
syscon madv POSIX_MADV_SEQUENTIAL 2 2 2 2 2 2 2 2 # unix consensus
|
||||
syscon madv POSIX_FADV_SEQUENTIAL 2 2 127 127 2 2 2 2 # TODO(jart): double check xnu
|
||||
syscon madv MADV_WILLNEED 3 3 3 3 3 3 3 3 # unix consensus (faked on NT)
|
||||
syscon compat POSIX_MADV_WILLNEED 3 3 3 3 3 3 3 3 # unix consensus
|
||||
syscon compat POSIX_FADV_WILLNEED 3 3 127 127 3 3 3 3 # TODO(jart): double check xnu
|
||||
syscon madv POSIX_MADV_WILLNEED 3 3 3 3 3 3 3 3 # unix consensus
|
||||
syscon madv POSIX_FADV_WILLNEED 3 3 127 127 3 3 3 3 # TODO(jart): double check xnu
|
||||
syscon madv MADV_MERGEABLE 12 12 127 127 127 127 127 127 # turns on (private anon range) page scanning and merging service (linux only)
|
||||
syscon madv MADV_UNMERGEABLE 13 13 127 127 127 127 127 127 # turns off mergeable (linux only)
|
||||
syscon madv MADV_FREE 8 8 5 5 5 6 6 8 # Linux 4.5+ (c. 2016) / NT Faked → VMOfferPriorityNormal (Win8+)
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon access,F_OK,0,0,0,0,0,0,0,0
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon compat,POSIX_FADV_DONTNEED,4,4,127,127,4,4,4,127
|
||||
.syscon madv,POSIX_FADV_DONTNEED,4,4,127,127,4,4,4,127
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon compat,POSIX_FADV_NORMAL,0,0,0,0,0,0,0,0
|
||||
.syscon madv,POSIX_FADV_NORMAL,0,0,0,0,0,0,0,0
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon compat,POSIX_FADV_RANDOM,1,1,127,127,1,1,1,1
|
||||
.syscon madv,POSIX_FADV_RANDOM,1,1,127,127,1,1,1,1
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon compat,POSIX_FADV_SEQUENTIAL,2,2,127,127,2,2,2,2
|
||||
.syscon madv,POSIX_FADV_SEQUENTIAL,2,2,127,127,2,2,2,2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon compat,POSIX_FADV_WILLNEED,3,3,127,127,3,3,3,3
|
||||
.syscon madv,POSIX_FADV_WILLNEED,3,3,127,127,3,3,3,3
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon compat,POSIX_MADV_DONTNEED,4,4,4,4,4,4,4,127
|
||||
.syscon madv,POSIX_MADV_DONTNEED,4,4,4,4,4,4,4,127
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon compat,POSIX_MADV_NORMAL,0,0,0,0,0,0,0,0
|
||||
.syscon madv,POSIX_MADV_NORMAL,0,0,0,0,0,0,0,0
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon compat,POSIX_MADV_RANDOM,1,1,1,1,1,1,1,1
|
||||
.syscon madv,POSIX_MADV_RANDOM,1,1,1,1,1,1,1,1
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon compat,POSIX_MADV_SEQUENTIAL,2,2,2,2,2,2,2,2
|
||||
.syscon madv,POSIX_MADV_SEQUENTIAL,2,2,2,2,2,2,2,2
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue