Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137#include "execve.h"#include "../base.h"#include "../errno.h"#include <linux-syscalls/linux.h>#include "../fcntl/open.h"#include "../unistd/read.h"#include "../unistd/close.h"#include "../unistd/readlink.h"#include "../signal/sigexc.h"#include <stdint.h>#include <stddef.h>#include <stdbool.h>#include <errno.h>#include <lkm/api.h>#include <mach/lkm.h>#include "../vchroot_expand.h"#include "../bsdthread/per_thread_wd.h"
static inline bool istext(char c){ return c >= 0x20 && c < 0x7F;}
long sys_execve(char* fname, char** argvp, char** envp){ int ret; struct vchroot_expand_args vc;
vc.flags = VCHROOT_FOLLOW; vc.dfd = get_perthread_wd(); strcpy(vc.path, fname);
ret = vchroot_expand(&vc); __simple_kprintf("execve expand %s -> %s, ret %d", fname, vc.path, ret); if (ret < 0) return errno_linux_to_bsd(ret);
char shebang[256]; int fd = sys_open(fname, BSD_O_RDONLY, 0); if (fd < 0) return fd; ret = sys_read(fd, shebang, sizeof(shebang)); if (ret < 0) return ret;
close_internal(fd);
bool is_script = false; if (ret >= 4) { is_script = shebang[0] == '#' && shebang[1] == '!'; if (!is_script) { if (istext(shebang[0]) && istext(shebang[1]) && istext(shebang[2]) && istext(shebang[3])) { strcpy(shebang, "#!/bin/sh\n"); is_script = true; } } }
if (is_script) { char *nl, *interp, *arg; char** modargvp; int i, j, len = 0;
nl = memchr(shebang, '\n', ret); if (!nl) return -ENOEXEC; *nl = '\0'; for (i = 2; isspace(shebang[i]); i++); interp = &shebang[i]; for (i = 0; !isspace(interp[i]) && interp[i]; i++); if (interp[i] == '\0') arg = NULL; else arg = &interp[i]; if (arg != NULL) { *arg = '\0'; // terminate interp arg++; while (isspace(*arg) && *arg) arg++; if (*arg == '\0') arg = NULL; // no argument, just whitespace } // Count original arguments while (argvp[len++]); // Allocate a new argvp modargvp = (char**) __builtin_alloca(sizeof(void*) * (len+2)); i = 0; modargvp[i++] = interp; if (arg != NULL) modargvp[i++] = arg; modargvp[i] = fname; // Append original arguments for (j = 1; j < len+1; j++) modargvp[i+j] = argvp[j]; argvp = modargvp; strcpy(vc.path, interp);
ret = vchroot_expand(&vc); if (ret < 0) return ret; }
linux_sigset_t set; set = (1ull << (SIGNAL_SIGEXC_SUSPEND-1)); //set |= (1ull << (SIGNAL_SIGEXC_THUPDATE-1));
LINUX_SYSCALL(__NR_rt_sigprocmask, 0 /* LINUX_SIG_BLOCK */, &set, NULL, sizeof(linux_sigset_t));
ret = LINUX_SYSCALL(__NR_execve, vc.path, argvp, envp); if (ret < 0) ret = errno_linux_to_bsd(ret);
LINUX_SYSCALL(__NR_rt_sigprocmask, 1 /* LINUX_SIG_UNBLOCK */, &set, NULL, sizeof(linux_sigset_t));
return ret;}