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 | |
parent | fe15c05b97dcd47643c774d720bbd632c38b2104 (diff) |
Make reincarnation both a tool and a translator
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | fsys_proxy.c | 159 | ||||
-rw-r--r-- | priv.h | 50 | ||||
-rw-r--r-- | reincarnation.c | 196 | ||||
-rw-r--r-- | reincarnation.h | 2 |
5 files changed, 381 insertions, 32 deletions
@@ -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; +} @@ -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 |