mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 14:58:30 +00:00
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:
parent
d44ff6ce1f
commit
d230a01222
160 changed files with 2754 additions and 1342 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 *,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 "
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
63
libc/x/xfixpath.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue