summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustus Winter <justus@gnupg.org>2016-04-25 15:40:40 +0200
committerJustus Winter <justus@gnupg.org>2016-04-25 15:40:40 +0200
commitfd4f5a99a9d62d0b8006be2179363474cc0af60f (patch)
tree3deea44a8489bc278d32a0af0dbf9c551a2bb374
parent2b8de3404d76f4ac20373ca7070cf7b4cd4c909f (diff)
add patch series
-rw-r--r--debian/patches/series3
-rw-r--r--debian/patches/shutdown0001-startup-implement-bits-of-the-fs-and-io-protocols.patch126
-rw-r--r--debian/patches/shutdown0002-trans-add-shutdown-translator.patch581
-rw-r--r--debian/patches/shutdown0003-xxx-halt-hack.patch45
4 files changed, 755 insertions, 0 deletions
diff --git a/debian/patches/series b/debian/patches/series
index 0fa931f2..64f5df1f 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -48,3 +48,6 @@ fixes0002-libtrivfs-fix-notion-of-privileged-user.patch
fixes0003-utils-settrans-implement-active-translator-stacking.patch
fixes0004-Avoid-superfluous-locking-of-node.patch
fixes0005-fstests-new-micro-benchmark.patch
+shutdown0001-startup-implement-bits-of-the-fs-and-io-protocols.patch
+shutdown0002-trans-add-shutdown-translator.patch
+shutdown0003-xxx-halt-hack.patch
diff --git a/debian/patches/shutdown0001-startup-implement-bits-of-the-fs-and-io-protocols.patch b/debian/patches/shutdown0001-startup-implement-bits-of-the-fs-and-io-protocols.patch
new file mode 100644
index 00000000..bd242773
--- /dev/null
+++ b/debian/patches/shutdown0001-startup-implement-bits-of-the-fs-and-io-protocols.patch
@@ -0,0 +1,126 @@
+From eadbc8748478f8cb2551e5d362330ab8be35c568 Mon Sep 17 00:00:00 2001
+From: Justus Winter <justus@gnupg.org>
+Date: Sat, 23 Apr 2016 17:52:33 +0200
+Subject: [PATCH hurd 1/3] startup: implement bits of the fs and io protocols
+
+* startup/Makefile: Build fs and io server with default
+implementations.
+(mung_msg_S.h): Tune regexp only to match the include guard.
+* startup/startup.c (demuxer): Add new protocols. Nicer implementation.
+(S_file_check_access): New function.
+(S_io_restrict_auth): Likewise.
+---
+ startup/Makefile | 6 ++++--
+ startup/startup.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++---------
+ 2 files changed, 50 insertions(+), 11 deletions(-)
+
+diff --git a/startup/Makefile b/startup/Makefile
+index ee2ecdd5..db062ad 100644
+--- a/startup/Makefile
++++ b/startup/Makefile
+@@ -21,15 +21,17 @@ makemode := server
+ SRCS = startup.c
+ OBJS = $(SRCS:.c=.o) \
+ startupServer.o notifyServer.o startup_replyUser.o msgServer.o \
+- startup_notifyUser.o fsysServer.o
++ startup_notifyUser.o fsysServer.o fsServer.o ioServer.o
+ target = startup
+ HURDLIBS = shouldbeinlibc
+
+ # startup does not use libports. Disable the default payload to port
+ # conversion.
+ MIGSFLAGS="-DHURD_DEFAULT_PAYLOAD_TO_PORT=1"
++fsServer-CFLAGS="-DMIG_EOPNOTSUPP=EOPNOTSUPP"
++ioServer-CFLAGS="-DMIG_EOPNOTSUPP=EOPNOTSUPP"
+
+ include ../Makeconf
+
+ mung_msg_S.h: msg_S.h
+- sed 's/msg_server/mung_msg_server/' < $< > $@
++ sed 's/_msg_server/_mung_msg_server/' < $< > $@
+diff --git a/startup/startup.c b/startup/startup.c
+index 9c45f4b..172857b 100644
+--- a/startup/startup.c
++++ b/startup/startup.c
+@@ -51,12 +51,16 @@
+ #include <version.h>
+ #include <argp.h>
+ #include <pids.h>
++#include <idvec.h>
+
+ #include "startup_notify_U.h"
+ #include "startup_reply_U.h"
+ #include "startup_S.h"
+ #include "notify_S.h"
+ #include "mung_msg_S.h"
++#include "fsys_S.h"
++#include "fs_S.h"
++#include "io_S.h"
+
+ /* host_reboot flags for when we crash. */
+ static int crash_flags = RB_AUTOBOOT;
+@@ -502,15 +506,19 @@ static int
+ demuxer (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+ {
+- extern int notify_server (mach_msg_header_t *, mach_msg_header_t *);
+- extern int startup_server (mach_msg_header_t *, mach_msg_header_t *);
+- extern int msg_server (mach_msg_header_t *, mach_msg_header_t *);
+- extern int fsys_server (mach_msg_header_t *, mach_msg_header_t *);
+-
+- return (notify_server (inp, outp) ||
+- msg_server (inp, outp) ||
+- fsys_server (inp, outp) ||
+- startup_server (inp, outp));
++ mig_routine_t routine;
++ if ((routine = notify_server_routine (inp)) ||
++ (routine = msg_server_routine (inp)) ||
++ (routine = fsys_server_routine (inp)) ||
++ (routine = fs_server_routine (inp)) ||
++ (routine = io_server_routine (inp)) ||
++ (routine = startup_server_routine (inp)))
++ {
++ (*routine) (inp, outp);
++ return TRUE;
++ }
++ else
++ return FALSE;
+ }
+
+ error_t
+@@ -1703,3 +1711,32 @@ S_fsys_forward (mach_port_t server, mach_port_t requestor,
+ {
+ return EOPNOTSUPP;
+ }
++
++error_t
++S_file_check_access (mach_port_t server,
++ int *allowed)
++{
++ if (server != startup)
++ return EOPNOTSUPP;
++ *allowed = 0;
++}
++
++error_t
++S_io_restrict_auth (mach_port_t server,
++ mach_port_t *newport,
++ mach_msg_type_name_t *newporttype,
++ uid_t *uids, size_t nuids,
++ uid_t *gids, size_t ngids)
++{
++ struct idvec user = { uids, (unsigned) nuids, (unsigned) nuids };
++
++ if (server != startup)
++ return EOPNOTSUPP;
++
++ if (! idvec_contains (&user, 0))
++ return EPERM;
++
++ *newport = server;
++ *newporttype = MACH_MSG_TYPE_COPY_SEND;
++ return 0;
++}
+--
+2.1.4
+
diff --git a/debian/patches/shutdown0002-trans-add-shutdown-translator.patch b/debian/patches/shutdown0002-trans-add-shutdown-translator.patch
new file mode 100644
index 00000000..db7b5748
--- /dev/null
+++ b/debian/patches/shutdown0002-trans-add-shutdown-translator.patch
@@ -0,0 +1,581 @@
+From 83de7bc788a3ceb0b76dfc284efe423a9b899030 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Tue, 13 Jan 2015 19:01:50 +0100
+Subject: [PATCH hurd 2/3] trans: add shutdown translator
+
+Provide a stripped-down version of the startup translator that
+supervises core servers and handles server shutdown.
+
+* trans/shutdown.c: New file.
+* trans/Makefile: Add shutdown translator.
+---
+ trans/Makefile | 18 +-
+ trans/shutdown.c | 514 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 528 insertions(+), 4 deletions(-)
+ create mode 100644 trans/shutdown.c
+
+diff --git a/trans/Makefile b/trans/Makefile
+index 65b51d1..39dfa9b 100644
+--- a/trans/Makefile
++++ b/trans/Makefile
+@@ -21,14 +21,14 @@ makemode := servers
+
+ targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \
+ password hello hello-mt streamio fakeroot proxy-defpager remap \
+- mtab
++ mtab shutdown
+ SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c \
+ crash.c firmlink.c password.c hello.c hello-mt.c streamio.c \
+- fakeroot.c proxy-defpager.c remap.c mtab.c
++ fakeroot.c proxy-defpager.c remap.c mtab.c shutdown.c
+ OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \
+ crashServer.o crash_replyUser.o msgServer.o \
+ default_pagerServer.o default_pagerUser.o \
+- device_replyServer.o elfcore.o
++ device_replyServer.o elfcore.o startup_notifyServer.o startupServer.o
+ HURDLIBS = ports netfs trivfs iohelp fshelp pipe ihash shouldbeinlibc
+ LDLIBS += -lpthread
+ password-LDLIBS = -lcrypt
+@@ -66,8 +66,18 @@ streamio: device_replyServer.o
+ symlink: fsysServer.o
+
+ fakeroot: ../libnetfs/libnetfs.a
++shutdown: startupServer.o startup_notifyUser.o
++
++# startupServer is used by the shutdown translator.
++startup-MIGSFLAGS=\
++ "-DSTARTUP_INTRAN=trivfs_protid_t trivfs_begin_using_protid (startup_t)" \
++ "-DSTARTUP_INTRAN_PAYLOAD=trivfs_protid_t trivfs_begin_using_protid_payload" \
++ "-DSTARTUP_DESTRUCTOR=trivfs_end_using_protid (trivfs_protid_t)" \
++ "-DSTARTUP_IMPORTS=import \"../libtrivfs/mig-decls.h\";"
++
++
+ fifo new-fifo: ../libpipe/libpipe.a
+-crash fifo firmlink hello hello-mt ifsock magic mtab new-fifo null password proxy-defpager remap streamio: ../libtrivfs/libtrivfs.a
++crash fifo firmlink hello hello-mt ifsock magic mtab new-fifo null password proxy-defpager remap streamio shutdown: ../libtrivfs/libtrivfs.a
+ $(targets): ../libfshelp/libfshelp.a \
+ ../libihash/libihash.a \
+ ../libiohelp/libiohelp.a \
+diff --git a/trans/shutdown.c b/trans/shutdown.c
+new file mode 100644
+index 0000000..6824cf6
+--- /dev/null
++++ b/trans/shutdown.c
+@@ -0,0 +1,514 @@
++/* Start and maintain hurd core servers and system run state
++
++ Copyright (C) 1993-2015 Free Software Foundation, Inc.
++ This file is part of the GNU Hurd.
++
++ The GNU Hurd 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.
++
++ The GNU Hurd 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 the GNU Hurd; see the file COPYING. If not, write to
++ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
++
++/* Written by Michael I. Bushnell and Roland McGrath. */
++
++/* This is probably more include files than I've ever seen before for
++ one file. */
++
++#include <argp.h>
++#include <argz.h>
++#include <error.h>
++#include <fcntl.h>
++#include <hurd/ports.h>
++#include <hurd/trivfs.h>
++#include <hurd/startup.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <sys/mman.h>
++#include <sys/reboot.h>
++#include <unistd.h>
++#include <version.h>
++
++#include "startup_notify_U.h"
++#include "startup_reply_U.h"
++#include "startup_S.h"
++#include "notify_S.h"
++
++/* The privileged host control port. Used for communication with the
++ kernel, and for authentication with our parent shutdown server. */
++mach_port_t host_priv;
++
++int system_mode;
++int supervise;
++
++/* Time to wait for translators to shut down. */
++mach_msg_timeout_t timeout = 5000;
++
++/* Time to wait for privileged translators to shut down. */
++mach_msg_timeout_t privileged_timeout = 60000;
++
++/* We receive dead-name notifications here. */
++struct port_info *notification;
++
++/* host_reboot flags for when we crash. */
++static int crash_flags = RB_AUTOBOOT;
++
++
++
++#define BOOT(flags) ((flags & RB_HALT) ? "halt" : "reboot")
++
++
++
++/* This structure keeps track of each notified task. */
++struct ntfy_task
++ {
++ struct ntfy_task *next;
++ mach_port_t notify_port;
++ int privileged;
++ char *name;
++ };
++
++/* This structure keeps track of each registered essential task. */
++struct ess_task
++ {
++ struct ess_task *next;
++ task_t task_port;
++ char *name;
++ };
++
++/* These are linked lists of all of the registered items. */
++static struct ess_task *ess_tasks;
++static struct ntfy_task *ntfy_tasks;
++
++/* Our trivfs control structure. */
++struct trivfs_control *control;
++
++
++
++const char *argp_program_version = STANDARD_HURD_VERSION (shutdown);
++
++/* Trivfs hooks. */
++int trivfs_fstype = FSTYPE_MISC;
++int trivfs_fsid = 0;
++
++int trivfs_allow_open = 0;
++int trivfs_support_read = 0;
++int trivfs_support_write = 0;
++int trivfs_support_exec = 0;
++
++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_IFCHR | S_IRUSR | S_IRGRP | S_IROTH);
++ st->st_size = 0;
++}
++
++error_t
++trivfs_goaway (struct trivfs_control *cntl, int flags)
++{
++ if (ntfy_tasks && (flags & FSYS_GOAWAY_FORCE) == 0)
++ return EBUSY;
++
++ exit (0);
++}
++
++/* Options processing. We accept the same options on the command line
++ and from fsys_set_options. */
++
++#define OPT_SUPERVISE -1
++#define OPT_SYSTEM -2
++static const struct argp_option options[] =
++{
++ {"supervise", OPT_SUPERVISE, NULL, 0,
++ "Enable supervision of essential servers", 0},
++ {"system", OPT_SYSTEM, NULL, 0,
++ "Actually shut down the system (requires privileges)", 0},
++ {"crash-debug", 'H', NULL, 0,
++ "On system crash, go to the kernel debugger", 0},
++ {0}
++};
++
++static error_t
++parse_opt (int opt, char *arg, struct argp_state *state)
++{
++ switch (opt)
++ {
++ case 'H':
++ crash_flags = RB_DEBUGGER;
++ break;
++
++ case OPT_SUPERVISE:
++ supervise = 1;
++ break;
++
++ case OPT_SYSTEM:
++ system_mode = 1;
++ break;
++
++ default:
++ return ARGP_ERR_UNKNOWN;
++ case ARGP_KEY_INIT:
++ case ARGP_KEY_SUCCESS:
++ case ARGP_KEY_ERROR:
++ 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 = 0;
++
++ if (! err && supervise)
++ err = argz_add (argz, argz_len, "--supervise");
++
++ if (! err && system_mode)
++ err = argz_add (argz, argz_len, "--system");
++
++ if (! err && crash_flags == RB_DEBUGGER)
++ err = argz_add (argz, argz_len, "--crash-debug");
++
++ return err;
++}
++
++static const char doc[] =
++ "Supervise and shut down Hurd servers.";
++
++static struct argp argp =
++ {
++ .options = options,
++ .parser = parse_opt,
++ .args_doc = NULL,
++ .doc = doc,
++ };
++
++/* Setting this variable makes libtrivfs use our argp to
++ parse options passed in an fsys_set_options RPC. */
++struct argp *trivfs_runtime_argp = &argp;
++
++static int
++demuxer (mach_msg_header_t *inp,
++ mach_msg_header_t *outp)
++{
++ mig_routine_t routine;
++ if ((routine = startup_server_routine (inp)) ||
++ (routine = NULL, trivfs_demuxer (inp, outp)))
++ {
++ if (routine)
++ (*routine) (inp, outp);
++ return TRUE;
++ }
++ else
++ return FALSE;
++}
++
++static int
++isowner (trivfs_protid_t cred)
++{
++ return idvec_contains (cred->user->uids, getuid ());
++}
++
++int
++main (int argc, char **argv)
++{
++ error_t err;
++ mach_port_t bootstrap;
++ struct port_class *notification_class;
++
++ /* We use the same argp for options available at startup
++ as for options we'll accept in an fsys_set_options RPC. */
++ argp_parse (&argp, argc, argv, 0, 0, 0);
++
++ err = get_privileged_ports (&host_priv, NULL);
++ if (err && system_mode)
++ error (1, err, "Must be started as root in system mode");
++
++ 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, &control);
++ if (err)
++ error (3, err, "trivfs_startup");
++
++ err = mach_port_deallocate (mach_task_self (), bootstrap);
++ assert_perror (err);
++
++ notification_class = ports_create_class (NULL, NULL);
++ if (! notification_class)
++ error (1, errno, "ports_create_class");
++
++ err = ports_create_port (notification_class, control->pi.bucket, 0,
++ &notification);
++ if (err)
++ error (1, err, "ports_create_port");
++
++ /* Launch. */
++ ports_manage_port_operations_one_thread (control->pi.bucket, demuxer, 0);
++
++ return 0;
++}
++
++
++
++/** System shutdown **/
++
++/* Reboot the microkernel. */
++void
++reboot_mach (int flags)
++{
++ error_t err;
++
++ if (system_mode)
++ {
++ fprintf (stderr, "%s: %sing Mach (flags %#x)...\n",
++ program_invocation_short_name, BOOT (flags), flags);
++ sleep (5);
++ while ((err = host_reboot (host_priv, flags)))
++ error (0, err, "reboot");
++ for (;;);
++ }
++
++ err = startup_reboot (control->underlying, host_priv, flags);
++ if (err)
++ error (1, err, "Failed to contact next shutdown server");
++ exit (EXIT_FAILURE);
++}
++
++/* Reboot the microkernel, specifying that this is a crash. */
++void
++crash_mach (void)
++{
++ reboot_mach (crash_flags);
++}
++
++/* Notify all tasks that have requested shutdown notifications. */
++void
++notify_shutdown (const char *msg)
++{
++ struct ntfy_task *n;
++
++ for (n = ntfy_tasks; n != NULL; n = n->next)
++ {
++ error_t err;
++ fprintf (stderr, "%s: notifying %s of %s...",
++ program_invocation_short_name, n->name, msg);
++ err = startup_dosync (n->notify_port,
++ n->privileged ? privileged_timeout : timeout);
++ if (err == MACH_SEND_INVALID_DEST)
++ fprintf (stderr, "(no longer present)\n");
++ else if (err)
++ fprintf (stderr, "%s\n", strerror (err));
++ else
++ fprintf (stderr, "done\n");
++ }
++}
++
++/* Reboot the Hurd. */
++void
++reboot_system (int flags)
++{
++ notify_shutdown (BOOT (flags));
++ reboot_mach (flags);
++}
++
++/* Request a dead-name notification sent to our port. */
++static error_t
++request_dead_name (mach_port_t name)
++{
++ error_t err;
++ mach_port_t prev;
++ err = mach_port_request_notification (mach_task_self (), name,
++ MACH_NOTIFY_DEAD_NAME, 1,
++ notification->port_right,
++ MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
++ if (! err && MACH_PORT_VALID (prev))
++ mach_port_deallocate (mach_task_self (), prev);
++ return err;
++}
++
++/* Record an essential task in the list. */
++static error_t
++record_essential_task (const char *name, task_t task)
++{
++ error_t err;
++ struct ess_task *et;
++ /* Record this task as essential. */
++ et = malloc (sizeof (struct ess_task));
++ if (et == NULL)
++ return ENOMEM;
++ et->task_port = task;
++ et->name = strdup (name);
++ if (et->name == NULL)
++ {
++ free (et);
++ return ENOMEM;
++ }
++ et->next = ess_tasks;
++ ess_tasks = et;
++
++ /* Dead-name notification on the task port will tell us when it dies. */
++ err = request_dead_name (task);
++ if (err)
++ return err;
++
++ return 0;
++}
++
++kern_return_t
++S_startup_essential_task (trivfs_protid_t cred,
++ mach_port_t reply,
++ mach_msg_type_name_t replytype,
++ task_t task,
++ mach_port_t excpt,
++ char *name,
++ mach_port_t credential)
++{
++ error_t err;
++ mach_port_deallocate (mach_task_self (), credential);
++
++ if (! cred->isroot && ! isowner (cred))
++ return EPERM;
++
++ if (system_mode && credential != host_priv)
++ return EPERM;
++
++ if (! supervise)
++ return EOPNOTSUPP;
++
++ err = record_essential_task (name, task);
++ if (err)
++ return err;
++
++ return 0;
++}
++
++kern_return_t
++S_startup_request_notification (trivfs_protid_t cred,
++ mach_port_t notify,
++ char *name)
++{
++ error_t err;
++ struct ntfy_task *nt;
++
++ err = request_dead_name (notify);
++ if (err)
++ return err;
++
++ /* Note that the ntfy_tasks list is kept in inverse order of the
++ calls; this is important. We need later notification requests
++ to get executed first. */
++ nt = malloc (sizeof (struct ntfy_task));
++ if (nt == NULL)
++ return ENOMEM;
++ nt->next = ntfy_tasks;
++ nt->notify_port = notify;
++ nt->privileged = cred->isroot;
++ nt->name = strdup (name);
++ ntfy_tasks = nt;
++ return 0;
++}
++
++kern_return_t
++S_startup_procinit (trivfs_protid_t cred,
++ mach_port_t reply,
++ mach_msg_type_name_t replyPoly,
++ process_t procserver,
++ mach_port_t *startuptask,
++ auth_t *auth,
++ mach_port_t *hostpriv,
++ mach_msg_type_name_t *hostprivPoly,
++ mach_port_t *devmaster,
++ mach_msg_type_name_t *devmasterPoly)
++{
++ return EOPNOTSUPP;
++}
++
++kern_return_t
++S_startup_authinit (trivfs_protid_t cred,
++ mach_port_t reply,
++ mach_msg_type_name_t replyPoly,
++ mach_port_t auth,
++ mach_port_t *proc,
++ mach_msg_type_name_t *procPoly)
++{
++ return EOPNOTSUPP;
++}
++
++error_t
++ports_do_mach_notify_dead_name (struct port_info *pi,
++ mach_port_t dead_name)
++{
++ error_t err;
++ struct ntfy_task *nt, *pnt;
++ struct ess_task *et;
++
++ if (!pi)
++ return EOPNOTSUPP;
++
++ ports_dead_name (pi, dead_name);
++
++ /* Drop gratuitous extra reference that the notification creates. */
++ err = mach_port_deallocate (mach_task_self (), dead_name);
++ assert_perror (err);
++
++ if (pi != notification)
++ return 0;
++
++ for (et = ess_tasks; et != NULL; et = et->next)
++ if (et->task_port == dead_name)
++ /* An essential task has died. */
++ {
++ error (0, 0, "Crashing system; essential task %s died", et->name);
++ reboot_system (crash_flags);
++ }
++
++ for (nt = ntfy_tasks, pnt = NULL; nt != NULL; pnt = nt, nt = nt->next)
++ if (nt->notify_port == dead_name)
++ {
++ /* Someone who wanted to be notified is gone. */
++ err = mach_port_deallocate (mach_task_self (), dead_name);
++ assert_perror (err);
++ if (pnt != NULL)
++ pnt->next = nt->next;
++ else
++ ntfy_tasks = nt->next;
++ free (nt);
++
++ return 0;
++ }
++
++ return 0;
++}
++
++kern_return_t
++S_startup_reboot (trivfs_protid_t cred,
++ mach_port_t refpt,
++ int code)
++{
++ mach_port_deallocate (mach_task_self (), refpt);
++
++ if (! cred->isroot && ! isowner (cred))
++ return EPERM;
++
++ if (system_mode && refpt != host_priv)
++ return EPERM;
++
++ reboot_system (code);
++ for (;;);
++}
+--
+2.1.4
+
diff --git a/debian/patches/shutdown0003-xxx-halt-hack.patch b/debian/patches/shutdown0003-xxx-halt-hack.patch
new file mode 100644
index 00000000..3f6820af
--- /dev/null
+++ b/debian/patches/shutdown0003-xxx-halt-hack.patch
@@ -0,0 +1,45 @@
+From c5f12b3940116917929fefc41a948297371c09c4 Mon Sep 17 00:00:00 2001
+From: Justus Winter <justus@gnupg.org>
+Date: Fri, 22 Apr 2016 02:53:44 +0200
+Subject: [PATCH hurd 3/3] xxx halt hack
+
+---
+ sutils/halt.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/sutils/halt.c b/sutils/halt.c
+index 08f754c..4d36ca2 100644
+--- a/sutils/halt.c
++++ b/sutils/halt.c
+@@ -25,6 +25,8 @@
+ #include <argp.h>
+ #include <error.h>
+ #include <hurd.h>
++#include <hurd/paths.h>
++#include <hurd/startup.h>
+ #include <version.h>
+
+ const char *argp_program_version = STANDARD_HURD_VERSION (halt);
+@@ -32,9 +34,17 @@ const char *argp_program_version = STANDARD_HURD_VERSION (halt);
+ int
+ main (int argc, char *argv[])
+ {
++ error_t err;
++ file_t server;
+ struct argp argp = {0, 0, 0, "Halt the system"};
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+- reboot (RB_HALT);
+- error (1, errno, "reboot");
++
++ server = file_name_lookup (_SERVERS_STARTUP, 0, 0);
++ if (! MACH_PORT_VALID (server))
++ error (1, errno, _HURD_STARTUP);
++
++ err = startup_reboot (server, MACH_PORT_NULL, RB_HALT);
++ if (err)
++ error (1, err, "reboot");
+ return 1;
+ }
+--
+2.1.4
+