summaryrefslogtreecommitdiff
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
parentfe15c05b97dcd47643c774d720bbd632c38b2104 (diff)
Make reincarnation both a tool and a translator
-rw-r--r--Makefile6
-rw-r--r--fsys_proxy.c159
-rw-r--r--priv.h50
-rw-r--r--reincarnation.c196
-rw-r--r--reincarnation.h2
5 files changed, 381 insertions, 32 deletions
diff --git a/Makefile b/Makefile
index b5db788..76cdbc0 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,8 @@ OBJS = $(SRCS:.c=.o) \
notifyServer.o \
reincarnationServer.o \
reincarnationUser.o \
- start-translator-long.o \
+ fsysServer.o \
+ fsys_proxy.o \
targets = reincarnation persistent-hello
HURDLIBS = fshelp trivfs ihash shouldbeinlibc
@@ -35,7 +36,8 @@ HURDLIBS = fshelp trivfs ihash shouldbeinlibc
include ../Makeconf
reincarnation: stubs.o notifyServer.o reincarnationServer.o \
- start-translator-long.o
+ fsysServer.o fsys_proxy.o \
+ ../libfshelp/libfshelp.a
persistent-hello: reincarnationUser.o ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a ../libihash/libihash.a
$(targets): %: %.o lib.o
diff --git a/fsys_proxy.c b/fsys_proxy.c
new file mode 100644
index 0000000..0af04ac
--- /dev/null
+++ b/fsys_proxy.c
@@ -0,0 +1,159 @@
+/* A proxy for fsys messages.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <4winter@informatik.uni-hamburg.de>
+
+ This file might one day be a part of the GNU Hurd.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "priv.h"
+
+#include <hurd/fsys.h>
+
+error_t
+S_fsys_startup (mach_port_t bootstrap, int flags, mach_port_t control,
+ mach_port_t *real, mach_msg_type_name_t *realtype)
+{
+ error_t err;
+
+ if (failures == 0)
+ {
+ /* This is our first child, do the rendezvous on our bootstrap
+ port. */
+ err = fsys_startup (our_bootstrap,
+ flags,
+ reincarnation_port,
+ MACH_MSG_TYPE_COPY_SEND,
+ real);
+ if (err)
+ return err;
+
+ /* Steal the underlying node. */
+ node = *real;
+ }
+ else
+ /* Provide the underlying node. */
+ *real = node;
+
+ /* Always create a copy. */
+ *realtype = MACH_MSG_TYPE_COPY_SEND;
+
+ /* Update the control port. */
+ active_control = control;
+
+ if (failures > 0)
+ {
+ /* Reinstall the translator. */
+ err = install_translator ();
+ if (err)
+ return err;
+ }
+
+ err = register_dead_name_notification ();
+ if (err)
+ return err;
+
+ return err;
+}
+
+error_t
+S_fsys_getroot (mach_port_t fsys_t,
+ mach_port_t dotdotnode,
+ uid_t *uids, size_t nuids,
+ uid_t *gids, size_t ngids,
+ int flags,
+ retry_type *do_retry,
+ char *retry_name,
+ mach_port_t *ret,
+ mach_msg_type_name_t *rettype)
+{
+ *rettype = MACH_MSG_TYPE_MOVE_SEND;
+ return fsys_getroot (active_control,
+ dotdotnode, MACH_MSG_TYPE_MOVE_SEND,
+ uids, nuids,
+ gids, ngids,
+ flags,
+ do_retry,
+ retry_name,
+ ret);
+}
+
+error_t
+S_fsys_goaway (mach_port_t control, int flags)
+{
+ /* XXX we never get to see those... */
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_syncfs (mach_port_t control,
+ int wait,
+ int recurse)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_set_options (mach_port_t control,
+ char *data, mach_msg_type_number_t len,
+ int do_children)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_get_options (mach_port_t control,
+ char **data, mach_msg_type_number_t *len)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_getfile (mach_port_t control,
+ uid_t *uids, size_t nuids,
+ uid_t *gids, size_t ngids,
+ char *handle, size_t handllen,
+ mach_port_t *pt,
+ mach_msg_type_name_t *pttype)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_getpriv (mach_port_t control,
+ mach_port_t *host_priv, mach_msg_type_name_t *host_priv_type,
+ mach_port_t *dev_master, mach_msg_type_name_t *dev_master_type,
+ task_t *fs_task, mach_msg_type_name_t *fs_task_type)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_init (mach_port_t control,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ mach_port_t proc,
+ auth_t auth)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_forward (mach_port_t server, mach_port_t requestor,
+ char *argz, size_t argz_len)
+{
+ return EOPNOTSUPP;
+}
diff --git a/priv.h b/priv.h
new file mode 100644
index 0000000..d3e3dbe
--- /dev/null
+++ b/priv.h
@@ -0,0 +1,50 @@
+/* Reincarnation services for translators.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <4winter@informatik.uni-hamburg.de>
+
+ This file might one day be a part of the GNU Hurd.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef __REINCARNATION_PRIV_H__
+#define __REINCARNATION_PRIV_H__
+
+#include "reincarnation.h"
+
+/* The number of failures. */
+extern unsigned int failures;
+
+/* XXX currently we handle all messages on this port. */
+extern mach_port_t reincarnation_port;
+
+/* Our bootstrap port in case we are called as a translator. */
+extern mach_port_t our_bootstrap;
+
+/* The filesystem node we're putting a translator on. */
+extern file_t node;
+
+/* The control port for any active translator we start up. */
+extern fsys_t active_control;
+
+/* XXX */
+error_t
+register_dead_name_notification (void);
+
+/* XXX */
+error_t
+install_translator (void);
+
+#endif /* __REINCARNATION_PRIV_H__ */
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)
diff --git a/reincarnation.h b/reincarnation.h
index 7e1b16e..8432e42 100644
--- a/reincarnation.h
+++ b/reincarnation.h
@@ -22,7 +22,9 @@
#ifndef __REINCARNATION_H__
#define __REINCARNATION_H__
+#include <error.h>
#include <hurd.h>
+#include <mach.h>
#define TASK_PORT_REGISTER_REINCARNATION 0