diff --git a/lib/libc/CMakeLists.txt b/lib/libc/CMakeLists.txt index d8c9081..29589fa 100644 --- a/lib/libc/CMakeLists.txt +++ b/lib/libc/CMakeLists.txt @@ -1,4 +1,4 @@ -set(source_dirs core malloc io) +set(source_dirs core malloc io exec) set(public_include_dirs ${CMAKE_CURRENT_SOURCE_DIR}/include) @@ -26,7 +26,7 @@ bsp_add_library( NAME libc LIB_DIR /usr/lib) -target_link_libraries(libc PRIVATE librosetta libxpc-static interface::fs) +target_link_libraries(libc PRIVATE librosetta libxpc-static liblaunch-static interface::fs) target_link_libraries(libc PUBLIC libmagenta) target_compile_definitions(libc PRIVATE ENABLE_GLOBAL_HEAP=1) diff --git a/lib/libc/exec/CMakeLists.txt b/lib/libc/exec/CMakeLists.txt new file mode 100644 index 0000000..50acfdd --- /dev/null +++ b/lib/libc/exec/CMakeLists.txt @@ -0,0 +1,33 @@ +set(source_dirs unistd spawn) + +file(GLOB sources *.c *.h) + +foreach (dir ${source_dirs}) + file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c) + file(GLOB dir_headers ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.h) + + set(sources ${sources} ${dir_sources}) + set(headers ${headers} ${dir_headers}) +endforeach (dir) + +file(GLOB_RECURSE sub_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h) +set(headers ${headers} ${sub_headers}) + +set(component_sources ${sources} PARENT_SCOPE) +set(component_headers ${headers} PARENT_SCOPE) +set(component_public_include_dirs ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE) + +rosetta_add_library(STATIC + NAME libc-exec + PUBLIC_INCLUDE_DIRS + ${public_include_dirs} + ${CMAKE_CURRENT_SOURCE_DIR}/include + SOURCES ${sources} + HEADERS ${headers}) + +sysroot_add_library( + NAME libc-exec + HEADER_DIR /usr/include + LIB_DIR /usr/lib) + +target_link_libraries(libc-exec libc-core libc-io libmagenta liblaunch-static) diff --git a/lib/libc/exec/spawn/file-actions.c b/lib/libc/exec/spawn/file-actions.c new file mode 100644 index 0000000..e69de29 diff --git a/lib/libc/exec/spawn/file-actions.h b/lib/libc/exec/spawn/file-actions.h new file mode 100644 index 0000000..c9fbbbf --- /dev/null +++ b/lib/libc/exec/spawn/file-actions.h @@ -0,0 +1,15 @@ +#ifndef LIBC_EXEC_SPAWN_FILE_ACTIONS_H_ +#define LIBC_EXEC_SPAWN_FILE_ACTIONS_H_ + +#include + +struct __posix_spawn_file_actions { + long temp[4]; +}; + +_Static_assert( + sizeof(struct __posix_spawn_file_actions) + <= __POSIX_SPAWN_FILE_ACTIONS_SIZE__, + "struct __posix_spawn_file_actions is too big"); + +#endif diff --git a/lib/libc/exec/spawn/posix-spawn.c b/lib/libc/exec/spawn/posix-spawn.c new file mode 100644 index 0000000..2d61936 --- /dev/null +++ b/lib/libc/exec/spawn/posix-spawn.c @@ -0,0 +1,176 @@ +#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); +} diff --git a/lib/libc/exec/spawn/spawnattr.c b/lib/libc/exec/spawn/spawnattr.c new file mode 100644 index 0000000..e69de29 diff --git a/lib/libc/exec/spawn/spawnattr.h b/lib/libc/exec/spawn/spawnattr.h new file mode 100644 index 0000000..e69de29 diff --git a/lib/libc/exec/unistd/exec.c b/lib/libc/exec/unistd/exec.c new file mode 100644 index 0000000..4a73aab --- /dev/null +++ b/lib/libc/exec/unistd/exec.c @@ -0,0 +1,94 @@ +#include +#include + +#define LD_EXTERN extern __attribute__((weak)) +LD_EXTERN int ld_execl(const char *path, const char *arg1, va_list arg); +LD_EXTERN int ld_execlp(const char *file, const char *arg1, va_list arg); +LD_EXTERN int ld_execle(const char *path, const char *arg1, va_list arg); +LD_EXTERN int ld_execv(const char *path, char *const argv[]); +LD_EXTERN int ld_execvp(const char *file, char *const argv[]); +LD_EXTERN int ld_execvpe( + const char *file, + char *const argv[], + char *const envp[]); + +int execl(const char *path, const char *arg, ...) +{ + va_list arglist; + va_start(arglist, arg); + int err = ld_execl(path, arg, arglist); + va_end(arglist); + + if (err < 0) { + return __set_errno(-err); + } + + /* this shouldn't happen */ + return __set_errno(ENOEXEC); +} + +int execlp(const char *file, const char *arg, ...) +{ + va_list arglist; + va_start(arglist, arg); + int err = ld_execlp(file, arg, arglist); + va_end(arglist); + + if (err < 0) { + return __set_errno(-err); + } + + /* this shouldn't happen */ + return __set_errno(ENOEXEC); +} + +int execle(const char *path, const char *arg, ...) +{ + va_list arglist; + va_start(arglist, arg); + int err = ld_execle(path, arg, arglist); + va_end(arglist); + + if (err < 0) { + return __set_errno(-err); + } + + /* this shouldn't happen */ + return __set_errno(ENOEXEC); +} + +int execv(const char *path, char *const argv[]) +{ + int err = ld_execv(path, argv); + + if (err < 0) { + return __set_errno(-err); + } + + /* this shouldn't happen */ + return __set_errno(ENOEXEC); +} + +int execvp(const char *file, char *const argv[]) +{ + int err = ld_execvp(file, argv); + + if (err < 0) { + return __set_errno(-err); + } + + /* this shouldn't happen */ + return __set_errno(ENOEXEC); +} + +int execvpe(const char *file, char *const argv[], char *const envp[]) +{ + int err = ld_execvpe(file, argv, envp); + + if (err < 0) { + return __set_errno(-err); + } + + /* this shouldn't happen */ + return __set_errno(ENOEXEC); +} diff --git a/lib/libc/include/spawn.h b/lib/libc/include/spawn.h new file mode 100644 index 0000000..9bee993 --- /dev/null +++ b/lib/libc/include/spawn.h @@ -0,0 +1,86 @@ +#ifndef SPAWN_H_ +#define SPAWN_H_ + +#include +#include + +#define __POSIX_SPAWN_FILE_ACTIONS_SIZE__ 32 +#define __POSIX_SPAWNATTR_SIZE__ 32 + +struct sched_param; + +typedef struct posix_spawn_file_actions { + char __opaque[__POSIX_SPAWN_FILE_ACTIONS_SIZE__]; +} posix_spawn_file_actions_t; + +typedef struct posix_spawnattr { + char __opaque[__POSIX_SPAWN_FILE_ACTIONS_SIZE__]; +} posix_spawnattr_t; + +extern int posix_spawn_file_actions_init( + posix_spawn_file_actions_t *restrict file_actions); +extern int posix_spawn_file_actions_destroy( + posix_spawn_file_actions_t *restrict file_actions); +extern int posix_spawn_file_actions_addopen( + posix_spawn_file_actions_t *restrict file_actions, + int fildes, + const char *path, + int oflag, + mode_t mode); +extern int posix_spawn_file_actions_addclose( + posix_spawn_file_actions_t *restrict file_actions, + int fildes); +extern int posix_spawn_file_actions_adddup2( + posix_spawn_file_actions_t *restrict file_actions, + int fildes, + int newfildes); + +extern int posix_spawnattr_init(posix_spawnattr_t *restrict attrp); +extern int posix_spawnattr_destroy(posix_spawnattr_t *restrict attrp); +extern int posix_spawnattr_getflags( + const posix_spawnattr_t *restrict attrp, + short *restrict flags); +extern int posix_spawnattr_setflags( + posix_spawnattr_t *restrict attrp, + short flags); +extern int posix_spawnattr_getschedpolicy( + const posix_spawnattr_t *restrict attrp, + int *restrict schedpolicy); +extern int posix_spawnattr_setschedpolicy( + posix_spawnattr_t *restrict attrp, + int schedpolicy); +extern int posix_spawnattr_getschedparam( + const posix_spawnattr_t *restrict attrp, + struct sched_param *restrict schedparam); +extern int posix_spawnattr_setschedparam( + posix_spawnattr_t *restrict attrp, + const struct sched_param *restrict schedparam); +extern int posix_spawnattr_getpgroup( + const posix_spawnattr_t *restrict attrp, + pid_t *restrict pgroup); +extern int posix_spawnattr_setpgroup( + posix_spawnattr_t *restrict attrp, + pid_t pgroup); +extern int posix_spawnattr_getsigmask( + const posix_spawnattr_t *restrict attrp, + sigset_t *restrict sigmask); +extern int posix_spawnattr_setsigmask( + posix_spawnattr_t *restrict attrp, + sigset_t sigmask); + +extern 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[]); +extern int posix_spawnp( + pid_t *restrict pid, + const char *restrict file, + const posix_spawn_file_actions_t *restrict file_actions, + const posix_spawnattr_t *restrict attrp, + char *const argv[], + char *const envp[]); + +#endif