Files
rosetta/lib/libc/exec/spawn/posix-spawn.c
T

177 lines
3.4 KiB
C
Raw Normal View History

2026-05-30 10:02:45 +01:00
#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);
}