2
Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License as
6
published by the Free Software Foundation; version 2 of the
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
25
#ifdef HAVE_SYS_WAIT_H
26
#include <sys/wait.h> /* wait4 */
29
#ifdef HAVE_SYS_RESOURCE_H
30
#include <sys/resource.h> /* getrusage */
43
#include "chassis-unix-daemon.h"
46
* start the app in the background
50
void chassis_unix_daemonize(void) {
52
g_assert_not_reached(); /* shouldn't be tried to be called on win32 */
55
signal(SIGTTOU, SIG_IGN);
58
signal(SIGTTIN, SIG_IGN);
61
signal(SIGTSTP, SIG_IGN);
63
if (fork() != 0) exit(0);
65
if (setsid() == -1) exit(0);
67
signal(SIGHUP, SIG_IGN);
69
if (fork() != 0) exit(0);
79
* forward the signal to the process group, but not us
81
static void chassis_unix_signal_forward(int sig) {
83
g_assert_not_reached(); /* shouldn't be tried to be called on win32 */
85
signal(sig, SIG_IGN); /* we don't want to create a loop here */
92
* keep the ourself alive
94
* if we or the child gets a SIGTERM, we quit too
95
* on everything else we restart it
97
int chassis_unix_proc_keepalive(int *child_exit_status) {
99
g_assert_not_reached(); /* shouldn't be tried to be called on win32 */
100
return 0; /* for VC++, to silence a warning */
103
pid_t child_pid = -1;
105
/* we ignore SIGINT and SIGTERM and just let it be forwarded to the child instead
106
* as we want to collect its PID before we shutdown too
108
* the child will have to set its own signal handlers for this
112
/* try to start the children */
119
g_debug("%s: we are the child: %d",
123
} else if (pid < 0) {
126
g_critical("%s: fork() failed: %s (%d)",
133
/* we are the angel, let's see what the child did */
134
g_message("%s: [angel] we try to keep PID=%d alive",
138
/* forward a few signals that are sent to us to the child instead */
139
signal(SIGINT, chassis_unix_signal_forward);
140
signal(SIGTERM, chassis_unix_signal_forward);
141
signal(SIGHUP, chassis_unix_signal_forward);
142
signal(SIGUSR1, chassis_unix_signal_forward);
143
signal(SIGUSR2, chassis_unix_signal_forward);
150
if (child_pid != -1) {
151
struct rusage rusage;
155
g_debug("%s: waiting for %d",
159
exit_pid = wait4(child_pid, &exit_status, 0, &rusage);
161
memset(&rusage, 0, sizeof(rusage)); /* make sure everything is zero'ed out */
162
exit_pid = waitpid(child_pid, &exit_status, 0);
164
g_debug("%s: %d returned: %d",
169
if (exit_pid == child_pid) {
170
/* our child returned, let's see how it went */
171
if (WIFEXITED(exit_status)) {
172
g_message("%s: [angel] PID=%d exited normally with exit-code = %d (it used %ld kBytes max)",
175
WEXITSTATUS(exit_status),
176
rusage.ru_maxrss / 1024);
177
if (child_exit_status) *child_exit_status = WEXITSTATUS(exit_status);
179
} else if (WIFSIGNALED(exit_status)) {
181
/* our child died on a signal
183
* log it and restart */
185
g_critical("%s: [angel] PID=%d died on signal=%d (it used %ld kBytes max) ... waiting 3min before restart",
188
WTERMSIG(exit_status),
189
rusage.ru_maxrss / 1024);
192
* to make sure we don't loop as fast as we can, sleep a bit between
196
signal(SIGINT, SIG_DFL);
197
signal(SIGTERM, SIG_DFL);
198
signal(SIGHUP, SIG_DFL);
199
while (time_towait > 0) time_towait = sleep(time_towait);
203
} else if (WIFSTOPPED(exit_status)) {
205
g_assert_not_reached();
207
} else if (-1 == exit_pid) {
208
/* EINTR is ok, all others bad */
209
if (EINTR != errno) {
210
/* how can this happen ? */
211
g_critical("%s: wait4(%d, ...) failed: %s (%d)",
220
g_assert_not_reached();