unix: make OpenBSD uv_exepath work

some users of libuv rely on uv_exepath to be an actual path to a
program. unfortunately, the OpenBSD KERN_PROC_ARGV sysctl just returns
what is in argv[0], so if the program was executed by being looked up in
$PATH, uv_exepath would only return the basename and not an actual path.

to fix, this use the same approach as IBM i, OS/390 and AIX by searching
with uv__search_path. this is also the same approach the Zig language
has taken for the similar selfExePath function for OpenBSD.

the tests expect that uv_exepath still works after uv_set_process_title,
which on BSD is a call to setproctitle. the place setproctitle stores to
is the same place that KERN_PROC_ARGV reads from, so we need to stash
the original argv[0] in uv_setup_args to recover it later in uv_exepath.
This commit is contained in:
mischief 2026-02-04 00:03:03 -08:00 committed by Saúl Ibarra Corretgé
parent 0db25a91f0
commit 71801576eb
4 changed files with 7 additions and 48 deletions

View File

@ -29,7 +29,7 @@
static uv_mutex_t process_title_mutex;
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static char* process_title;
char* uv_saved_argv0;
static void init_process_title_mutex_once(void) {
if (uv_mutex_init(&process_title_mutex))
@ -45,6 +45,7 @@ void uv__process_title_cleanup(void) {
char** uv_setup_args(int argc, char** argv) {
process_title = argc > 0 ? uv__strdup(argv[0]) : NULL;
uv_saved_argv0 = argc > 0 ? uv__strdup(argv[0]) : NULL;
return argv;
}

View File

@ -591,4 +591,6 @@ int uv__get_constrained_cpu(long long* quota);
#define UV__KQUEUE_EVFILT_USER 0
#endif
extern char* uv_saved_argv0;
#endif /* UV_UNIX_INTERNAL_H_ */

View File

@ -59,54 +59,13 @@ void uv_loadavg(double avg[3]) {
int uv_exepath(char* buffer, size_t* size) {
int mib[4];
char **argsbuf = NULL;
size_t argsbuf_size = 100U;
size_t exepath_size;
pid_t mypid;
int err;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
mypid = getpid();
for (;;) {
err = UV_ENOMEM;
argsbuf = uv__reallocf(argsbuf, argsbuf_size);
if (argsbuf == NULL)
goto out;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
mib[2] = mypid;
mib[3] = KERN_PROC_ARGV;
if (sysctl(mib, ARRAY_SIZE(mib), argsbuf, &argsbuf_size, NULL, 0) == 0) {
break;
}
if (errno != ENOMEM) {
err = UV__ERR(errno);
goto out;
}
argsbuf_size *= 2U;
}
if (uv_saved_argv0 == NULL)
return UV_EINVAL;
if (argsbuf[0] == NULL) {
err = UV_EINVAL; /* FIXME(bnoordhuis) More appropriate error. */
goto out;
}
*size -= 1;
exepath_size = strlen(argsbuf[0]);
if (*size > exepath_size)
*size = exepath_size;
memcpy(buffer, argsbuf[0], *size);
buffer[*size] = '\0';
err = 0;
out:
uv__free(argsbuf);
return err;
return uv__search_path(uv_saved_argv0, buffer, size);
}

View File

@ -35,9 +35,6 @@ TEST_IMPL(get_currentexe) {
#if defined(__QEMU__)
RETURN_SKIP("Test does not currently work in QEMU");
#endif
#if defined(__OpenBSD__)
RETURN_SKIP("Test does not currently work in OpenBSD");
#endif
char buffer[PATHMAX];
char path[PATHMAX];