mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-07 19:58:30 +00:00
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:
parent
2a938b3eaa
commit
b45d50b690
194 changed files with 4881 additions and 2966 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 ─╬─│┼
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
133
libc/calls/program_executable_name.c
Normal file
133
libc/calls/program_executable_name.c
Normal 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,
|
||||
};
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue