summaryrefslogtreecommitdiff
path: root/reincarnation.c
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2013-08-03 17:11:06 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2013-08-03 17:11:06 +0200
commitb71bdf9c357b562076f4ad21a8e52f160743ae49 (patch)
treeca4805d2ac0b23e0146989d877dde07486b4ff75 /reincarnation.c
parentfe15c05b97dcd47643c774d720bbd632c38b2104 (diff)
Make reincarnation both a tool and a translator
Diffstat (limited to 'reincarnation.c')
-rw-r--r--reincarnation.c196
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)