Make build hermetic without shell scripts

- Fix some minor issues in ar.com
- Have execve() look for `ape` command
- Rewrite NT paths using /c/ rather /??/c:/
- Replace broken GCC symlinks with .sym files
- Rewrite $PATH environment variables on startup
- Make $(APE_NO_MODIFY_SELF) the default bootloader
- Add all build command dependencies to build/bootstrap
- Get the repository mostly building from source on non-Linux
This commit is contained in:
Justine Tunney 2022-05-25 11:31:08 -07:00
parent d44ff6ce1f
commit d230a01222
160 changed files with 2754 additions and 1342 deletions

View file

@ -112,6 +112,7 @@ o/$(MODE)/libc/calls/execl.o \
o/$(MODE)/libc/calls/execle.o \
o/$(MODE)/libc/calls/execlp.o \
o/$(MODE)/libc/calls/execve-sysv.o \
o/$(MODE)/libc/calls/execve-nt.greg.o \
o/$(MODE)/libc/calls/mkntenvblock.o: \
OVERRIDE_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED

View file

@ -76,7 +76,7 @@ noinstrument int clock_gettime(int clockid, struct timespec *ts) {
/**
* Returns pointer to fastest clock_gettime().
*/
clock_gettime_f *__get_clock_gettime(bool *opt_out_isfast) {
clock_gettime_f *__clock_gettime_get(bool *opt_out_isfast) {
bool isfast;
clock_gettime_f *res;
if (IsLinux() && (res = __vdsosym("LINUX_2.6", "__vdso_clock_gettime"))) {
@ -99,6 +99,6 @@ clock_gettime_f *__get_clock_gettime(bool *opt_out_isfast) {
hidden int __clock_gettime_init(int clockid, struct timespec *ts) {
clock_gettime_f *gettime;
__clock_gettime = gettime = __get_clock_gettime(0);
__clock_gettime = gettime = __clock_gettime_get(0);
return gettime(clockid, ts);
}

View file

@ -8,7 +8,7 @@ typedef int clock_gettime_f(int, struct timespec *);
extern clock_gettime_f *__clock_gettime;
hidden clock_gettime_f __clock_gettime_init;
hidden clock_gettime_f *__get_clock_gettime(bool *);
hidden clock_gettime_f *__clock_gettime_get(bool *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -23,6 +23,7 @@
#include "libc/calls/ntspawn.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/mem/alloca.h"
#include "libc/nt/accounting.h"
#include "libc/nt/console.h"
@ -59,13 +60,28 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
int rc;
size_t i;
uint32_t dwExitCode;
char progbuf[PATH_MAX];
struct MemoryIntervals *mm;
struct NtStartupInfo startinfo;
struct NtProcessInformation procinfo;
if (strlen(program) + 4 + 1 > PATH_MAX) {
return enametoolong();
}
// this is a non-recoverable operation, so do some manual validation
if (sys_faccessat_nt(AT_FDCWD, program, X_OK, 0) == -1) {
return eacces();
stpcpy(stpcpy(progbuf, program), ".com");
if (sys_faccessat_nt(AT_FDCWD, progbuf, X_OK, 0) != -1) {
program = progbuf;
} else {
stpcpy(stpcpy(progbuf, program), ".exe");
if (sys_faccessat_nt(AT_FDCWD, progbuf, X_OK, 0) != -1) {
program = progbuf;
} else {
return eacces();
}
}
}
//////////////////////////////////////////////////////////////////////////////

View file

@ -16,28 +16,80 @@
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/syscall-sysv.internal.h"
#include "libc/errno.h"
#include "libc/mem/alloca.h"
#include "libc/paths.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/errfuns.h"
static bool CanExecute(const char *path) {
return !sys_faccessat(AT_FDCWD, path, X_OK, 0);
}
static bool IsApeBinary(const char *path) {
int fd;
char buf[8];
bool res = false;
if ((fd = sys_open(path, O_RDONLY, 0)) != -1) {
if (sys_read(fd, buf, 8) == 8 && READ64LE(buf) == READ64LE("MZqFpD='")) {
res = true;
}
sys_close(fd);
}
return res;
}
static const char *Join(const char *a, const char *b, char buf[PATH_MAX]) {
size_t n, m;
n = strlen(a);
m = strlen(b);
if (n + 1 + m + 1 < PATH_MAX) {
stpcpy(stpcpy(stpcpy(buf, a), "/"), b);
return buf;
} else {
return "";
}
}
int sys_execve(const char *prog, char *const argv[], char *const envp[]) {
int e;
size_t i;
char *buf;
char **shargs;
const char *ape;
e = errno;
__sys_execve(prog, argv, envp);
if (errno != ENOEXEC) return -1;
for (i = 0; argv[i];) ++i;
shargs = alloca((i + 2) * sizeof(char *));
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
if (IsFreebsd() || IsNetbsd()) {
shargs[0] = firstnonnull(commandv("bash", alloca(PATH_MAX), PATH_MAX),
_PATH_BSHELL);
buf = alloca(PATH_MAX);
shargs = alloca((i + 4) * sizeof(char *));
if (IsApeBinary(prog) &&
(CanExecute((ape = "/usr/bin/ape")) ||
CanExecute(
(ape = Join(firstnonnull(getenv("TMPDIR"), "/tmp"), "ape", buf))))) {
shargs[0] = ape;
shargs[1] = "-";
shargs[2] = prog;
memcpy(shargs + 3, argv, (i + 1) * sizeof(char *));
} else if (CanExecute(prog)) {
if (IsFreebsd() || IsNetbsd()) {
shargs[0] = firstnonnull(commandv("bash", buf, PATH_MAX), _PATH_BSHELL);
} else {
shargs[0] = _PATH_BSHELL;
}
shargs[1] = prog;
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
} else {
shargs[0] = _PATH_BSHELL;
return enoexec();
}
shargs[1] = prog;
errno = e;
return __sys_execve(shargs[0], shargs, envp);
}

View file

@ -32,14 +32,21 @@ textwindows char *sys_getcwd_nt(char *buf, size_t size) {
if ((n = GetCurrentDirectory(ARRAYLEN(p), p))) {
if (4 + n + 1 <= size && 4 + n + 1 <= ARRAYLEN(p)) {
tprecode16to8(buf, size, p);
i = 0;
j = 0;
if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') {
// turn c:\... into \c\...
p[1] = p[0];
p[0] = '\\';
} else if (n >= 7 && p[0] == '\\' && p[1] == '\\' && p[2] == '?' &&
p[3] == '\\' && isalpha(p[4]) && p[5] == ':' && p[6] == '\\') {
// turn \\?\c:\... into \c\...
buf[j++] = '/';
buf[j++] = p[4];
buf[j++] = '/';
buf[j++] = '?';
buf[j++] = '/';
i += 7;
}
for (i = 0; i < n;) {
while (i < n) {
x = p[i++] & 0xffff;
if (!IsUcs2(x)) {
if (i < n) {

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/macros.internal.h"
// Obtains WIN32 magic path, e.g. GetTempPathA.
@ -33,7 +34,13 @@ __getntsyspath:
movpp %rdi,%rcx # call f=%rax(p1=%rcx,p2=%rdx)
sub $40,%rsp
call *%rax
xor %edx,%edx
testb IsWindows()
jz 3f
mov (%rdi),%cl # turn c:\... into \c\...
movb $'\\',(%rdi)
mov %cl,1(%rdi)
movb $'\\',2(%rdi)
3: xor %edx,%edx
mov -8(%rbp),%ecx # restore %edx param as %ecx
cmp %eax,%ecx # use current dir on overflow
cmovbe %edx,%eax

View file

@ -34,6 +34,10 @@
char program_executable_name[PATH_MAX];
static inline int IsAlpha(int c) {
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
}
static inline char *StrCat(char buf[PATH_MAX], const char *a, const char *b) {
char *p, *e;
p = buf;
@ -56,16 +60,16 @@ static inline void GetProgramExecutableNameImpl(char *p, char *e) {
if (IsWindows()) {
n = GetModuleFileName(0, u.path16, ARRAYLEN(u.path16));
for (i = 0; i < n; ++i) {
// turn c:\foo\bar into c:/foo/bar
if (u.path16[i] == '\\') {
u.path16[i] = '/';
}
}
if (isalpha(u.path16[0]) && u.path16[1] == ':' && u.path16[2] == '/') {
p[0] = '/';
p[1] = '/';
p[2] = '?';
p[3] = '/';
p += 4;
if (IsAlpha(u.path16[0]) && u.path16[1] == ':' && u.path16[2] == '/') {
// turn c:/... into /c/...
u.path16[1] = u.path16[0];
u.path16[0] = '/';
u.path16[2] = '/';
}
tprecode16to8(p, e - p, u.path16);
return;

View file

@ -17,8 +17,10 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/arraylist2.internal.h"
#include "libc/bits/bits.h"
#include "libc/calls/ntspawn.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/mem/alloca.h"
#include "libc/mem/mem.h"
@ -31,15 +33,85 @@
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
static int CompareStrings(const char *l, const char *r) {
static inline int IsAlpha(int c) {
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
}
static inline char *StrChr(char *s, int c) {
for (;; ++s) {
if ((*s & 255) == (c & 255)) return s;
if (!*s) return 0;
}
}
static textwindows inline int CompareStrings(const char *l, const char *r) {
int a, b;
size_t i = 0;
while ((a = ToUpper(l[i] & 255)) == (b = ToUpper(r[i] & 255)) && r[i]) ++i;
return a - b;
}
static void InsertString(char **a, size_t i, char *s) {
size_t j;
static textwindows void FixPath(char *path) {
char *p;
size_t i;
// skip over variable name
while (*path++) {
if (path[-1] == '=') {
break;
}
}
// turn colon into semicolon
// unless it already looks like a dos path
for (p = path; *p; ++p) {
if (p[0] == ':' && p[1] != '\\') {
p[0] = ';';
}
}
// turn \c\... into c:\...
p = path;
if (p[0] == '/' && IsAlpha(p[1]) && p[2] == '/') {
p[0] = p[1];
p[1] = ':';
}
for (; *p; ++p) {
if (p[0] == ';' && p[1] == '/' && IsAlpha(p[2]) && p[3] == '/') {
p[1] = p[2];
p[2] = ':';
}
}
// turn slash into backslash
for (p = path; *p; ++p) {
if (*p == '/') {
*p = '\\';
}
}
}
static textwindows void InsertString(char **a, size_t i, char *s,
char buf[ARG_MAX], size_t *bufi) {
char *v;
size_t j, k;
// apply fixups to var=/c/...
if ((v = StrChr(s, '=')) && v[1] == '/' && IsAlpha(v[2]) && v[3] == '/') {
v = buf + *bufi;
for (k = 0; s[k]; ++k) {
if (*bufi + 1 < ARG_MAX) {
buf[(*bufi)++] = s[k];
}
}
if (*bufi < ARG_MAX) {
buf[(*bufi)++] = 0;
FixPath(v);
s = v;
}
}
// append to sorted list
for (j = i; j > 0 && CompareStrings(s, a[j - 1]) < 0; --j) {
a[j] = a[j - 1];
}
@ -58,18 +130,18 @@ static void InsertString(char **a, size_t i, char *s) {
* @error E2BIG if total number of shorts exceeded ARG_MAX/2 (32767)
*/
textwindows int mkntenvblock(char16_t envvars[ARG_MAX / 2], char *const envp[],
const char *extravar) {
const char *extravar, char buf[ARG_MAX]) {
bool v;
char *t;
axdx_t rc;
uint64_t w;
char **vars;
wint_t x, y;
size_t i, j, k, n, m;
size_t i, j, k, n, m, bufi = 0;
for (n = 0; envp[n];) n++;
vars = alloca((n + 1) * sizeof(char *));
for (i = 0; i < n; ++i) InsertString(vars, i, envp[i]);
if (extravar) InsertString(vars, n++, extravar);
for (i = 0; i < n; ++i) InsertString(vars, i, envp[i], buf, &bufi);
if (extravar) InsertString(vars, n++, extravar, buf, &bufi);
for (k = i = 0; i < n; ++i) {
j = 0;
v = false;

View file

@ -31,6 +31,10 @@ static inline bool IsSlash(char c) {
return c == '/' || c == '\\';
}
static inline int IsAlpha(int c) {
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
}
textwindows static const char *FixNtMagicPath(const char *path,
unsigned flags) {
const struct NtMagicPaths *mp = &kNtMagicPaths;
@ -78,18 +82,51 @@ textwindows int __mkntpath2(const char *path,
*/
char16_t *p;
const char *q;
size_t i, n, m, z;
bool isdospath;
size_t i, n, m, x, z;
if (!path) return efault();
path = FixNtMagicPath(path, flags);
p = path16;
q = path;
if (IsSlash(path[0]) && IsSlash(path[1]) && path[2] == '?' &&
IsSlash(path[3])) {
if (IsSlash(q[0]) && IsAlpha(q[1]) && IsSlash(q[2])) {
z = MIN(32767, PATH_MAX);
// turn "\c\foo" into "\\?\c:\foo"
p[0] = '\\';
p[1] = '\\';
p[2] = '?';
p[3] = '\\';
p[4] = q[1];
p[5] = ':';
p[6] = '\\';
p += 7;
q += 3;
z -= 7;
x = 7;
} else if (IsSlash(q[0]) && IsAlpha(q[1]) && IsSlash(q[2])) {
z = MIN(32767, PATH_MAX);
// turn "c:\foo" into "\\?\c:\foo"
p[0] = '\\';
p[1] = '\\';
p[2] = '?';
p[3] = '\\';
p[4] = q[0];
p[5] = ':';
p[6] = '\\';
p += 7;
q += 3;
z -= 7;
x = 7;
} else if (IsSlash(q[0]) && IsSlash(q[1]) && q[2] == '?' && IsSlash(q[3])) {
z = MIN(32767, PATH_MAX);
x = 0;
} else {
z = MIN(260, PATH_MAX);
x = 0;
}
if (IsSlash(q[0]) && q[1] == 't' && q[2] == 'm' && q[3] == 'p' &&
// turn /tmp into GetTempPath()
if (!x && IsSlash(q[0]) && q[1] == 't' && q[2] == 'm' && q[3] == 'p' &&
(IsSlash(q[4]) || !q[4])) {
m = GetTempPath(z, p);
if (!q[4]) return m;
@ -99,15 +136,20 @@ textwindows int __mkntpath2(const char *path,
} else {
m = 0;
}
// turn utf-8 into utf-16
n = tprecode8to16(p, z, q).ax;
if (n >= z - 1) {
STRACE("path too long for windows: %#s", path);
return enametoolong();
}
// turn slash into backslash
for (i = 0; i < n; ++i) {
if (p[i] == '/') {
p[i] = '\\';
}
}
return m + n;
return x + m + n;
}

View file

@ -102,7 +102,7 @@ static long double nowl_vdso(void) {
long double nowl_setup(void) {
bool isfast;
uint64_t ticks;
__gettime = __get_clock_gettime(&isfast);
__gettime = __clock_gettime_get(&isfast);
if (isfast) {
nowl = nowl_vdso;
} else if (X86_HAVE(INVTSC)) {

View file

@ -94,15 +94,15 @@ TryAgain:
}
} else {
rc = __winerr();
STRACE("%s failed: %m", "AccessCheck");
STRACE("%s(%#hs) failed: %m", "AccessCheck", pathname);
}
} else {
rc = __winerr();
STRACE("%s failed: %m", "DuplicateToken");
STRACE("%s(%#hs) failed: %m", "DuplicateToken", pathname);
}
} else {
rc = __winerr();
STRACE("%s failed: %m", "OpenProcessToken");
STRACE("%s(%#hs) failed: %m", "OpenProcessToken", pathname);
}
} else {
e = GetLastError();
@ -112,9 +112,11 @@ TryAgain:
goto TryAgain;
} else {
rc = enomem();
STRACE("%s(%#hs) failed: %m", "GetFileSecurity", pathname);
}
} else {
errno = e;
STRACE("%s(%#hs) failed: %m", "GetFileSecurity", pathname);
rc = -1;
}
}

View file

@ -36,8 +36,9 @@ struct SpawnBlock {
struct {
char16_t cmdline[ARG_MAX / 2];
char16_t envvars[ARG_MAX / 2];
char buf[ARG_MAX];
};
char __pad[ROUNDUP(ARG_MAX / 2 * 2 * sizeof(char16_t), FRAMESIZE)];
char __pad[ROUNDUP(ARG_MAX / 2 * 3 * sizeof(char16_t), FRAMESIZE)];
};
};
@ -83,7 +84,7 @@ textwindows int ntspawn(
(block = MapViewOfFileEx(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0,
sizeof(*block), 0)) &&
mkntcmdline(block->cmdline, prog, argv) != -1 &&
mkntenvblock(block->envvars, envp, extravar) != -1 &&
mkntenvblock(block->envvars, envp, extravar, block->buf) != -1 &&
CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes,
opt_lpThreadAttributes, bInheritHandles,
dwCreationFlags | kNtCreateUnicodeEnvironment,

View file

@ -7,7 +7,8 @@
COSMOPOLITAN_C_START_
int mkntcmdline(char16_t[ARG_MAX / 2], const char *, char *const[]) hidden;
int mkntenvblock(char16_t[ARG_MAX / 2], char *const[], const char *) hidden;
int mkntenvblock(char16_t[ARG_MAX / 2], char *const[], const char *,
char[ARG_MAX]) hidden;
int ntspawn(const char *, char *const[], char *const[], const char *,
struct NtSecurityAttributes *, struct NtSecurityAttributes *,
bool32, uint32_t, const char16_t *, const struct NtStartupInfo *,

View file

@ -58,10 +58,9 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
p = (char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer +
rdb->SymbolicLinkReparseBuffer.PrintNameOffset);
if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') {
buf[j++] = '/';
buf[j++] = '/';
buf[j++] = '?';
buf[j++] = '/';
p[1] = p[0];
p[0] = '/';
p[2] = '/';
}
while (i < n) {
x = p[i++] & 0xffff;

View file

@ -9,7 +9,7 @@
#define _KERNTRACE 0 /* not configurable w/ flag yet */
#define _POLLTRACE 0 /* not configurable w/ flag yet */
#define _DATATRACE 1 /* not configurable w/ flag yet */
#define _NTTRACE 1 /* not configurable w/ flag yet */
#define _NTTRACE 0 /* not configurable w/ flag yet */
#define STRACE_PROLOGUE "%rSYS %5P %'18T "

View file

@ -64,6 +64,7 @@ i32 sys_mknod(const char *, u32, u64) hidden;
i32 sys_mprotect(void *, u64, i32) hidden;
i32 sys_msync(void *, u64, i32) hidden;
i32 sys_munmap(void *, u64) hidden;
i32 sys_open(const char *, i32, u32) hidden;
i32 sys_openat(i32, const char *, i32, u32) hidden;
i32 sys_pause(void) hidden;
i32 sys_pipe(i32[hasatleast 2]) hidden;

View file

@ -62,19 +62,6 @@ static int __fmt_stoa_quoted(out_f out, void *a, uint64_t w) {
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
}
static int __fmt_stoa_quote(out_f out, void *arg, unsigned flags, char ch,
unsigned char signbit) {
if (flags & FLAGS_REPR) {
if (signbit == 63) {
if (out("L", arg, 1) == -1) return -1;
} else if (signbit == 15) {
if (out("u", arg, 1) == -1) return -1;
}
if (out(&ch, arg, 1) == -1) return -1;
}
return 0;
}
/**
* Converts string to array.
*
@ -103,8 +90,6 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
if (flags & FLAGS_PRECISION) {
precision = min(strlen(p), precision);
}
} else {
if (__fmt_stoa_quote(out, arg, flags, qchar, signbit) == -1) return -1;
}
ignorenul = false;
@ -153,6 +138,9 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
} else if (weaken(strnwidth)) {
w = weaken(strnwidth)(p, precision, 0);
}
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
w += 2 + (signbit == 63) + (signbit == 15);
}
if (w < width) {
pad = width - w;
}
@ -162,6 +150,16 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
if (__fmt_pad(out, arg, pad) == -1) return -1;
}
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
if (signbit == 63) {
if (out("L", arg, 1) == -1) return -1;
} else if (signbit == 15) {
if (out("u", arg, 1) == -1) return -1;
}
buf[0] = qchar;
if (out(buf, arg, 1) == -1) return -1;
}
if (justdobytes) {
while (precision--) {
wc = *p++ & 0xff;
@ -207,14 +205,14 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
}
}
if (pad && (flags & FLAGS_LEFT)) {
if (__fmt_pad(out, arg, pad) == -1) return -1;
}
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
buf[0] = qchar;
if (out(buf, arg, 1) == -1) return -1;
}
if (pad && (flags & FLAGS_LEFT)) {
if (__fmt_pad(out, arg, pad) == -1) return -1;
}
return 0;
}

View file

@ -22,6 +22,8 @@
#define INITIAL_CAPACITY 4
nop
// Invokes deferred function calls.
//
// This offers behavior similar to std::unique_ptr. Functions
@ -32,8 +34,6 @@
//
// @param rax,rdx,xmm0,xmm1,st0,st1 is return value
// @see test/libc/runtime/gc_test.c
nop # backtrace workaround
// <LIMBO>
__gc: decq __garbage(%rip)
mov __garbage(%rip),%r8
mov __garbage+16(%rip),%r9
@ -43,17 +43,16 @@ __gc: decq __garbage(%rip)
mov 8(%r8),%r9
mov 16(%r8),%rdi
push 24(%r8)
// </LIMBO>
push %rbp
mov %rsp,%rbp
sub $16,%rsp
push %rax
push %rdx
movdqa %xmm0,-16(%rbp)
sub $32,%rsp
mov %rax,-8(%rbp)
mov %rdx,-16(%rbp)
movdqa %xmm0,-32(%rbp)
call *%r9
movdqa -16(%rbp),%xmm0
pop %rdx
pop %rax
movdqa -32(%rbp),%xmm0
mov -16(%rbp),%rdx
mov -8(%rbp),%rax
leave
ret
9: hlt

View file

@ -35,23 +35,24 @@ const char *FindDebugBinary(void) {
char *p;
size_t n;
if (!once) {
if (!(res = getenv("COMDBG"))) {
p = GetProgramExecutableName();
n = strlen(p);
if (n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) {
res = p;
} else if (n > 4 && READ32LE(p + n - 4) == READ32LE(".com") &&
n + 4 < ARRAYLEN(buf)) {
mempcpy(mempcpy(buf, p, n), ".dbg", 5);
if (fileexists(buf)) {
res = buf;
}
} else if (n + 8 < ARRAYLEN(buf)) {
mempcpy(mempcpy(buf, p, n), ".com.dbg", 9);
if (fileexists(buf)) {
res = buf;
}
p = GetProgramExecutableName();
n = strlen(p);
if (n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) {
res = p;
} else if (n > 4 && READ32LE(p + n - 4) == READ32LE(".com") &&
n + 4 < ARRAYLEN(buf)) {
mempcpy(mempcpy(buf, p, n), ".dbg", 5);
if (fileexists(buf)) {
res = buf;
}
} else if (n + 8 < ARRAYLEN(buf)) {
mempcpy(mempcpy(buf, p, n), ".com.dbg", 9);
if (fileexists(buf)) {
res = buf;
}
}
if (!res) {
res = getenv("COMDBG");
}
once = true;
}

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
@ -23,6 +24,19 @@
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
forceinline int IsAlpha(int c) {
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
}
forceinline char *MemChr(const char *s, unsigned char c, unsigned long n) {
for (; n; --n, ++s) {
if ((*s & 255) == c) {
return s;
}
}
return 0;
}
static textwindows noasan noinstrument axdx_t Recode16to8(char *dst,
size_t dstsize,
const char16_t *src) {
@ -45,13 +59,51 @@ static textwindows noasan noinstrument axdx_t Recode16to8(char *dst,
}
w = tpenc(x);
do {
if (r.ax + 1 >= dstsize) break;
dst[r.ax++] = w;
if (r.ax + 1 < dstsize) {
dst[r.ax++] = w;
} else {
break;
}
} while ((w >>= 8));
}
if (r.ax < dstsize) {
dst[r.ax] = 0;
}
return r;
}
textwindows noinstrument noasan void FixPath(char *path) {
char *p;
size_t i;
// turn backslash into slash
for (p = path; *p; ++p) {
if (*p == '\\') {
*p = '/';
}
}
// turn c:/... into /c/...
p = path;
if (IsAlpha(p[0]) && p[1] == ':' && p[2] == '/') {
p[1] = p[0];
p[0] = '/';
}
for (; *p; ++p) {
if (p[0] == ';' && IsAlpha(p[1]) && p[2] == ':' && p[3] == '/') {
p[2] = p[1];
p[1] = '/';
}
}
// turn semicolon into colon
for (p = path; *p; ++p) {
if (*p == ';') {
*p = ':';
}
}
}
/**
* Transcodes NT environment variable block from UTF-16 to UTF-8.
*
@ -66,12 +118,17 @@ textwindows noasan noinstrument int GetDosEnviron(const char16_t *env,
char *buf, size_t size,
char **envp, size_t max) {
int i;
char *p;
axdx_t r;
i = 0;
--size;
while (*env) {
if (i + 1 < max) envp[i++] = buf;
r = Recode16to8(buf, size, env);
if ((p = memchr(buf, '=', r.ax)) && IsAlpha(p[1]) && p[2] == ':' &&
(p[3] == '\\' || p[3] == '/')) {
FixPath(p + 1);
}
size -= r.ax + 1;
buf += r.ax + 1;
env += r.dx;

View file

@ -73,6 +73,7 @@ char *xdirname(const char *) paramsnonnull() _XMAL;
char *xjoinpaths(const char *, const char *) paramsnonnull() _XMAL;
char *xreadlink(const char *) paramsnonnull() _XMAL;
char *xreadlinkat(int, const char *) paramsnonnull() _XMAL;
void xfixpath(void);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § eXtended apis » time

63
libc/x/xfixpath.c Normal file
View file

@ -0,0 +1,63 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 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/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/x/x.h"
static inline int IsAlpha(int c) {
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
}
/**
* Fixes $PATH environment variable on Windows.
*/
void xfixpath(void) {
size_t i;
char *p, *path;
path = strdup(getenv("PATH"));
if (strstr(path, "C:\\") && strstr(path, ";")) {
// turn backslash into slash
for (p = path; *p; ++p) {
if (*p == '\\') *p = '/';
}
// turn c:/... into /c/...
if (IsAlpha(path[0]) && path[1] == ':' && path[2] == '/') {
path[1] = path[0];
path[0] = '/';
}
for (p = path, i = 0; p[i]; ++i) {
if (p[i + 0] == ';' && IsAlpha(p[i + 1]) && p[i + 2] == ':' &&
p[i + 3] == '/') {
p[i + 2] = p[i + 1];
p[i + 1] = '/';
}
}
// turn semicolon into colon
for (p = path; *p; ++p) {
if (*p == ';') *p = ':';
}
setenv("PATH", path, true);
}
free(path);
}