summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2013-08-01 09:00:58 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2013-08-01 09:00:58 +0200
commit06c3b46e273598a94480df39d01617c14764ee39 (patch)
treee2984f9a285a521b07343873afc86d4954cc1605
Initial commit of the reincarnation prototype
-rw-r--r--Makefile39
-rw-r--r--persistent-hello.c336
-rw-r--r--reincarnation.c373
-rw-r--r--reincarnation.defs36
-rw-r--r--reincarnation.h29
5 files changed, 813 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..32c7be1
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,39 @@
+# 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/>.
+
+dir := reincarnation
+makemode := servers
+
+SRCS = reincarnation.c persistent-hello.c
+OBJS = $(SRCS:.c=.o) \
+ notifyServer.o \
+ reincarnationServer.o \
+ reincarnationUser.o \
+
+targets = reincarnation persistent-hello
+HURDLIBS = fshelp trivfs ihash shouldbeinlibc
+
+include ../Makeconf
+
+reincarnation: notifyServer.o reincarnationServer.o ../libfshelp/libfshelp.a
+persistent-hello: reincarnationUser.o ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a ../libihash/libihash.a
+
+$(targets): %: %.o
diff --git a/persistent-hello.c b/persistent-hello.c
new file mode 100644
index 0000000..0efc60f
--- /dev/null
+++ b/persistent-hello.c
@@ -0,0 +1,336 @@
+/* persistent-hello.c - A trivial single-file translator using
+ reincarnation services.
+
+ Based upon: hello.c - A trivial single-file translator
+
+ Copyright (C) 1998,1999,2001,02,2006 Free Software Foundation, Inc.
+ Gordon Matzigkeit <gord@fig.org>, 1999
+
+ 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#define _GNU_SOURCE 1
+
+#include <hurd/trivfs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <version.h>
+
+#include "reincarnation.h"
+#include "reincarnation_U.h"
+
+static mach_port_t reincarnation;
+
+const char *argp_program_version = STANDARD_HURD_VERSION (persistent-hello);
+
+/* The message we return when we are read. */
+static const char hello[] = "Hello, world!\n";
+static char *contents = (char *) hello;
+static size_t contents_len = sizeof hello - 1;
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_allow_open = O_READ;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+
+/* NOTE: This example is not robust: it is possible to trigger some
+ assertion failures because we don't implement the following:
+
+ $ cd /src/hurd/libtrivfs
+ $ grep -l 'assert.*!trivfs_support_read' *.c |
+ xargs grep '^trivfs_S_' | sed 's/^[^:]*:\([^ ]*\).*$/\1/'
+ trivfs_S_io_get_openmodes
+ trivfs_S_io_clear_some_openmodes
+ trivfs_S_io_set_some_openmodes
+ trivfs_S_io_set_all_openmodes
+ trivfs_S_io_readable
+ trivfs_S_io_select
+ $
+
+ For that reason, you should run this as an active translator
+ `settrans -ac testnode /path/to/thello' so that you can see the
+ error messages when they appear. */
+
+/* A hook for us to keep track of the file descriptor state. */
+struct open
+{
+ off_t offs;
+};
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ /* Mark the node as a read-only plain file. */
+ st->st_mode &= ~(S_IFMT | ALLPERMS);
+ st->st_mode |= (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH);
+ st->st_size = contents_len;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ exit (0);
+}
+
+
+static error_t
+open_hook (struct trivfs_peropen *peropen)
+{
+ struct open *op = malloc (sizeof (struct open));
+ if (op == NULL)
+ return ENOMEM;
+
+ /* Initialize the offset. */
+ op->offs = 0;
+ peropen->hook = op;
+ return 0;
+}
+
+
+static void
+close_hook (struct trivfs_peropen *peropen)
+{
+ free (peropen->hook);
+}
+
+
+/* Read data from an IO object. If offset is -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMOUNT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char **data, mach_msg_type_number_t *data_len,
+ loff_t offs, mach_msg_type_number_t amount)
+{
+ struct open *op;
+
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+
+ /* Get the offset. */
+ op = cred->po->hook;
+ if (offs == -1)
+ offs = op->offs;
+
+ /* Prune the amount they want to read. */
+ if (offs > contents_len)
+ offs = contents_len;
+ if (offs + amount > contents_len)
+ amount = contents_len - offs;
+
+ if (amount > 0)
+ {
+ /* Possibly allocate a new buffer. */
+ if (*data_len < amount)
+ {
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ return ENOMEM;
+ }
+
+ /* Copy the constant data into the buffer. */
+ memcpy ((char *) *data, contents + offs, amount);
+
+ /* Update the saved offset. */
+ op->offs += amount;
+ }
+
+ *data_len = amount;
+ return 0;
+}
+
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offs, int whence, off_t *new_offs)
+{
+ struct open *op;
+ error_t err = 0;
+ if (! cred)
+ return EOPNOTSUPP;
+
+ op = cred->po->hook;
+ switch (whence)
+ {
+ case SEEK_CUR:
+ offs += op->offs;
+ goto check;
+ case SEEK_END:
+ offs += contents_len;
+ case SEEK_SET:
+ check:
+ if (offs >= 0)
+ {
+ *new_offs = op->offs = offs;
+ break;
+ }
+ default:
+ err = EINVAL;
+ }
+
+ return err;
+}
+
+
+/* If this variable is set, it is called every time a new peropen
+ structure is created and initialized. */
+error_t (*trivfs_peropen_create_hook)(struct trivfs_peropen *) = open_hook;
+
+/* If this variable is set, it is called every time a peropen structure
+ is about to be destroyed. */
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
+
+
+/* Options processing. We accept the same options on the command line
+ and from fsys_set_options. */
+
+static const struct argp_option options[] =
+{
+ {"contents", 'c', "STRING", 0, "Specify the contents of the virtual file"},
+ {0}
+};
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ switch (opt)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+ case ARGP_KEY_INIT:
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR:
+ break;
+
+ case 'c':
+ {
+ char *new = strdup (arg);
+ if (new == NULL)
+ return ENOMEM;
+ if (contents != hello)
+ free (contents);
+ contents = new;
+ contents_len = strlen (new);
+
+ if (reincarnation != MACH_PORT_NULL)
+ {
+ error_t err = checkpoint (reincarnation, contents, contents_len);
+ if (err)
+ error (0, err, "checkpoint");
+ }
+
+ break;
+ }
+ }
+ return 0;
+}
+
+/* This will be called from libtrivfs to help construct the answer
+ to an fsys_get_options RPC. */
+error_t
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
+{
+ error_t err;
+ char *opt;
+
+ if (asprintf (&opt, "--contents=%s", contents) < 0)
+ return ENOMEM;
+
+ err = argz_add (argz, argz_len, opt);
+
+ free (opt);
+
+ return err;
+}
+
+static struct argp hello_argp =
+{ options, parse_opt, 0, "A translator providing a warm greeting." };
+
+/* Setting this variable makes libtrivfs use our argp to
+ parse options passed in an fsys_set_options RPC. */
+struct argp *trivfs_runtime_argp = &hello_argp;
+
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+
+ /* We use the same argp for options available at startup
+ as for options we'll accept in an fsys_set_options RPC. */
+ argp_parse (&hello_argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (3, err, "trivfs_startup");
+
+ /* Get reincarnation image. */
+ mach_port_t *registered_ports = NULL;
+ size_t registered_ports_len = 0;
+ err = mach_ports_lookup (mach_task_self (),
+ &registered_ports, &registered_ports_len);
+ if (err)
+ error (5, err, "mach_port_lookup");
+
+ reincarnation = registered_ports[0];
+
+ char *image = NULL;
+ size_t image_len = 0;
+ err = reincarnate (reincarnation, &image, &image_len);
+ if (err)
+ error (3, err, "getting reincarnation image");
+
+ if (image_len)
+ {
+ free (contents);
+ contents = malloc (image_len);
+ if (! contents)
+ error (3, ENOMEM, "malloc");
+
+ memcpy (contents, image, image_len);
+ contents_len = image_len;
+ }
+
+ /* Launch. */
+ ports_manage_port_operations_one_thread (fsys->pi.bucket, trivfs_demuxer, 0);
+
+ return 0;
+}
diff --git a/reincarnation.c b/reincarnation.c
new file mode 100644
index 0000000..8f333cf
--- /dev/null
+++ b/reincarnation.c
@@ -0,0 +1,373 @@
+/* A reincarnation server.
+
+ 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 <hurd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <argp.h>
+#include <error.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <error.h>
+#include <argz.h>
+#include <hurd/fshelp.h>
+#include <hurd/process.h>
+
+#include <hurd/lookup.h>
+#include <hurd/fsys.h>
+#include <mach.h>
+#include <mach/notify.h>
+
+#include <version.h>
+
+#include "reincarnation.h"
+#include "reincarnation_S.h"
+
+const char const *argp_program_version = STANDARD_HURD_VERSION (reincarnation);
+
+/* The filesystem node we're putting a translator on. */
+char *node_name = NULL;
+file_t node;
+
+/* The translator's arg vector, in '\0' separated format. */
+char *argz = NULL;
+size_t argz_len = 0;
+
+/* The control port for any active translator we start up. */
+fsys_t active_control = MACH_PORT_NULL;
+task_t child_task;
+
+int active_flags = FS_TRANS_SET;
+int passive_flags = 0;
+int lookup_flags = O_NOTRANS;
+int goaway_flags = 0;
+
+/* Various option flags. */
+int passive = 0, active = 0, keep_active = 0, do_pause = 0, kill_active = 0,
+ orphan = 0;
+int excl = 0;
+#define DEFAULT_TIMEOUT 60
+int timeout = DEFAULT_TIMEOUT * 1000; /* ms */
+
+/* child stuff */
+mach_port_t ports[INIT_PORT_REINCARNATION + 1];
+mach_port_t fds[STDERR_FILENO + 1];
+int ints[INIT_INT_MAX];
+
+#define _STRINGIFY(arg) #arg
+#define STRINGIFY(arg) _STRINGIFY (arg)
+
+static const struct argp_option const options[] =
+{
+ {"create", 'c', 0, 0, "Create NODE if it doesn't exist" },
+ {"pause", 'P', 0, 0, "When starting an active translator, prompt and"
+ " wait for a newline on stdin before completing the startup handshake"},
+ {"goaway", 'g', 0, 0, "Ask the active translator to go away"},
+ {"keep-active", 'k', 0, 0, "Leave any existing active translator running"},
+
+ {0,0,0,0, "When an active translator is told to go away:"},
+ {"recursive", 'R', 0, 0, "Shutdown its children too"},
+ {"force", 'f', 0, 0, "Ask it to ignore current users and shutdown "
+ "anyway." },
+ {"nosync", 'S', 0, 0, "Don't sync it before killing it"},
+ {0, 0}
+};
+static const char const args_doc[] = "NODE [TRANSLATOR ARG...]";
+static const char const doc[] = "Set the active translator on NODE and provide "
+ "reincarnation services for that translator.";
+
+/* Parse our options... */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 'P': do_pause = 1; break;
+ case 'c': lookup_flags |= O_CREAT; break;
+ case 'L': lookup_flags &= ~O_NOTRANS; break;
+
+ case 'R': goaway_flags |= FSYS_GOAWAY_RECURSE; break;
+ case 'S': goaway_flags |= FSYS_GOAWAY_NOSYNC; break;
+ case 'f': goaway_flags |= FSYS_GOAWAY_FORCE; break;
+
+ /* Use atof so the user can specifiy fractional timeouts. */
+ case 't': timeout = atof (arg) * 1000.0; break;
+
+ case ARGP_KEY_ARG:
+ if (state->arg_num == 0)
+ node_name = arg;
+ else /* command */
+ {
+ error_t err =
+ argz_create (state->argv + state->next - 1, &argz, &argz_len);
+ if (err)
+ error(3, err, "Can't create options vector");
+ state->next = state->argc; /* stop parsing */
+ }
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+ return EINVAL;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+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 ();
+
+ return (notify_server (inp, outp) ||
+ reincarnation_server (inp, outp));
+}
+
+error_t
+prepare_child (void)
+{
+ for (int i = 0; i < INIT_PORT_REINCARNATION; i++)
+ ports[i] = MACH_PORT_NULL;
+
+ for (int i = 0; i < STDERR_FILENO + 1; i++)
+ fds[i] = MACH_PORT_NULL;
+
+ memset (ints, 0, INIT_INT_MAX * sizeof (int));
+
+ ports[INIT_PORT_CWDIR] = getcwdir ();
+ ports[INIT_PORT_CRDIR] = getcrdir ();
+ ports[INIT_PORT_AUTH] = getauth ();
+ ports[INIT_PORT_REINCARNATION] = reincarnation_port;
+ fds[STDERR_FILENO] = getdport (STDERR_FILENO);
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+
+ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+
+ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &reincarnation_port);
+ if (err)
+ error (5, err, "mach_port_allocate");
+
+ mach_msg_type_name_t acquired_type;
+ err = mach_port_extract_right (mach_task_self (),
+ reincarnation_port,
+ MACH_MSG_TYPE_MAKE_SEND,
+ &reincarnation_port,
+ &acquired_type);
+ if (err)
+ error (3, err, "mach_port_extract_right");
+
+ prepare_child ();
+
+ mach_port_t registered_ports[] = { reincarnation_port, };
+ err = mach_ports_register (mach_task_self (),
+ &registered_ports, 1);
+ if (err)
+ error (5, err, "mach_port_register");
+
+ err = start_child ();
+ if (err)
+ error (5, err, "starting child");
+
+ while (1)
+ {
+ err = mach_msg_server (demuxer, 0, reincarnation_port);
+ if (err)
+ error (6, err, "mach_msg_server");
+ }
+}
+
+error_t
+start_child (void)
+{
+ error_t err;
+
+ error (0, 0, "Starting child: %s", argz);
+
+ /* Error during file lookup; we use this to avoid duplicating error
+ messages. */
+ error_t open_err = 0;
+
+ /* The callback to start_translator opens NODE as a side effect. */
+ error_t open_node (int flags,
+ mach_port_t *underlying,
+ mach_msg_type_name_t *underlying_type,
+ task_t task, void *cookie)
+ {
+ child_task = task;
+
+ if (do_pause)
+ {
+ fprintf (stderr, "Translator pid: %d\nPausing...",
+ task2pid (task));
+ getchar ();
+ }
+
+ if (node == MACH_PORT_NULL)
+ {
+ node = file_name_lookup (node_name, flags | lookup_flags, 0666);
+ if (node == MACH_PORT_NULL)
+ {
+ open_err = errno;
+ return open_err;
+ }
+ }
+
+ *underlying = node;
+ *underlying_type = MACH_MSG_TYPE_COPY_SEND;
+
+ 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_REINCARNATION,
+ ints, INIT_INT_MAX,
+ geteuid (),
+ timeout, &active_control);
+ if (err)
+ return 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);
+ 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);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+kern_return_t
+do_mach_notify_dead_name (mach_port_t notify,
+ mach_port_t name)
+{
+ error_t err;
+ mach_port_deallocate (mach_task_self (), name);
+
+ if (name != active_control)
+ return EPERM;
+
+ error (0, 0, "child died");
+
+ err = start_child ();
+ if (err)
+ error (0, err, "starting child");
+
+ return 0;
+}
+
+data_t stored_image;
+size_t stored_image_len;
+
+error_t
+S_reincarnate(mach_port_t server,
+ data_t *image,
+ mach_msg_type_number_t *imageCnt)
+{
+ *image = stored_image;
+ *imageCnt = stored_image_len;
+ return 0;
+}
+
+error_t
+S_checkpoint(mach_port_t server,
+ data_t image,
+ mach_msg_type_number_t imageCnt)
+{
+ free (stored_image);
+ stored_image = malloc (imageCnt);
+ if (! stored_image)
+ return ENOMEM;
+
+ memcpy (stored_image, image, imageCnt);
+ stored_image_len = imageCnt;
+ return 0;
+}
+
+/* Stubs for unused notification RPCs. */
+
+kern_return_t
+do_mach_notify_port_destroyed (mach_port_t notify,
+ mach_port_t rights)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_send_once (mach_port_t notify)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_no_senders (mach_port_t port, mach_port_mscount_t mscount)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_port_deleted (mach_port_t notify,
+ mach_port_t name)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_msg_accepted (mach_port_t notify,
+ mach_port_t name)
+{
+ return EOPNOTSUPP;
+}
diff --git a/reincarnation.defs b/reincarnation.defs
new file mode 100644
index 0000000..cb47680
--- /dev/null
+++ b/reincarnation.defs
@@ -0,0 +1,36 @@
+/* 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/>. */
+
+subsystem reincarnation 36270;
+
+#include <hurd/hurd_types.defs>
+
+#ifdef FILE_IMPORTS
+FILE_IMPORTS
+#endif
+
+routine reincarnate (
+ server: mach_port_t;
+ out image: data_t);
+
+routine checkpoint (
+ server: mach_port_t;
+ in image: data_t);
diff --git a/reincarnation.h b/reincarnation.h
new file mode 100644
index 0000000..19a3a8d
--- /dev/null
+++ b/reincarnation.h
@@ -0,0 +1,29 @@
+/* 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_H__
+#define __REINCARNATION_H__
+
+#include <hurd.h>
+
+#define INIT_PORT_REINCARNATION INIT_PORT_MAX
+
+#endif /* __REINCARNATION_H__ */