libc: initial implementation of posix_spawn

This commit is contained in:
2026-05-30 10:02:45 +01:00
parent 2413538cb6
commit bfd191a336
9 changed files with 406 additions and 2 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
set(source_dirs core malloc io) set(source_dirs core malloc io exec)
set(public_include_dirs set(public_include_dirs
${CMAKE_CURRENT_SOURCE_DIR}/include) ${CMAKE_CURRENT_SOURCE_DIR}/include)
@@ -26,7 +26,7 @@ bsp_add_library(
NAME libc NAME libc
LIB_DIR /usr/lib) 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_link_libraries(libc PUBLIC libmagenta)
target_compile_definitions(libc PRIVATE ENABLE_GLOBAL_HEAP=1) target_compile_definitions(libc PRIVATE ENABLE_GLOBAL_HEAP=1)
+33
View File
@@ -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)
View File
+15
View File
@@ -0,0 +1,15 @@
#ifndef LIBC_EXEC_SPAWN_FILE_ACTIONS_H_
#define LIBC_EXEC_SPAWN_FILE_ACTIONS_H_
#include <spawn.h>
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
+176
View File
@@ -0,0 +1,176 @@
#include "file-actions.h"
#include <errno.h>
#include <fcntl.h>
#include <launch.h>
#include <magenta/handle.h>
#include <magenta/log.h>
#include <magenta/task.h>
#include <rosetta/fs.h>
#include <spawn.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
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,
&params,
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);
}
View File
View File
+94
View File
@@ -0,0 +1,94 @@
#include <errno.h>
#include <stdarg.h>
#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);
}
+86
View File
@@ -0,0 +1,86 @@
#ifndef SPAWN_H_
#define SPAWN_H_
#include <signal.h>
#include <sys/types.h>
#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