diff options
| author | Justus Winter <4winter@informatik.uni-hamburg.de> | 2013-08-03 17:11:06 +0200 |
|---|---|---|
| committer | Justus Winter <4winter@informatik.uni-hamburg.de> | 2013-08-03 17:11:06 +0200 |
| commit | b71bdf9c357b562076f4ad21a8e52f160743ae49 (patch) | |
| tree | ca4805d2ac0b23e0146989d877dde07486b4ff75 /reincarnation.c | |
| parent | fe15c05b97dcd47643c774d720bbd632c38b2104 (diff) | |
Make reincarnation both a tool and a translator
Diffstat (limited to 'reincarnation.c')
| -rw-r--r-- | reincarnation.c | 196 |
1 files changed, 166 insertions, 30 deletions
diff --git a/reincarnation.c b/reincarnation.c index 29b3505..f780b75 100644 --- a/reincarnation.c +++ b/reincarnation.c @@ -40,11 +40,21 @@ #include <version.h> +#include "priv.h" #include "reincarnation.h" #include "reincarnation_S.h" const char const *argp_program_version = STANDARD_HURD_VERSION (reincarnation); +/* Our bootstrap port in case we are called as a translator. */ +mach_port_t our_bootstrap; + +/* The number of failures. */ +unsigned int failures; + +/* XXX currently we handle all messages on this port. */ +mach_port_t reincarnation_port; + /* The filesystem node we're putting a translator on. */ char *node_name = NULL; file_t node; @@ -73,6 +83,25 @@ int timeout = DEFAULT_TIMEOUT * 1000; /* ms */ mach_port_t ports[INIT_PORT_MAX]; mach_port_t fds[STDERR_FILENO + 1]; int ints[INIT_INT_MAX]; + +/* Forward declarations. */ +int +translator_mode (void); + +error_t +start_child (void); + +error_t +chainload_translator (char *name, char *argz, + int argz_len, mach_port_t *fds, + mach_msg_type_name_t fds_type, int fds_len, + mach_port_t *ports, + mach_msg_type_name_t ports_type, int ports_len, + int *ints, int ints_len, + uid_t owner_uid, + task_t *task); + +/* Command line parsing. */ #define _STRINGIFY(arg) #arg #define STRINGIFY(arg) _STRINGIFY (arg) @@ -114,7 +143,7 @@ parse_opt (int key, char *arg, struct argp_state *state) case 't': timeout = atof (arg) * 1000.0; break; case ARGP_KEY_ARG: - if (state->arg_num == 0) + if (state->arg_num == 0 && ! translator_mode ()) node_name = arg; else /* command */ { @@ -136,19 +165,17 @@ parse_opt (int key, char *arg, struct argp_state *state) } struct argp argp = {options, parse_opt, args_doc, doc}; -mach_port_t reincarnation_port; -error_t -start_child (void); - static int demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) { extern int notify_server (); extern int reincarnation_server (); + extern int fsys_server (); return (notify_server (inp, outp) || - reincarnation_server (inp, outp)); + reincarnation_server (inp, outp) || + fsys_server (inp, outp)); } error_t @@ -171,10 +198,23 @@ prepare_child (void) } int +translator_mode (void) +{ + return our_bootstrap != MACH_PORT_NULL; +} + +int main (int argc, char **argv) { error_t err; + /* See if we are used as translator. */ + task_get_bootstrap_port (mach_task_self (), &our_bootstrap); + if (translator_mode ()) + { + active_flags |= FS_TRANS_ORPHAN; + } + argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0); err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, @@ -197,7 +237,7 @@ main (int argc, char **argv) err = start_child (); if (err) - error (5, err, "starting child"); + error (5, err, "starting initial child"); while (1) { @@ -249,40 +289,135 @@ start_child (void) return 0; } - err = fshelp_start_translator_long (open_node, NULL, - argz, argz, argz_len, - fds, MACH_MSG_TYPE_COPY_SEND, - STDERR_FILENO + 1, - ports, MACH_MSG_TYPE_COPY_SEND, - INIT_PORT_MAX, - ints, INIT_INT_MAX, - geteuid (), - timeout, &active_control); - if (err) - return err; + if (translator_mode ()) + { + ports[INIT_PORT_BOOTSTRAP] = reincarnation_port; /* XXX */ + err = chainload_translator (argz, argz, argz_len, + fds, MACH_MSG_TYPE_COPY_SEND, + STDERR_FILENO + 1, + ports, MACH_MSG_TYPE_COPY_SEND, + INIT_PORT_MAX, + ints, INIT_INT_MAX, + geteuid (), + &child_task); + } + else + { + err = fshelp_start_translator_long (open_node, NULL, + argz, argz, argz_len, + fds, MACH_MSG_TYPE_COPY_SEND, + STDERR_FILENO + 1, + ports, MACH_MSG_TYPE_COPY_SEND, + INIT_PORT_MAX, + ints, INIT_INT_MAX, + geteuid (), + timeout, &active_control); + if (err) + return err; + + err = install_translator (); + if (err) + return err; + + err = register_dead_name_notification (); + } + + return err; +} + +error_t +register_dead_name_notification (void) +{ + error_t err; /* Ask to be told if TASK dies. */ mach_port_t prev_notify; err = - mach_port_request_notification(mach_task_self(), - active_control, MACH_NOTIFY_DEAD_NAME, 0, - reincarnation_port, - MACH_MSG_TYPE_MAKE_SEND_ONCE, - &prev_notify); + mach_port_request_notification (mach_task_self (), + active_control, + MACH_NOTIFY_DEAD_NAME, 0, + reincarnation_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &prev_notify); if (err) return err; if (prev_notify != MACH_PORT_NULL) mach_port_deallocate (mach_task_self (), prev_notify); - err = file_set_translator (node, - passive_flags, active_flags, goaway_flags, - argz, argz_len, - active_control, MACH_MSG_TYPE_COPY_SEND); + return err; +} + +error_t +install_translator (void) +{ + error_t err = file_set_translator (node, + passive_flags, active_flags, goaway_flags, + argz, argz_len, + active_control, MACH_MSG_TYPE_COPY_SEND); + return err; +} + +error_t +chainload_translator (char *name, char *argz, + int argz_len, mach_port_t *fds, + mach_msg_type_name_t fds_type, int fds_len, + mach_port_t *ports, + mach_msg_type_name_t ports_type, int ports_len, + int *ints, int ints_len, + uid_t owner_uid, + task_t *task) +{ + error_t err; + + /* Find the translator itself. */ + file_t executable = file_name_lookup (name, O_EXEC, 0); + if (executable == MACH_PORT_NULL) + return errno; + + /* Create the task for the translator. */ + err = task_create (mach_task_self (), +#ifdef KERN_INVALID_LEDGER + NULL, 0, /* OSF Mach */ +#endif + 0, task); if (err) - return err; + goto lose; - return 0; + /* XXX 25 is BASEPRI_USER, which isn't exported by the kernel. Ideally, + nice values should be used, perhaps with a simple wrapper to convert + them to Mach priorities. */ + err = task_priority (*task, 25, FALSE); + if (err) + goto lose; + + /* Designate TASK as our child and set it's owner accordingly. */ + mach_port_t proc = getproc (); + proc_child (proc, *task); + mach_port_t childproc; + err = proc_task2proc (proc, *task, &childproc); + mach_port_deallocate (mach_task_self (), proc); + if (err) + goto lose; + err = proc_setowner (childproc, owner_uid, owner_uid == (uid_t) -1); + mach_port_deallocate (mach_task_self (), childproc); + if (err) + goto lose; + + /* Try and exec the translator in TASK... */ + err = file_exec (executable, *task, EXEC_DEFAULTS, + argz, argz_len, 0, 0, + fds, fds_type, fds_len, + ports, ports_type, ports_len, + ints, ints_len, 0, 0, 0, 0); + if (err) + { + task_terminate (*task); + goto lose; + } + + lose: + return err; } kern_return_t @@ -295,7 +430,8 @@ do_mach_notify_dead_name (mach_port_t notify, if (name != active_control) return EPERM; - error (0, 0, "child died"); + failures += 1; + error (0, 0, "Child died (%u failure%s)", failures, failures > 1? "s": ""); err = start_child (); if (err) |
