Prepend getcwd to exename early in init (#1048)

This commit is contained in:
Jōshin 2024-01-01 10:23:23 -05:00 committed by GitHub
parent 2f89c2482a
commit 68dbe5312f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 70 additions and 22 deletions

View file

@ -34,6 +34,10 @@
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/ok.h"
#ifdef __x86_64__
__static_yoink("_init_program_executable_name");
#endif
#define CTL_KERN 1
#define KERN_PROC 14
#define KERN_PROC_PATHNAME_FREEBSD 12
@ -88,31 +92,37 @@ static int OldApeLoader(char *s) {
(!strncmp((b = basename(s)), ".ape-", 5) && AllNumDot(b + 5));
}
// 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) {
char c, *p, *e;
if (!q) return 0;
p = g_prog.u.buf;
e = p + sizeof(g_prog.u.buf);
static char *CopyWithCwd(const char *q, char *p, char *e) {
char c;
if (*q != '/') {
if (q[0] == '.' && q[1] == '/') {
q += 2;
}
int got = __getcwd(p, e - p - 1 /* '/' */ - com * 4);
int got = __getcwd(p, e - p - 1 /* '/' */);
if (got != -1) {
p += got - 1;
*p++ = '/';
}
}
while ((c = *q++)) {
if (p + com * 4 + 1 /* nul */ < e) {
if (p + 1 /* nul */ < e) {
*p++ = c;
} else {
return 0;
return NULL;
}
}
*p = 0;
return p;
}
// 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) {
char *p;
if (!(p = CopyWithCwd(q, g_prog.u.buf,
g_prog.u.buf + sizeof(g_prog.u.buf) - com * 4))) {
return 0;
}
if (!sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0)) return 1;
if (!com) return 0;
p = WRITE32LE(p, READ32LE(".com"));
@ -121,6 +131,16 @@ static int TryPath(const char *q, int com) {
return 0;
}
// if the loader passed a relative path, prepend cwd to it.
// called early in init.
void __init_program_executable_name(void) {
if (__program_executable_name && *__program_executable_name != '/' &&
CopyWithCwd(__program_executable_name, g_prog.u.buf,
g_prog.u.buf + sizeof(g_prog.u.buf))) {
__program_executable_name = g_prog.u.buf;
}
}
static inline void InitProgramExecutableNameImpl(void) {
size_t n;
ssize_t got;
@ -167,18 +187,6 @@ static inline void InitProgramExecutableNameImpl(void) {
goto UseEmpty;
}
}
if (*__program_executable_name == '/') {
return;
}
// loader passed us a relative path; prepend cwd.
if (TryPath(__program_executable_name, 0)) {
goto UseBuf;
}
/* if TryPath fails, it probably failed because getcwd() was too long.
we are out of options now; KERN_PROC_PATHNAME et al will return the
name of the loader not the binary, and argv et al will at best have
the same problem. just use the relative path we got from the loader
as-is, and accept that if we chdir then things will break. */
return;
}

View file

@ -0,0 +1,27 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi
Copyright 2023 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/macros.internal.h"
.init.start 305,_init_program_executable_name
push %rdi
push %rsi
call __init_program_executable_name
pop %rsi
pop %rdi
.init.end 305,_init_program_executable_name

View file

@ -172,6 +172,9 @@ wontreturn textstartup void cosmo(long *sp, struct Syslib *m1, char *exename,
// initialize file system
__init_fds(argc, argv, envp);
// prepend cwd to executable path
__init_program_executable_name();
__enable_tls();
#if 0

View file

@ -47,6 +47,7 @@ void *__mmap_unlocked(void *, size_t, int, int, int, int64_t);
int __munmap_unlocked(char *, size_t);
void __on_arithmetic_overflow(void);
void __init_fds(int, char **, char **);
void __init_program_executable_name(void);
COSMOPOLITAN_C_END_
#endif /* ANSI */

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/metalfile.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/limits.h"
#include "libc/runtime/runtime.h"
@ -57,6 +58,9 @@ void SetUpOnce(void) {
__attribute__((__constructor__)) static void Child(int argc, char *argv[]) {
if (argc >= 2 && !strcmp(argv[1], "Child")) {
if (sys_chdir("/")) {
exit(122);
}
if (strcmp(argv[2], GetProgramExecutableName())) {
exit(123);
}
@ -138,4 +142,9 @@ TEST(GetProgramExecutableName, movedSelf) {
execve(buf, (char *[]){"hello", "Child", buf, "hello", 0}, (char *[]){0});
abort();
EXITS(0);
SPAWN(fork);
execve("./test", (char *[]){"hello", "Child", buf, "hello", 0},
(char *[]){0});
abort();
EXITS(0);
}