Make improvements

- Fix build flakes
- Polyfill SIGWINCH on Windows
- Fix an execve issue on Windows
- Make strerror show more information
- Improve cmd.exe setup/teardown on Windows
- Support bracketed paste mode in Blinkenlights
- Show keyboard shortcuts in Blinkenlights status bar
- Fixed copy_file_range() and copyfile() w/ zip filesystem
- Size optimize GetDosArgv() to keep life.com 12kb in size
- Improve Blinkenlights ability to load weird ELF executables
- Fix program_executable_name and add GetInterpreterExecutableName
- Make Python in tiny mode fail better if docstrings are requested
- Update Python test exclusions in tiny* modes such as tinylinux
- Add bulletproof unbreakable kprintf() troubleshooting function
- Remove "oldskool" keyword from ape.S for virus scanners
- Fix issue that caused backtraces to not print sometimes
- Improve Blinkenlights serial uart character i/o
- Make clock_gettime() not clobber errno on xnu
- Improve sha256 cpuid check for old computers
- Integrate some bestline linenoise fixes
- Show runit process names better in htop
- Remove SIGPIPE from ShowCrashReports()
- Make realpath() not clobber errno
- Avoid attaching GDB on non-Linux
- Improve img.com example
This commit is contained in:
Justine Tunney 2022-03-16 13:33:13 -07:00
parent 2a938b3eaa
commit b45d50b690
194 changed files with 4881 additions and 2966 deletions

View file

@ -19,7 +19,7 @@
#include "libc/calls/math.h"
/**
* Adds two microsecond timestamps.
* Adds two nanosecond timestamps.
*/
struct timespec AddTimespec(struct timespec x, struct timespec y) {
x.tv_sec += y.tv_sec;

View file

@ -40,13 +40,18 @@
* @asyncsignalsafe
*/
int clock_gettime(int clockid, struct timespec *ts) {
int rc;
int rc, e;
axdx_t ad;
if (!ts) return efault();
if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) return efault();
if (clockid == -1) return einval();
if (!IsWindows()) {
if ((rc = sys_clock_gettime(clockid, ts)) == -1 && errno == ENOSYS) {
if (!ts) {
rc = efault();
} else if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) {
rc = efault();
} else if (clockid == -1) {
rc = einval();
} else if (!IsWindows()) {
e = errno;
if ((rc = sys_clock_gettime(clockid, ts))) {
errno = e;
ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL);
assert(ad.ax != -1);
if (SupportsXnu() && ad.ax) {
@ -56,8 +61,9 @@ int clock_gettime(int clockid, struct timespec *ts) {
ts->tv_nsec *= 1000;
rc = 0;
}
return rc;
} else {
return sys_clock_gettime_nt(clockid, ts);
rc = sys_clock_gettime_nt(clockid, ts);
}
/* TODO(jart): Add get_clock_gettime() so we can STRACE() */
return rc;
}

View file

@ -16,60 +16,69 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/errfuns.h"
static noasan bool EndsWithIgnoreCase(const char *p, size_t n, const char *s) {
size_t i, m;
m = __strlen(s);
if (n >= m) {
for (i = n - m; i < n; ++i) {
if (kToLower[p[i] & 255] != (*s++ & 255)) {
return false;
}
}
return true;
} else {
return false;
}
static noasan bool IsExePath(const char *s, size_t n) {
return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".exe") ||
READ32LE(s + n - 4) == READ32LE(".EXE"));
}
static noasan bool IsComPath(const char *s, size_t n) {
return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".com") ||
READ32LE(s + n - 4) == READ32LE(".COM"));
}
static noasan bool IsComDbgPath(const char *s, size_t n) {
return n >= 8 && (READ64LE(s + n - 8) == READ64LE(".com.dbg") ||
READ64LE(s + n - 8) == READ64LE(".COM.DBG"));
}
static noasan bool AccessCommand(const char *name,
char path[hasatleast PATH_MAX], size_t namelen,
const char *suffix, size_t pathlen) {
int *err, const char *suffix, size_t pathlen) {
size_t suffixlen;
suffixlen = __strlen(suffix);
if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return -1;
suffixlen = strlen(suffix);
if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return false;
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
path[pathlen] = !IsWindows() ? '/'
: __memchr(path, '\\', pathlen) ? '\\'
: '/';
path[pathlen] = !IsWindows() ? '/'
: memchr(path, '\\', pathlen) ? '\\'
: '/';
pathlen++;
}
__repmovsb(path + pathlen, name, namelen);
__repmovsb(path + pathlen + namelen, suffix, suffixlen + 1);
return isexecutable(path);
memcpy(path + pathlen, name, namelen);
memcpy(path + pathlen + namelen, suffix, suffixlen + 1);
if (!access(path, X_OK)) return true;
if (errno == EACCES || *err != EACCES) *err = errno;
return false;
}
static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
size_t namelen, const char *suffix) {
size_t namelen, int *err, const char *suffix) {
char sep;
size_t i;
const char *p;
p = firstnonnull(emptytonull(getenv("PATH")), "/bin:/usr/local/bin:/usr/bin");
if (!(p = getenv("PATH"))) p = "/bin:/usr/local/bin:/usr/bin";
sep = IsWindows() && strchr(p, ';') ? ';' : ':';
for (;;) {
for (i = 0; p[i] && p[i] != ':' && p[i] != ';'; ++i) {
for (i = 0; p[i] && p[i] != sep; ++i) {
if (i < PATH_MAX) {
path[i] = p[i];
}
}
if (AccessCommand(name, path, namelen, suffix, i)) {
if (AccessCommand(name, path, namelen, err, suffix, i)) {
return true;
}
if (p[i] == ':' || p[i] == ';') {
if (p[i] == sep) {
p += i + 1;
} else {
break;
@ -80,19 +89,37 @@ static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
static noasan bool FindCommand(const char *name,
char pathbuf[hasatleast PATH_MAX],
size_t namelen, const char *suffix) {
if (memchr(name, '/', namelen) || memchr(name, '\\', namelen)) {
size_t namelen, bool priorityonly,
const char *suffix, int *err) {
if (priorityonly &&
(memchr(name, '/', namelen) || memchr(name, '\\', namelen))) {
pathbuf[0] = 0;
return AccessCommand(name, pathbuf, namelen, suffix, 0);
return AccessCommand(name, pathbuf, namelen, err, suffix, 0);
}
return ((IsWindows() &&
(AccessCommand(name, pathbuf, namelen, suffix,
stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) ||
AccessCommand(name, pathbuf, namelen, suffix,
stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf) ||
AccessCommand(name, pathbuf, namelen, suffix,
stpcpy(pathbuf, ".") - pathbuf))) ||
SearchPath(name, pathbuf, namelen, suffix));
if (IsWindows() && priorityonly) {
return AccessCommand(name, pathbuf, namelen, err, suffix,
stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) ||
AccessCommand(name, pathbuf, namelen, err, suffix,
stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf);
}
return (IsWindows() && AccessCommand(name, pathbuf, namelen, err, suffix,
stpcpy(pathbuf, ".") - pathbuf)) ||
SearchPath(name, pathbuf, namelen, err, suffix);
}
static noasan bool FindVerbatim(const char *name,
char pathbuf[hasatleast PATH_MAX],
size_t namelen, bool priorityonly, int *err) {
return FindCommand(name, pathbuf, namelen, priorityonly, "", err);
}
static noasan bool FindSuffixed(const char *name,
char pathbuf[hasatleast PATH_MAX],
size_t namelen, bool priorityonly, int *err) {
return !IsExePath(name, namelen) && !IsComPath(name, namelen) &&
!IsComDbgPath(name, namelen) &&
(FindCommand(name, pathbuf, namelen, priorityonly, ".com", err) ||
FindCommand(name, pathbuf, namelen, priorityonly, ".exe", err));
}
/**
@ -105,28 +132,33 @@ static noasan bool FindCommand(const char *name,
* @vforksafe
*/
noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
int olderr;
int e, f;
char *res;
size_t namelen;
res = 0;
if (!name) {
efault();
return 0;
}
if (!(namelen = __strlen(name))) {
} else if (!(namelen = strlen(name))) {
enoent();
return 0;
}
if (namelen + 1 > PATH_MAX) {
} else if (namelen + 1 > PATH_MAX) {
enametoolong();
return 0;
}
if (FindCommand(name, pathbuf, namelen, "") ||
(!EndsWithIgnoreCase(name, namelen, ".exe") &&
!EndsWithIgnoreCase(name, namelen, ".com") &&
!EndsWithIgnoreCase(name, namelen, ".com.dbg") &&
(FindCommand(name, pathbuf, namelen, ".com") ||
FindCommand(name, pathbuf, namelen, ".exe")))) {
return pathbuf;
} else {
return 0;
e = errno;
f = ENOENT;
if ((IsWindows() && (FindSuffixed(name, pathbuf, namelen, true, &f) ||
FindSuffixed(name, pathbuf, namelen, true, &f) ||
FindVerbatim(name, pathbuf, namelen, false, &f) ||
FindVerbatim(name, pathbuf, namelen, false, &f))) ||
(!IsWindows() && (FindVerbatim(name, pathbuf, namelen, true, &f) ||
FindSuffixed(name, pathbuf, namelen, true, &f) ||
FindVerbatim(name, pathbuf, namelen, false, &f) ||
FindSuffixed(name, pathbuf, namelen, false, &f)))) {
errno = e;
res = pathbuf;
} else {
errno = f;
}
}
SYSDEBUG("commandv(%#s, %p) → %#s% m", name, pathbuf, res);
return res;
}

View file

@ -20,6 +20,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
@ -66,12 +67,12 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
int64_t inoffset, outoffset;
int rc, srcfd, dstfd, oflags, omode;
rc = -1;
if ((srcfd = sys_openat(AT_FDCWD, src, O_RDONLY, 0)) != -1) {
if (sys_fstat(srcfd, &st) != -1) {
if ((srcfd = openat(AT_FDCWD, src, O_RDONLY, 0)) != -1) {
if (fstat(srcfd, &st) != -1) {
omode = st.st_mode & 0777;
oflags = O_WRONLY | O_CREAT;
if (flags & COPYFILE_NOCLOBBER) oflags |= O_EXCL;
if ((dstfd = sys_openat(AT_FDCWD, dst, oflags, omode)) != -1) {
if ((dstfd = openat(AT_FDCWD, dst, oflags, omode)) != -1) {
remaining = st.st_size;
ftruncate(dstfd, remaining);
inoffset = 0;
@ -86,13 +87,13 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
if (flags & COPYFILE_PRESERVE_TIMESTAMPS) {
amtime[0] = st.st_atim;
amtime[1] = st.st_mtim;
sys_utimensat(dstfd, NULL, amtime, 0);
utimensat(dstfd, NULL, amtime, 0);
}
}
rc |= sys_close(dstfd);
rc |= close(dstfd);
}
}
rc |= sys_close(srcfd);
rc |= close(srcfd);
}
return rc;
}
@ -108,7 +109,7 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
* @return 0 on success, or -1 w/ errno
*/
int copyfile(const char *src, const char *dst, int flags) {
if (!IsWindows()) {
if (!IsWindows() || startswith(src, "/zip/") || startswith(dst, "/zip/")) {
return sys_copyfile(src, dst, flags);
} else {
return sys_copyfile_nt(src, dst, flags);

View file

@ -21,6 +21,7 @@
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/libfatal.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
@ -47,17 +48,17 @@ int execve(const char *program, char *const argv[], char *const envp[]) {
return efault();
}
if (DEBUGSYS) {
__printf("SYS: execve(%s, {", program);
kprintf("SYS: execve(%s, {", program);
for (i = 0; argv[i]; ++i) {
if (i) __printf(", ");
__printf("%s", argv[i]);
if (i) kprintf(", ");
kprintf("%s", argv[i]);
}
__printf("}, {");
kprintf("}, {");
for (i = 0; envp[i]; ++i) {
if (i) __printf(", ");
__printf("%s", envp[i]);
if (i) kprintf(", ");
kprintf("%s", envp[i]);
}
__printf("})\n");
kprintf("})\n");
}
for (i = 3; i < g_fds.n; ++i) {
if (g_fds.p[i].kind != kFdEmpty && (g_fds.p[i].flags & O_CLOEXEC)) {

View file

@ -16,27 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/nt/process.h"
#include "libc/runtime/runtime.h"
static int __pid;
static int __getpid(void) {
if (!IsWindows()) {
return sys_getpid().ax;
} else {
return GetCurrentProcessId();
}
}
static void __updatepid(void) {
__pid = __getpid();
}
extern int __pid;
/**
* Returns process id.
@ -44,15 +27,11 @@ static void __updatepid(void) {
* @vforksafe
*/
int getpid(void) {
static bool once;
if (__vforked) {
return sys_getpid().ax;
int rc;
if (!__vforked) {
rc = __pid;
} else {
rc = sys_getpid().ax;
}
if (!once) {
__updatepid();
if (cmpxchg(&once, false, true)) {
atfork(__updatepid, NULL);
}
}
return __pid;
return rc;
}

View file

@ -12,6 +12,7 @@
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/ucontext.h"
#include "libc/dce.h"
#include "libc/limits.h"
@ -299,6 +300,7 @@ ssize_t sys_open_nt(int, const char *, u32, i32) nodiscard hidden;
ssize_t sys_read_nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
ssize_t sys_readlinkat_nt(int, const char *, char *, size_t) hidden;
ssize_t sys_write_nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
int ioctl_tiocgwinsz_nt(struct Fd *, struct winsize *) hidden;
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § syscalls » windows nt » support

View file

@ -25,6 +25,8 @@
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
extern bool __nomultics;
int ioctl_tcsets_nt(int, uint64_t, const struct termios *);
static int ioctl_tcsets_metal(int fd, uint64_t request,
@ -35,7 +37,7 @@ static int ioctl_tcsets_metal(int fd, uint64_t request,
static inline void *__termios2host(union metatermios *mt,
const struct termios *lt) {
if (!IsXnu() && !IsFreebsd() && !IsOpenbsd() && !IsNetbsd()) {
return lt;
return (/*unconst*/ void *)lt;
} else if (IsXnu()) {
COPY_TERMIOS(&mt->xnu, lt);
return &mt->xnu;
@ -60,23 +62,29 @@ static int ioctl_tcsets_sysv(int fd, uint64_t request,
* @see ioctl(fd, TIOCGETA{,W,F}, tio) dispatches here
*/
int ioctl_tcsets(int fd, uint64_t request, ...) {
int rc;
va_list va;
const struct termios *tio;
va_start(va, request);
tio = va_arg(va, const struct termios *);
va_end(va);
if (!tio) return efault();
if (fd >= 0) {
if (!tio) {
rc = efault();
} else if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return enotty();
rc = enotty();
} else if (IsMetal()) {
return ioctl_tcsets_metal(fd, request, tio);
rc = ioctl_tcsets_metal(fd, request, tio);
} else if (!IsWindows()) {
return ioctl_tcsets_sysv(fd, request, tio);
rc = ioctl_tcsets_sysv(fd, request, tio);
} else {
return ioctl_tcsets_nt(fd, request, tio);
rc = ioctl_tcsets_nt(fd, request, tio);
}
} else {
return einval();
rc = einval();
}
if (rc != -1) {
__nomultics = !(tio->c_oflag & OPOST);
}
return rc;
}

View file

@ -27,20 +27,21 @@
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
textwindows int ioctl_tiocgwinsz_nt(int fd, struct winsize *ws) {
int i, fds[3];
textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) {
int i;
uint32_t mode;
struct Fd *fds[3];
struct NtStartupInfo startinfo;
struct NtConsoleScreenBufferInfoEx sbinfo;
if (!ws) return efault();
fds[0] = fd, fds[1] = 1, fds[2] = 0;
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 (__isfdkind(fds[i], kFdFile) || __isfdkind(fds[i], kFdConsole)) {
if (GetConsoleMode(g_fds.p[fds[i]].handle, &mode)) {
if (fds[i]->kind == kFdFile || fds[i]->kind == kFdConsole) {
if (GetConsoleMode(fds[i]->handle, &mode)) {
bzero(&sbinfo, sizeof(sbinfo));
sbinfo.cbSize = sizeof(sbinfo);
if (GetConsoleScreenBufferInfoEx(g_fds.p[fds[i]].handle, &sbinfo)) {
if (GetConsoleScreenBufferInfoEx(fds[i]->handle, &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;

View file

@ -24,8 +24,6 @@
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
int ioctl_tiocgwinsz_nt(int, struct winsize *);
/**
* Returns width and height of terminal.
*
@ -44,7 +42,7 @@ int ioctl_tiocgwinsz(int fd, ...) {
} else if (!IsWindows()) {
return sys_ioctl(fd, TIOCGWINSZ, ws);
} else {
return ioctl_tiocgwinsz_nt(fd, ws);
return ioctl_tiocgwinsz_nt(g_fds.p + fd, ws);
}
} else {
return einval();

View file

@ -25,8 +25,6 @@
#include "libc/nt/thunk/msabi.h"
#include "libc/sysv/consts/nr.h"
extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect;
/**
* Modifies restrictions on virtual memory address range.
*

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,29 +16,33 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#define ShouldUseMsabiAttribute() 1
#include "libc/calls/internal.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nt/enum/status.h"
#include "libc/errno.h"
#include "libc/macros.internal.h"
#include "libc/nt/errors.h"
#include "libc/nt/nt/time.h"
#include "libc/nt/synchronization.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_nanosleep_nt(const struct timespec *req,
struct timespec *rem) {
textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req,
struct timespec *rem) {
/* no function tracing because timing sensitive */
int64_t millis, hectonanos, relasleep;
if (rem) memcpy(rem, req, sizeof(*rem));
hectonanos = req->tv_sec * 10000000ull + div100int64(req->tv_nsec);
hectonanos = req->tv_sec * 10000000 + req->tv_nsec / 100;
hectonanos = MAX(1, hectonanos);
relasleep = -hectonanos;
if (NtError(NtDelayExecution(true, &relasleep))) {
millis = div10000int64(hectonanos);
if (NtError(__imp_NtDelayExecution(true, &relasleep))) {
millis = hectonanos / 10000;
millis = MAX(1, millis);
if (SleepEx(millis, true) == kNtWaitIoCompletion) {
return eintr();
if (__imp_SleepEx(millis, true) == kNtWaitIoCompletion) {
errno = EINTR;
return -1;
}
}
if (rem) bzero(rem, sizeof(*rem));
if (rem) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
}
return 0;
}

View file

@ -84,7 +84,7 @@ textwindows int ntspawn(
(block =
MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0,
blocksize, NULL, kNtNumaNoPreferredNode))) {
if (mkntcmdline(block->cmdline, prog, argv) != -1 &&
if (mkntcmdline(block->cmdline, prog, argv + 1) != -1 &&
mkntenvblock(block->envvars, envp, extravar) != -1) {
if (CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes,
opt_lpThreadAttributes, bInheritHandles,

View file

@ -63,7 +63,7 @@ ssize_t preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
/*
* NT, XNU, and 2007-era Linux don't support this system call.
*/
if (!once) {
if (!__vforked && !once) {
err = errno;
rc = sys_preadv(fd, iov, iovlen, off, off);
if (rc == -1 && errno == ENOSYS) {

View file

@ -0,0 +1,133 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/mem/alloca.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
#include "libc/str/utf16.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/consts/prot.h"
#define SIZE 1024
#define CTL_KERN 1
#define KERN_PROC 14
#define KERN_PROC_PATHNAME_FREEBSD 12
#define KERN_PROC_PATHNAME_NETBSD 5
/**
* Absolute path of executable.
*
* This variable is initialized automatically at startup. The path is
* basically `argv[0]` except some extra vetting is done to provide
* stronger assurance that the path can be counted upon to exist.
*
* For example, if your program is executed as a relative path and then
* your program calls `chdir()`, then `argv[0]` will be incorrect; but
* `program_executable_name` will work, because it prefixed `getcwd()`
* early in the initialization phase.
*
* @see GetInterpreterExecutableName()
* @see program_invocation_short_name
* @see program_invocation_name
*/
char program_executable_name[SIZE];
static textwindows bool GetNtExePath(char executable[SIZE]) {
uint64_t w;
wint_t x, y;
uint32_t i, j;
char16_t path16[PATH_MAX + 1];
if (!GetModuleFileName(0, path16, ARRAYLEN(path16))) return 0;
for (i = j = 0; (x = path16[i++] & 0xffff);) {
if (!IsUcs2(x)) {
y = path16[i++] & 0xffff;
x = MergeUtf16(x, y);
}
if (x == '\\') x = '/';
w = tpenc(x);
do {
executable[j] = w;
if (++j == SIZE) {
return false;
}
} while ((w >>= 8));
}
executable[j] = 0;
return true;
}
static textstartup void GetProgramExecutableName(char executable[SIZE],
char *argv0, intptr_t *auxv) {
size_t m;
ssize_t n;
int cmd[4];
char *p, *t;
if (IsWindows() && GetNtExePath(executable)) return;
for (p = 0; *auxv; auxv += 2) {
if (*auxv == AT_EXECFN) {
p = (char *)auxv[1];
break;
}
}
n = 0;
if (!p) p = argv0;
if (p) {
if (!_isabspath(p)) {
if (getcwd(executable, SIZE - 1)) {
n = strlen(executable);
executable[n++] = '/';
}
}
for (; *p; ++p) {
if (n + 1 < SIZE) {
executable[n++] = *p;
}
}
}
executable[n] = 0;
}
textstartup void program_executable_name_init(int argc, char **argv,
char **envp, intptr_t *auxv) {
int e;
static bool once;
char executable[SIZE];
if (!cmpxchg(&once, 0, 1)) return;
e = errno;
GetProgramExecutableName(executable, argv[0], auxv);
errno = e;
__stpcpy(program_executable_name, executable);
SYSDEBUG("program_executable_name → %#s", program_executable_name);
}
const void *const program_executable_name_init_ctor[] initarray = {
program_executable_name_init,
};

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/errno.h"
@ -45,6 +46,7 @@ textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov,
ssize_t rc;
uint32_t size;
size_t i, total;
if (weaken(_check_sigwinch) && weaken(_check_sigwinch)(fd)) return eintr();
while (iovlen && !iov[0].iov_len) iov++, iovlen--;
if (iovlen) {
for (total = i = 0; i < iovlen; ++i) {

View file

@ -35,21 +35,12 @@ static int GetFirstIov(struct iovec *iov, int iovlen) {
}
ssize_t sys_readv_serial(struct Fd *fd, const struct iovec *iov, int iovlen) {
size_t i, j, got = 0;
size_t i;
if ((i = GetFirstIov(iov, iovlen)) != -1) {
while (!IsDataAvailable(fd)) asm("pause");
i = 0;
j = 0;
do {
++got;
((char *)iov[i].iov_base)[j] = inb(fd->handle);
if (++j == iov[i].iov_len) {
j = 0;
if (++i == iovlen) {
break;
}
}
} while (IsDataAvailable(fd));
((char *)iov[i].iov_base)[0] = inb(fd->handle);
return 1;
} else {
return 0;
}
return got;
}

View file

@ -25,13 +25,14 @@
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/log/backtrace.internal.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
@ -73,12 +74,13 @@ static char *ResolvePath(char *d, const char *s, size_t n)
* symbolic link then it's resolved.
*
* @param resolved needs PATH_MAX bytes or NULL to use malloc()
* @return resolved or NULL w/ errno
*/
char *realpath(const char *filename, char *resolved)
{
ssize_t k;
int up, check_dir=0;
size_t p, q, l, l0, cnt=0, nup=0;
ssize_t rc;
int e, up, check_dir=0;
size_t k, p, q, l, l0, cnt=0, nup=0;
char output[PATH_MAX], stack[PATH_MAX+1], *z;
if (!filename) {
@ -160,15 +162,10 @@ restart:
* directories, processing .. can skip readlink. */
if (!check_dir) goto skip_readlink;
}
k = readlink(output, stack, p);
if (k<0) SYSDEBUG("realpath readlink failed %d", (long)errno);
if (k==p) goto toolong;
if (!k) {
errno = ENOENT;
return 0;
}
if (k<0) {
e = errno;
if ((rc = readlink(output, stack, p)) == -1) {
if (errno != EINVAL) return 0;
errno = e; /* [jart] undirty errno if not a symlink */
skip_readlink:
check_dir = 0;
if (up) {
@ -180,6 +177,14 @@ skip_readlink:
check_dir = stack[p];
continue;
}
k = rc;
assert(k <= p);
if (k==p)
goto toolong;
if (!k) {
errno = ENOENT;
return 0;
}
if (++cnt == SYMLOOP_MAX) {
errno = ELOOP;
return 0;

View file

@ -16,6 +16,43 @@
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/calls/struct/winsize.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/errno.h"
#include "libc/nt/struct/consolescreenbufferinfoex.h"
#include "libc/str/str.h"
int __vforked;
static struct winsize __ws;
textwindows bool _check_sigwinch(struct Fd *fd) {
int e;
siginfo_t si;
struct winsize ws, old;
struct NtConsoleScreenBufferInfoEx sbinfo;
old = __ws;
if (old.ws_row != 0xffff) {
e = errno;
if (ioctl_tiocgwinsz_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) {
SYSDEBUG("SIGWINCH %hhu×%hhu → %hhu×%hhu", old.ws_col, old.ws_row,
ws.ws_col, ws.ws_row);
if (__sighandrvas[SIGWINCH] >= kSigactionMinRva) {
bzero(&si, sizeof(si));
((sigaction_f)(_base + __sighandrvas[SIGWINCH]))(SIGWINCH, &si, 0);
return true;
}
}
}
} else {
errno = e;
if (!old.ws_row && !old.ws_col) {
__ws.ws_row = 0xffff;
}
}
}
return false;
}

View file

@ -32,9 +32,10 @@ static ssize_t splicer(int infd, int64_t *inoffset, int outfd,
if (!uptobytes || flags == -1) return einval();
if (IsModeDbg() && uptobytes > 1) uptobytes >>= 1;
olderr = errno;
if ((transferred =
if (__isfdkind(infd, kFdZip) || __isfdkind(outfd, kFdZip) ||
(transferred =
impl(infd, inoffset, outfd, outoffset, uptobytes, flags)) == -1 &&
errno == ENOSYS) {
errno == ENOSYS) {
errno = olderr;
transferred = copyfd(infd, inoffset, outfd, outoffset, uptobytes, flags);
}

View file

@ -24,6 +24,7 @@ COSMOPOLITAN_C_START_
void _init_onntconsoleevent(void);
void _init_wincrash(void);
bool _check_sigwinch();
#ifndef __SIGACTION_YOINK
#define __SIGACTION_YOINK(SIG) \
@ -44,12 +45,16 @@ void _init_wincrash(void);
case SIGFPE: \
YOINK(_init_wincrash); \
break; \
case SIGWINCH: \
YOINK(_check_sigwinch); \
break; \
default: \
break; \
} \
} else { \
YOINK(_init_onntconsoleevent); \
YOINK(_init_wincrash); \
YOINK(_check_sigwinch); \
} \
} \
} while (0)

View file

@ -7,7 +7,7 @@
#endif
#if DEBUGSYS
#define SYSDEBUG(FMT, ...) __printf("SYS: " FMT "\n", ##__VA_ARGS__)
#define SYSDEBUG(FMT, ...) kprintf("SYS: " FMT "\n", ##__VA_ARGS__)
#else
#define SYSDEBUG(FMT, ...) (void)0
#endif