#include "file-actions.h" #include #include #include #include #include #include #include #include #include #include #include static enum launch_status resolve_dependency( struct launch_ctx *ctx, const char *name, kern_handle_t *out, void *arg) { int fd = open(name, O_RDONLY); if (fd < 0) { return fd; } int err = 0; kern_handle_t image = KERN_HANDLE_INVALID; kern_status_t status = fs_map( fd, PROT_READ | PROT_EXEC, MAP_SHARED | MAP_EXECUTABLE, &err, &image); close(fd); if (status != KERN_OK || err != SUCCESS) { return LAUNCH_ERR_CANNOT_RESOLVE_DEPENDENCY; } *out = image; return LAUNCH_OK; } static size_t count_array_items(char *const items[]) { size_t i; for (i = 0; items[i]; i++) ; return i; } static const char *get_task_name(const char *path) { const char *name = path; for (size_t i = 0; path[i]; i++) { char c = path[i]; char c2 = path[i + 1]; if (c != '/') { continue; } if (c2 == '\0' || c2 == '/') { continue; } name = path + i + 1; } return name; } int posix_spawn( pid_t *restrict pid, const char *restrict path, const posix_spawn_file_actions_t *restrict file_actions, const posix_spawnattr_t *restrict attrp, char *const argv[], char *const envp[]) { int fd = open(path, O_RDONLY); if (fd < 0) { return fd; } int err = 0; kern_handle_t image = KERN_HANDLE_INVALID; kern_status_t status = fs_map( fd, PROT_READ | PROT_EXEC, MAP_SHARED | MAP_EXECUTABLE, &err, &image); close(fd); if (status != KERN_OK) { return __set_errno(__errno_from_kern_status(status)); } if (err != SUCCESS) { return __set_errno(err); } struct launch_ctx launch; struct launch_result result; size_t argc = 0, envc = 0; if (argv) { argc = count_array_items(argv); } if (envp) { envc = count_array_items(envp); } kern_handle_t self = KERN_HANDLE_INVALID, address_space = KERN_HANDLE_INVALID; task_self(&self); task_get_address_space(self, &address_space); struct launch_parameters params = { .p_exec_image = image, .p_exec_path = path, .p_parent_task = self, .p_task_name = get_task_name(path), .p_local_address_space = address_space, .p_resolver_arg = NULL, .p_argc = argc, .p_argv = (const char **)argv, .p_envc = envc, .p_envp = (const char **)envp, .p_channel_count = 0, .p_channels = NULL, .p_stdio = { KERN_HANDLE_INVALID, KERN_HANDLE_INVALID, KERN_HANDLE_INVALID, }, }; launch_ctx_init(&launch); launch.ctx_resolve_library = resolve_dependency; enum launch_status launch_status = launch_ctx_execute( &launch, ¶ms, LAUNCH_F_CLONE_ALL_HANDLES, &result); kern_handle_close(address_space); kern_handle_close(self); kern_handle_close(image); switch (launch_status) { case LAUNCH_OK: break; case LAUNCH_ERR_NO_MEMORY: return __set_errno(ENOMEM); case LAUNCH_ERR_INVALID_EXECUTABLE: case LAUNCH_ERR_UNSUPPORTED_EXECUTABLE: case LAUNCH_ERR_MISSING_SYMBOL: case LAUNCH_ERR_INTERPRETER_REQUIRED: return __set_errno(ENOEXEC); case LAUNCH_ERR_CANNOT_RESOLVE_DEPENDENCY: return __set_errno(ENOENT); default: /* TODO */ return __set_errno(EPERM); } tid_t child_id = 0; task_config_get(result.r_task, TASK_CFG_ID, &child_id, sizeof child_id); *pid = child_id; return __set_errno(SUCCESS); }