Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7eb236f6f | ||
|
|
1936d73eb1 | ||
|
|
58872fc090 | ||
|
|
fc35eb90ca | ||
|
|
b18be3f970 | ||
|
|
027438f775 | ||
|
|
93e159ae85 | ||
|
|
bcfcf50562 | ||
|
|
d0097cc10f | ||
|
|
eecf868e3c | ||
|
|
a5cd486a7f | ||
|
|
6e6b4ac5fa | ||
|
|
558ff4d5fb | ||
|
|
490f855aef | ||
|
|
d1491e201d | ||
|
|
3231af9375 | ||
|
|
a5758e7aef | ||
|
|
61a9393ce1 | ||
|
|
161d22cb07 | ||
|
|
3a96ca1c96 | ||
|
|
934530914b | ||
|
|
b717625cd2 | ||
|
|
b475396134 | ||
|
|
e7b1d898ca | ||
|
|
5cd09a6f44 | ||
|
|
f3c70bf5b5 | ||
|
|
f5acc66db7 | ||
|
|
fdce4769f2 | ||
|
|
35b1996704 | ||
|
|
3c8e7ed255 |
222
ChangeLog
222
ChangeLog
@@ -1,4 +1,196 @@
|
||||
commit 8122e2d8f4fa8538e62f6a5e6b7306afcfc23c1c
|
||||
commit 1936d73eb1aecf31029d53e75e6bb14e307f8e1c
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
fix issue with --reexec call
|
||||
|
||||
commit 58872fc090af5047547bc561a5e58c50be0fc235
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
version 0.34.5
|
||||
|
||||
commit fc35eb90cab625966ca718a80dd0d38dfffe05b8
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
Update ChangeLog
|
||||
|
||||
commit b18be3f970eba04589977438faaa726b5c3a6cd2
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
supervise-daemon: use RC_SVCNAME as the first argument to the daemon
|
||||
|
||||
This makes ps show which service the supervisor is monitoring.
|
||||
|
||||
commit 027438f7759dbbc19ac1bedeff3f502c891e4d4e
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
supervise-daemon: fix logging for reexec and the child command line
|
||||
|
||||
commit 93e159ae8541b82fd5e1843f60dce135e2eb5517
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
log as supervise-daemon not the service
|
||||
|
||||
commit bcfcf50562a081088248f693dfab62d3eab04efa
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
version 0.34.4
|
||||
|
||||
commit d0097cc10f8701de1b6a5665c54abf909e897233
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
Update ChangeLog
|
||||
|
||||
commit eecf868e3c4a763b08cd4b3803f4839e8e710413
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
supervise-daemon: clarify a log message
|
||||
|
||||
commit a5cd486a7fbb5acf8e8f3085500fd86c23dd8641
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
Update ChangeLog
|
||||
|
||||
commit 6e6b4ac5fa935eb8052d293f2b8378e0395572e1
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
supervise-daemon: log the command line we run to spawn the child process
|
||||
|
||||
commit 558ff4d5fb90b751ebc2852ea907873af2c236fa
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
supervise-daemon: log with the service name instead of "supervise-daemon"
|
||||
|
||||
commit 490f855aef581a720c6c0be0d8407fe6d279f9f5
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
implement "unsupervised" status
|
||||
|
||||
The unsupervised status is to be used when a supervisor of a supervised
|
||||
service dies but leaves the service daemon itself running.
|
||||
|
||||
commit d1491e201d3ad364e25a55b29ff8035775a6acac
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
supervise-daemon: remove child_pid from saved options during shutdown
|
||||
|
||||
This allows us to detect when the supervisor dies unexpectedly because
|
||||
in that case child_pid will still exist.
|
||||
|
||||
commit 3231af937590b1c00af1a459009472a371aeb04a
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
rc_service_value_set: remove the option if NULL is the value
|
||||
|
||||
This allows the equivalent of "unsetting" a value for a service.
|
||||
|
||||
commit a5758e7aeffbeb9766ba3055a3fc347f0ccd3d35
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
supervise-daemon.sh: fix status function with no namespaces
|
||||
|
||||
commit 61a9393ce12fda412bdca4002ac71e7df82384df
|
||||
Author: Patrick McLean <chutzpah@gentoo.org>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
cgroups_cleanup: clean up shutdown signaling
|
||||
|
||||
- do not sleep for the full 90 seconds if processes are dead
|
||||
- re-arrange the order of signals we attempt to send to the processes
|
||||
|
||||
commit 161d22cb074ecef7003e19682d72a8ee61c14490
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
version 0.34.3
|
||||
|
||||
commit 3a96ca1c966c3cc44a2e0e51b383ab47d078bcc1
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
Update ChangeLog
|
||||
|
||||
commit 934530914bd507476b428d3f6572bbb1c5bbfd16
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
add "unsupervised" status and return code 64 to supervise-daemon status function
|
||||
|
||||
This is to be used if the service is being supervised and the
|
||||
supervisor is somehow killed.
|
||||
|
||||
Currently, this is very linux specific, but I will expand to other
|
||||
platforms, patches are welcome.
|
||||
|
||||
commit b717625cd27950c3f00b5345bc1cee9700e79498
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
version 0.34.2
|
||||
|
||||
commit b47539613431521e5e99bc388e6a9d8eb0e48801
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
Update ChangeLog
|
||||
|
||||
commit e7b1d898ca7896d6443ba1e5167eb6bcf3f92929
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
supervise-daemon: fix build issue for >=glibc-2.26
|
||||
|
||||
X-Gentoo-Bug: 635334
|
||||
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=635334
|
||||
|
||||
commit 5cd09a6f44aa7d16ab7de1453e37d01448426031
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
version 0.34.1
|
||||
|
||||
commit f3c70bf5b5aa18e8dc94d4949f05568e0741c5cb
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
Update ChangeLog
|
||||
|
||||
commit f5acc66db7d1a0bfad6a40eefc0240b80f52df94
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
rc_find_pids: ignore pids that are not in our pid namespace
|
||||
|
||||
X-Gentoo-Bug: 634634
|
||||
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=634634
|
||||
|
||||
commit fdce4769f2e0f4175163ffa181c7b3b2192f7b22
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
supervise-daemon: multiple fixes
|
||||
|
||||
- Harden against dying by handling all signals that would terminate the
|
||||
program and adding --reexec support
|
||||
- factor the supervisor into its own function
|
||||
- fix test for whether we are already running
|
||||
|
||||
commit 35b1996704f6635bb29ea3604410e133209e6432
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
@@ -8,11 +200,11 @@ Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
we were supervising at the info level. This change moves the logs to
|
||||
warnings.
|
||||
|
||||
commit ff07754be27e20a4d272661b071b63b435018b51
|
||||
commit 3c8e7ed255edb8df0d548d6ce514544d5422cbf0
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
version 0.33.1
|
||||
version 0.34
|
||||
|
||||
commit acaed1f910a2a00fdd5b6aeab752c552075a7292
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
@@ -1428,27 +1620,3 @@ Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
src/rc/rc: do not try to start services if fork fails
|
||||
|
||||
commit 003657c973ea338a19f2b7294190af9d76cf5cea
|
||||
Author: Robin H. Johnson <robbat2@gentoo.org>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
init.d/loopback: drop scope on loopback
|
||||
|
||||
Busybox does not support the 'scope' argument on 'ip address add' or 'ip
|
||||
route add', this is documented in BUSYBOX.md, but is no longer actually
|
||||
needed, as the kernel does get it right without manual specification,
|
||||
and the ifconfig variant already relies on the kernel to get it right.
|
||||
This is part of #103.
|
||||
|
||||
X-Gentoo-Bug: 487208
|
||||
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=487208
|
||||
|
||||
commit 4fd144c0a6526963c70f18cb34a65354c2f0a48c
|
||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||
|
||||
src/rc/rc-misc.c: report error if call to flock() fails
|
||||
|
||||
X-Gentoo-Bug: 597390
|
||||
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=597390
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
NAME= openrc
|
||||
VERSION= 0.33.1
|
||||
VERSION= 0.34.5
|
||||
PKG= ${NAME}-${VERSION}
|
||||
|
||||
@@ -203,15 +203,21 @@ cgroup_cleanup()
|
||||
{
|
||||
cgroup_running || return 0
|
||||
ebegin "starting cgroups cleanup"
|
||||
local pids
|
||||
local pids loops=0
|
||||
pids="$(cgroup_get_pids)"
|
||||
if [ -n "${pids}" ]; then
|
||||
kill -s "${stopsig:-TERM}" ${pids} 2> /dev/null
|
||||
kill -s CONT ${pids} 2> /dev/null
|
||||
kill -s "${stopsig:-TERM}" ${pids} 2> /dev/null
|
||||
yesno "${rc_send_sighup:-no}" &&
|
||||
kill -s HUP ${pids} 2> /dev/null
|
||||
sleep "${rc_timeout_stopsec:-90}"
|
||||
yesno "${rc_send_sigkill:-yes}" &&
|
||||
kill -s "${stopsig:-TERM}" ${pids} 2> /dev/null
|
||||
while [ -n "$(cgroup_get_pids)" ] &&
|
||||
[ "${loops}" -lt "${rc_timeout_stopsec:-90}" ]; do
|
||||
loops=$((loops+1))
|
||||
sleep 1
|
||||
done
|
||||
pids="$(cgroup_get_pids)"
|
||||
[ -n "${pids}" ] && yesno "${rc_send_sigkill:-yes}" &&
|
||||
kill -s KILL ${pids} 2> /dev/null
|
||||
fi
|
||||
cgroup2_remove
|
||||
|
||||
@@ -22,7 +22,7 @@ supervise_start()
|
||||
# The eval call is necessary for cases like:
|
||||
# command_args="this \"is a\" test"
|
||||
# to work properly.
|
||||
eval supervise-daemon --start \
|
||||
eval supervise-daemon "${RC_SVCNAME}" --start \
|
||||
${retry:+--retry} $retry \
|
||||
${chroot:+--chroot} $chroot \
|
||||
${pidfile:+--pidfile} $pidfile \
|
||||
@@ -49,14 +49,48 @@ supervise_stop()
|
||||
pidfile="${startpidfile:-$pidfile}"
|
||||
[ -n "$pidfile" ] || return 0
|
||||
ebegin "Stopping ${name:-$RC_SVCNAME}"
|
||||
supervise-daemon --stop \
|
||||
supervise-daemon "${RC_SVCNAME}" --stop \
|
||||
${pidfile:+--pidfile} $chroot$pidfile \
|
||||
${stopsig:+--signal} $stopsig
|
||||
|
||||
eend $? "Failed to stop ${name:-$RC_SVCNAME}"
|
||||
}
|
||||
|
||||
_check_supervised()
|
||||
{
|
||||
local child_pid start_time
|
||||
child_pid="$(service_get_value "child_pid")"
|
||||
start_time="$(service_get_value "start_time")"
|
||||
if [ -n "${child_pid}" ] && [ -n "${start_time}" ]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
supervise_status()
|
||||
{
|
||||
_status
|
||||
if service_stopping; then
|
||||
ewarn "status: stopping"
|
||||
return 4
|
||||
elif service_starting; then
|
||||
ewarn "status: starting"
|
||||
return 8
|
||||
elif service_inactive; then
|
||||
ewarn "status: inactive"
|
||||
return 16
|
||||
elif service_started; then
|
||||
if service_crashed; then
|
||||
if ! _check_supervised; then
|
||||
eerror "status: unsupervised"
|
||||
return 64
|
||||
fi
|
||||
eerror "status: crashed"
|
||||
return 32
|
||||
fi
|
||||
einfo "status: started"
|
||||
return 0
|
||||
else
|
||||
einfo "status: stopped"
|
||||
return 3
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ bool rc_conf_yesno(const char *var);
|
||||
void env_filter(void);
|
||||
void env_config(void);
|
||||
int signal_setup(int sig, void (*handler)(int));
|
||||
int signal_setup_restart(int sig, void (*handler)(int));
|
||||
int svc_lock(const char *);
|
||||
int svc_unlock(const char *, int);
|
||||
pid_t exec_service(const char *, const char *);
|
||||
|
||||
@@ -80,9 +80,12 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
|
||||
DIR *procdir;
|
||||
struct dirent *entry;
|
||||
FILE *fp;
|
||||
int rc;
|
||||
bool container_pid = false;
|
||||
bool openvz_host = false;
|
||||
char *line = NULL;
|
||||
char my_ns[30];
|
||||
char proc_ns[30];
|
||||
size_t len = 0;
|
||||
pid_t p;
|
||||
char buffer[PATH_MAX];
|
||||
@@ -131,6 +134,14 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
|
||||
}
|
||||
}
|
||||
|
||||
memset(my_ns, 0, sizeof(my_ns));
|
||||
memset(proc_ns, 0, sizeof(proc_ns));
|
||||
if (exists("/proc/self/ns/pid")) {
|
||||
rc = readlink("/proc/self/ns/pid", my_ns, sizeof(my_ns));
|
||||
if (rc <= 0)
|
||||
my_ns[0] = '\0';
|
||||
}
|
||||
|
||||
while ((entry = readdir(procdir)) != NULL) {
|
||||
if (sscanf(entry->d_name, "%d", &p) != 1)
|
||||
continue;
|
||||
@@ -138,6 +149,14 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
|
||||
continue;
|
||||
if (pid != 0 && pid != p)
|
||||
continue;
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%d/ns/pid", p);
|
||||
if (exists(buffer)) {
|
||||
rc = readlink(buffer, proc_ns, sizeof(proc_ns));
|
||||
if (rc <= 0)
|
||||
proc_ns[0] = '\0';
|
||||
}
|
||||
if (strcmp(my_ns, proc_ns))
|
||||
continue;
|
||||
if (uid) {
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%d", p);
|
||||
if (stat(buffer, &sb) != 0 || sb.st_uid != uid)
|
||||
|
||||
@@ -894,12 +894,15 @@ rc_service_value_set(const char *service, const char *option,
|
||||
return false;
|
||||
|
||||
snprintf(p, sizeof(file) - (p - file), "/%s", option);
|
||||
if (!(fp = fopen(file, "w")))
|
||||
return false;
|
||||
if (value)
|
||||
if (value) {
|
||||
if (!(fp = fopen(file, "w")))
|
||||
return false;
|
||||
fprintf(fp, "%s", value);
|
||||
fclose(fp);
|
||||
return true;
|
||||
fclose(fp);
|
||||
} else {
|
||||
unlink(file);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
librc_hidden_def(rc_service_value_set)
|
||||
|
||||
|
||||
@@ -217,6 +217,18 @@ signal_setup(int sig, void (*handler)(int))
|
||||
return sigaction(sig, &sa, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
signal_setup_restart(int sig, void (*handler)(int))
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
memset(&sa, 0, sizeof (sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_handler = handler;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
return sigaction(sig, &sa, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
svc_lock(const char *applet)
|
||||
{
|
||||
|
||||
@@ -128,6 +128,8 @@ print_service(const char *service)
|
||||
{
|
||||
char status[60];
|
||||
char uptime [40];
|
||||
char *child_pid = NULL;
|
||||
char *start_time = NULL;
|
||||
int cols = printf(" %s", service);
|
||||
const char *c = ecolor(ECOLOR_GOOD);
|
||||
RC_SERVICE state = rc_service_state(service);
|
||||
@@ -147,7 +149,14 @@ print_service(const char *service)
|
||||
rc_service_daemons_crashed(service) &&
|
||||
errno != EACCES)
|
||||
{
|
||||
snprintf(status, sizeof(status), " crashed ");
|
||||
child_pid = rc_service_value_get(service, "child_pid");
|
||||
start_time = rc_service_value_get(service, "start_time");
|
||||
if (start_time && child_pid)
|
||||
snprintf(status, sizeof(status), " unsupervised ");
|
||||
else
|
||||
snprintf(status, sizeof(status), " crashed ");
|
||||
free(child_pid);
|
||||
free(start_time);
|
||||
} else {
|
||||
get_uptime(service, uptime, 40);
|
||||
snprintf(status, sizeof(status), " started %s", uptime);
|
||||
|
||||
@@ -67,7 +67,7 @@ static struct pam_conv conv = { NULL, NULL};
|
||||
|
||||
const char *applet = NULL;
|
||||
const char *extraopts = NULL;
|
||||
const char *getoptstring = "D:d:e:g:I:Kk:m:N:p:R:r:Su:1:2:" \
|
||||
const char *getoptstring = "D:d:e:g:I:Kk:m:N:p:R:r:Su:1:2:3" \
|
||||
getoptstring_COMMON;
|
||||
const struct option longopts[] = {
|
||||
{ "respawn-delay", 1, NULL, 'D'},
|
||||
@@ -87,6 +87,7 @@ const struct option longopts[] = {
|
||||
{ "user", 1, NULL, 'u'},
|
||||
{ "stdout", 1, NULL, '1'},
|
||||
{ "stderr", 1, NULL, '2'},
|
||||
{ "reexec", 0, NULL, '3'},
|
||||
longopts_COMMON
|
||||
};
|
||||
const char * const longopts_help[] = {
|
||||
@@ -107,6 +108,7 @@ const char * const longopts_help[] = {
|
||||
"Change the process user",
|
||||
"Redirect stdout to file",
|
||||
"Redirect stderr to file",
|
||||
"reexec (used internally)",
|
||||
longopts_help_COMMON
|
||||
};
|
||||
const char *usagestring = NULL;
|
||||
@@ -127,6 +129,13 @@ static bool exiting = false;
|
||||
#ifdef TIOCNOTTY
|
||||
static int tty_fd = -1;
|
||||
#endif
|
||||
static pid_t child_pid;
|
||||
static int respawn_count = 0;
|
||||
static int respawn_delay = 0;
|
||||
static int respawn_max = 10;
|
||||
static int respawn_period = 5;
|
||||
static char *pidfile = NULL;
|
||||
static char *svcname = NULL;
|
||||
|
||||
extern char **environ;
|
||||
|
||||
@@ -150,8 +159,72 @@ static void cleanup(void)
|
||||
free(changeuser);
|
||||
}
|
||||
|
||||
static void child_process(char *exec, char **argv, char *svcname,
|
||||
int start_count)
|
||||
static void re_exec(void)
|
||||
{
|
||||
syslog(LOG_WARNING, "Re-executing for %s", svcname);
|
||||
execlp("supervise-daemon", "supervise-daemon", svcname, "--reexec",
|
||||
(char *) NULL);
|
||||
syslog(LOG_ERR, "Unable to execute supervise-daemon: %s",
|
||||
strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void handle_signal(int sig)
|
||||
{
|
||||
int serrno = errno;
|
||||
|
||||
syslog(LOG_WARNING, "caught signal %d", sig);
|
||||
|
||||
if (sig == SIGTERM)
|
||||
exiting = true;
|
||||
/* Restore errno */
|
||||
errno = serrno;
|
||||
if (! exiting)
|
||||
re_exec();
|
||||
}
|
||||
|
||||
static char * expand_home(const char *home, const char *path)
|
||||
{
|
||||
char *opath, *ppath, *p, *nh;
|
||||
size_t len;
|
||||
struct passwd *pw;
|
||||
|
||||
if (!path || *path != '~')
|
||||
return xstrdup(path);
|
||||
|
||||
opath = ppath = xstrdup(path);
|
||||
if (ppath[1] != '/' && ppath[1] != '\0') {
|
||||
p = strchr(ppath + 1, '/');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
pw = getpwnam(ppath + 1);
|
||||
if (pw) {
|
||||
home = pw->pw_dir;
|
||||
ppath = p;
|
||||
if (ppath)
|
||||
*ppath = '/';
|
||||
} else
|
||||
home = NULL;
|
||||
} else
|
||||
ppath++;
|
||||
|
||||
if (!home) {
|
||||
free(opath);
|
||||
return xstrdup(path);
|
||||
}
|
||||
if (!ppath) {
|
||||
free(opath);
|
||||
return xstrdup(home);
|
||||
}
|
||||
|
||||
len = strlen(ppath) + strlen(home) + 1;
|
||||
nh = xmalloc(len);
|
||||
snprintf(nh, len, "%s%s", home, ppath);
|
||||
free(opath);
|
||||
return nh;
|
||||
}
|
||||
|
||||
static void child_process(char *exec, char **argv)
|
||||
{
|
||||
RC_STRINGLIST *env_list;
|
||||
RC_STRING *env;
|
||||
@@ -176,11 +249,13 @@ static void child_process(char *exec, char **argv, char *svcname,
|
||||
setsid();
|
||||
|
||||
if (svcname) {
|
||||
start_time = time(NULL);
|
||||
from_time_t(start_time_string, start_time);
|
||||
start_time = time(NULL);
|
||||
from_time_t(start_time_string, start_time);
|
||||
rc_service_value_set(svcname, "start_time", start_time_string);
|
||||
sprintf(start_count_string, "%i", start_count);
|
||||
sprintf(start_count_string, "%i", respawn_count);
|
||||
rc_service_value_set(svcname, "start_count", start_count_string);
|
||||
sprintf(start_count_string, "%d", getpid());
|
||||
rc_service_value_set(svcname, "child_pid", start_count_string);
|
||||
}
|
||||
|
||||
if (nicelevel) {
|
||||
@@ -323,12 +398,12 @@ sprintf(start_count_string, "%i", start_count);
|
||||
|
||||
*cmdline = '\0';
|
||||
c = argv;
|
||||
while (*c) {
|
||||
while (c && *c) {
|
||||
strcat(cmdline, *c);
|
||||
strcat(cmdline, " ");
|
||||
c++;
|
||||
}
|
||||
syslog(LOG_INFO, "Running command line: %s", cmdline);
|
||||
syslog(LOG_INFO, "Child command line: %s", cmdline);
|
||||
execvp(exec, argv);
|
||||
|
||||
#ifdef HAVE_PAM
|
||||
@@ -338,108 +413,161 @@ sprintf(start_count_string, "%i", start_count);
|
||||
eerrorx("%s: failed to exec `%s': %s", applet, exec,strerror(errno));
|
||||
}
|
||||
|
||||
static void handle_signal(int sig)
|
||||
static void supervisor(char *exec, char **argv)
|
||||
{
|
||||
int serrno = errno;
|
||||
char signame[10] = { '\0' };
|
||||
FILE *fp;
|
||||
int i;
|
||||
int nkilled;
|
||||
time_t respawn_now= 0;
|
||||
time_t first_spawn= 0;
|
||||
|
||||
switch (sig) {
|
||||
case SIGINT:
|
||||
snprintf(signame, sizeof(signame), "SIGINT");
|
||||
break;
|
||||
case SIGTERM:
|
||||
snprintf(signame, sizeof(signame), "SIGTERM");
|
||||
break;
|
||||
case SIGQUIT:
|
||||
snprintf(signame, sizeof(signame), "SIGQUIT");
|
||||
break;
|
||||
#ifndef RC_DEBUG
|
||||
signal_setup_restart(SIGHUP, handle_signal);
|
||||
signal_setup_restart(SIGINT, handle_signal);
|
||||
signal_setup_restart(SIGQUIT, handle_signal);
|
||||
signal_setup_restart(SIGILL, handle_signal);
|
||||
signal_setup_restart(SIGABRT, handle_signal);
|
||||
signal_setup_restart(SIGFPE, handle_signal);
|
||||
signal_setup_restart(SIGSEGV, handle_signal);
|
||||
signal_setup_restart(SIGPIPE, handle_signal);
|
||||
signal_setup_restart(SIGALRM, handle_signal);
|
||||
signal_setup(SIGTERM, handle_signal);
|
||||
signal_setup_restart(SIGUSR1, handle_signal);
|
||||
signal_setup_restart(SIGUSR2, handle_signal);
|
||||
signal_setup_restart(SIGBUS, handle_signal);
|
||||
signal_setup_restart(SIGPOLL, handle_signal);
|
||||
signal_setup_restart(SIGPROF, handle_signal);
|
||||
signal_setup_restart(SIGSYS, handle_signal);
|
||||
signal_setup_restart(SIGTRAP, handle_signal);
|
||||
signal_setup_restart(SIGVTALRM, handle_signal);
|
||||
signal_setup_restart(SIGXCPU, handle_signal);
|
||||
signal_setup_restart(SIGXFSZ, handle_signal);
|
||||
#ifdef SIGEMT
|
||||
signal_setup_restart(SIGEMT, handle_signal);
|
||||
#endif
|
||||
signal_setup_restart(SIGIO, handle_signal);
|
||||
signal_setup_restart(SIGPWR, handle_signal);
|
||||
#ifdef SIGUNUSED
|
||||
signal_setup_restart(SIGUNUSED, handle_signal);
|
||||
#endif
|
||||
#ifdef SIGRTMIN
|
||||
for (i = SIGRTMIN; i <= SIGRTMAX; i++)
|
||||
signal_setup_restart(i, handle_signal);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
fp = fopen(pidfile, "w");
|
||||
if (! fp)
|
||||
eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
|
||||
fprintf(fp, "%d\n", getpid());
|
||||
fclose(fp);
|
||||
|
||||
if (svcname)
|
||||
rc_service_daemon_set(svcname, exec, (const char * const *) argv,
|
||||
pidfile, true);
|
||||
|
||||
/* remove the controlling tty */
|
||||
#ifdef TIOCNOTTY
|
||||
ioctl(tty_fd, TIOCNOTTY, 0);
|
||||
close(tty_fd);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Supervisor main loop
|
||||
*/
|
||||
i = 0;
|
||||
while (!exiting) {
|
||||
wait(&i);
|
||||
if (exiting) {
|
||||
signal_setup(SIGCHLD, SIG_IGN);
|
||||
syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid);
|
||||
nkilled = run_stop_schedule(applet, exec, NULL, child_pid, 0,
|
||||
false, false, true);
|
||||
if (nkilled > 0)
|
||||
syslog(LOG_INFO, "killed %d processes", nkilled);
|
||||
} else {
|
||||
sleep(respawn_delay);
|
||||
if (respawn_max > 0 && respawn_period > 0) {
|
||||
respawn_now = time(NULL);
|
||||
if (first_spawn == 0)
|
||||
first_spawn = respawn_now;
|
||||
if (respawn_now - first_spawn > respawn_period) {
|
||||
respawn_count = 0;
|
||||
first_spawn = 0;
|
||||
} else
|
||||
respawn_count++;
|
||||
if (respawn_count >= respawn_max) {
|
||||
syslog(LOG_WARNING,
|
||||
"respawned \"%s\" too many times, exiting", exec);
|
||||
exiting = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (WIFEXITED(i))
|
||||
syslog(LOG_WARNING, "%s, pid %d, exited with return code %d",
|
||||
exec, child_pid, WEXITSTATUS(i));
|
||||
else if (WIFSIGNALED(i))
|
||||
syslog(LOG_WARNING, "%s, pid %d, terminated by signal %d",
|
||||
exec, child_pid, WTERMSIG(i));
|
||||
child_pid = fork();
|
||||
if (child_pid == -1)
|
||||
eerrorx("%s: fork: %s", applet, strerror(errno));
|
||||
if (child_pid == 0)
|
||||
child_process(exec, argv);
|
||||
}
|
||||
}
|
||||
|
||||
if (*signame != 0) {
|
||||
syslog(LOG_INFO, "%s: caught signal %s, exiting", applet, signame);
|
||||
exiting = true;
|
||||
} else
|
||||
syslog(LOG_INFO, "%s: caught unknown signal %d", applet, sig);
|
||||
|
||||
/* Restore errno */
|
||||
errno = serrno;
|
||||
}
|
||||
|
||||
static char * expand_home(const char *home, const char *path)
|
||||
{
|
||||
char *opath, *ppath, *p, *nh;
|
||||
size_t len;
|
||||
struct passwd *pw;
|
||||
|
||||
if (!path || *path != '~')
|
||||
return xstrdup(path);
|
||||
|
||||
opath = ppath = xstrdup(path);
|
||||
if (ppath[1] != '/' && ppath[1] != '\0') {
|
||||
p = strchr(ppath + 1, '/');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
pw = getpwnam(ppath + 1);
|
||||
if (pw) {
|
||||
home = pw->pw_dir;
|
||||
ppath = p;
|
||||
if (ppath)
|
||||
*ppath = '/';
|
||||
} else
|
||||
home = NULL;
|
||||
} else
|
||||
ppath++;
|
||||
|
||||
if (!home) {
|
||||
free(opath);
|
||||
return xstrdup(path);
|
||||
if (pidfile && exists(pidfile))
|
||||
unlink(pidfile);
|
||||
if (svcname) {
|
||||
rc_service_daemon_set(svcname, exec, (const char *const *)argv,
|
||||
pidfile, false);
|
||||
rc_service_mark(svcname, RC_SERVICE_STOPPED);
|
||||
rc_service_value_set(svcname, "child_pid", NULL);
|
||||
}
|
||||
if (!ppath) {
|
||||
free(opath);
|
||||
return xstrdup(home);
|
||||
}
|
||||
|
||||
len = strlen(ppath) + strlen(home) + 1;
|
||||
nh = xmalloc(len);
|
||||
snprintf(nh, len, "%s%s", home, ppath);
|
||||
free(opath);
|
||||
return nh;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
char **c;
|
||||
int x;
|
||||
bool start = false;
|
||||
bool stop = false;
|
||||
bool reexec = false;
|
||||
char *exec = NULL;
|
||||
char *pidfile = NULL;
|
||||
char *retry = NULL;
|
||||
int nkilled;
|
||||
int sig = SIGTERM;
|
||||
char *home = NULL;
|
||||
int tid = 0;
|
||||
pid_t child_pid, pid;
|
||||
char *svcname = getenv("RC_SVCNAME");
|
||||
pid_t pid;
|
||||
char *tmp;
|
||||
char *p;
|
||||
char *token;
|
||||
int i;
|
||||
int n;
|
||||
char exec_file[PATH_MAX];
|
||||
int respawn_count = 0;
|
||||
int respawn_delay = 0;
|
||||
int respawn_max = 10;
|
||||
int respawn_period = 5;
|
||||
time_t respawn_now= 0;
|
||||
time_t first_spawn= 0;
|
||||
char name[PATH_MAX];
|
||||
struct timespec ts;
|
||||
struct passwd *pw;
|
||||
struct group *gr;
|
||||
FILE *fp;
|
||||
mode_t numask = 022;
|
||||
int child_argc = 0;
|
||||
char **child_argv = NULL;
|
||||
char *str = NULL;
|
||||
char cmdline[PATH_MAX];
|
||||
|
||||
applet = basename_c(argv[0]);
|
||||
atexit(cleanup);
|
||||
svcname = getenv("RC_SVCNAME");
|
||||
if (!svcname)
|
||||
eerrorx("%s: The RC_SVCNAME environment variable is not set", applet);
|
||||
openlog(applet, LOG_PID, LOG_DAEMON);
|
||||
|
||||
if (argc >= 1 && svcname && strcmp(argv[1], svcname))
|
||||
eerrorx("%s: the first argument must be %s", applet, svcname);
|
||||
|
||||
if ((tmp = getenv("SSD_NICELEVEL")))
|
||||
if (sscanf(tmp, "%d", &nicelevel) != 1)
|
||||
@@ -461,6 +589,17 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
*cmdline = '\0';
|
||||
c = argv;
|
||||
while (c && *c) {
|
||||
strcat(cmdline, *c);
|
||||
strcat(cmdline, " ");
|
||||
c++;
|
||||
}
|
||||
if (svcname) {
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
while ((opt = getopt_long(argc, argv, getoptstring, longopts,
|
||||
(int *) 0)) != -1)
|
||||
switch (opt) {
|
||||
@@ -493,8 +632,8 @@ int main(int argc, char **argv)
|
||||
|
||||
case 'P': /* --respawn-period time */
|
||||
n = sscanf(optarg, "%d", &respawn_period);
|
||||
if (n != 1 || respawn_delay < 1)
|
||||
eerrorx("Invalid respawn-delay value '%s'", optarg);
|
||||
if (n != 1 || respawn_period < 1)
|
||||
eerrorx("Invalid respawn-period value '%s'", optarg);
|
||||
break;
|
||||
|
||||
case 'S': /* --start */
|
||||
@@ -590,86 +729,173 @@ int main(int argc, char **argv)
|
||||
case '2': /* --stderr /path/to/stderr.logfile */
|
||||
redirect_stderr = optarg;
|
||||
break;
|
||||
case '3': /* --reexec */
|
||||
reexec = true;
|
||||
break;
|
||||
|
||||
case_RC_COMMON_GETOPT
|
||||
}
|
||||
|
||||
if (!pidfile)
|
||||
if (!pidfile && !reexec)
|
||||
eerrorx("%s: --pidfile must be specified", applet);
|
||||
|
||||
endpwent();
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
exec = *argv;
|
||||
|
||||
if (start) {
|
||||
if (!exec)
|
||||
eerrorx("%s: nothing to start", applet);
|
||||
if (respawn_delay * respawn_max > respawn_period) {
|
||||
ewarn("%s: Please increase the value of --respawn-period to more "
|
||||
"than %d to avoid infinite respawning", applet,
|
||||
respawn_delay * respawn_max);
|
||||
}
|
||||
if (retry)
|
||||
parse_schedule(applet, retry, sig);
|
||||
else
|
||||
parse_schedule(applet, NULL, sig);
|
||||
}
|
||||
|
||||
/* Expand ~ */
|
||||
if (ch_dir && *ch_dir == '~')
|
||||
ch_dir = expand_home(home, ch_dir);
|
||||
if (ch_root && *ch_root == '~')
|
||||
ch_root = expand_home(home, ch_root);
|
||||
if (exec) {
|
||||
if (*exec == '~')
|
||||
exec = expand_home(home, exec);
|
||||
|
||||
/* Validate that the binary exists if we are starting */
|
||||
if (*exec == '/' || *exec == '.') {
|
||||
/* Full or relative path */
|
||||
if (ch_root)
|
||||
snprintf(exec_file, sizeof(exec_file),
|
||||
"%s/%s", ch_root, exec);
|
||||
else
|
||||
snprintf(exec_file, sizeof(exec_file),
|
||||
"%s", exec);
|
||||
} else {
|
||||
/* Something in $PATH */
|
||||
p = tmp = xstrdup(getenv("PATH"));
|
||||
*exec_file = '\0';
|
||||
while ((token = strsep(&p, ":"))) {
|
||||
umask(numask);
|
||||
|
||||
if (reexec) {
|
||||
str = rc_service_value_get(svcname, "argc");
|
||||
sscanf(str, "%d", &child_argc);
|
||||
child_argv = xmalloc((child_argc + 1) * sizeof(char *));
|
||||
memset(child_argv, 0, (child_argc + 1) * sizeof(char *));
|
||||
for (x = 0; x < child_argc; x++) {
|
||||
sprintf(name, "argv_%d", x);
|
||||
str = rc_service_value_get(svcname, name);
|
||||
child_argv[x] = str;
|
||||
}
|
||||
free(str);
|
||||
str = rc_service_value_get(svcname, "child_pid");
|
||||
sscanf(str, "%d", &child_pid);
|
||||
free(str);
|
||||
exec = rc_service_value_get(svcname, "exec");
|
||||
pidfile = rc_service_value_get(svcname, "pidfile");
|
||||
retry = rc_service_value_get(svcname, "retry");
|
||||
if (retry) {
|
||||
parse_schedule(applet, retry, sig);
|
||||
rc_service_value_set(svcname, "retry", retry);
|
||||
} else
|
||||
parse_schedule(applet, NULL, sig);
|
||||
|
||||
str = rc_service_value_get(svcname, "respawn_delay");
|
||||
sscanf(str, "%d", &respawn_delay);
|
||||
str = rc_service_value_get(svcname, "respawn_max");
|
||||
sscanf(str, "%d", &respawn_max);
|
||||
supervisor(exec, child_argv);
|
||||
} else if (start) {
|
||||
if (exec) {
|
||||
if (*exec == '~')
|
||||
exec = expand_home(home, exec);
|
||||
|
||||
/* Validate that the binary exists if we are starting */
|
||||
if (*exec == '/' || *exec == '.') {
|
||||
/* Full or relative path */
|
||||
if (ch_root)
|
||||
snprintf(exec_file, sizeof(exec_file),
|
||||
"%s/%s/%s",
|
||||
ch_root, token, exec);
|
||||
"%s/%s", ch_root, exec);
|
||||
else
|
||||
snprintf(exec_file, sizeof(exec_file),
|
||||
"%s/%s", token, exec);
|
||||
if (exists(exec_file))
|
||||
break;
|
||||
"%s", exec);
|
||||
} else {
|
||||
/* Something in $PATH */
|
||||
p = tmp = xstrdup(getenv("PATH"));
|
||||
*exec_file = '\0';
|
||||
while ((token = strsep(&p, ":"))) {
|
||||
if (ch_root)
|
||||
snprintf(exec_file, sizeof(exec_file),
|
||||
"%s/%s/%s",
|
||||
ch_root, token, exec);
|
||||
else
|
||||
snprintf(exec_file, sizeof(exec_file),
|
||||
"%s/%s", token, exec);
|
||||
if (exists(exec_file))
|
||||
break;
|
||||
*exec_file = '\0';
|
||||
}
|
||||
free(tmp);
|
||||
}
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
if (start && !exists(exec_file))
|
||||
eerrorx("%s: %s does not exist", applet,
|
||||
*exec_file ? exec_file : exec);
|
||||
if ( !exists(exec_file))
|
||||
eerrorx("%s: %s does not exist", applet,
|
||||
*exec_file ? exec_file : exec);
|
||||
} else
|
||||
eerrorx("%s: nothing to start", applet);
|
||||
|
||||
if (stop) {
|
||||
pid = get_pid(applet, pidfile);
|
||||
if (pid != -1)
|
||||
if (do_stop(applet, exec, (const char * const *)argv, pid, uid,
|
||||
0, false, true) > 0)
|
||||
eerrorx("%s: %s is already running", applet, exec);
|
||||
|
||||
if (respawn_delay * respawn_max > respawn_period)
|
||||
ewarn("%s: Please increase the value of --respawn-period to more "
|
||||
"than %d to avoid infinite respawning", applet,
|
||||
respawn_delay * respawn_max);
|
||||
|
||||
if (retry) {
|
||||
parse_schedule(applet, retry, sig);
|
||||
rc_service_value_set(svcname, "retry", retry);
|
||||
} else
|
||||
parse_schedule(applet, NULL, sig);
|
||||
|
||||
einfov("Detaching to start `%s'", exec);
|
||||
syslog(LOG_INFO, "Supervisor command line: %s", cmdline);
|
||||
|
||||
/* Remove existing pidfile */
|
||||
if (pidfile)
|
||||
unlink(pidfile);
|
||||
|
||||
/* Make sure we can write a pid file */
|
||||
fp = fopen(pidfile, "w");
|
||||
if (! fp)
|
||||
eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
|
||||
fclose(fp);
|
||||
|
||||
rc_service_value_set(svcname, "pidfile", pidfile);
|
||||
sprintf(name, "%i", respawn_delay);
|
||||
rc_service_value_set(svcname, "respawn_delay", name);
|
||||
sprintf(name, "%i", respawn_max);
|
||||
rc_service_value_set(svcname, "respawn_max", name);
|
||||
sprintf(name, "%i", respawn_period);
|
||||
rc_service_value_set(svcname, "respawn_period", name);
|
||||
child_pid = fork();
|
||||
if (child_pid == -1)
|
||||
eerrorx("%s: fork: %s", applet, strerror(errno));
|
||||
if (child_pid != 0)
|
||||
/* first parent process, do nothing. */
|
||||
exit(EXIT_SUCCESS);
|
||||
#ifdef TIOCNOTTY
|
||||
tty_fd = open("/dev/tty", O_RDWR);
|
||||
#endif
|
||||
devnull_fd = open("/dev/null", O_RDWR);
|
||||
child_pid = fork();
|
||||
if (child_pid == -1)
|
||||
eerrorx("%s: fork: %s", applet, strerror(errno));
|
||||
else if (child_pid != 0) {
|
||||
c = argv;
|
||||
x = 0;
|
||||
while (c && *c) {
|
||||
snprintf(name, sizeof(name), "argv_%-d",x);
|
||||
rc_service_value_set(svcname, name, *c);
|
||||
x++;
|
||||
c++;
|
||||
}
|
||||
sprintf(name, "%d", x);
|
||||
rc_service_value_set(svcname, "argc", name);
|
||||
rc_service_value_set(svcname, "exec", exec);
|
||||
supervisor(exec, argv);
|
||||
} else
|
||||
child_process(exec, argv);
|
||||
} else if (stop) {
|
||||
pid = get_pid(applet, pidfile);
|
||||
if (pid != -1) {
|
||||
i = kill(pid, SIGTERM);
|
||||
if (i != 0)
|
||||
/* We failed to send the signal */
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
/* wait for the supervisor to go down */
|
||||
while (kill(pid, 0) == 0) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1;
|
||||
nanosleep(&ts, NULL);
|
||||
ewarn("Unable to shut down the supervisor");
|
||||
else {
|
||||
/* wait for the supervisor to go down */
|
||||
while (kill(pid, 0) == 0) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1;
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -687,119 +913,4 @@ int main(int argc, char **argv)
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
pid = get_pid(applet, pidfile);
|
||||
if (pid != -1)
|
||||
if (kill(pid, 0) == 0)
|
||||
eerrorx("%s: %s is already running", applet, exec);
|
||||
|
||||
einfov("Detaching to start `%s'", exec);
|
||||
eindentv();
|
||||
|
||||
/* Remove existing pidfile */
|
||||
if (pidfile)
|
||||
unlink(pidfile);
|
||||
|
||||
/*
|
||||
* Make sure we can write a pid file
|
||||
*/
|
||||
fp = fopen(pidfile, "w");
|
||||
if (! fp)
|
||||
eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
|
||||
fclose(fp);
|
||||
|
||||
child_pid = fork();
|
||||
if (child_pid == -1)
|
||||
eerrorx("%s: fork: %s", applet, strerror(errno));
|
||||
|
||||
/* first parent process, do nothing. */
|
||||
if (child_pid != 0)
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
#ifdef TIOCNOTTY
|
||||
tty_fd = open("/dev/tty", O_RDWR);
|
||||
#endif
|
||||
devnull_fd = open("/dev/null", O_RDWR);
|
||||
child_pid = fork();
|
||||
if (child_pid == -1)
|
||||
eerrorx("%s: fork: %s", applet, strerror(errno));
|
||||
|
||||
if (child_pid != 0) {
|
||||
/* this is the supervisor */
|
||||
umask(numask);
|
||||
openlog(applet, LOG_PID, LOG_DAEMON);
|
||||
signal_setup(SIGTERM, handle_signal);
|
||||
|
||||
fp = fopen(pidfile, "w");
|
||||
if (! fp)
|
||||
eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
|
||||
fprintf(fp, "%d\n", getpid());
|
||||
fclose(fp);
|
||||
|
||||
if (svcname)
|
||||
rc_service_daemon_set(svcname, exec,
|
||||
(const char * const *) argv, pidfile, true);
|
||||
|
||||
/* remove the controlling tty */
|
||||
#ifdef TIOCNOTTY
|
||||
ioctl(tty_fd, TIOCNOTTY, 0);
|
||||
close(tty_fd);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Supervisor main loop
|
||||
*/
|
||||
i = 0;
|
||||
while (!exiting) {
|
||||
wait(&i);
|
||||
if (exiting) {
|
||||
signal_setup(SIGCHLD, SIG_IGN);
|
||||
syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid);
|
||||
nkilled = run_stop_schedule(applet, exec, NULL, child_pid,
|
||||
0, false, false, true);
|
||||
if (nkilled > 0)
|
||||
syslog(LOG_INFO, "killed %d processes", nkilled);
|
||||
} else {
|
||||
sleep(respawn_delay);
|
||||
if (respawn_max > 0 && respawn_period > 0) {
|
||||
respawn_now = time(NULL);
|
||||
if (first_spawn == 0)
|
||||
first_spawn = respawn_now;
|
||||
if (respawn_now - first_spawn > respawn_period) {
|
||||
respawn_count = 0;
|
||||
first_spawn = 0;
|
||||
} else
|
||||
respawn_count++;
|
||||
if (respawn_count >= respawn_max) {
|
||||
syslog(LOG_WARNING, "respawned \"%s\" too many times, "
|
||||
"exiting", exec);
|
||||
exiting = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (WIFEXITED(i))
|
||||
syslog(LOG_WARNING, "%s, pid %d, exited with return code %d",
|
||||
exec, child_pid, WEXITSTATUS(i));
|
||||
else if (WIFSIGNALED(i))
|
||||
syslog(LOG_WARNING, "%s, pid %d, terminated by signal %d",
|
||||
exec, child_pid, WTERMSIG(i));
|
||||
child_pid = fork();
|
||||
if (child_pid == -1)
|
||||
eerrorx("%s: fork: %s", applet, strerror(errno));
|
||||
if (child_pid == 0)
|
||||
child_process(exec, argv, svcname, respawn_count);
|
||||
}
|
||||
}
|
||||
|
||||
if (pidfile && exists(pidfile))
|
||||
unlink(pidfile);
|
||||
if (svcname) {
|
||||
rc_service_daemon_set(svcname, exec,
|
||||
(const char *const *)argv,
|
||||
pidfile, false);
|
||||
rc_service_mark(svcname, RC_SERVICE_STOPPED);
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
} else if (child_pid == 0)
|
||||
child_process(exec, argv, svcname, respawn_count);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user