379 lines
9.3 KiB
C
379 lines
9.3 KiB
C
#include <magenta/task.h>
|
|
#include <magenta/tunnel.h>
|
|
#include <magenta/bootstrap.h>
|
|
#include <magenta/signals.h>
|
|
#include <magenta/errors.h>
|
|
#include <magenta/handle.h>
|
|
#include <magenta/misc.h>
|
|
#include <magenta/object.h>
|
|
#include <mio/object.h>
|
|
#include <mio/fd.h>
|
|
#include <mio/fs.h>
|
|
#include <mio/namespace.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "__init.h"
|
|
#include "__heap.h"
|
|
#include "__fio.h"
|
|
|
|
/* maximum of 32 handles can be received sent as arguments */
|
|
#define MAX_HANDLE_ARGS 32
|
|
|
|
/* maximum size of bootstrap message that can be received */
|
|
#define MAX_MSG_SIZE 0x2000
|
|
|
|
#if 1
|
|
#define dbg_log(...)
|
|
#else
|
|
static void dbg_log(const char *format, ...)
|
|
{
|
|
char buf[1024];
|
|
|
|
va_list arg;
|
|
va_start(arg, format);
|
|
|
|
int r = vsnprintf(buf, sizeof buf, format, arg);
|
|
va_end(arg);
|
|
|
|
mx_console_write(buf, r);
|
|
}
|
|
#endif
|
|
|
|
#ifdef DYLD_PARENT_IMAGE
|
|
extern mx_vaddr_t dyld_load_exec(int argc, const char **argv);
|
|
#endif
|
|
|
|
static const char **environ = NULL;
|
|
static char arg_msg_buf[MAX_MSG_SIZE];
|
|
static mx_bootstrap_handle_t arg_handles[MAX_HANDLE_ARGS];
|
|
|
|
const char **__crt_environ()
|
|
{
|
|
return environ;
|
|
}
|
|
|
|
extern int main(int, const char **);
|
|
extern void __crt_run_atexit();
|
|
|
|
static void extract_arg_handles(mx_bootstrap_msg_t *args,
|
|
mx_handle_t *handles, int hndc, mx_bootstrap_handle_t *out)
|
|
{
|
|
uint32_t *hent = (uint32_t *)((char *)args + args->handle_info_off);
|
|
|
|
for (int i = 0; i < hndc; i++) {
|
|
out[i].info = hent[i];
|
|
out[i].handle = handles[i];
|
|
}
|
|
}
|
|
|
|
static void parse_args(mx_bootstrap_msg_t *args,
|
|
const char **argv, const char **envp, const char **namep)
|
|
{
|
|
if (args->args_num > 0) {
|
|
char *arg_buf = (char *)args + args->args_off;
|
|
int arg_i = 0;
|
|
int arg_off = 0;
|
|
|
|
for (int i = 0; ; i++) {
|
|
if (arg_buf[i] == '\0') {
|
|
argv[arg_i++] = arg_buf + arg_off;
|
|
arg_off = i + 1;
|
|
}
|
|
|
|
if (arg_i == (int)args->args_num) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (args->environ_num > 0) {
|
|
char *env_buf = (char *)args + args->environ_off;
|
|
int env_i = 0;
|
|
int env_off = 0;
|
|
|
|
for (int i = 0; ; i++) {
|
|
if (env_buf[i] == '\0') {
|
|
envp[env_i++] = env_buf + env_off;
|
|
env_off = i + 1;
|
|
}
|
|
|
|
if (env_i == (int)args->environ_num) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (args->names_num) {
|
|
char *name_buf = (char *)args + args->names_off;
|
|
int name_i = 0;
|
|
int name_off = 0;
|
|
|
|
for (int i = 0; ; i++) {
|
|
if (name_buf[i] == '\0') {
|
|
namep[name_i++] = name_buf + name_off;
|
|
name_off = i + 1;
|
|
}
|
|
|
|
if (name_i == (int)args->names_num) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void hang()
|
|
{
|
|
while (1) {
|
|
mx_nanosleep(mx_deadline_after(MX_SEC(1)));
|
|
}
|
|
}
|
|
|
|
static void init_stdio_fd(int fd, mx_handle_t *handles, size_t nhandles)
|
|
{
|
|
if (handles[0] == MX_NULL_HANDLE) {
|
|
dbg_log("** photon: FD %d is closed\n", fd);
|
|
return;
|
|
}
|
|
|
|
mx_info_basic_t handle0_info;
|
|
mx_status_t err = mx_object_get_info(handles[0], MX_INFO_HANDLE_BASIC, &handle0_info, sizeof(handle0_info));
|
|
if (err != MX_OK) {
|
|
/* bad handle. TODO report error somehow */
|
|
return;
|
|
}
|
|
|
|
mio_object *obj = NULL;
|
|
|
|
if (handle0_info.type == MX_OBJECT_PIPE) {
|
|
obj = mio_pipe_create(handles[0]);
|
|
dbg_log("** photon: FD %d is a pipe\n", fd);
|
|
} else {
|
|
/* just assume all other stdio handles implement the file protocol over a tunnel */
|
|
obj = mio_file_create(handles[0]);
|
|
dbg_log("** photon: FD %d is a file\n", fd);
|
|
}
|
|
|
|
mio_fd_list_alloc_at(mio_global_fd_list(), obj, fd);
|
|
}
|
|
|
|
static void init_stdio(mx_bootstrap_handle_t *handles, size_t nhandles)
|
|
{
|
|
dbg_log("** photon: initialising stdio\n");
|
|
bool no_fds = true;
|
|
int max_fd = 0;
|
|
for (size_t i = 0; i < nhandles; i++) {
|
|
uint32_t info = handles[i].info;
|
|
if (MX_B_HND_TYPE(info) != MX_B_FD) {
|
|
continue;
|
|
}
|
|
|
|
no_fds = false;
|
|
int fd = MX_B_HND_ARG(info);
|
|
if (fd > max_fd) {
|
|
max_fd = fd;
|
|
}
|
|
}
|
|
|
|
if (no_fds) {
|
|
dbg_log("** photon: we've been given no FDs\n");
|
|
return;
|
|
}
|
|
|
|
int nfds = max_fd + 1;
|
|
dbg_log("** photon: we've been given up to %d FDs\n", nfds);
|
|
|
|
/* Supports up to two handles per FD */
|
|
mx_handle_t fd_handles[nfds][2];
|
|
memset(fd_handles, 0x0, sizeof(mx_handle_t) * 2 * nfds);
|
|
|
|
for (size_t i = 0; i < nhandles; i++) {
|
|
uint32_t info = handles[i].info;
|
|
if (MX_B_HND_TYPE(info) != MX_B_FD) {
|
|
continue;
|
|
}
|
|
|
|
int fd = MX_B_HND_ARG(info);
|
|
mx_handle_t *this_fd_handles = fd_handles[fd];
|
|
|
|
if (this_fd_handles[0] != MX_NULL_HANDLE) {
|
|
this_fd_handles[1] = handles[i].handle;
|
|
} else {
|
|
this_fd_handles[0] = handles[i].handle;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < nfds; i++) {
|
|
size_t n = 1;
|
|
if (fd_handles[i][1] != MX_NULL_HANDLE) {
|
|
n++;
|
|
}
|
|
|
|
//dbg_log("** photon: handles for FD %d = { %x, %x }\n", i, fd_handles[i][0], fd_handles[i][1]);
|
|
|
|
init_stdio_fd(i, fd_handles[i], n);
|
|
}
|
|
|
|
__fio_init(0, 1, 2);
|
|
dbg_log("** photon: stdio init finished\n");
|
|
}
|
|
|
|
static int do_init(mx_handle_t bootstrap, bool enable_fs, bool enable_stdio, int *out_argc, const char ***out_argv)
|
|
{
|
|
dbg_log("reading bootstrap message from %x\n", bootstrap);
|
|
mx_signals_t sig = 0;
|
|
mx_object_wait(bootstrap, MX_TUNNEL_READABLE, 0, &sig);
|
|
if (!(sig & MX_TUNNEL_READABLE)) {
|
|
dbg_log("no bootstrap message!\n");
|
|
return -1;
|
|
}
|
|
|
|
size_t msg_size = 0;
|
|
size_t nr_handles = 0;
|
|
|
|
mx_handle_t handles[MAX_HANDLE_ARGS + 1];
|
|
|
|
dbg_log("receiving message from handle %lx\n", bootstrap);
|
|
mx_status_t err = mx_tunnel_read(bootstrap,
|
|
arg_msg_buf, MAX_MSG_SIZE,
|
|
handles, MAX_HANDLE_ARGS,
|
|
&msg_size, &nr_handles);
|
|
|
|
if (err != MX_OK) {
|
|
dbg_log("error: cannot read bootstrap message from handle %lx (error %d)\n",
|
|
bootstrap, err);
|
|
return -1;
|
|
}
|
|
|
|
mx_bootstrap_msg_t *msg = (mx_bootstrap_msg_t *)arg_msg_buf;
|
|
|
|
dbg_log("extracting handles\n");
|
|
extract_arg_handles(msg, handles, nr_handles, arg_handles);
|
|
#if 0
|
|
arg_handles[nr_handles].handle = bootstrap;
|
|
arg_handles[nr_handles].info = MX_B_HND(MX_B_TUNNEL_BTSTP, 0);
|
|
nr_handles++;
|
|
#endif
|
|
|
|
dbg_log("extracted %zu handles\n", nr_handles);
|
|
|
|
mx_bootstrap_handle_init(arg_handles, nr_handles);
|
|
|
|
const char **argv = NULL, **envp = NULL, **namep = NULL;
|
|
|
|
dbg_log("allocating buffers (%u, %u, %u)\n", msg->args_num, msg->environ_num, msg->names_num);
|
|
|
|
argv = calloc(sizeof *argv, msg->args_num + 1);
|
|
envp = calloc(sizeof *envp, msg->environ_num + 1);
|
|
namep = calloc(sizeof *namep, msg->names_num + 1);
|
|
|
|
environ = envp;
|
|
|
|
parse_args(msg, argv, envp, namep);
|
|
|
|
*out_argc = msg->args_num;
|
|
*out_argv = argv;
|
|
|
|
if (enable_stdio) {
|
|
init_stdio(arg_handles, nr_handles);
|
|
} else {
|
|
__fio_init(-1, -1, -1);
|
|
}
|
|
|
|
if (!enable_fs) {
|
|
return 0;
|
|
}
|
|
|
|
mio_namespace *ns = mio_namespace_create();
|
|
|
|
dbg_log("received %u names/%zu handles\n", msg->names_num, nr_handles);
|
|
if (msg->names_num > 0) {
|
|
for (size_t i = 0; i < nr_handles; i++) {
|
|
int type = MX_B_HND_TYPE(arg_handles[i].info);
|
|
int arg = MX_B_HND_ARG(arg_handles[i].info);
|
|
|
|
if (type != MX_B_NS_DIR && type != MX_B_TUNNEL_CWD) {
|
|
dbg_log(" * wrong type %x\n", type);
|
|
continue;
|
|
}
|
|
|
|
const char *path = namep[arg];
|
|
dbg_log(" * %s = %x\n", path, arg_handles[i].handle);
|
|
|
|
if (type == MX_B_TUNNEL_CWD) {
|
|
mio_set_cwd(arg_handles[i].handle, path);
|
|
} else {
|
|
mio_namespace_add_entry(ns, path, arg_handles[i].handle);
|
|
}
|
|
}
|
|
}
|
|
|
|
mio_set_global_namespace(ns);
|
|
return 0;
|
|
}
|
|
|
|
static int do_run(mx_handle_t bootstrap)
|
|
{
|
|
int argc;
|
|
const char **argv;
|
|
|
|
int err = do_init(bootstrap, true, true, &argc, &argv);
|
|
if (err != 0) {
|
|
return err;
|
|
}
|
|
|
|
return main(argc, argv);
|
|
}
|
|
|
|
#ifdef DYLD_PARENT_IMAGE
|
|
static int do_load_and_run(mx_handle_t bootstrap)
|
|
{
|
|
int argc;
|
|
const char **argv;
|
|
|
|
int err = do_init(bootstrap, false, true, &argc, &argv);
|
|
if (err != 0) {
|
|
return err;
|
|
}
|
|
|
|
mx_vaddr_t main_ptr = dyld_load_exec(argc, argv);
|
|
if (!main_ptr) {
|
|
return -1;
|
|
}
|
|
|
|
mx_bootstrap_handle_cleanup();
|
|
|
|
err = do_init(bootstrap, true, true, &argc, &argv);
|
|
if (err != 0) {
|
|
return err;
|
|
}
|
|
|
|
int(*main_func)(int, const char **) = (int(*)(int, const char **))main_ptr;
|
|
if (!main_func) {
|
|
return -1;
|
|
}
|
|
|
|
return main_func(argc, argv);
|
|
}
|
|
#endif
|
|
|
|
int __crt_init(mx_handle_t bootstrap, mx_vaddr_t arg2)
|
|
{
|
|
#ifndef DYLD_PARENT_IMAGE
|
|
int ret = do_run(bootstrap);
|
|
#else
|
|
int ret = do_load_and_run(bootstrap);
|
|
#endif
|
|
|
|
fflush(stdout);
|
|
fflush(stderr);
|
|
__crt_run_atexit();
|
|
mio_fd_cleanup();
|
|
mio_fs_cleanup();
|
|
mx_task_kill(mx_bootstrap_handle_get(MX_B_TASK_SELF), ret);
|
|
|
|
/* unreachable */
|
|
hang();
|
|
return 0;
|
|
}
|