Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a96ca1c96 | ||
|
|
934530914b | ||
|
|
b717625cd2 | ||
|
|
b475396134 | ||
|
|
e7b1d898ca | ||
|
|
5cd09a6f44 | ||
|
|
f3c70bf5b5 | ||
|
|
f5acc66db7 | ||
|
|
fdce4769f2 | ||
|
|
35b1996704 | ||
|
|
3c8e7ed255 | ||
|
|
acaed1f910 | ||
|
|
91109e31d8 | ||
|
|
2b6eeea01d | ||
|
|
a15de23e57 | ||
|
|
efa9ba485d | ||
| d4ddd72701 | |||
|
|
1e9af2cd42 | ||
|
|
3c05db74f6 | ||
|
|
edc54b0377 |
226
ChangeLog
226
ChangeLog
@@ -1,3 +1,155 @@
|
|||||||
|
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>
|
||||||
|
|
||||||
|
supervise-daemon: elevate some log messages to warnings
|
||||||
|
|
||||||
|
Prior to this change, we were logging unexpected terminations of daemons
|
||||||
|
we were supervising at the info level. This change moves the logs to
|
||||||
|
warnings.
|
||||||
|
|
||||||
|
commit 3c8e7ed255edb8df0d548d6ce514544d5422cbf0
|
||||||
|
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
|
||||||
|
version 0.34
|
||||||
|
|
||||||
|
commit acaed1f910a2a00fdd5b6aeab752c552075a7292
|
||||||
|
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
|
||||||
|
Update ChangeLog
|
||||||
|
|
||||||
|
commit 91109e31d81ecd48f5690ad6f63103fca545dec7
|
||||||
|
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
|
||||||
|
update news
|
||||||
|
|
||||||
|
commit 2b6eeea01d1c64d58929788f4bfa0758393885bf
|
||||||
|
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
|
||||||
|
man: remove service(8) man page
|
||||||
|
|
||||||
|
commit a15de23e5713d840d871c526b46050983dc6ea1e
|
||||||
|
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
|
||||||
|
typo fix
|
||||||
|
|
||||||
|
commit efa9ba485d9328f780f3e60dc18339c75974c6c6
|
||||||
|
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
|
||||||
|
init.d/sysfs.in: fix reference to RC_LIBEXECDIR
|
||||||
|
|
||||||
|
The sysfs init script referred to @LIBEXECDIR@ before this change, but
|
||||||
|
it is better to refer to RC_LIBEXECDIR so that we get rid of a sed
|
||||||
|
substitution.
|
||||||
|
|
||||||
|
commit d4ddd72701ff5533a1ba07b1da60806859c63d88
|
||||||
|
Author: Chris Cromer <chris@cromer.cl>
|
||||||
|
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
|
||||||
|
add option to make agetty startup quiet
|
||||||
|
|
||||||
|
This fixes #150
|
||||||
|
|
||||||
|
commit 1e9af2cd421423404ffe1491bd35af76c2885f1f
|
||||||
|
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
|
||||||
|
fix compiler warning
|
||||||
|
|
||||||
|
commit 3c05db74f6e733890e9035c183a774db3d512512
|
||||||
|
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
|
||||||
|
remove service binary
|
||||||
|
|
||||||
|
The service binary was just a synonym for rc-service, so use rc-service
|
||||||
|
instead of service. If you want a "service" binary, it should be
|
||||||
|
something that can determine which service manager you are running and
|
||||||
|
run the appropriate service manager commands.
|
||||||
|
|
||||||
|
commit edc54b03770d5f58d1a4969d06c28660003dfb04
|
||||||
|
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
|
||||||
|
version 0.33
|
||||||
|
|
||||||
|
commit 8e53a3fa8a33fb714064ddbe38bff2213fcf6837
|
||||||
|
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
|
|
||||||
|
Update ChangeLog
|
||||||
|
|
||||||
commit 7f3b41311119e3a96a15b0fb473b44f422e903e9
|
commit 7f3b41311119e3a96a15b0fb473b44f422e903e9
|
||||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
Author: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
||||||
@@ -1341,77 +1493,3 @@ Author: William Hubbs <w.d.hubbs@gmail.com>
|
|||||||
Commit: 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
|
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
|
|
||||||
|
|
||||||
commit c44c904a61418189c989e978b0237e5b161263ef
|
|
||||||
Author: Joe Maloney <jpm820@gmail.com>
|
|
||||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
|
||||||
|
|
||||||
init.d.misc/wpa_supplicant: find wireless interface for FreeBSD
|
|
||||||
|
|
||||||
This fixes #101.
|
|
||||||
|
|
||||||
commit 78146b0e14cb57dda8a3aed3d4f8d6b1db7a3c7e
|
|
||||||
Author: Sven Wegener <swegener@gentoo.org>
|
|
||||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
|
||||||
|
|
||||||
do_service: Initialize idx to 0
|
|
||||||
|
|
||||||
If index is not explicitly specified for service_started_daemon, it will
|
|
||||||
look for daemons by random index.
|
|
||||||
|
|
||||||
This fixes #100.
|
|
||||||
|
|
||||||
commit deaae7ab5c499191426cec81f6e803c972f0cca3
|
|
||||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
|
||||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
|
||||||
|
|
||||||
init.d/sysfs: load efivarfs module when booting in efi mode:1
|
|
||||||
|
|
||||||
The presence of /sys/firmware/efi is used to indicate that the system
|
|
||||||
was booted in efi mode.
|
|
||||||
|
|
||||||
commit 3d2c2f0b871944492036d04b0c220ccba1fa2dd5
|
|
||||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
|
||||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
|
||||||
|
|
||||||
init.d/sysfs: fix efivarfs module test
|
|
||||||
|
|
||||||
commit 6a0c033a64ce18056625cd37a94b9810dc5784e3
|
|
||||||
Author: William Hubbs <w.d.hubbs@gmail.com>
|
|
||||||
Commit: William Hubbs <w.d.hubbs@gmail.com>
|
|
||||||
|
|
||||||
init.d/sysfs: fix efivarfs handling
|
|
||||||
|
|
||||||
Separate loading the module, if it isn't built in or loaded, from
|
|
||||||
mounting the file system.
|
|
||||||
|
|
||||||
This also makes sure the warning about configuring the module in
|
|
||||||
/etc/conf.d/modules or building it in is displayed only if it is loaded
|
|
||||||
successfully.
|
|
||||||
|
|
||||||
X-Gentoo-Bug: 595836
|
|
||||||
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=595836
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
NAME= openrc
|
NAME= openrc
|
||||||
VERSION= 0.32
|
VERSION= 0.34.2
|
||||||
PKG= ${NAME}-${VERSION}
|
PKG= ${NAME}-${VERSION}
|
||||||
|
|||||||
9
NEWS.md
9
NEWS.md
@@ -3,6 +3,15 @@
|
|||||||
This file will contain a list of notable changes for each release. Note
|
This file will contain a list of notable changes for each release. Note
|
||||||
the information in this file is in reverse order.
|
the information in this file is in reverse order.
|
||||||
|
|
||||||
|
## OpenRC 0.33
|
||||||
|
|
||||||
|
This version removes the "service" binary which was just a copy of
|
||||||
|
"rc-service" provided for compatibility.
|
||||||
|
|
||||||
|
If you still need the "service" binary, as opposed to "rc-service", it is
|
||||||
|
recommended that you use something like Debian's init-system-helpers.
|
||||||
|
Otherwise, just use "rc-service" in place of "service".
|
||||||
|
|
||||||
## OpenRC 0.31
|
## OpenRC 0.31
|
||||||
|
|
||||||
This version adds support for Control Groups version 2, which is
|
This version adds support for Control Groups version 2, which is
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
# make agetty quiet
|
||||||
|
#quiet="yes"
|
||||||
|
|
||||||
# Set the baud rate of the terminal line
|
# Set the baud rate of the terminal line
|
||||||
#baud=""
|
#baud=""
|
||||||
|
|
||||||
|
|||||||
3
guide.md
3
guide.md
@@ -53,9 +53,6 @@ Calling `openrc` without any arguments will try to reset all services so
|
|||||||
that the current runlevel is satisfied; if you manually started apache it will be
|
that the current runlevel is satisfied; if you manually started apache it will be
|
||||||
stopped, and if squid died but is in the current runlevel it'll be restarted.
|
stopped, and if squid died but is in the current runlevel it'll be restarted.
|
||||||
|
|
||||||
There is a `service` helper that emulates the syntax seen on e.g. older Redhat
|
|
||||||
and Ubuntu (`service nginx start` etc.)
|
|
||||||
|
|
||||||
# Runlevels
|
# Runlevels
|
||||||
|
|
||||||
OpenRC has a concept of runlevels, similar to what sysvinit historically
|
OpenRC has a concept of runlevels, similar to what sysvinit historically
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ term_type="${term_type:-linux}"
|
|||||||
command=/sbin/agetty
|
command=/sbin/agetty
|
||||||
command_args_foreground="${agetty_options} ${port} ${baud} ${term_type}"
|
command_args_foreground="${agetty_options} ${port} ${baud} ${term_type}"
|
||||||
pidfile="/run/${RC_SVCNAME}.pid"
|
pidfile="/run/${RC_SVCNAME}.pid"
|
||||||
|
export EINFO_QUIET="${quiet:-yes}"
|
||||||
|
|
||||||
depend() {
|
depend() {
|
||||||
after local
|
after local
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
S#!@BINDIR@/openrc-run
|
#!@SBINDIR@/openrc-run
|
||||||
# Copyright (c) 2009-2015 The OpenRC Authors.
|
# Copyright (c) 2009-2015 The OpenRC Authors.
|
||||||
# See the Authors file at the top-level directory of this distribution and
|
# See the Authors file at the top-level directory of this distribution and
|
||||||
# https://github.com/OpenRC/openrc/blob/master/AUTHORS
|
# https://github.com/OpenRC/openrc/blob/master/AUTHORS
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ cgroup1_base()
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if ! mountinfo -q /sys/fs/cgroup/openrc; then
|
if ! mountinfo -q /sys/fs/cgroup/openrc; then
|
||||||
local agent="@LIBEXECDIR@/sh/cgroup-release-agent.sh"
|
local agent="${RC_LIBEXECDIR}/sh/cgroup-release-agent.sh"
|
||||||
mkdir /sys/fs/cgroup/openrc
|
mkdir /sys/fs/cgroup/openrc
|
||||||
mount -n -t cgroup \
|
mount -n -t cgroup \
|
||||||
-o none,${sysfs_opts},name=openrc,release_agent="$agent" \
|
-o none,${sysfs_opts},name=openrc,release_agent="$agent" \
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ MAN3= einfo.3 \
|
|||||||
rc_config.3 rc_deptree.3 rc_find_pids.3 rc_plugin_hook.3 \
|
rc_config.3 rc_deptree.3 rc_find_pids.3 rc_plugin_hook.3 \
|
||||||
rc_runlevel.3 rc_service.3 rc_stringlist.3
|
rc_runlevel.3 rc_service.3 rc_stringlist.3
|
||||||
MAN8= rc-service.8 rc-status.8 rc-update.8 openrc.8 openrc-run.8 \
|
MAN8= rc-service.8 rc-status.8 rc-update.8 openrc.8 openrc-run.8 \
|
||||||
service.8 start-stop-daemon.8 supervise-daemon.8
|
start-stop-daemon.8 supervise-daemon.8
|
||||||
|
|
||||||
ifeq (${OS},Linux)
|
ifeq (${OS},Linux)
|
||||||
MAN8 += rc-sstat.8 openrc-init.8 openrc-shutdown.8
|
MAN8 += rc-sstat.8 openrc-init.8 openrc-shutdown.8
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
.so rc-service.8
|
|
||||||
@@ -56,7 +56,50 @@ supervise_stop()
|
|||||||
eend $? "Failed to stop ${name:-$RC_SVCNAME}"
|
eend $? "Failed to stop ${name:-$RC_SVCNAME}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_check_supervised()
|
||||||
|
{
|
||||||
|
[ "$RC_UNAME" != Linux ] && return 0
|
||||||
|
local child_pid="$(service_get_value "child_pid")"
|
||||||
|
local pid="$(cat ${pidfile})"
|
||||||
|
if [ -n "${child_pid}" ]; then
|
||||||
|
if ! [ -e "/proc/${pid}" ] && [ -e "/proc/${child_pid}" ]; then
|
||||||
|
if [ -e "/proc/self/ns/pid" ] && [ -e "/proc/${child_pid}/ns/pid" ]; then
|
||||||
|
local n1 n2
|
||||||
|
n1=$(readlink "/proc/self/ns/pid")
|
||||||
|
n2=$(readlink "/proc/${child_pid}/ns/pid")
|
||||||
|
if [ "${n1}" = "${n2}" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
supervise_status()
|
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_filter(void);
|
||||||
void env_config(void);
|
void env_config(void);
|
||||||
int signal_setup(int sig, void (*handler)(int));
|
int signal_setup(int sig, void (*handler)(int));
|
||||||
|
int signal_setup_restart(int sig, void (*handler)(int));
|
||||||
int svc_lock(const char *);
|
int svc_lock(const char *);
|
||||||
int svc_unlock(const char *, int);
|
int svc_unlock(const char *, int);
|
||||||
pid_t exec_service(const char *, const char *);
|
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;
|
DIR *procdir;
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
int rc;
|
||||||
bool container_pid = false;
|
bool container_pid = false;
|
||||||
bool openvz_host = false;
|
bool openvz_host = false;
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
|
char my_ns[30];
|
||||||
|
char proc_ns[30];
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
pid_t p;
|
pid_t p;
|
||||||
char buffer[PATH_MAX];
|
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) {
|
while ((entry = readdir(procdir)) != NULL) {
|
||||||
if (sscanf(entry->d_name, "%d", &p) != 1)
|
if (sscanf(entry->d_name, "%d", &p) != 1)
|
||||||
continue;
|
continue;
|
||||||
@@ -138,6 +149,14 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
|
|||||||
continue;
|
continue;
|
||||||
if (pid != 0 && pid != p)
|
if (pid != 0 && pid != p)
|
||||||
continue;
|
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) {
|
if (uid) {
|
||||||
snprintf(buffer, sizeof(buffer), "/proc/%d", p);
|
snprintf(buffer, sizeof(buffer), "/proc/%d", p);
|
||||||
if (stat(buffer, &sb) != 0 || sb.st_uid != uid)
|
if (stat(buffer, &sb) != 0 || sb.st_uid != uid)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ SBINDIR= ${PREFIX}/sbin
|
|||||||
LINKDIR= ${LIBEXECDIR}
|
LINKDIR= ${LIBEXECDIR}
|
||||||
|
|
||||||
BINPROGS= rc-status
|
BINPROGS= rc-status
|
||||||
SBINPROGS = openrc openrc-run rc rc-service rc-update runscript service \
|
SBINPROGS = openrc openrc-run rc rc-service rc-update runscript \
|
||||||
start-stop-daemon supervise-daemon
|
start-stop-daemon supervise-daemon
|
||||||
RC_BINPROGS= einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \
|
RC_BINPROGS= einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \
|
||||||
eindent eoutdent esyslog eval_ecolors ewaitfile \
|
eindent eoutdent esyslog eval_ecolors ewaitfile \
|
||||||
@@ -150,7 +150,7 @@ rc-depend: rc-depend.o _usage.o rc-misc.o
|
|||||||
rc-status: rc-status.o _usage.o rc-misc.o
|
rc-status: rc-status.o _usage.o rc-misc.o
|
||||||
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
|
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
|
||||||
|
|
||||||
rc-service service: rc-service.o _usage.o rc-misc.o
|
rc-service: rc-service.o _usage.o rc-misc.o
|
||||||
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
|
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
|
||||||
|
|
||||||
rc-update: rc-update.o _usage.o rc-misc.o
|
rc-update: rc-update.o _usage.o rc-misc.o
|
||||||
|
|||||||
@@ -217,6 +217,18 @@ signal_setup(int sig, void (*handler)(int))
|
|||||||
return sigaction(sig, &sa, NULL);
|
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
|
int
|
||||||
svc_lock(const char *applet)
|
svc_lock(const char *applet)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -408,11 +408,12 @@ int run_stop_schedule(const char *applet,
|
|||||||
|
|
||||||
if (progressed)
|
if (progressed)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
if (! quiet)
|
if (! quiet) {
|
||||||
if (nrunning == 1)
|
if (nrunning == 1)
|
||||||
eerror("%s: %d process refused to stop", applet, nrunning);
|
eerror("%s: %d process refused to stop", applet, nrunning);
|
||||||
else
|
else
|
||||||
eerror("%s: %d process(es) refused to stop", applet, nrunning);
|
eerror("%s: %d process(es) refused to stop", applet, nrunning);
|
||||||
|
}
|
||||||
|
|
||||||
return -nrunning;
|
return -nrunning;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ static struct pam_conv conv = { NULL, NULL};
|
|||||||
|
|
||||||
const char *applet = NULL;
|
const char *applet = NULL;
|
||||||
const char *extraopts = 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;
|
getoptstring_COMMON;
|
||||||
const struct option longopts[] = {
|
const struct option longopts[] = {
|
||||||
{ "respawn-delay", 1, NULL, 'D'},
|
{ "respawn-delay", 1, NULL, 'D'},
|
||||||
@@ -87,6 +87,7 @@ const struct option longopts[] = {
|
|||||||
{ "user", 1, NULL, 'u'},
|
{ "user", 1, NULL, 'u'},
|
||||||
{ "stdout", 1, NULL, '1'},
|
{ "stdout", 1, NULL, '1'},
|
||||||
{ "stderr", 1, NULL, '2'},
|
{ "stderr", 1, NULL, '2'},
|
||||||
|
{ "reexec", 0, NULL, '3'},
|
||||||
longopts_COMMON
|
longopts_COMMON
|
||||||
};
|
};
|
||||||
const char * const longopts_help[] = {
|
const char * const longopts_help[] = {
|
||||||
@@ -107,6 +108,7 @@ const char * const longopts_help[] = {
|
|||||||
"Change the process user",
|
"Change the process user",
|
||||||
"Redirect stdout to file",
|
"Redirect stdout to file",
|
||||||
"Redirect stderr to file",
|
"Redirect stderr to file",
|
||||||
|
"reexec (used internally)",
|
||||||
longopts_help_COMMON
|
longopts_help_COMMON
|
||||||
};
|
};
|
||||||
const char *usagestring = NULL;
|
const char *usagestring = NULL;
|
||||||
@@ -127,6 +129,13 @@ static bool exiting = false;
|
|||||||
#ifdef TIOCNOTTY
|
#ifdef TIOCNOTTY
|
||||||
static int tty_fd = -1;
|
static int tty_fd = -1;
|
||||||
#endif
|
#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;
|
extern char **environ;
|
||||||
|
|
||||||
@@ -150,8 +159,71 @@ static void cleanup(void)
|
|||||||
free(changeuser);
|
free(changeuser);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void child_process(char *exec, char **argv, char *svcname,
|
static void re_exec(void)
|
||||||
int start_count)
|
{
|
||||||
|
syslog(LOG_WARNING, "Re-executing supervise-daemon");
|
||||||
|
execlp("supervise-daemon", "supervise-daemon", "--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_STRINGLIST *env_list;
|
||||||
RC_STRING *env;
|
RC_STRING *env;
|
||||||
@@ -176,11 +248,13 @@ static void child_process(char *exec, char **argv, char *svcname,
|
|||||||
setsid();
|
setsid();
|
||||||
|
|
||||||
if (svcname) {
|
if (svcname) {
|
||||||
start_time = time(NULL);
|
start_time = time(NULL);
|
||||||
from_time_t(start_time_string, start_time);
|
from_time_t(start_time_string, start_time);
|
||||||
rc_service_value_set(svcname, "start_time", start_time_string);
|
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);
|
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) {
|
if (nicelevel) {
|
||||||
@@ -323,7 +397,7 @@ sprintf(start_count_string, "%i", start_count);
|
|||||||
|
|
||||||
*cmdline = '\0';
|
*cmdline = '\0';
|
||||||
c = argv;
|
c = argv;
|
||||||
while (*c) {
|
while (c && *c) {
|
||||||
strcat(cmdline, *c);
|
strcat(cmdline, *c);
|
||||||
strcat(cmdline, " ");
|
strcat(cmdline, " ");
|
||||||
c++;
|
c++;
|
||||||
@@ -338,108 +412,154 @@ sprintf(start_count_string, "%i", start_count);
|
|||||||
eerrorx("%s: failed to exec `%s': %s", applet, exec,strerror(errno));
|
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;
|
FILE *fp;
|
||||||
char signame[10] = { '\0' };
|
int i;
|
||||||
|
int nkilled;
|
||||||
|
time_t respawn_now= 0;
|
||||||
|
time_t first_spawn= 0;
|
||||||
|
|
||||||
switch (sig) {
|
openlog(applet, LOG_PID, LOG_DAEMON);
|
||||||
case SIGINT:
|
#ifndef RC_DEBUG
|
||||||
snprintf(signame, sizeof(signame), "SIGINT");
|
signal_setup_restart(SIGHUP, handle_signal);
|
||||||
break;
|
signal_setup_restart(SIGINT, handle_signal);
|
||||||
case SIGTERM:
|
signal_setup_restart(SIGQUIT, handle_signal);
|
||||||
snprintf(signame, sizeof(signame), "SIGTERM");
|
signal_setup_restart(SIGILL, handle_signal);
|
||||||
break;
|
signal_setup_restart(SIGABRT, handle_signal);
|
||||||
case SIGQUIT:
|
signal_setup_restart(SIGFPE, handle_signal);
|
||||||
snprintf(signame, sizeof(signame), "SIGQUIT");
|
signal_setup_restart(SIGSEGV, handle_signal);
|
||||||
break;
|
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) {
|
if (pidfile && exists(pidfile))
|
||||||
syslog(LOG_INFO, "%s: caught signal %s, exiting", applet, signame);
|
unlink(pidfile);
|
||||||
exiting = true;
|
if (svcname) {
|
||||||
} else
|
rc_service_daemon_set(svcname, exec, (const char *const *)argv,
|
||||||
syslog(LOG_INFO, "%s: caught unknown signal %d", applet, sig);
|
pidfile, false);
|
||||||
|
rc_service_mark(svcname, RC_SERVICE_STOPPED);
|
||||||
/* 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 (!ppath) {
|
exit(EXIT_SUCCESS);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int opt;
|
int opt;
|
||||||
|
char **c;
|
||||||
|
int x;
|
||||||
bool start = false;
|
bool start = false;
|
||||||
bool stop = false;
|
bool stop = false;
|
||||||
|
bool reexec = false;
|
||||||
char *exec = NULL;
|
char *exec = NULL;
|
||||||
char *pidfile = NULL;
|
|
||||||
char *retry = NULL;
|
char *retry = NULL;
|
||||||
int nkilled;
|
|
||||||
int sig = SIGTERM;
|
int sig = SIGTERM;
|
||||||
char *home = NULL;
|
char *home = NULL;
|
||||||
int tid = 0;
|
int tid = 0;
|
||||||
pid_t child_pid, pid;
|
pid_t pid;
|
||||||
char *svcname = getenv("RC_SVCNAME");
|
|
||||||
char *tmp;
|
char *tmp;
|
||||||
char *p;
|
char *p;
|
||||||
char *token;
|
char *token;
|
||||||
int i;
|
int i;
|
||||||
int n;
|
int n;
|
||||||
char exec_file[PATH_MAX];
|
char exec_file[PATH_MAX];
|
||||||
int respawn_count = 0;
|
char name[PATH_MAX];
|
||||||
int respawn_delay = 0;
|
|
||||||
int respawn_max = 10;
|
|
||||||
int respawn_period = 5;
|
|
||||||
time_t respawn_now= 0;
|
|
||||||
time_t first_spawn= 0;
|
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
struct group *gr;
|
struct group *gr;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
mode_t numask = 022;
|
mode_t numask = 022;
|
||||||
|
int child_argc = 0;
|
||||||
|
char **child_argv = NULL;
|
||||||
|
char *str = NULL;
|
||||||
|
|
||||||
applet = basename_c(argv[0]);
|
applet = basename_c(argv[0]);
|
||||||
atexit(cleanup);
|
atexit(cleanup);
|
||||||
|
svcname = getenv("RC_SVCNAME");
|
||||||
|
|
||||||
if ((tmp = getenv("SSD_NICELEVEL")))
|
if ((tmp = getenv("SSD_NICELEVEL")))
|
||||||
if (sscanf(tmp, "%d", &nicelevel) != 1)
|
if (sscanf(tmp, "%d", &nicelevel) != 1)
|
||||||
@@ -493,8 +613,8 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
case 'P': /* --respawn-period time */
|
case 'P': /* --respawn-period time */
|
||||||
n = sscanf(optarg, "%d", &respawn_period);
|
n = sscanf(optarg, "%d", &respawn_period);
|
||||||
if (n != 1 || respawn_delay < 1)
|
if (n != 1 || respawn_period < 1)
|
||||||
eerrorx("Invalid respawn-delay value '%s'", optarg);
|
eerrorx("Invalid respawn-period value '%s'", optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'S': /* --start */
|
case 'S': /* --start */
|
||||||
@@ -590,11 +710,14 @@ int main(int argc, char **argv)
|
|||||||
case '2': /* --stderr /path/to/stderr.logfile */
|
case '2': /* --stderr /path/to/stderr.logfile */
|
||||||
redirect_stderr = optarg;
|
redirect_stderr = optarg;
|
||||||
break;
|
break;
|
||||||
|
case '3': /* --reexec */
|
||||||
|
reexec = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case_RC_COMMON_GETOPT
|
case_RC_COMMON_GETOPT
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pidfile)
|
if (!pidfile && !reexec)
|
||||||
eerrorx("%s: --pidfile must be specified", applet);
|
eerrorx("%s: --pidfile must be specified", applet);
|
||||||
|
|
||||||
endpwent();
|
endpwent();
|
||||||
@@ -602,74 +725,158 @@ int main(int argc, char **argv)
|
|||||||
argv += optind;
|
argv += optind;
|
||||||
exec = *argv;
|
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 ~ */
|
/* Expand ~ */
|
||||||
if (ch_dir && *ch_dir == '~')
|
if (ch_dir && *ch_dir == '~')
|
||||||
ch_dir = expand_home(home, ch_dir);
|
ch_dir = expand_home(home, ch_dir);
|
||||||
if (ch_root && *ch_root == '~')
|
if (ch_root && *ch_root == '~')
|
||||||
ch_root = expand_home(home, 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 */
|
umask(numask);
|
||||||
if (*exec == '/' || *exec == '.') {
|
|
||||||
/* Full or relative path */
|
if (reexec) {
|
||||||
if (ch_root)
|
str = rc_service_value_get(svcname, "argc");
|
||||||
snprintf(exec_file, sizeof(exec_file),
|
sscanf(str, "%d", &child_argc);
|
||||||
"%s/%s", ch_root, exec);
|
child_argv = xmalloc((child_argc + 1) * sizeof(char *));
|
||||||
else
|
memset(child_argv, 0, (child_argc + 1) * sizeof(char *));
|
||||||
snprintf(exec_file, sizeof(exec_file),
|
for (x = 0; x < child_argc; x++) {
|
||||||
"%s", exec);
|
sprintf(name, "argv_%d", x);
|
||||||
} else {
|
str = rc_service_value_get(svcname, name);
|
||||||
/* Something in $PATH */
|
child_argv[x] = str;
|
||||||
p = tmp = xstrdup(getenv("PATH"));
|
}
|
||||||
*exec_file = '\0';
|
free(str);
|
||||||
while ((token = strsep(&p, ":"))) {
|
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)
|
if (ch_root)
|
||||||
snprintf(exec_file, sizeof(exec_file),
|
snprintf(exec_file, sizeof(exec_file),
|
||||||
"%s/%s/%s",
|
"%s/%s", ch_root, exec);
|
||||||
ch_root, token, exec);
|
|
||||||
else
|
else
|
||||||
snprintf(exec_file, sizeof(exec_file),
|
snprintf(exec_file, sizeof(exec_file),
|
||||||
"%s/%s", token, exec);
|
"%s", exec);
|
||||||
if (exists(exec_file))
|
} else {
|
||||||
break;
|
/* Something in $PATH */
|
||||||
|
p = tmp = xstrdup(getenv("PATH"));
|
||||||
*exec_file = '\0';
|
*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 ( !exists(exec_file))
|
||||||
}
|
eerrorx("%s: %s does not exist", applet,
|
||||||
}
|
*exec_file ? exec_file : exec);
|
||||||
if (start && !exists(exec_file))
|
} else
|
||||||
eerrorx("%s: %s does not exist", applet,
|
eerrorx("%s: nothing to start", applet);
|
||||||
*exec_file ? exec_file : exec);
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
/* 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);
|
pid = get_pid(applet, pidfile);
|
||||||
if (pid != -1) {
|
if (pid != -1) {
|
||||||
i = kill(pid, SIGTERM);
|
i = kill(pid, SIGTERM);
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
/* We failed to send the signal */
|
/* We failed to send the signal */
|
||||||
exit(EXIT_FAILURE);
|
ewarn("Unable to shut down the supervisor");
|
||||||
|
else {
|
||||||
/* wait for the supervisor to go down */
|
/* wait for the supervisor to go down */
|
||||||
while (kill(pid, 0) == 0) {
|
while (kill(pid, 0) == 0) {
|
||||||
ts.tv_sec = 0;
|
ts.tv_sec = 0;
|
||||||
ts.tv_nsec = 1;
|
ts.tv_nsec = 1;
|
||||||
nanosleep(&ts, NULL);
|
nanosleep(&ts, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -687,119 +894,4 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
exit(EXIT_SUCCESS);
|
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_INFO, "respawned \"%s\" too many times, "
|
|
||||||
"exiting", exec);
|
|
||||||
exiting = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (WIFEXITED(i))
|
|
||||||
syslog(LOG_INFO, "%s, pid %d, exited with return code %d",
|
|
||||||
exec, child_pid, WEXITSTATUS(i));
|
|
||||||
else if (WIFSIGNALED(i))
|
|
||||||
syslog(LOG_INFO, "%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