1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
/* A minimalist init for the Hurd
Copyright (C) 2013,14 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 Hurd. If not, see <http://www.gnu.org/licenses/>. */
#include <argp.h>
#include <error.h>
#include <hurd.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <version.h>
const char *argp_program_version = STANDARD_HURD_VERSION (init);
static pid_t child_pid;
static int single;
static struct argp_option
options[] =
{
/* XXX: Currently, -s does nothing. */
{"single-user", 's', NULL, 0, "Startup system in single-user mode", 0},
{NULL, 'a', NULL, 0, "Ignored for compatibility with sysvinit", 0},
{0}
};
static char doc[] = "A minimalist init for the Hurd";
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
switch (key)
{
case 's':
single = 1;
break;
case 'a':
/* Ignored. */
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
void
sigchld_handler(int signal)
{
/* A child died. Find its status. */
int status;
pid_t pid;
while (1)
{
pid = waitpid (WAIT_ANY, &status, WNOHANG | WUNTRACED);
if (pid <= 0)
break; /* No more children. */
/* Since we are init, orphaned processes get reparented to us and
alas, all our adopted children eventually die. Woe is us. We
just need to reap the zombies to relieve the proc server of
its burden, and then we can forget about the little varmints. */
if (pid == child_pid)
{
/* The big magilla bit the dust. */
child_pid = -1;
error_t err;
char *desc = NULL;
if (WIFSIGNALED (status))
err = asprintf (&desc, "terminated abnormally (%s)",
strsignal (WTERMSIG (status)));
else if (WIFSTOPPED (status))
err = asprintf (&desc, "stopped abnormally (%s)",
strsignal (WTERMSIG (status)));
else if (WEXITSTATUS (status) == 0)
{
desc = strdup ("finished");
err = (desc == 0 ? -1 : 0);
}
else
err = asprintf (&desc, "exited with status %d",
WEXITSTATUS (status));
if (err == -1)
error (0, 0, "couldn't allocate exit reason message");
else
{
error (0, 0, "child %s", desc);
free (desc);
}
/* XXX: launch emergency shell. */
error (23, 0, "panic!!");
}
}
}
int
main (int argc, char **argv)
{
struct argp argp =
{
.options = options,
.parser = parse_opt,
.doc = doc,
};
argp_parse (&argp, argc, argv, 0, 0, 0);
if (getpid () != 1)
error (1, 0, "can only be run as PID 1");
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigemptyset (&sa.sa_mask);
sigaction (SIGHUP, &sa, NULL);
sigaction (SIGINT, &sa, NULL);
sigaction (SIGQUIT, &sa, NULL);
sigaction (SIGTERM, &sa, NULL);
sigaction (SIGUSR1, &sa, NULL);
sigaction (SIGUSR2, &sa, NULL);
sigaction (SIGTSTP, &sa, NULL);
sa.sa_handler = sigchld_handler;
sa.sa_flags |= SA_RESTART;
sigaction (SIGCHLD, &sa, NULL);
char *args[] = { LIBEXECDIR "/runsystem.hurd", NULL };
switch (child_pid = fork ())
{
case -1:
error (1, errno, "failed to fork");
case 0:
execv (args[0], args);
error (2, errno, "failed to execv child %s", args[0]);
}
select (0, NULL, NULL, NULL, NULL);
/* Not reached. */
return 0;
}
|