177 lines
3.4 KiB
C
177 lines
3.4 KiB
C
|
|
#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,
|
||
|
|
¶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);
|
||
|
|
}
|