mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-07 10:20:29 +00:00
Merge branches *-realpath
Merges branches 'm1-realpath', 'loader-realpath' and 'getprogramexecutablename-realpath' into no-realpath
This commit is contained in:
commit
0734b9c225
2 changed files with 66 additions and 82 deletions
53
ape/loader.c
53
ape/loader.c
|
@ -545,40 +545,6 @@ __attribute__((__noreturn__)) static void Pexit(int os, const char *c, int rc,
|
||||||
Exit(127, os);
|
Exit(127, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PSFD "/proc/self/fd/"
|
|
||||||
|
|
||||||
static int RealPath(int os, int fd, char *path, char **resolved) {
|
|
||||||
char buf[PATH_MAX];
|
|
||||||
int rc;
|
|
||||||
if (IsLinux()) {
|
|
||||||
char psfd[sizeof(PSFD) + 19];
|
|
||||||
MemMove(psfd, PSFD, sizeof(PSFD) - 1);
|
|
||||||
Utoa(psfd + sizeof(PSFD) - 1, fd);
|
|
||||||
rc = SystemCall(-100, (long)psfd, (long)buf, PATH_MAX, 0, 0, 0,
|
|
||||||
IsAarch64() ? 78 : 267);
|
|
||||||
if (rc >= 0) {
|
|
||||||
if (rc == PATH_MAX) {
|
|
||||||
rc = -36;
|
|
||||||
} else {
|
|
||||||
buf[rc] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (IsXnu()) {
|
|
||||||
rc = SystemCall(fd, 50, (long)buf, 0, 0, 0, 0, 92 | 0x2000000);
|
|
||||||
} else if (IsOpenbsd()) {
|
|
||||||
rc = SystemCall((long)path, (long)buf, 0, 0, 0, 0, 0, 115);
|
|
||||||
} else {
|
|
||||||
*resolved = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (rc >= 0) {
|
|
||||||
MemMove(path, buf, StrLen(buf) + 1);
|
|
||||||
*resolved = path;
|
|
||||||
rc = 0;
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
||||||
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0;
|
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||||
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
||||||
|
@ -644,9 +610,8 @@ static char *Commandv(struct PathSearcher *ps, int os, const char *name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((__noreturn__)) static void Spawn(int os, const char *exe,
|
__attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
||||||
char *path, int fd, long *sp,
|
long *sp, unsigned long pagesz,
|
||||||
unsigned long pagesz,
|
|
||||||
struct ElfEhdr *e,
|
struct ElfEhdr *e,
|
||||||
struct ElfPhdr *p) {
|
struct ElfPhdr *p) {
|
||||||
long rc;
|
long rc;
|
||||||
|
@ -803,12 +768,12 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe,
|
||||||
Msyscall(dynbase + code, codesize, os);
|
Msyscall(dynbase + code, codesize, os);
|
||||||
|
|
||||||
/* call program entrypoint */
|
/* call program entrypoint */
|
||||||
Launch(IsFreebsd() ? sp : 0, dynbase + e->e_entry, path, sp, os);
|
Launch(IsFreebsd() ? sp : 0, dynbase + e->e_entry, exe, sp, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||||
const char *exe, char *path, int fd, long *sp,
|
char *exe, int fd, long *sp, long *auxv,
|
||||||
long *auxv, unsigned long pagesz, int os) {
|
unsigned long pagesz, int os) {
|
||||||
long i, rc;
|
long i, rc;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
struct ElfEhdr *e;
|
struct ElfEhdr *e;
|
||||||
|
@ -923,7 +888,7 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we're now ready to load */
|
/* we're now ready to load */
|
||||||
Spawn(os, exe, path, fd, sp, pagesz, e, p);
|
Spawn(os, exe, fd, sp, pagesz, e, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((__noreturn__)) static void ShowUsage(int os, int fd, int rc) {
|
__attribute__((__noreturn__)) static void ShowUsage(int os, int fd, int rc) {
|
||||||
|
@ -1081,8 +1046,6 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
||||||
Pexit(os, prog, 0, "not found (maybe chmod +x or ./ needed)");
|
Pexit(os, prog, 0, "not found (maybe chmod +x or ./ needed)");
|
||||||
} else if ((fd = Open(exe, O_RDONLY, 0, os)) < 0) {
|
} else if ((fd = Open(exe, O_RDONLY, 0, os)) < 0) {
|
||||||
Pexit(os, exe, fd, "open");
|
Pexit(os, exe, fd, "open");
|
||||||
} else if ((rc = RealPath(os, fd, exe, &prog)) < 0) {
|
|
||||||
Pexit(os, exe, rc, "realpath");
|
|
||||||
} else if ((rc = Pread(fd, ebuf->buf, sizeof(ebuf->buf), 0, os)) < 0) {
|
} else if ((rc = Pread(fd, ebuf->buf, sizeof(ebuf->buf), 0, os)) < 0) {
|
||||||
Pexit(os, exe, rc, "read");
|
Pexit(os, exe, rc, "read");
|
||||||
} else if ((unsigned long)rc < sizeof(ebuf->ehdr)) {
|
} else if ((unsigned long)rc < sizeof(ebuf->ehdr)) {
|
||||||
|
@ -1122,9 +1085,9 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i >= sizeof(ebuf->ehdr)) {
|
if (i >= sizeof(ebuf->ehdr)) {
|
||||||
TryElf(M, ebuf, exe, prog, fd, sp, auxv, pagesz, os);
|
TryElf(M, ebuf, exe, fd, sp, auxv, pagesz, os);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Pexit(os, exe, 0, TryElf(M, ebuf, exe, prog, fd, sp, auxv, pagesz, os));
|
Pexit(os, exe, 0, TryElf(M, ebuf, exe, fd, sp, auxv, pagesz, os));
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#define KERN_PROC 14
|
#define KERN_PROC 14
|
||||||
#define KERN_PROC_PATHNAME_FREEBSD 12
|
#define KERN_PROC_PATHNAME_FREEBSD 12
|
||||||
#define KERN_PROC_PATHNAME_NETBSD 5
|
#define KERN_PROC_PATHNAME_NETBSD 5
|
||||||
|
#define DEV_FD "/dev/fd/"
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
atomic_uint once;
|
atomic_uint once;
|
||||||
|
@ -50,15 +51,49 @@ static inline int IsAlpha(int c) {
|
||||||
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if q exists then turn it into an absolute path. we also try adding
|
||||||
|
// a .com suffix since the ape auto-appends it when resolving
|
||||||
|
static int TryPath(const char *q, int com) {
|
||||||
|
if (!q) return 0;
|
||||||
|
char *p = g_prog.u.buf;
|
||||||
|
char *e = p + sizeof(g_prog.u.buf);
|
||||||
|
int c, f_ok;
|
||||||
|
if ((f_ok = !sys_faccessat(AT_FDCWD, q, F_OK, 0))) {
|
||||||
|
com = 0;
|
||||||
|
} else {
|
||||||
|
if (!com) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*q != '/') {
|
||||||
|
if (q[0] == '.' && q[1] == '/') {
|
||||||
|
q += 2;
|
||||||
|
}
|
||||||
|
int got = __getcwd(p, e - p - 1 - com * 4); // for / and .com
|
||||||
|
if (got != -1) {
|
||||||
|
p += got - 1;
|
||||||
|
*p++ = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while ((c = *q++)) {
|
||||||
|
if (p + 1 + com * 4 < e) { // for nul and .com
|
||||||
|
*p++ = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (f_ok) {
|
||||||
|
*p = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
p = WRITE32LE(p, READ32LE(".com"));
|
||||||
|
*p = 0;
|
||||||
|
return !sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void InitProgramExecutableNameImpl(void) {
|
static inline void InitProgramExecutableNameImpl(void) {
|
||||||
size_t n;
|
size_t n;
|
||||||
ssize_t got;
|
ssize_t got;
|
||||||
char c, *q, *b;
|
char c, *q, *b;
|
||||||
|
|
||||||
if (__program_executable_name) {
|
|
||||||
/* already set by the loader */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
int n = GetModuleFileName(0, g_prog.u.buf16, ARRAYLEN(g_prog.u.buf16));
|
int n = GetModuleFileName(0, g_prog.u.buf16, ARRAYLEN(g_prog.u.buf16));
|
||||||
for (int i = 0; i < n; ++i) {
|
for (int i = 0; i < n; ++i) {
|
||||||
|
@ -83,6 +118,20 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (issetugid() && __program_executable_name) {
|
||||||
|
if ((IsNetbsd() || IsOpenbsd() || IsXnu()) /* any others? */ &&
|
||||||
|
!strncmp(DEV_FD, __program_executable_name, sizeof(DEV_FD) - 1) &&
|
||||||
|
isdigit(__program_executable_name[sizeof(DEV_FD)]) &&
|
||||||
|
!strchr(__program_executable_name + sizeof(DEV_FD) + 1, '/')) {
|
||||||
|
/* loader passed us a secure path */
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
/* we cannot use KERN_PROC_PATHNAME or its ilk in the loader case. they
|
||||||
|
will report the path of the loader, not the path of the binary. */
|
||||||
|
goto UseEmpty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
b = g_prog.u.buf;
|
b = g_prog.u.buf;
|
||||||
n = sizeof(g_prog.u.buf) - 1;
|
n = sizeof(g_prog.u.buf) - 1;
|
||||||
if (IsFreebsd() || IsNetbsd()) {
|
if (IsFreebsd() || IsNetbsd()) {
|
||||||
|
@ -116,43 +165,15 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||||
goto UseEmpty;
|
goto UseEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if argv[0] exists then turn it into an absolute path. we also try
|
// Try what the loader supplied first. Fall back to argv[0],
|
||||||
// adding a .com suffix since the ape auto-appends it when resolving
|
// then argv[0].com, then $_, then $_.com.
|
||||||
if ((q = __argv[0])) {
|
if (TryPath(__program_executable_name, 0) || TryPath(__argv[0], 1) ||
|
||||||
char *p = g_prog.u.buf;
|
TryPath(__getenv(__envp, "_").s, 1)) {
|
||||||
char *e = p + sizeof(g_prog.u.buf);
|
goto UseBuf;
|
||||||
if (*q != '/') {
|
|
||||||
if (q[0] == '.' && q[1] == '/') {
|
|
||||||
q += 2;
|
|
||||||
}
|
|
||||||
int got = __getcwd(p, e - p - 1 - 4); // for / and .com
|
|
||||||
if (got != -1) {
|
|
||||||
p += got - 1;
|
|
||||||
*p++ = '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ((c = *q++)) {
|
|
||||||
if (p + 1 + 4 < e) { // for nul and .com
|
|
||||||
*p++ = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*p = 0;
|
|
||||||
if (!sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0)) goto UseBuf;
|
|
||||||
p = WRITE32LE(p, READ32LE(".com"));
|
|
||||||
*p = 0;
|
|
||||||
if (!sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0)) goto UseBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the previous loader supplied the full program path as the first
|
|
||||||
environment variable. we also try "_". */
|
|
||||||
if ((q = __getenv(__envp, "COSMOPOLITAN_PROGRAM_EXECUTABLE").s) ||
|
|
||||||
(q = __getenv(__envp, "_").s)) {
|
|
||||||
goto CopyString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// give up and just copy argv[0] into it
|
// give up and just copy argv[0] into it
|
||||||
if ((q = __argv[0])) {
|
if ((q = __argv[0])) {
|
||||||
CopyString:
|
|
||||||
char *p = g_prog.u.buf;
|
char *p = g_prog.u.buf;
|
||||||
char *e = p + sizeof(g_prog.u.buf);
|
char *e = p + sizeof(g_prog.u.buf);
|
||||||
while ((c = *q++)) {
|
while ((c = *q++)) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue