diff --git a/libc/calls/execve-sysv.c b/libc/calls/execve-sysv.c index fe5137af7..7bd2987be 100644 --- a/libc/calls/execve-sysv.c +++ b/libc/calls/execve-sysv.c @@ -25,14 +25,18 @@ #include "libc/errno.h" #include "libc/intrin/bits.h" #include "libc/intrin/safemacros.internal.h" +#include "libc/intrin/weaken.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/f.h" +#include "libc/sysv/consts/fd.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/ok.h" #include "libc/sysv/errfuns.h" +#include "libc/zipos/zipos.internal.h" static bool CanExecute(const char *path) { return !sys_faccessat(AT_FDCWD, path, X_OK, 0); @@ -71,16 +75,42 @@ static const char *Join(const char *a, const char *b, char buf[PATH_MAX]) { int sys_execve(const char *prog, char *const argv[], char *const envp[]) { size_t i; - int e, rc; - char *buf; + int e, rc, fd, flags; + char *buf, *newprog; char **shargs; const char *ape; + struct ZiposUri uri; + if (_weaken(__zipos_parseuri)(prog, &uri) != -1) { + if (IsLinux()) { + newprog = alloca(PATH_MAX); + fd = _weaken(__zipos_uri_to_mem_file)(&uri, newprog); + prog = newprog; + } else if (IsFreebsd()) { + if ((fd = _weaken(__zipos_uri_to_mem_file)(&uri, NULL)) != -1) { + return sys_fexecve(fd, argv, envp); + } + } else { + return enosys(); + } + if (fd == -1) { + return -1; + } + } else { + fd = -1; + } e = errno; __sys_execve(prog, argv, envp); if (errno == ENOEXEC) { for (i = 0; argv[i];) ++i; buf = alloca(PATH_MAX); shargs = alloca((i + 4) * sizeof(char *)); + if (fd != -1) { + flags = fcntl(fd, F_GETFD); + if (flags != -1) { + fcntl(fd, F_SETFD, flags & (~FD_CLOEXEC)); + flags = fcntl(fd, F_GETFD); + } + } if (IsApeBinary(prog) && (CanExecute((ape = "/usr/bin/ape")) || CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"), diff --git a/test/libc/calls/execve_test.c b/test/libc/calls/execve_test.c index f0ce111ea..6477ced0e 100644 --- a/test/libc/calls/execve_test.c +++ b/test/libc/calls/execve_test.c @@ -17,6 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/dce.h" +#include "libc/errno.h" #include "libc/fmt/conv.h" #include "libc/fmt/itoa.h" #include "libc/runtime/runtime.h" @@ -58,3 +60,27 @@ TEST(execve, testArgPassing) { EXITS(0); } } + +TEST(execve, ziposELF) { + if (!IsLinux() && !IsFreebsd()) { + EXPECT_SYS(ENOSYS, -1, + execve("/zip/life.elf", (char *const[]){0}, (char *const[]){0})); + return; + } + SPAWN(fork); + execve("/zip/life.elf", (char *const[]){0}, (char *const[]){0}); + notpossible; + EXITS(42); +} + +TEST(execve, ziposAPE) { + if (!IsLinux()) { + EXPECT_EQ(-1, execve("/zip/life-nomod.com", (char *const[]){0}, + (char *const[]){0})); + return; + } + SPAWN(fork); + execve("/zip/life-nomod.com", (char *const[]){0}, (char *const[]){0}); + notpossible; + EXITS(42); +}