Compare commits

..

78 Commits
0.37 ... 0.40.x

Author SHA1 Message Date
William Hubbs
4a3454966a Update ChangeLog 2018-12-21 12:24:18 -06:00
William Hubbs
63e40f31bf fix compiler warnings 2018-12-21 12:20:35 -06:00
William Hubbs
e43ee29eb4 supervise-daemon: do not use the exec_service() function
In order to run healthcheck() and the unhealthy() function, add an
exec_command call to the supervisor.
Another difference is This function also logs errors instead of
attempting to display them.

This is for #271.
2018-12-21 12:20:35 -06:00
William Hubbs
a3555b1442 Add debug logging to start-stop-daemon and rc-supervisor
This will make it easier to track down why the supervisor intermittently
hangs after it runs for a long time.
2018-12-21 12:20:35 -06:00
William Hubbs
eb863156fb version 0.40.3 2018-12-21 12:20:12 -06:00
William Hubbs
ac76b24b85 Update ChangeLog 2018-12-06 17:40:06 -06:00
William Hubbs
b8e57c693a init.d/agetty: set default respawn period to 60 seconds
Without a respawn period setting, the supervisor will give up on
respawning agetty after it is respawned respawn_max times. For most
daemons giving up like this is reasonable, but not for agettys. Agettys
should always be respawned unless they are respawning too fafst,.

If an agetty is respawning faster than 10 times in 60 seconds, this
seems to be too fast.
2018-12-06 16:56:20 -06:00
William Hubbs
5df12e2414 supervise-daemon: fix busy loop
This fixes #264.
2018-12-06 16:56:20 -06:00
William Hubbs
461df0c78b version 0.40.2 2018-12-06 16:55:51 -06:00
William Hubbs
cefae65392 Update ChangeLog 2018-12-04 17:27:46 -06:00
Alexander Zubkov
69fbd12993 supervise-daemon: redirect std{in,out,err} to /dev/null after demonizing
This fixes #239.
2018-12-04 17:23:27 -06:00
William Hubbs
4aa5686d90 version 0.40.1 2018-12-04 17:21:55 -06:00
William Hubbs
ab6c8d56f1 Update ChangeLog 2018-12-03 15:56:19 -06:00
Austin English
fb4dd351c7 misc: make checks always fatal
This fixes #263.
2018-12-03 15:26:42 -06:00
Austin English
10dc65cc46 src/rc/supervise-daemon.c: fix style issue
This is for #263.
2018-12-03 15:26:20 -06:00
William Hubbs
9a2115f762 rc-status: show status for supervised services instead of a list 2018-12-03 15:16:17 -06:00
William Hubbs
eeba6df476 Update supervise-daemon man page 2018-12-03 13:08:25 -06:00
William Hubbs
ac42e81a64 supervise-daemon.sh: drop the unused stopsig variable 2018-12-03 12:43:12 -06:00
William Hubbs
af70862a7a supervise-daemon: use a default pid file if one is not specified
Since the pid file is internal to us, start moving toward deprecating it
by not requiring the user to specify it.
In the next release, I plan on working on code to start phasing out the
use of a pid file if this is possible.
2018-12-03 12:41:29 -06:00
William Hubbs
fa6611b5af rc-status: add --supervised option to show supervised services 2018-12-02 18:33:25 -06:00
William Hubbs
db01442580 rc-status: show failed services as failed 2018-12-02 18:33:25 -06:00
William Hubbs
ebf79db79e supervise-daemon: mark a service failed if it respawns too many times 2018-12-02 18:33:25 -06:00
William Hubbs
1b5a3b4ef4 supervise-daemon: make respawn-max and respawn-period independent settings 2018-12-02 18:33:25 -06:00
William Hubbs
77262c359c supervise-daemon: add support for a fifo
This will allow us to signal the daemon we are supervising as well as
send other commands to the supervisor in the future.

This fixes #227.
2018-12-02 18:33:25 -06:00
William Hubbs
7f23e0461d supervise-daemon: rework signal handling and main loop
This is needed in preparation for adding support for a fifo to allow us
to communicate with the supervisor to ask it to signal the child it is
supervising.
2018-12-02 18:33:25 -06:00
William Hubbs
ff4af908a5 Revert "checkpath: use O_PATH when available"
This reverts commit 2af0cedd59.

After speaking with Luis Ressel on the Gentoo selinux team, I am reverting
this commit for the following reasons:

- Luis told me that he feels this is not the solution we need to address
  the concern with checkpath; I will be working with him on another
  solution.

- There are concerns about the way the path variable was handled
  and the assert() call.
  The path variable should be dynamically allocated using xasprintf
  instead of defining a length at compile time. This would eliminate the
  need for the assert() call.

- It introduces the definition of _GNU_SOURCE which makes it
  easier to introduce portability concerns in the future (see #262).
2018-12-02 16:08:42 -06:00
Mike Gilbert
2af0cedd59 checkpath: use O_PATH when available
This avoids opening directories/files with read permission, which is
sometimes rejected by selinux policy.

Bug: https://bugs.gentoo.org/667122
2018-12-01 21:43:18 -08:00
William Hubbs
ee41e444ad rc.conf: typo fix
X-Gentoo-Bug: 670874
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=670874
2018-11-29 08:19:56 -06:00
William Hubbs
b7828651ba supervise-daemon: fix type of exiting flag 2018-11-28 16:06:07 -06:00
Austin English
e96f7d5658 src/tests/runtests.sh: add a FATAL_CHECKS variable to make whitespace/etc. fatal 2018-11-27 21:22:29 -05:00
Austin English
28b73fc524 src/rc/openrc-shutdown.c: fix style 2018-11-27 21:22:29 -05:00
Austin English
7a00c63420 fix misc whitespace issues 2018-11-27 21:22:29 -05:00
Austin English
f4597c546a give TravisCI a try 2018-11-27 21:22:29 -05:00
Austin English
e10afc8e75 sh/functions.sh.in: return a different value for invalid input in yesno() 2018-11-18 13:22:59 -05:00
William Hubbs
0f704402a2 supervise-daemon: make the pidfile an implementation detail
The pidfile of the supervisor doesn't need to be adjustable by the
service script. It is only used so the supervisor can stop itself when
the --stop option is used.
2018-11-15 14:15:15 -06:00
William Hubbs
2504a2c25b Do not complain if interrupted by a signal
In start-stop-daemon and rc-schedules, we were printing out a warning if
the nanosleep call was interrupted by a signal, but we did not treat
this as an error situation other than displaying the message, so there
is no need for the message.
2018-11-15 14:03:06 -06:00
William Hubbs
7eb3975543 Create save-keymaps and save-ktermencoding services
These services represent the parts of the keymaps and termencoding
services which saved the settings back to the root file system so they
can be loaded very early in the boot process.
These are needed to allow keymaps and termencoding to run earlier in the
boot sequence.

X-Gentoo-Bug: 446018
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=446018
2018-11-07 08:55:44 -06:00
William Hubbs
60e60dc9bb supervise-daemon.sh: drop invalid --signal switch
This fixes #230.
2018-11-06 10:54:02 -06:00
William Hubbs
008c9d0036 supervise-daemon: reap zombies
We need to make sure to reap zombies so that we can shut down
successfully.

Fixes #252.
Possibly related to #250.
2018-11-05 21:35:00 -06:00
William Hubbs
025c9693cc rc-service: fix help output 2018-11-05 11:39:39 -06:00
William Hubbs
ee3c4afdb7 openrc-init: add SELinux support
This is for #173.
2018-11-02 18:22:11 -05:00
William Hubbs
e2416d0893 openrc-shutdown: do not require a time for -w switch
X-Gentoo-Bug: 669500
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=669500
2018-10-24 15:24:40 -05:00
William Hubbs
a2bcfeb428 version 0.40 2018-10-24 15:18:10 -05:00
William Hubbs
53f7afd3b3 Update ChangeLog 2018-10-23 17:14:01 -05:00
William Hubbs
75e9b66f6f news.md: add information about the modules service changes 2018-10-23 16:59:20 -05:00
William Hubbs
d70b1c55b6 modules: Add --first-time switch to modprobe commands
On Linux, kernel modules should be loaded once during boot, either in an
initramfs or by this service.

This does not change anything other than printing out messages if a
module is loaded more than once.

X-Gentoo-Bug: 659530
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=659530
2018-10-23 16:47:37 -05:00
William Hubbs
c1e582586d supervise-daemon: add health checks
Health checks are a way to monitor a service and make sure it stays
healthy.

If a service is not healthy, it will be automatically restarted after
running the unhealthy() function to clean up.
2018-10-23 13:38:14 -05:00
William Hubbs
7a75bfb00c news.md: add note about scheduled shutdown 2018-10-23 13:34:08 -05:00
William Hubbs
aacf841de4 supervise-daemon-guide.md: re-format and add more variables 2018-10-22 17:49:25 -05:00
William Hubbs
3f918161aa openrc-shutdown: Add scheduled shutdown and the ability to cancel a shutdown
You can now schedule a shutdown for a certain time or a cpecific number
of minutes into the future.

When a shutdown is running, you can now cancel it with ^c from the
keyboard or by running "openrc-shutdown -c" from another shell.
2018-10-18 17:56:36 -05:00
Zac Medico
710c874e6e supervise-daemon: fix respawn_max off by one
Fix the comparison between respawn_count and respawn_max so that
respawn_max = 1 will allow for one respawn. Since respawn_count is
incremented before the comparison, use a 'greater than' comparison
so that respawn will be triggered when respawn_count is equal to
respawn_max.

Fixes: https://github.com/OpenRC/openrc/issues/247
Fixes: https://github.com/OpenRC/openrc/issues/248
2018-10-15 11:50:42 -05:00
Austin English
07908be090 misc: style fixups 2018-10-13 12:53:54 -04:00
Austin English
02af093043 misc: whitespace fixes 2018-10-13 12:53:54 -04:00
William Hubbs
67e2d6033d Complete implementation of forever timeout value in stop schedules 2018-10-09 11:34:52 -05:00
William Hubbs
eca4357892 supervise-daemon: use nanosleep() instead of sleep()
We will be using sigalrm in this process for health checking, and
sigalrm cannot be used with sleep() safely.
2018-10-06 12:51:04 -05:00
William Hubbs
7ee3e5b2d6 openrc-init: convert sleep() call to nanosleep()
Nanosleep is the safer call to use in case we need to use alarms
eventually.
2018-10-06 12:49:44 -05:00
William Hubbs
7cb8d94323 Stop mounting efivarfs read-only
We do not need to do this any longer since all supported linux kernels
make efivarfs immutable and the tools that manipulate it are aware of
this feature.

This fixes https://github.com/openrc/openrc/issues/238.
2018-08-14 10:21:27 -05:00
Zac Medico
84ed570eae librc: fix EACCES errno false-positive crash
Use errno != EACCES to fix false-positive for non-root users
with grsecurity kernels.

Fixes: 37e2944272 ("librc: Add check for crashed state")
This fixes #237
2018-08-06 17:39:52 -05:00
William Hubbs
2eea73bfd5 rc-functions.sh: Remove addon support
This is an old relic from Gentoo baselayout-1.x which should not be used
any longer.
2018-07-09 19:44:40 -05:00
William Hubbs
a571a42421 modules: remove the ability to rename modules on the fly
Kmod doesn't support the -o switch, so if you have been using this your
module loads have been failing.
2018-06-29 15:29:46 -05:00
Holger Hoffstätte
79648ac1c6 rc-status: initialize uptime pointer to prevent memory corruption
This fixes #231.
2018-06-29 08:49:13 -05:00
William Hubbs
02af762e83 version 0.39 2018-06-28 13:32:19 -05:00
William Hubbs
01c34c28e6 Update ChangeLog 2018-06-28 13:02:42 -05:00
William Hubbs
56ddda54b5 supervise-daemon.c: clean up memory leaks 2018-06-27 17:37:11 -05:00
William Hubbs
3a803b3135 librc-daemon.c: fix memory leaks 2018-06-27 12:06:19 -05:00
William Hubbs
72df51e17b librc-daemon: convert most snprintf calls to xasprintf 2018-06-22 15:41:25 -05:00
William Hubbs
b2f5531194 librc-misc: convert snprintf calls to xasprintf 2018-06-20 17:45:01 -05:00
William Hubbs
19bf49a710 libeinfo: convert remaining snprintf calls to xasprintf 2018-06-20 12:36:51 -05:00
William Hubbs
64354831da openrc: convert snprintf calls to xasprintf 2018-06-20 09:37:20 -05:00
William Hubbs
e14edd765f supervise-daemon: convert snprintf calls to xasprintf 2018-06-19 17:57:10 -05:00
William Hubbs
f9d41243d8 start-stop-daemon: convert snprintf calls to xasprintf 2018-06-19 17:46:12 -05:00
William Hubbs
be7ad06d4a rc-status: convert snprintf calls to xasprintf 2018-06-19 17:06:33 -05:00
William Hubbs
a616516895 rc-status: fix gcc 7 warnings 2018-06-19 16:18:48 -05:00
William Hubbs
04721ece03 start-stop-daemon: fix gcc 7 warnings 2018-06-19 15:32:10 -05:00
William Hubbs
c7e8f1133a checkpath: fix gcc 7 warnings 2018-06-19 14:01:54 -05:00
William Hubbs
47e4bfae57 fix gcc 7 warnings in pipe routines 2018-06-19 13:59:16 -05:00
William Hubbs
8a945194af libeinfo: clean up gcc 7 compiler warnings 2018-06-19 13:52:40 -05:00
William Hubbs
aa4a004c29 version 0.38 2018-06-17 12:45:51 -05:00
49 changed files with 1799 additions and 1260 deletions

14
.travis.yml Normal file
View File

@@ -0,0 +1,14 @@
# Travis build integration.
# https://docs.travis-ci.com/
language: c
os:
- linux
compiler:
- gcc
- clang
script:
- ./test/travis.sh

1521
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,3 @@
NAME= openrc
VERSION= 0.37
VERSION= 0.40.3
PKG= ${NAME}-${VERSION}

41
NEWS.md
View File

@@ -4,6 +4,47 @@ OpenRC NEWS
This file will contain a list of notable changes for each release. Note
the information in this file is in reverse order.
## OpenRC 0.40
In this version, the keymaps and termencoding services on Linux needed
to be modified so they do not write to the root file system. This was
done so they can run earlier in the boot sequence. AS a result, you will
need to add save-termencoding and save-keymaps to your boot runlevel.
This can be done as follows:
```
# rc-update add save-keymaps boot
# rc-update add save-termencoding boot
```
## OpenRC 0.39
This version removes the support for addons.
The only place I know that this was used was Gentoo Baselayout 1.x, so
it shouldn't affect anyone since baselayout-1 has been dead for a few
years.
Since all supported Linux kernel versions now make efivarfs immutable
and all of the tools that access efivarfs are aware of this, we no
longer mount efivarfs read-only. See the following github issue for more
information:
https://github.com/openrc/openrc/issues/238
This version adds timed shutdown and cancelation of shutdown to
openrc-shutdown. Shutdowns can now be delayed for a certain amount of
time or scheduled for an exact time.
supervise-daemon supports health checks, which are a periodic way to make sure a
service is healthy. For more information on setting this up, please see
supervise-daemon-guide.md.
The --first-time switch has been added to all modprobe commands in the
modules service. This means that, on Linux, you will see failures if a
module was loaded by an initramfs or device manager before this service
runs. These messages are harmless, but to clean them up, you should adjust your
modules autoload configuration.
## OpenRC 0.37
start-stop-daemon now supports logging stdout and stderr of daemons to

View File

@@ -8,11 +8,6 @@
#modules_2="ipv6"
#modules="ohci1394"
# Linux users can give modules a different name when they load - the new name
# will also be used to pick arguments below.
# This is not supported on FreeBSD.
#modules="dummy:dummy1"
# Linux users can give the modules some arguments if needed, per version
# if necessary.
# Again, the most specific versioned variable will take precedence.

View File

@@ -230,7 +230,7 @@ rc_tty_number=12
# The following setting turns on the memory.use_hierarchy setting in the
# root memory cgroup for cgroups v1.
# It must be set to yes in this file if you want this functionality.
#rc_cggroup_memory_use_hierarchy="NO"
#rc_cgroup_memory_use_hierarchy="NO"
# The following settings allow you to set up values for the cgroups version 1
# controllers for your services.

2
init.d/.gitignore vendored
View File

@@ -41,6 +41,8 @@ rc-enabled
rpcbind
runsvdir
savecore
save-keymaps
save-termencoding
swap-blk
swclock
syslogd

View File

@@ -23,8 +23,8 @@ SRCS-FreeBSD+= adjkerntz.in devd.in dumpon.in encswap.in ipfw.in \
SRCS-Linux= agetty.in binfmt.in devfs.in cgroups.in dmesg.in hwclock.in \
consolefont.in keymaps.in killprocs.in modules.in \
mount-ro.in mtab.in numlock.in procfs.in net-online.in sysfs.in \
termencoding.in
mount-ro.in mtab.in numlock.in procfs.in net-online.in save-keymaps.in \
save-termencoding.in sysfs.in termencoding.in
# Generic BSD scripts
SRCS-NetBSD= hostid.in moused.in newsyslog.in pf.in rarpd.in rc-enabled.in \

View File

@@ -12,6 +12,7 @@
description="start agetty on a terminal line"
supervisor=supervise-daemon
port="${RC_SVCNAME#*.}"
respawn_period="${respawn_period:-60}"
term_type="${term_type:-linux}"
command=/sbin/agetty
command_args_foreground="${agetty_options} ${port} ${baud} ${term_type}"

View File

@@ -14,7 +14,7 @@ description="Applies a keymap for the consoles."
depend()
{
need termencoding
after bootmisc clock
after devfs
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
}
@@ -68,10 +68,5 @@ start()
echo "altgr keycode 18 = U+20AC" | loadkeys -q -
eend $?
fi
# Save the keymapping for use immediately at boot
if checkpath -W "$RC_LIBEXECDIR"; then
mkdir -p "$RC_LIBEXECDIR"/console
dumpkeys >"$RC_LIBEXECDIR"/console/keymap
fi
return 0
}

View File

@@ -56,11 +56,12 @@ load_modules()
ebegin "Loading module $x"
case "$RC_UNAME" in
FreeBSD) kldload "$x"; rc=$? ;;
Linux) modprobe --use-blacklist -q "$x"; rc=$? ;;
Linux) modprobe --first-time -q --use-blacklist "$x"; rc=$? ;;
*) ;;
esac
eend $rc "Failed to load $x"
done
return 0
}
modules_load_d()
@@ -103,7 +104,7 @@ Linux_modules()
x=${x%.*}
done
local list= x= xx= y= args= mpargs= a=
local list= x= xx= y= args=
for x in $kv_variant_list ; do
eval list=\$modules_$(shell_var "$x")
[ -n "$list" ] && break
@@ -112,24 +113,13 @@ Linux_modules()
[ -n "$list" ] && ebegin "Loading kernel modules"
for x in $list; do
a=${x#*:}
if [ "$a" = "$x" ]; then
unset mpargs
else
x=${x%%:*}
mpargs="-o $a"
fi
aa=$(shell_var "$a")
xx=$(shell_var "$x")
for y in $kv_variant_list ; do
eval args=\$module_${aa}_args_$(shell_var "$y")
[ -n "${args}" ] && break
eval args=\$module_${xx}_args_$(shell_var "$y")
[ -n "${args}" ] && break
done
[ -z "$args" ] && eval args=\$module_${aa}_args
[ -z "$args" ] && eval args=\$module_${xx}_args
eval modprobe --use-blacklist --verbose "$mpargs" "$x" "$args"
eval modprobe --first-time --use-blacklist --verbose "$x" "$args"
done
[ -n "$list" ] && eend
}
@@ -137,7 +127,7 @@ Linux_modules()
start()
{
case "$RC_UNAME" in
FreeBSD|Linux)
FreeBSD|Linux)
modules_load_d
${RC_UNAME}_modules
;;

28
init.d/save-keymaps.in Normal file
View File

@@ -0,0 +1,28 @@
#!@SBINDIR@/openrc-run
# Copyright (c) 2018 Sony Interactive Entertainment, Inc.
#
# This file is part of OpenRC. It is subject to the license terms in
# the LICENSE file found in the top-level directory of this
# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE
# This file may not be copied, modified, propagated, or distributed
# except according to the terms contained in the LICENSE file.
description="Save the keymap for use as early as possible"
depend()
{
need termencoding
after bootmisc clock keymaps
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
}
start()
{
# Save the keymapping for use immediately at boot
ebegin "Saving key mapping"
if checkpath -W "$RC_LIBEXECDIR"; then
mkdir -p "$RC_LIBEXECDIR"/console
dumpkeys >"$RC_LIBEXECDIR"/console/keymap
fi
eend $? "Unable to save keymapping"
}

View File

@@ -0,0 +1,35 @@
#!@SBINDIR@/openrc-run
# Copyright (c) 2018 Sony Interactive Entertainment, Inc.
#
# This file is part of OpenRC. It is subject to the license terms in
# the LICENSE file found in the top-level directory of this
# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE
# This file may not be copied, modified, propagated, or distributed
# except according to the terms contained in the LICENSE file.
description="Configures terminal encoding."
ttyn=${rc_tty_number:-${RC_TTY_NUMBER:-12}}
: ${unicode:=${UNICODE}}
depend()
{
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
use root
after bootmisc clock termencoding
}
start()
{
ebegin "Saving terminal encoding"
# Save the encoding for use immediately at boot
if checkpath -W "$RC_LIBEXECDIR"; then
mkdir -p "$RC_LIBEXECDIR"/console
if yesno ${unicode:-${UNICODE}}; then
echo "" > "$RC_LIBEXECDIR"/console/unicode
else
rm -f "$RC_LIBEXECDIR"/console/unicode
fi
fi
eend 0
}

View File

@@ -101,7 +101,7 @@ mount_misc()
if [ -d /sys/firmware/efi/efivars ] &&
! mountinfo -q /sys/firmware/efi/efivars; then
ebegin "Mounting efivarfs filesystem"
mount -n -t efivarfs -o ro \
mount -n -t efivarfs -o ${sysfs_opts} \
efivarfs /sys/firmware/efi/efivars 2> /dev/null
eend 0
fi

View File

@@ -17,8 +17,7 @@ ttyn=${rc_tty_number:-${RC_TTY_NUMBER:-12}}
depend()
{
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
use root
after bootmisc clock
after devfs
}
start()

View File

@@ -16,6 +16,7 @@
.Nd bring the system down
.Sh SYNOPSIS
.Nm
.Op Fl c , -cancel
.Op Fl d , -no-write
.Op Fl D , -dry-run
.Op Fl H , -halt
@@ -32,6 +33,8 @@ is the utility that communicates with
to bring down the system or instruct openrc-init to re-execute itself.
It supports the following options:
.Bl -tag -width "poweroff"
.It Fl c , -cancel
Cancel a pending shutdown.
.It Fl d , -no-write
Do not write the wtmp boot record.
.It Fl D , -dry-run

View File

@@ -43,6 +43,8 @@ List all defined runlevels.
Show all manually started services.
.It Fl r , -runlevel
Print the current runlevel name.
.It Fl S , -supervised
Show all supervised services.
.It Fl s , -servicelist
Show all services.
.It Fl u , -unused

View File

@@ -16,6 +16,11 @@
.Nd starts a daemon and restarts it if it crashes
.Sh SYNOPSIS
.Nm
servicename
.Fl a , -healthcheck-timer
.Ar seconds
.Fl A , -healthcheck-delay
.Ar seconds
.Fl D , -respawn-delay
.Ar seconds
.Fl d , -chdir
@@ -32,8 +37,6 @@
.Ar count
.Fl N , -nicelevel
.Ar level
.Fl p , -pidfile
.Ar pidfile
.Fl P , -respawn-period
.Ar seconds
.Fl R , -retry
@@ -51,10 +54,15 @@
.Op Fl -
.Op Ar arguments
.Nm
servicename
.Fl K , -stop
.Ar daemon
.Fl p , -pidfile
.Ar pidfile
.Fl r , -chroot
.Ar chrootpath
.Nm
servicename
.Fl s , -signal
.Ar signal
.Fl r , -chroot
.Ar chrootpath
.Sh DESCRIPTION
@@ -62,22 +70,15 @@
provides a consistent method of starting, stopping and restarting
daemons. If
.Fl K , -stop
or
.Fl s , -signal
is not provided, then we assume we are starting the daemon.
.Nm
only works with daemons which do not fork. Also, it uses its own pid
file, so the daemon should not write a pid file, or the pid file passed
to
.Nm
should not be the one the daemon writes.
only works with daemons which do not fork. If your daemon has options to
tell it not to fork, it should be configured to not fork.
.Pp
Here are the options to specify the daemon and how it should start or stop:
.Bl -tag -width indent
.It Fl p , -pidfile Ar pidfile
When starting, we write a
.Ar pidfile
so we know which supervisor to stop. When stopping we only stop the pid(s)
listed in the
.Ar pidfile .
.It Fl u , -user Ar user Ns Op : Ns Ar group
Start the daemon as the
.Ar user
@@ -90,6 +91,11 @@ Print the action(s) that are taken just before doing them.
.Pp
The options are as follows:
.Bl -tag -width indent
.Fl a , -healthcheck-timer Ar seconds
Run the healthcheck() command, possibly followed by the unhealthy()
command every time this number of seconds passes.
.Fl A , -healthcheck-delay Ar seconds
Wait this long before the first health check.
.It Fl D , -respawn-delay Ar seconds
wait this number of seconds before restarting a daemon after it crashes.
The default is 0.
@@ -106,16 +112,19 @@ Data can be from 0 to 7 inclusive.
.It Fl k , -umask Ar mode
Set the umask of the daemon.
.It Fl m , -respawn-max Ar count
Sets the maximum number of times a daemon will be respawned during a
respawn period. If a daemon dies more than this number of times during a
respawn period,
Sets the maximum number of times a daemon will be respawned. If a daemon
crashes more than this number of times,
.Nm
will give up trying to respawn it and exit. The default is 10, and 0
means unlimited.
will give up and exit. The default is 10 and 0 means unlimited.
.Pp
If respawn-period is also set, more than respawn-max crashes must occur
during respawn-period seconds to cause
.Nm
to give up and exit.
.It Fl N , -nicelevel Ar level
Modifies the scheduling priority of the daemon.
.It Fl P , -respawn-period Ar seconds
Sets the length of a respawn period. The default is 10 seconds. See the
Sets the length of a respawn period. See the
description of --respawn-max for more information.
.It Fl R , -retry Ar timeout | Ar signal Ns / Ns Ar timeout
The retry specification can be either a timeout in seconds or multiple
@@ -123,7 +132,11 @@ signal/timeout pairs (like SIGTERM/5).
If this option is not given, the default is SIGTERM/5.
.It Fl r , -chroot Ar path
chroot to this directory before starting the daemon. All other paths, such
as the path to the daemon, chdir and pidfile, should be relative to the chroot.
as the path to the daemon and chdir should be relative to the chroot.
.It Fl , -signal Ar signal
Instruct a supervisor to signal the process it is supervising. The
process to communicate with is determined by the name of the service
taken from the RC_SVCNAME environment variable.
.It Fl u , -user Ar user
Start the daemon as the specified user.
.It Fl 1 , -stdout Ar logfile
@@ -136,7 +149,6 @@ The same thing as
.Fl 1 , -stdout
but with the standard error output.
.El
.El
.Sh ENVIRONMENT
.Va SSD_NICELEVEL
can also set the scheduling priority of the daemon, but the command line
@@ -158,15 +170,16 @@ make sure the settings mmake sense. For example, a respawn period of 5
seconds with a respawn max of 10 and a respawn delay of 1 second leads
to infinite respawning since there can never be 10 respawns within 5
seconds.
.Sh NOTE
Invoking supervise-daemon requires both the RC_SVCNAME environment
variable to be set and the name of the service as the first argument on
the command line, so it is best to invoke it inside a service script
rather than manually.
.Sh SEE ALSO
.Xr chdir 2 ,
.Xr chroot 2 ,
.Xr getopt 3 ,
.Xr nice 2 ,
.Xr rc_find_pids 3
.Sh BUGS
.Nm
cannot stop an interpreted daemon that no longer exists without a pidfile.
.Sh HISTORY
.Nm
first appeared in Debian.

View File

@@ -36,7 +36,8 @@ BOOT-FreeBSD+= hostid modules newsyslog savecore syslogd
# FreeBSD specific stuff
BOOT-FreeBSD+= adjkerntz dumpon syscons
BOOT-Linux+= binfmt hwclock keymaps modules mtab procfs termencoding
BOOT-Linux+= binfmt hwclock keymaps modules mtab procfs save-keymaps \
save-termencoding termencoding
SHUTDOWN-Linux= killprocs mount-ro
SYSINIT-Linux= devfs cgroups dmesg sysfs

1
sh/.gitignore vendored
View File

@@ -1,6 +1,5 @@
functions.sh
gendepends.sh
rc-functions.sh
openrc-run.sh
cgroup-release-agent.sh
init.sh

View File

@@ -1,6 +1,6 @@
DIR= ${LIBEXECDIR}/sh
SRCS= init.sh.in functions.sh.in gendepends.sh.in \
openrc-run.sh.in rc-functions.sh.in ${SRCS-${OS}}
openrc-run.sh.in ${SRCS-${OS}}
INC= rc-mount.sh functions.sh rc-functions.sh runit.sh s6.sh \
start-stop-daemon.sh supervise-daemon.sh
BIN= gendepends.sh init.sh openrc-run.sh ${BIN-${OS}}

View File

@@ -46,7 +46,7 @@ yesno()
case "$value" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) return 0;;
[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) return 1;;
*) vewarn "\$$1 is not set properly"; return 1;;
*) vewarn "\$$1 is not set properly"; return 2;;
esac
}

View File

@@ -62,7 +62,7 @@ cgroup_set_values()
while [ -n "$1" ] && [ "$controller" != "cpuacct" ]; do
case "$1" in
$controller.*)
if [ -n "${name}" ] && [ -w "${cgroup}/${name}" ] &&
if [ -n "${name}" ] && [ -w "${cgroup}/${name}" ] &&
[ -n "${val}" ]; then
veinfo "$RC_SVCNAME: Setting $cgroup/$name to $val"
printf "%s" "$val" > "$cgroup/$name"

View File

@@ -2,42 +2,6 @@
# Copyright (c) 2007-2009 Roy Marples <roy@marples.name>
# Released under the 2-clause BSD license.
has_addon()
{
[ -e /@LIB@/rc/addons/"$1".sh -o -e /@LIB@/rcscripts/addons/"$1".sh ]
}
_addon_warn()
{
eindent
ewarn "$RC_SVCNAME uses addon code which is deprecated"
ewarn "and may not be available in the future."
eoutdent
}
import_addon()
{
if [ -e /@LIB@/rc/addons/"$1".sh ]; then
_addon_warn
. /@LIB@/rc/addons/"$1".sh
elif [ -e /@LIB@/rcscripts/addons/"$1".sh ]; then
_addon_warn
. /@LIB@/rcscripts/addons/"$1".sh
else
return 1
fi
}
start_addon()
{
( import_addon "$1-start" )
}
stop_addon()
{
( import_addon "$1-stop" )
}
net_fs_list="afs ceph cifs coda davfs fuse fuse.sshfs gfs glusterfs lustre
ncpfs nfs nfs4 ocfs2 shfs smbfs"
is_net_fs()

View File

@@ -57,7 +57,7 @@ s6_stop()
ebegin "Stopping ${name:-$RC_SVCNAME}"
s6-svc -d -wD -T ${s6_service_timeout_stop:-60000} "${s6_service_link}"
set -- $(s6-svstat "${s6_service_link}")
[ "$1" = "up" ] &&
[ "$1" = "up" ] &&
yesno "${s6_force_kill:-yes}" &&
_s6_force_kill "$@"
set -- $(s6-svstat "${s6_service_link}")

View File

@@ -38,9 +38,9 @@ ssd_start()
service_inactive && _inactive=true
mark_service_inactive
fi
[ -n "$output_logger" ] &&
[ -n "$output_logger" ] &&
output_logger_arg="--stdout-logger \"$output_logger\""
[ -n "$error_logger" ] &&
[ -n "$error_logger" ] &&
error_logger_arg="--stderr-logger \"$error_logger\""
#the eval call is necessary for cases like:
# command_args="this \"is a\" test"

View File

@@ -10,6 +10,8 @@
# This file may not be copied, modified, propagated, or distributed
# except according to the terms contained in the LICENSE file.
extra_commands="healthcheck unhealthy ${extra_commands}"
supervise_start()
{
if [ -z "$command" ]; then
@@ -32,6 +34,8 @@ supervise_start()
${respawn_delay:+--respawn-delay} $respawn_delay \
${respawn_max:+--respawn-max} $respawn_max \
${respawn_period:+--respawn-period} $respawn_period \
${healthcheck_delay:+--healthcheck-delay} $healthcheck_delay \
${healthcheck_timer:+--healthcheck-timer} $healthcheck_timer \
${command_user+--user} $command_user \
${umask+--umask} $umask \
${supervise_daemon_args:-${start_stop_daemon_args}} \
@@ -51,11 +55,9 @@ supervise_stop()
local startpidfile="$(service_get_value "pidfile")"
chroot="${startchroot:-$chroot}"
pidfile="${startpidfile:-$pidfile}"
[ -n "$pidfile" ] || return 0
ebegin "Stopping ${name:-$RC_SVCNAME}"
supervise-daemon "${RC_SVCNAME}" --stop \
${pidfile:+--pidfile} $chroot$pidfile \
${stopsig:+--signal} $stopsig
${pidfile:+--pidfile} $chroot$pidfile
eend $? "Failed to stop ${name:-$RC_SVCNAME}"
}
@@ -98,3 +100,13 @@ supervise_status()
return 3
fi
}
healthcheck()
{
return 0
}
unhealthy()
{
return 0
}

View File

@@ -883,7 +883,7 @@ eindent(void)
{
char *env = getenv("EINFO_INDENT");
int amount = 0;
char num[10];
char *num;
if (env) {
errno = 0;
@@ -894,8 +894,9 @@ eindent(void)
amount += INDENT_WIDTH;
if (amount > INDENT_MAX)
amount = INDENT_MAX;
snprintf(num, 10, "%08d", amount);
xasprintf(&num, "%08d", amount);
setenv("EINFO_INDENT", num, 1);
free(num);
}
hidden_def(eindent)
@@ -903,7 +904,7 @@ void eoutdent(void)
{
char *env = getenv("EINFO_INDENT");
int amount = 0;
char num[10];
char *num = NULL;
int serrno = errno;
if (!env)
@@ -917,8 +918,9 @@ void eoutdent(void)
if (amount <= 0)
unsetenv("EINFO_INDENT");
else {
snprintf(num, 10, "%08d", amount);
xasprintf(&num, "%08d", amount);
setenv("EINFO_INDENT", num, 1);
free(num);
}
errno = serrno;
}

View File

@@ -23,13 +23,13 @@
static bool
pid_is_exec(pid_t pid, const char *exec)
{
char buffer[32];
char *buffer = NULL;
FILE *fp;
int c;
bool retval = false;
exec = basename_c(exec);
snprintf(buffer, sizeof(buffer), "/proc/%d/stat", pid);
xasprintf(&buffer, "/proc/%d/stat", pid);
if ((fp = fopen(buffer, "r"))) {
while ((c = getc(fp)) != EOF && c != '(')
;
@@ -41,23 +41,27 @@ pid_is_exec(pid_t pid, const char *exec)
}
fclose(fp);
}
free(buffer);
return retval;
}
static bool
pid_is_argv(pid_t pid, const char *const *argv)
{
char cmdline[32];
char *cmdline = NULL;
int fd;
char buffer[PATH_MAX];
char *p;
ssize_t bytes;
snprintf(cmdline, sizeof(cmdline), "/proc/%u/cmdline", pid);
if ((fd = open(cmdline, O_RDONLY)) < 0)
xasprintf(&cmdline, "/proc/%u/cmdline", pid);
if ((fd = open(cmdline, O_RDONLY)) < 0) {
free(cmdline);
return false;
}
bytes = read(fd, buffer, sizeof(buffer));
close(fd);
free(cmdline);
if (bytes == -1)
return false;
@@ -88,7 +92,7 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
char proc_ns[30];
size_t len = 0;
pid_t p;
char buffer[PATH_MAX];
char *buffer = NULL;
struct stat sb;
pid_t openrc_pid = 0;
char *pp;
@@ -149,18 +153,22 @@ 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);
xasprintf(&buffer, "/proc/%d/ns/pid", p);
if (exists(buffer)) {
rc = readlink(buffer, proc_ns, sizeof(proc_ns));
if (rc <= 0)
proc_ns[0] = '\0';
}
free(buffer);
if (strlen(my_ns) && strlen (proc_ns) && strcmp(my_ns, proc_ns))
continue;
if (uid) {
snprintf(buffer, sizeof(buffer), "/proc/%d", p);
if (stat(buffer, &sb) != 0 || sb.st_uid != uid)
xasprintf(&buffer, "/proc/%d", p);
if (stat(buffer, &sb) != 0 || sb.st_uid != uid) {
free(buffer);
continue;
}
free(buffer);
}
if (exec && !pid_is_exec(p, exec))
continue;
@@ -169,9 +177,10 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
continue;
/* If this is an OpenVZ host, filter out container processes */
if (openvz_host) {
snprintf(buffer, sizeof(buffer), "/proc/%d/status", p);
xasprintf(&buffer, "/proc/%d/status", p);
if (exists(buffer)) {
fp = fopen(buffer, "r");
free(buffer);
if (! fp)
continue;
while (! feof(fp)) {
@@ -315,12 +324,13 @@ _match_daemon(const char *path, const char *file, RC_STRINGLIST *match)
{
char *line = NULL;
size_t len = 0;
char ffile[PATH_MAX];
char *ffile = NULL;
FILE *fp;
RC_STRING *m;
snprintf(ffile, sizeof(ffile), "%s/%s", path, file);
xasprintf(&ffile, "%s/%s", path, file);
fp = fopen(ffile, "r");
free(ffile);
if (!fp)
return false;
@@ -346,29 +356,22 @@ _match_list(const char *exec, const char *const *argv, const char *pidfile)
{
RC_STRINGLIST *match = rc_stringlist_new();
int i = 0;
size_t l;
char *m;
if (exec) {
l = strlen(exec) + 6;
m = xmalloc(sizeof(char) * l);
snprintf(m, l, "exec=%s", exec);
xasprintf(&m, "exec=%s", exec);
rc_stringlist_add(match, m);
free(m);
}
while (argv && argv[i]) {
l = strlen(*argv) + strlen("argv_=") + 16;
m = xmalloc(sizeof(char) * l);
snprintf(m, l, "argv_0=%s", argv[i++]);
xasprintf(&m, "argv_0=%s", argv[i++]);
rc_stringlist_add(match, m);
free(m);
}
if (pidfile) {
l = strlen(pidfile) + 9;
m = xmalloc(sizeof(char) * l);
snprintf(m, l, "pidfile=%s", pidfile);
xasprintf(&m, "pidfile=%s", pidfile);
rc_stringlist_add(match, m);
free(m);
}
@@ -381,8 +384,8 @@ rc_service_daemon_set(const char *service, const char *exec,
const char *const *argv,
const char *pidfile, bool started)
{
char dirpath[PATH_MAX];
char file[PATH_MAX];
char *dirpath = NULL;
char *file = NULL;
int nfiles = 0;
char oldfile[PATH_MAX] = { '\0' };
bool retval = false;
@@ -397,8 +400,7 @@ rc_service_daemon_set(const char *service, const char *exec,
return false;
}
snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s",
basename_c(service));
xasprintf(&dirpath, RC_SVCDIR "/daemons/%s", basename_c(service));
/* Regardless, erase any existing daemon info */
if ((dp = opendir(dirpath))) {
@@ -407,8 +409,7 @@ rc_service_daemon_set(const char *service, const char *exec,
if (d->d_name[0] == '.')
continue;
snprintf(file, sizeof(file), "%s/%s",
dirpath, d->d_name);
xasprintf(&file, "%s/%s", dirpath, d->d_name);
nfiles++;
if (!*oldfile) {
@@ -421,6 +422,7 @@ rc_service_daemon_set(const char *service, const char *exec,
rename(file, oldfile);
strlcpy(oldfile, file, sizeof(oldfile));
}
free(file);
}
closedir(dp);
rc_stringlist_free(match);
@@ -429,8 +431,7 @@ rc_service_daemon_set(const char *service, const char *exec,
/* Now store our daemon info */
if (started) {
if (mkdir(dirpath, 0755) == 0 || errno == EEXIST) {
snprintf(file, sizeof(file), "%s/%03d",
dirpath, nfiles + 1);
xasprintf(&file, "%s/%03d", dirpath, nfiles + 1);
if ((fp = fopen(file, "w"))) {
fprintf(fp, "exec=");
if (exec)
@@ -446,10 +447,12 @@ rc_service_daemon_set(const char *service, const char *exec,
fclose(fp);
retval = true;
}
free(file);
}
} else
retval = true;
free(dirpath);
return retval;
}
librc_hidden_def(rc_service_daemon_set)
@@ -458,8 +461,8 @@ bool
rc_service_started_daemon(const char *service,
const char *exec, const char *const *argv, int indx)
{
char dirpath[PATH_MAX];
char file[16];
char *dirpath = NULL;
char *file = NULL;
RC_STRINGLIST *match;
bool retval = false;
DIR *dp;
@@ -468,13 +471,13 @@ rc_service_started_daemon(const char *service,
if (!service || !exec)
return false;
snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s",
basename_c(service));
xasprintf(&dirpath, RC_SVCDIR "/daemons/%s", basename_c(service));
match = _match_list(exec, argv, NULL);
if (indx > 0) {
snprintf(file, sizeof(file), "%03d", indx);
xasprintf(&file, "%03d", indx);
retval = _match_daemon(dirpath, file, match);
free(file);
} else {
if ((dp = opendir(dirpath))) {
while ((d = readdir(dp))) {
@@ -489,6 +492,7 @@ rc_service_started_daemon(const char *service,
}
rc_stringlist_free(match);
free(dirpath);
return retval;
}
librc_hidden_def(rc_service_started_daemon)

View File

@@ -237,13 +237,9 @@ static void rc_config_set_value(RC_STRINGLIST *config, char *value)
if (token[i] == '\n')
token[i] = 0;
i = strlen(entry) + strlen(token) + 2;
newline = xmalloc(sizeof(char) * i);
snprintf(newline, i, "%s=%s", entry, token);
xasprintf(&newline, "%s=%s", entry, token);
} else {
i = strlen(entry) + 2;
newline = xmalloc(sizeof(char) * i);
snprintf(newline, i, "%s=", entry);
xasprintf(&newline, "%s=", entry);
}
replaced = false;
@@ -281,7 +277,6 @@ static RC_STRINGLIST *rc_config_kcl(RC_STRINGLIST *config)
char *tmp = NULL;
char *value = NULL;
size_t varlen = 0;
size_t len = 0;
overrides = rc_stringlist_new();
@@ -299,9 +294,7 @@ static RC_STRINGLIST *rc_config_kcl(RC_STRINGLIST *config)
}
if (value != NULL) {
len = varlen + strlen(value) + 2;
tmp = xmalloc(sizeof(char) * len);
snprintf(tmp, len, "%s=%s", override->value, value);
xasprintf(&tmp, "%s=%s", override->value, value);
}
/*

View File

@@ -850,7 +850,7 @@ rc_service_state(const char *service)
}
if (state & RC_SERVICE_STARTED) {
if (rc_service_daemons_crashed(service))
if (rc_service_daemons_crashed(service) && errno != EACCES)
state |= RC_SERVICE_CRASHED;
}
if (state & RC_SERVICE_STOPPED) {

View File

@@ -14,7 +14,7 @@ SRCS+= rc-selinux.c
endif
ifeq (${OS},Linux)
SRCS+= kill_all.c openrc-init.c openrc-shutdown.c rc-wtmp.c
SRCS+= kill_all.c openrc-init.c openrc-shutdown.c broadcast.c rc-wtmp.c
endif
CLEANFILES= version.h rc-selinux.o
@@ -134,7 +134,7 @@ mountinfo: mountinfo.o _usage.o rc-misc.o
openrc rc: rc.o rc-logger.o rc-misc.o rc-plugin.o _usage.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
openrc-shutdown: openrc-shutdown.o _usage.o rc-wtmp.o
openrc-shutdown: openrc-shutdown.o rc-misc.o _usage.o broadcast.o rc-wtmp.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
openrc-run runscript: openrc-run.o _usage.o rc-misc.o rc-plugin.o
@@ -161,7 +161,7 @@ rc-update: rc-update.o _usage.o rc-misc.o
start-stop-daemon: start-stop-daemon.o _usage.o rc-misc.o rc-pipes.o rc-schedules.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
supervise-daemon: supervise-daemon.o _usage.o rc-misc.o rc-schedules.o
supervise-daemon: supervise-daemon.o _usage.o rc-misc.o rc-plugin.o rc-schedules.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
service_get_value service_set_value get_options save_options: do_value.o rc-misc.o

209
src/rc/broadcast.c Normal file
View File

@@ -0,0 +1,209 @@
/*
* broadcast.c
* broadcast a message to every logged in user
*/
/*
* Copyright 2018 Sony Interactive Entertainment Inc.
*
* This file is part of OpenRC. It is subject to the license terms in
* the LICENSE file found in the top-level directory of this
* distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE
* This file may not be copied, modified, propagated, or distributed
* except according to the terms contained in the LICENSE file.
*/
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <utmpx.h>
#include <pwd.h>
#include <fcntl.h>
#include <signal.h>
#include <setjmp.h>
#include <paths.h>
#include <sys/utsname.h>
#include "broadcast.h"
#include "helpers.h"
#ifndef _PATH_DEV
# define _PATH_DEV "/dev/"
#endif
#ifndef UT_LINESIZE
#define UT_LINESIZE __UT_LINESIZE
#endif
static sigjmp_buf jbuf;
/*
* Alarm handler
*/
/*ARGSUSED*/
# ifdef __GNUC__
static void handler(int arg __attribute__((unused)))
# else
static void handler(int arg)
# endif
{
siglongjmp(jbuf, 1);
}
static void getuidtty(char **userp, char **ttyp)
{
struct passwd *pwd;
uid_t uid;
char *tty;
static char uidbuf[32];
static char ttynm[UT_LINESIZE + 4];
uid = getuid();
if ((pwd = getpwuid(uid)) != NULL) {
uidbuf[0] = 0;
strncat(uidbuf, pwd->pw_name, sizeof(uidbuf) - 1);
} else {
if (uid)
sprintf(uidbuf, "uid %d", (int) uid);
else
sprintf(uidbuf, "root");
}
if ((tty = ttyname(0)) != NULL) {
const size_t plen = strlen(_PATH_DEV);
if (strncmp(tty, _PATH_DEV, plen) == 0) {
tty += plen;
if (tty[0] == '/')
tty++;
}
snprintf(ttynm, sizeof(ttynm), "(%.*s) ",
UT_LINESIZE, tty);
} else
ttynm[0] = 0;
*userp = uidbuf;
*ttyp = ttynm;
}
/*
* Check whether the given filename looks like a tty device.
*/
static int file_isatty(const char *fname)
{
struct stat st;
int major;
if (stat(fname, &st) < 0)
return 0;
if (st.st_nlink != 1 || !S_ISCHR(st.st_mode))
return 0;
/*
* It would be an impossible task to list all major/minors
* of tty devices here, so we just exclude the obvious
* majors of which just opening has side-effects:
* printers and tapes.
*/
major = major(st.st_dev);
if (major == 1 || major == 2 || major == 6 || major == 9 ||
major == 12 || major == 16 || major == 21 || major == 27 ||
major == 37 || major == 96 || major == 97 || major == 206 ||
major == 230)
return 0;
return 1;
}
/*
* broadcast function.
*/
void broadcast(char *text)
{
char *tty;
char *user;
struct utsname name;
time_t t;
char *date;
char *p;
char *line = NULL;
struct sigaction sa;
volatile int fd;
FILE *tp;
int flags;
char *term = NULL;
struct utmpx *utmp;
getuidtty(&user, &tty);
/*
* Get and report current hostname, to make it easier to find out
* which machine is being shut down.
*/
uname(&name);
/* Get the time */
time(&t);
date = ctime(&t);
p = strchr(date, '\n');
if (p)
*p = 0;
xasprintf(&line, "\007\r\nBroadcast message from %s@%s %s(%s):\r\n\r\n",
user, name.nodename, tty, date);
/*
* Fork to avoid hanging in a write()
*/
if (fork() != 0)
return;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sigaction(SIGALRM, &sa, NULL);
setutxent();
while ((utmp = getutxent()) != NULL) {
if (utmp->ut_type != USER_PROCESS || utmp->ut_user[0] == 0)
continue;
if (strncmp(utmp->ut_line, _PATH_DEV, strlen(_PATH_DEV)) == 0)
xasprintf(&term, "%s", utmp->ut_line);
else
xasprintf(&term, "%s%s", _PATH_DEV, utmp->ut_line);
if (strstr(term, "/../")) {
free(term);
continue;
}
/*
* Open it non-delay
*/
if (sigsetjmp(jbuf, 1) == 0) {
alarm(2);
flags = O_WRONLY|O_NDELAY|O_NOCTTY;
if (file_isatty(term) && (fd = open(term, flags)) >= 0) {
if (isatty(fd) && (tp = fdopen(fd, "w")) != NULL) {
fputs(line, tp);
fputs(text, tp);
fflush(tp);
}
}
}
alarm(0);
if (fd >= 0)
close(fd);
if (tp != NULL)
fclose(tp);
free(term);
}
endutxent();
free(line);
exit(0);
}

16
src/rc/broadcast.h Normal file
View File

@@ -0,0 +1,16 @@
/*
* Copyright 2018 Sony Interactive Entertainment Inc.
*
* This file is part of OpenRC. It is subject to the license terms in
* the LICENSE file found in the top-level directory of this
* distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE
* This file may not be copied, modified, propagated, or distributed
* except according to the terms contained in the LICENSE file.
*/
#ifndef BROADCAST_H
#define BROADCAST_H
void broadcast(char *text);
#endif

View File

@@ -269,11 +269,13 @@ int main(int argc, char **argv)
switch (opt) {
case 'D':
trunc = true;
/* falls through */
case 'd':
type = inode_dir;
break;
case 'F':
trunc = true;
/* falls through */
case 'f':
type = inode_file;
break;

View File

@@ -58,7 +58,7 @@ static int mount_proc(void)
if (exists("/proc/version"))
return 0;
pid = fork();
switch(pid) {
switch (pid) {
case -1:
syslog(LOG_ERR, "Unable to fork");
return -1;
@@ -248,7 +248,7 @@ int main(int argc, char **argv)
usage(EXIT_FAILURE);
}
}
openlog(applet, LOG_CONS|LOG_PID, LOG_DAEMON);
if (mount_proc() != 0) {
rc_stringlist_free(omits);

View File

@@ -24,12 +24,17 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/reboot.h>
#include <sys/wait.h>
#ifdef HAVE_SELINUX
# include <selinux/selinux.h>
#endif
#include "helpers.h"
#include "rc.h"
#include "rc-wtmp.h"
@@ -44,7 +49,7 @@ static pid_t do_openrc(const char *runlevel)
sigset_t signals;
pid = fork();
switch(pid) {
switch (pid) {
case -1:
perror("fork");
break;
@@ -96,12 +101,15 @@ static void handle_reexec(char *my_name)
static void handle_shutdown(const char *runlevel, int cmd)
{
pid_t pid;
struct timespec ts;
pid = do_openrc(runlevel);
while (waitpid(pid, NULL, 0) != pid);
printf("Sending the final term signal\n");
kill(-1, SIGTERM);
sleep(3);
ts.tv_sec = 3;
ts.tv_nsec = 0;
nanosleep(&ts, NULL);
printf("Sending the final kill signal\n");
kill(-1, SIGKILL);
sync();
@@ -135,7 +143,7 @@ static void reap_zombies(void)
static void signal_handler(int sig)
{
switch(sig) {
switch (sig) {
case SIGINT:
handle_shutdown("reboot", RB_AUTOBOOT);
break;
@@ -157,10 +165,36 @@ int main(int argc, char **argv)
bool reexec = false;
sigset_t signals;
struct sigaction sa;
#ifdef HAVE_SELINUX
int enforce = 0;
#endif
if (getpid() != 1)
return 1;
#ifdef HAVE_SELINUX
if (getenv("SELINUX_INIT") == NULL) {
if (is_selinux_enabled() != 1) {
if (selinux_init_load_policy(&enforce) == 0) {
putenv("SELINUX_INIT=YES");
execv(argv[0], argv);
} else {
if (enforce > 0) {
/*
* SELinux in enforcing mode but load_policy failed
* At this point, we probably can't open /dev/console,
* so log() won't work
*/
fprintf(stderr,"Unable to load SELinux Policy.\n");
fprintf(stderr,"Machine is in enforcing mode.\n");
fprintf(stderr,"Halting now.\n");
exit(1);
}
}
}
}
#endif
printf("OpenRC init version %s starting\n", VERSION);
if (argc > 1)

View File

@@ -25,20 +25,24 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include "broadcast.h"
#include "einfo.h"
#include "rc.h"
#include "helpers.h"
#include "rc-misc.h"
#include "_usage.h"
#include "rc-wtmp.h"
const char *applet = NULL;
const char *extraopts = NULL;
const char *getoptstring = "dDHKpRrsw" getoptstring_COMMON;
const char *getoptstring = "cdDfFHKpRrsw" getoptstring_COMMON;
const struct option longopts[] = {
{ "cancel", no_argument, NULL, 'c'},
{ "no-write", no_argument, NULL, 'd'},
{ "dry-run", no_argument, NULL, 'D'},
{ "halt", no_argument, NULL, 'H'},
@@ -51,6 +55,7 @@ const struct option longopts[] = {
longopts_COMMON
};
const char * const longopts_help[] = {
"cancel a pending shutdown",
"do not write wtmp record",
"print actions instead of executing them",
"halt the system",
@@ -64,8 +69,12 @@ const char * const longopts_help[] = {
};
const char *usagestring = NULL;
const char *exclusive = "Select one of "
"--halt, --kexec, --poweroff, --reexec, --reboot, --single or --write-only";
"--cancel, --halt, --kexec, --poweroff, --reexec, --reboot, --single or \n"
"--write-only";
const char *nologin_file = RC_SYSCONFDIR"/nologin";
const char *shutdown_pid = "/run/openrc-shutdown.pid";
static bool do_cancel = false;
static bool do_dryrun = false;
static bool do_halt = false;
static bool do_kexec = false;
@@ -76,6 +85,40 @@ static bool do_single = false;
static bool do_wtmp = true;
static bool do_wtmp_only = false;
static void cancel_shutdown(void)
{
pid_t pid;
pid = get_pid(applet, shutdown_pid);
if (pid <= 0)
eerrorx("%s: Unable to cancel shutdown", applet);
if (kill(pid, SIGTERM) != -1)
einfo("%s: shutdown canceled", applet);
else
eerrorx("%s: Unable to cancel shutdown", applet);
}
/*
* Create the nologin file.
*/
static void create_nologin(int mins)
{
FILE *fp;
time_t t;
time(&t);
t += 60 * mins;
if ((fp = fopen(nologin_file, "w")) != NULL) {
fprintf(fp, "\rThe system is going down on %s\r\n", ctime(&t));
fclose(fp);
}
}
/*
* Send a command to our init
*/
static void send_cmd(const char *cmd)
{
FILE *fifo;
@@ -99,16 +142,57 @@ static void send_cmd(const char *cmd)
fclose(fifo);
}
/*
* sleep without being interrupted.
* The idea for this code came from sysvinit.
*/
static void sleep_no_interrupt(int seconds)
{
struct timespec duration;
struct timespec remaining;
duration.tv_sec = seconds;
duration.tv_nsec = 0;
while (nanosleep(&duration, &remaining) < 0 && errno == EINTR)
duration = remaining;
}
static void stop_shutdown(int sig)
{
(void) sig;
unlink(nologin_file);
unlink(shutdown_pid);
einfo("Shutdown canceled");
exit(0);
}
int main(int argc, char **argv)
{
char *ch = NULL;
int opt;
int cmd_count = 0;
int hour = 0;
int min = 0;
int shutdown_delay = 0;
struct sigaction sa;
struct tm *lt;
time_t tv;
bool need_warning = false;
char *msg = NULL;
char *state = NULL;
char *time_arg = NULL;
FILE *fp;
applet = basename_c(argv[0]);
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
{
switch (opt) {
case 'c':
do_cancel = true;
cmd_count++;
break;
case 'd':
do_wtmp = false;
break;
@@ -117,14 +201,17 @@ int main(int argc, char **argv)
break;
case 'H':
do_halt = true;
xasprintf(&state, "%s", "halt");
cmd_count++;
break;
case 'K':
do_kexec = true;
xasprintf(&state, "%s", "reboot");
cmd_count++;
break;
case 'p':
do_poweroff = true;
xasprintf(&state, "%s", "power off");
cmd_count++;
break;
case 'R':
@@ -133,10 +220,12 @@ int main(int argc, char **argv)
break;
case 'r':
do_reboot = true;
xasprintf(&state, "%s", "reboot");
cmd_count++;
break;
case 's':
do_single = true;
xasprintf(&state, "%s", "go down for maintenance");
cmd_count++;
break;
case 'w':
@@ -146,12 +235,91 @@ int main(int argc, char **argv)
case_RC_COMMON_GETOPT
}
}
if (geteuid() != 0 && ! do_dryrun)
if (geteuid() != 0)
eerrorx("%s: you must be root\n", applet);
if (cmd_count != 1) {
eerror("%s: %s\n", applet, exclusive);
usage(EXIT_FAILURE);
}
if (do_cancel) {
cancel_shutdown();
exit(EXIT_SUCCESS);
} else if (do_reexec) {
send_cmd("reexec");
exit(EXIT_SUCCESS);
} else if (do_wtmp_only) {
log_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
exit(EXIT_SUCCESS);
}
if (optind >= argc) {
eerror("%s: No shutdown time specified", applet);
usage(EXIT_FAILURE);
}
time_arg = argv[optind];
if (*time_arg == '+')
time_arg++;
if (strcasecmp(time_arg, "now") == 0)
strcpy(time_arg, "0");
for (ch=time_arg; *ch; ch++)
if ((*ch < '0' || *ch > '9') && *ch != ':') {
eerror("%s: invalid time %s", applet, time_arg);
usage(EXIT_FAILURE);
}
if (strchr(time_arg, ':')) {
if ((sscanf(time_arg, "%2d:%2d", &hour, &min) != 2) ||
(hour > 23) || (min > 59)) {
eerror("%s: invalid time %s", applet, time_arg);
usage(EXIT_FAILURE);
}
time(&tv);
lt = localtime(&tv);
shutdown_delay = (hour * 60 + min) - (lt->tm_hour * 60 + lt->tm_min);
if (shutdown_delay < 0)
shutdown_delay += 1440;
} else {
shutdown_delay = atoi(time_arg);
}
fp = fopen(shutdown_pid, "w");
if (!fp)
eerrorx("%s: fopen `%s': %s", applet, shutdown_pid, strerror(errno));
fprintf(fp, "%d\n", getpid());
fclose(fp);
openlog(applet, LOG_PID, LOG_DAEMON);
memset(&sa, 0, sizeof(sa));
sa.sa_handler = stop_shutdown;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
while (shutdown_delay > 0) {
need_warning = false;
if (shutdown_delay > 180)
need_warning = (shutdown_delay % 60 == 0);
else if (shutdown_delay > 60)
need_warning = (shutdown_delay % 30 == 0);
else if (shutdown_delay > 10)
need_warning = (shutdown_delay % 15 == 0);
else
need_warning = true;
if (shutdown_delay <= 5)
create_nologin(shutdown_delay);
if (need_warning) {
xasprintf(&msg, "\rThe system will %s in %d minutes\r\n",
state, shutdown_delay);
broadcast(msg);
free(msg);
}
sleep_no_interrupt(60);
shutdown_delay--;
}
xasprintf(&msg, "\rThe system will %s now\r\n", state);
broadcast(msg);
syslog(LOG_NOTICE, "The system will %s now", state);
unlink(nologin_file);
unlink(shutdown_pid);
if (do_halt)
send_cmd("halt");
else if (do_kexec)
@@ -160,10 +328,6 @@ int main(int argc, char **argv)
send_cmd("poweroff");
else if (do_reboot)
send_cmd("reboot");
else if (do_reexec)
send_cmd("reexec");
else if (do_wtmp_only)
log_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
else if (do_single)
send_cmd("single");
return 0;

View File

@@ -37,21 +37,20 @@ int rc_pipe_command(char *cmd)
return -1;
pid = fork();
if (pid < 0)
return -1;
else if (pid > 0) {
if (pid > 0) {
/* parent */
close(pfd[0]);
close(pfd[pipe_read_end]);
return pfd[pipe_write_end];
} else if (pid == 0) {
/* child */
close(pfd[pipe_write_end]);
if (pfd[0] != STDIN_FILENO) {
if (dup2(pfd[0], STDIN_FILENO) < 0)
if (pfd[pipe_read_end] != STDIN_FILENO) {
if (dup2(pfd[pipe_read_end], STDIN_FILENO) < 0)
exit(1);
close(pfd[0]);
close(pfd[pipe_read_end]);
}
execl("/bin/sh", "sh", "-c", cmd, NULL);
exit(1);
}
return -1;
}

View File

@@ -28,6 +28,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
@@ -270,8 +271,11 @@ int do_stop(const char *applet, const char *exec, const char *const *argv,
einfo("Would send signal %d to PID %d", sig, pi->pid);
nkilled++;
} else {
if (!quiet)
ebeginv("Sending signal %d to PID %d", sig, pi->pid);
if (sig) {
syslog(LOG_DEBUG, "Sending signal %d to PID %d", sig, pi->pid);
if (!quiet)
ebeginv("Sending signal %d to PID %d", sig, pi->pid);
}
errno = 0;
killed = (kill(pi->pid, sig) == 0 ||
errno == ESRCH ? true : false);
@@ -279,6 +283,9 @@ int do_stop(const char *applet, const char *exec, const char *const *argv,
eendv(killed ? 0 : 1,
"%s: failed to send signal %d to PID %d: %s",
applet, sig, pi->pid, strerror(errno));
else if (!killed)
syslog(LOG_ERR, "Failed to send signal %d to PID %d: %s",
sig, pi->pid, strerror(errno));
if (!killed) {
nkilled = -1;
} else {
@@ -310,12 +317,18 @@ int run_stop_schedule(const char *applet,
if (!(pid > 0 || exec || uid || (argv && *argv)))
return 0;
if (exec)
if (exec) {
einfov("Will stop %s", exec);
if (pid > 0)
syslog(LOG_DEBUG, "Will stop %s", exec);
}
if (pid > 0) {
einfov("Will stop PID %d", pid);
if (uid)
syslog(LOG_DEBUG, "Will stop PID %d", pid);
}
if (uid) {
einfov("Will stop processes owned by UID %d", uid);
syslog(LOG_DEBUG, "Will stop processes owned by UID %d", uid);
}
if (argv && *argv) {
einfovn("Will stop processes of `");
if (rc_yesno(getenv("EINFO_VERBOSE"))) {
@@ -351,8 +364,9 @@ int run_stop_schedule(const char *applet,
tkilled += nkilled;
break;
case SC_FOREVER:
case SC_TIMEOUT:
if (item->value < 1) {
if (item->type == SC_TIMEOUT && item->value < 1) {
item = NULL;
break;
}
@@ -360,7 +374,7 @@ int run_stop_schedule(const char *applet,
ts.tv_sec = 0;
ts.tv_nsec = POLL_INTERVAL;
for (nsecs = 0; nsecs < item->value; nsecs++) {
for (nsecs = 0; item->type == SC_FOREVER || nsecs < item->value; nsecs++) {
for (nloops = 0;
nloops < ONE_SECOND / POLL_INTERVAL;
nloops++)
@@ -375,10 +389,7 @@ int run_stop_schedule(const char *applet,
printf("\n");
progressed = false;
}
if (errno == EINTR)
eerror("%s: caught an"
" interrupt", applet);
else {
if (errno != EINTR) {
eerror("%s: nanosleep: %s",
applet, strerror(errno));
return 0;

View File

@@ -49,10 +49,12 @@ const char * const longopts_help[] = {
"set xtrace when running the command",
"ignore dependencies",
"tests if the service exists or not",
"if the service is crashed then run the command",
"if the service exists then run the command",
"if the service is inactive then run the command",
"if the service is not started then run the command",
"if the service is crashed run the command",
"if the service exists run the command",
"if the service is inactive run the command",
"if the service is not started run the command",
"if the service is started run the command",
"if the service is stopped run the command",
"list all available services",
"resolve the service name to an init script",
"dry run (show what would happen)",

View File

@@ -29,7 +29,7 @@
const char *applet = NULL;
const char *extraopts = NULL;
const char *getoptstring = "aclmrsu" getoptstring_COMMON;
const char *getoptstring = "aclmrsSu" getoptstring_COMMON;
const struct option longopts[] = {
{"all", 0, NULL, 'a'},
{"crashed", 0, NULL, 'c'},
@@ -37,6 +37,7 @@ const struct option longopts[] = {
{"manual", 0, NULL, 'm'},
{"runlevel", 0, NULL, 'r'},
{"servicelist", 0, NULL, 's'},
{"supervised", 0, NULL, 'S'},
{"unused", 0, NULL, 'u'},
longopts_COMMON
};
@@ -47,6 +48,7 @@ const char * const longopts_help[] = {
"Show manually started services",
"Show the name of the current runlevel",
"Show service list",
"show supervised services",
"Show services not assigned to any runlevel",
longopts_help_COMMON
};
@@ -75,7 +77,7 @@ print_level(const char *prefix, const char *level)
printf("%s\n", level);
}
static void get_uptime(const char *service, char *uptime, int uptime_size)
static char *get_uptime(const char *service)
{
RC_SERVICE state = rc_service_state(service);
char *start_count;
@@ -87,8 +89,8 @@ static void get_uptime(const char *service, char *uptime, int uptime_size)
time_t diff_hours = (time_t) 0;
time_t diff_mins = (time_t) 0;
time_t diff_secs = (time_t) 0;
char *uptime = NULL;
uptime[0] = '\0';
if (state & RC_SERVICE_STARTED) {
start_count = rc_service_value_get(service, "start_count");
start_time_string = rc_service_value_get(service, "start_time");
@@ -110,23 +112,24 @@ static void get_uptime(const char *service, char *uptime, int uptime_size)
diff_secs %= diff_mins * (time_t) 60;
}
if (diff_days > 0)
snprintf(uptime, uptime_size,
xasprintf(&uptime,
"%ld day(s) %02ld:%02ld:%02ld (%s)",
diff_days, diff_hours, diff_mins, diff_secs,
start_count);
else
snprintf(uptime, uptime_size,
xasprintf(&uptime,
"%02ld:%02ld:%02ld (%s)",
diff_hours, diff_mins, diff_secs, start_count);
}
}
return uptime;
}
static void
print_service(const char *service)
{
char status[60];
char uptime [40];
char *status = NULL;
char *uptime = NULL;
char *child_pid = NULL;
char *start_time = NULL;
int cols = printf(" %s", service);
@@ -135,12 +138,12 @@ print_service(const char *service)
ECOLOR color = ECOLOR_BAD;
if (state & RC_SERVICE_STOPPING)
snprintf(status, sizeof(status), "stopping ");
xasprintf(&status, "stopping ");
else if (state & RC_SERVICE_STARTING) {
snprintf(status, sizeof(status), "starting ");
xasprintf(&status, "starting ");
color = ECOLOR_WARN;
} else if (state & RC_SERVICE_INACTIVE) {
snprintf(status, sizeof(status), "inactive ");
xasprintf(&status, "inactive ");
color = ECOLOR_WARN;
} else if (state & RC_SERVICE_STARTED) {
errno = 0;
@@ -149,26 +152,34 @@ print_service(const char *service)
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 ");
xasprintf(&status, " unsupervised ");
else
snprintf(status, sizeof(status), " crashed ");
xasprintf(&status, " crashed ");
free(child_pid);
free(start_time);
} else {
get_uptime(service, uptime, 40);
snprintf(status, sizeof(status), " started %s", uptime);
uptime = get_uptime(service);
if (uptime) {
xasprintf(&status, " started %s", uptime);
free(uptime);
} else
xasprintf(&status, " started ");
color = ECOLOR_GOOD;
}
} else if (state & RC_SERVICE_SCHEDULED) {
snprintf(status, sizeof(status), "scheduled");
xasprintf(&status, "scheduled");
color = ECOLOR_WARN;
} else if (state & RC_SERVICE_FAILED) {
xasprintf(&status, "failed");
color = ECOLOR_WARN;
} else
snprintf(status, sizeof(status), " stopped ");
xasprintf(&status, " stopped ");
errno = 0;
if (c && *c && isatty(fileno(stdout)))
printf("\n");
ebracket(cols, color, status);
free(status);
}
static void
@@ -232,6 +243,7 @@ print_stacked_services(const char *runlevel)
int main(int argc, char **argv)
{
RC_SERVICE state;
RC_STRING *s, *l, *t, *level;
bool show_all = false;
char *p, *runlevel = NULL;
@@ -286,6 +298,14 @@ int main(int argc, char **argv)
printf("%s\n", runlevel);
goto exit;
/* NOTREACHED */
case 'S':
services = rc_services_in_state(RC_SERVICE_STARTED);
TAILQ_FOREACH_SAFE(s, services, entries, t)
if (!rc_service_value_get(s->value, "child_pid"))
TAILQ_REMOVE(services, s, entries);
print_services(NULL, services);
goto exit;
/* NOTREACHED */
case 's':
services = rc_services_in_runlevel(NULL);
print_services(NULL, services);
@@ -367,11 +387,14 @@ int main(int argc, char **argv)
free(nservices);
}
TAILQ_FOREACH_SAFE(s, services, entries, t) {
state = rc_service_state(s->value);
if ((rc_stringlist_find(sservices, s->value) ||
(rc_service_state(s->value) & ( RC_SERVICE_STOPPED | RC_SERVICE_HOTPLUGGED)))) {
TAILQ_REMOVE(services, s, entries);
free(s->value);
free(s);
(state & ( RC_SERVICE_STOPPED | RC_SERVICE_HOTPLUGGED)))) {
if (! (state & RC_SERVICE_FAILED)) {
TAILQ_REMOVE(services, s, entries);
free(s->value);
free(s);
}
}
}
needsme = rc_stringlist_new();

View File

@@ -42,7 +42,7 @@ void log_wtmp(const char *user, const char *id, pid_t pid, int type,
strncpy(utmp.ut_name, user, sizeof(utmp.ut_name));
strncpy(utmp.ut_id , id , sizeof(utmp.ut_id ));
strncpy(utmp.ut_line, line, sizeof(utmp.ut_line));
/* Put the OS version in place of the hostname */
if (uname(&uname_buf) == 0)
strncpy(utmp.ut_host, uname_buf.release, sizeof(utmp.ut_host));

View File

@@ -101,7 +101,6 @@ clean_failed(void)
{
DIR *dp;
struct dirent *d;
size_t l;
char *path;
/* Clean the failed services state dir now */
@@ -112,16 +111,11 @@ clean_failed(void)
(d->d_name[1] == '.' && d->d_name[2] == '\0')))
continue;
l = strlen(RC_SVCDIR "/failed/") +
strlen(d->d_name) + 1;
path = xmalloc(sizeof(char) * l);
snprintf(path, l, RC_SVCDIR "/failed/%s", d->d_name);
if (path) {
if (unlink(path))
eerror("%s: unlink `%s': %s",
applet, path, strerror(errno));
free(path);
}
xasprintf(&path, RC_SVCDIR "/failed/%s", d->d_name);
if (unlink(path))
eerror("%s: unlink `%s': %s",
applet, path, strerror(errno));
free(path);
}
closedir(dp);
}
@@ -391,7 +385,7 @@ static void
handle_signal(int sig)
{
int serrno = errno;
char signame[10] = { '\0' };
char *signame = NULL;
pid_t pid;
RC_PID *pi;
int status = 0;
@@ -422,16 +416,16 @@ handle_signal(int sig)
break;
case SIGINT:
if (!signame[0])
snprintf(signame, sizeof(signame), "SIGINT");
if (!signame)
xasprintf(&signame, "SIGINT");
/* FALLTHROUGH */
case SIGTERM:
if (!signame[0])
snprintf(signame, sizeof(signame), "SIGTERM");
if (!signame)
xasprintf(&signame, "SIGTERM");
/* FALLTHROUGH */
case SIGQUIT:
if (!signame[0])
snprintf(signame, sizeof(signame), "SIGQUIT");
if (!signame)
xasprintf(&signame, "SIGQUIT");
eerrorx("%s: caught %s, aborting", applet, signame);
/* NOTREACHED */
case SIGUSR1:
@@ -512,14 +506,11 @@ runlevel_config(const char *service, const char *level)
{
char *init = rc_service_resolve(service);
char *conf, *dir;
size_t l;
bool retval;
dir = dirname(init);
dir = dirname(init);
l = strlen(dir) + strlen(level) + strlen(service) + 10;
conf = xmalloc(sizeof(char) * l);
snprintf(conf, l, "%s/conf.d/%s.%s", dir, service, level);
xasprintf(&conf, "%s/conf.d/%s.%s", dir, service, level);
retval = exists(conf);
free(conf);
free(init);
@@ -744,7 +735,7 @@ int main(int argc, char **argv)
bool going_down = false;
int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
char *krunlevel = NULL;
char pidstr[10];
char *pidstr = NULL;
int opt;
bool parallel;
int regen = 0;
@@ -844,8 +835,9 @@ int main(int argc, char **argv)
setenv("EINFO_LOG", "openrc", 1);
/* Export our PID */
snprintf(pidstr, sizeof(pidstr), "%d", getpid());
xasprintf(&pidstr, "%d", getpid());
setenv("RC_PID", pidstr, 1);
free(pidstr);
/* Create a list of all services which should be started for the new or
* current runlevel including those in boot, sysinit and hotplugged

View File

@@ -167,20 +167,20 @@ handle_signal(int sig)
{
int status;
int serrno = errno;
char signame[10] = { '\0' };
char *signame = NULL;
switch (sig) {
case SIGINT:
if (!signame[0])
snprintf(signame, sizeof(signame), "SIGINT");
if (!signame)
xasprintf(&signame, "SIGINT");
/* FALLTHROUGH */
case SIGTERM:
if (!signame[0])
snprintf(signame, sizeof(signame), "SIGTERM");
if (!signame)
xasprintf(&signame, "SIGTERM");
/* FALLTHROUGH */
case SIGQUIT:
if (!signame[0])
snprintf(signame, sizeof(signame), "SIGQUIT");
if (!signame)
xasprintf(&signame, "SIGQUIT");
eerrorx("%s: caught %s, aborting", applet, signame);
/* NOTREACHED */
@@ -199,6 +199,9 @@ handle_signal(int sig)
eerror("%s: caught unknown signal %d", applet, sig);
}
/* free signame */
free(signame);
/* Restore errno */
errno = serrno;
}
@@ -207,7 +210,6 @@ static char *
expand_home(const char *home, const char *path)
{
char *opath, *ppath, *p, *nh;
size_t len;
struct passwd *pw;
if (!path || *path != '~')
@@ -238,9 +240,7 @@ expand_home(const char *home, const char *path)
return xstrdup(home);
}
len = strlen(ppath) + strlen(home) + 1;
nh = xmalloc(len);
snprintf(nh, len, "%s%s", home, ppath);
xasprintf(&nh, "%s%s", home, ppath);
free(opath);
return nh;
}
@@ -386,6 +386,7 @@ int main(int argc, char **argv)
case 'c': /* --chuid <username>|<uid> */
/* DEPRECATED */
ewarn("WARNING: -c/--chuid is deprecated and will be removed in the future, please use -u/--user instead");
/* falls through */
case 'u': /* --user <username>|<uid> */
{
p = optarg;
@@ -995,9 +996,7 @@ int main(int argc, char **argv)
ts.tv_sec = start_wait / 1000;
ts.tv_nsec = (start_wait % 1000) * ONE_MS;
if (nanosleep(&ts, NULL) == -1) {
if (errno == EINTR)
eerror("%s: caught an interrupt", applet);
else {
if (errno != EINTR) {
eerror("%s: nanosleep: %s",
applet, strerror(errno));
return 0;

View File

@@ -61,15 +61,18 @@ static struct pam_conv conv = { NULL, NULL};
#include "queue.h"
#include "rc.h"
#include "rc-misc.h"
#include "rc-plugin.h"
#include "rc-schedules.h"
#include "_usage.h"
#include "helpers.h"
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:3" \
const char *getoptstring = "A:a:D:d:e:g:H:I:Kk:m:N:p:R:r:s:Su:1:2:3" \
getoptstring_COMMON;
const struct option longopts[] = {
{ "healthcheck-timer", 1, NULL, 'a'},
{ "healthcheck-delay", 1, NULL, 'A'},
{ "respawn-delay", 1, NULL, 'D'},
{ "chdir", 1, NULL, 'd'},
{ "env", 1, NULL, 'e'},
@@ -83,6 +86,7 @@ const struct option longopts[] = {
{ "respawn-period", 1, NULL, 'P'},
{ "retry", 1, NULL, 'R'},
{ "chroot", 1, NULL, 'r'},
{ "signal", 1, NULL, 's'},
{ "start", 0, NULL, 'S'},
{ "user", 1, NULL, 'u'},
{ "stdout", 1, NULL, '1'},
@@ -91,6 +95,8 @@ const struct option longopts[] = {
longopts_COMMON
};
const char * const longopts_help[] = {
"set an initial health check delay",
"set a health check timer",
"Set a respawn delay",
"Change the PWD",
"Set an environment string",
@@ -104,6 +110,7 @@ const char * const longopts_help[] = {
"Set respawn time period",
"Retry schedule to use when stopping",
"Chroot to this directory",
"Send a signal to the daemon",
"Start daemon",
"Change the process user",
"Redirect stdout to file",
@@ -113,6 +120,10 @@ const char * const longopts_help[] = {
};
const char *usagestring = NULL;
static int healthcheckdelay = 0;
static int healthchecktimer = 0;
static volatile sig_atomic_t do_healthcheck = 0;
static volatile sig_atomic_t exiting = 0;
static int nicelevel = 0;
static int ionicec = -1;
static int ioniced = 0;
@@ -125,7 +136,6 @@ static int stdout_fd;
static int stderr_fd;
static char *redirect_stderr = NULL;
static char *redirect_stdout = NULL;
static bool exiting = false;
#ifdef TIOCNOTTY
static int tty_fd = -1;
#endif
@@ -133,7 +143,9 @@ 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 int respawn_period = 0;
static char *fifopath = NULL;
static int fifo_fd = 0;
static char *pidfile = NULL;
static char *svcname = NULL;
@@ -172,21 +184,37 @@ static void re_exec_supervisor(void)
static void handle_signal(int sig)
{
int serrno = errno;
pid_t pid;
syslog(LOG_WARNING, "caught signal %d", sig);
if (sig == SIGTERM)
exiting = true;
switch (sig) {
case SIGALRM:
do_healthcheck = 1;
break;
case SIGCHLD:
if (exiting)
while (waitpid((pid_t)(-1), NULL, WNOHANG) > 0) {}
else {
while ((pid = waitpid((pid_t)(-1), NULL, WNOHANG|WNOWAIT)) > 0) {
if (pid == child_pid)
break;
pid = waitpid(pid, NULL, WNOHANG);
}
}
break;
case SIGTERM:
exiting = 1;
break;
default:
syslog(LOG_WARNING, "caught signal %d", sig);
re_exec_supervisor();
}
/* Restore errno */
errno = serrno;
if (! exiting)
re_exec_supervisor();
}
static char * expand_home(const char *home, const char *path)
{
char *opath, *ppath, *p, *nh;
size_t len;
struct passwd *pw;
if (!path || *path != '~')
@@ -217,9 +245,7 @@ static char * expand_home(const char *home, const char *path)
return xstrdup(home);
}
len = strlen(ppath) + strlen(home) + 1;
nh = xmalloc(len);
snprintf(nh, len, "%s%s", home, ppath);
xasprintf(&nh, "%s%s", home, ppath);
free(opath);
return nh;
}
@@ -241,6 +267,56 @@ static char *make_cmdline(char **argv)
return cmdline;
}
static pid_t exec_command(const char *cmd)
{
char *file;
pid_t pid = -1;
sigset_t full;
sigset_t old;
struct sigaction sa;
file = rc_service_resolve(svcname);
if (!exists(file)) {
free(file);
return 0;
}
/* We need to block signals until we have forked */
memset(&sa, 0, sizeof (sa));
sa.sa_handler = SIG_DFL;
sigemptyset(&sa.sa_mask);
sigfillset(&full);
sigprocmask(SIG_SETMASK, &full, &old);
pid = fork();
if (pid == 0) {
/* Restore default handlers */
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
sigaction(SIGWINCH, &sa, NULL);
/* Unmask signals */
sigprocmask(SIG_SETMASK, &old, NULL);
/* Safe to run now */
execl(file, file, cmd, (char *) NULL);
syslog(LOG_ERR, "unable to exec `%s': %s\n",
file, strerror(errno));
_exit(EXIT_FAILURE);
}
if (pid == -1)
syslog(LOG_ERR, "fork: %s\n",strerror (errno));
sigprocmask(SIG_SETMASK, &old, NULL);
free(file);
return pid;
}
static void child_process(char *exec, char **argv)
{
RC_STRINGLIST *env_list;
@@ -426,49 +502,37 @@ static void child_process(char *exec, char **argv)
static void supervisor(char *exec, char **argv)
{
FILE *fp;
char buf[2048];
char cmd[2048];
int count;
int failing;
int health_status;
int healthcheck_respawn;
int i;
int nkilled;
int sig_send;
pid_t health_pid;
pid_t wait_pid;
sigset_t old_signals;
sigset_t signals;
struct sigaction sa;
struct timespec ts;
time_t respawn_now= 0;
time_t first_spawn= 0;
#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);
#ifdef SIGPOLL
signal_setup_restart(SIGPOLL, handle_signal);
#endif
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);
#ifdef SIGPWR
signal_setup_restart(SIGPWR, handle_signal);
#endif
#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
/* block all signals we do not handle */
sigfillset(&signals);
sigdelset(&signals, SIGALRM);
sigdelset(&signals, SIGCHLD);
sigdelset(&signals, SIGTERM);
sigprocmask(SIG_SETMASK, &signals, &old_signals);
/* install signal handler */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handle_signal;
sigaction(SIGALRM, &sa, NULL);
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
fp = fopen(pidfile, "w");
if (! fp)
@@ -489,56 +553,131 @@ static void supervisor(char *exec, char **argv)
/*
* Supervisor main loop
*/
i = 0;
if (healthcheckdelay)
alarm(healthcheckdelay);
else if (healthchecktimer)
alarm(healthchecktimer);
failing = 0;
while (!exiting) {
wait(&i);
if (exiting) {
signal_setup(SIGCHLD, SIG_IGN);
healthcheck_respawn = 0;
fifo_fd = open(fifopath, O_RDONLY);
if (fifo_fd > 0) {
memset(buf, 0, sizeof(buf));
count = read(fifo_fd, buf, sizeof(buf) - 1);
close(fifo_fd);
if (count != -1)
buf[count] = 0;
if (count == 0)
continue;
syslog(LOG_DEBUG, "Received %s from fifo", buf);
if (strncasecmp(buf, "sig", 3) == 0) {
if ((sscanf(buf, "%s %d", cmd, &sig_send) == 2)
&& (sig_send >= 0 && sig_send < NSIG)) {
syslog(LOG_INFO, "Sending signal %d to %d", sig_send,
child_pid);
if (kill(child_pid, sig_send) == -1)
syslog(LOG_ERR, "Unable to send signal %d to %d",
sig_send, child_pid);
}
}
continue;
}
if (do_healthcheck) {
do_healthcheck = 0;
alarm(0);
syslog(LOG_DEBUG, "running health check for %s", svcname);
health_pid = exec_command("healthcheck");
health_status = rc_waitpid(health_pid);
if (WIFEXITED(health_status) && WEXITSTATUS(health_status) == 0)
alarm(healthchecktimer);
else {
syslog(LOG_WARNING, "health check for %s failed", svcname);
health_pid = exec_command("unhealthy");
rc_waitpid(health_pid);
syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid);
nkilled = run_stop_schedule(applet, NULL, NULL, child_pid, 0,
false, false, true);
if (nkilled < 0)
syslog(LOG_INFO, "Unable to kill %d: %s",
child_pid, strerror(errno));
else
healthcheck_respawn = 1;
}
}
if (exiting ) {
alarm(0);
syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid);
nkilled = run_stop_schedule(applet, exec, NULL, child_pid, 0,
nkilled = run_stop_schedule(applet, NULL, 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;
}
}
continue;
}
wait_pid = waitpid(child_pid, &i, WNOHANG);
if (wait_pid == child_pid) {
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));
}
if (wait_pid == child_pid || healthcheck_respawn) {
do_healthcheck = 0;
healthcheck_respawn = 0;
alarm(0);
respawn_now = time(NULL);
if (first_spawn == 0)
first_spawn = respawn_now;
if ((respawn_period > 0)
&& (respawn_now - first_spawn > respawn_period)) {
respawn_count = 0;
first_spawn = 0;
} else
respawn_count++;
if (respawn_max > 0 && respawn_count > respawn_max) {
syslog(LOG_WARNING, "respawned \"%s\" too many times, exiting",
exec);
exiting = 1;
failing = 1;
continue;
}
ts.tv_sec = respawn_delay;
ts.tv_nsec = 0;
nanosleep(&ts, NULL);
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
if (child_pid == 0)
if (child_pid == -1) {
syslog(LOG_ERR, "%s: fork: %s", applet, strerror(errno));
exit(EXIT_FAILURE);
}
if (child_pid == 0) {
sigprocmask(SIG_SETMASK, &old_signals, NULL);
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
sigaction(SIGALRM, &sa, NULL);
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
child_process(exec, argv);
}
if (healthcheckdelay)
alarm(healthcheckdelay);
else if (healthchecktimer)
alarm(healthchecktimer);
}
}
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);
rc_service_mark(svcname, RC_SERVICE_STOPPED);
if (failing)
rc_service_mark(svcname, RC_SERVICE_FAILED);
}
if (pidfile && exists(pidfile))
unlink(pidfile);
if (fifopath && exists(fifopath))
unlink(fifopath);
exit(EXIT_SUCCESS);
}
@@ -550,6 +689,7 @@ int main(int argc, char **argv)
bool start = false;
bool stop = false;
bool reexec = false;
bool sendsig = false;
char *exec = NULL;
char *retry = NULL;
int sig = SIGTERM;
@@ -612,6 +752,16 @@ int main(int argc, char **argv)
while ((opt = getopt_long(argc, argv, getoptstring, longopts,
(int *) 0)) != -1)
switch (opt) {
case 'a': /* --healthcheck-timer <time> */
if (sscanf(optarg, "%d", &healthchecktimer) != 1 || healthchecktimer < 1)
eerrorx("%s: invalid health check timer %s", applet, optarg);
break;
case 'A': /* --healthcheck-delay <time> */
if (sscanf(optarg, "%d", &healthcheckdelay) != 1 || healthcheckdelay < 1)
eerrorx("%s: invalid health check delay %s", applet, optarg);
break;
case 'D': /* --respawn-delay time */
n = sscanf(optarg, "%d", &respawn_delay);
if (n != 1 || respawn_delay < 1)
@@ -645,6 +795,10 @@ int main(int argc, char **argv)
eerrorx("Invalid respawn-period value '%s'", optarg);
break;
case 's': /* --signal */
sig = parse_signal(applet, optarg);
sendsig = true;
break;
case 'S': /* --start */
start = true;
break;
@@ -668,6 +822,11 @@ int main(int argc, char **argv)
gid = gr->gr_gid;
break;
case 'H': /* --healthcheck-timer <minutes> */
if (sscanf(optarg, "%d", &healthchecktimer) != 1 || healthchecktimer < 1)
eerrorx("%s: invalid health check timer %s", applet, optarg);
break;
case 'k':
if (parse_mode(&numask, optarg))
eerrorx("%s: invalid mode `%s'",
@@ -745,8 +904,6 @@ int main(int argc, char **argv)
case_RC_COMMON_GETOPT
}
if (!pidfile && !reexec)
eerrorx("%s: --pidfile must be specified", applet);
endpwent();
argc -= optind;
argv += optind;
@@ -759,6 +916,12 @@ int main(int argc, char **argv)
ch_root = expand_home(home, ch_root);
umask(numask);
if (!pidfile)
xasprintf(&pidfile, "/var/run/supervise-%s.pid", svcname);
xasprintf(&fifopath, "%s/supervise-%s.ctl", RC_SVCDIR, svcname);
if (mkfifo(fifopath, 0600) == -1 && errno != EEXIST)
eerrorx("%s: unable to create control fifo: %s",
applet, strerror(errno));
if (reexec) {
str = rc_service_value_get(svcname, "argc");
@@ -833,9 +996,9 @@ int main(int argc, char **argv)
0, false, true) > 0)
eerrorx("%s: %s is already running", applet, exec);
if (respawn_delay * respawn_max > respawn_period)
if (respawn_period > 0 && respawn_delay * respawn_max > respawn_period)
ewarn("%s: Please increase the value of --respawn-period to more "
"than %d to avoid infinite respawning", applet,
"than %d to avoid infinite respawning", applet,
respawn_delay * respawn_max);
if (retry) {
@@ -863,10 +1026,13 @@ int main(int argc, char **argv)
varbuf = NULL;
xasprintf(&varbuf, "%i", respawn_delay);
rc_service_value_set(svcname, "respawn_delay", varbuf);
free(varbuf);
xasprintf(&varbuf, "%i", respawn_max);
rc_service_value_set(svcname, "respawn_max", varbuf);
free(varbuf);
xasprintf(&varbuf, "%i", respawn_period);
rc_service_value_set(svcname, "respawn_period", varbuf);
free(varbuf);
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
@@ -877,6 +1043,9 @@ int main(int argc, char **argv)
tty_fd = open("/dev/tty", O_RDWR);
#endif
devnull_fd = open("/dev/null", O_RDWR);
dup2(devnull_fd, STDIN_FILENO);
dup2(devnull_fd, STDOUT_FILENO);
dup2(devnull_fd, STDERR_FILENO);
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
@@ -894,6 +1063,7 @@ int main(int argc, char **argv)
}
xasprintf(&varbuf, "%d", x);
rc_service_value_set(svcname, "argc", varbuf);
free(varbuf);
rc_service_value_set(svcname, "exec", exec);
supervisor(exec, argv);
} else
@@ -928,5 +1098,18 @@ int main(int argc, char **argv)
rc_service_mark(svcname, RC_SERVICE_STOPPED);
}
exit(EXIT_SUCCESS);
} else if (sendsig) {
fifo_fd = open(fifopath, O_WRONLY |O_NONBLOCK);
if (fifo_fd < 0)
eerrorx("%s: unable to open control fifo %s", applet, strerror(errno));
xasprintf(&str, "sig %d", sig);
x = write(fifo_fd, str, strlen(str));
if (x == -1) {
free(tmp);
eerrorx("%s: error writing to control fifo: %s", applet,
strerror(errno));
}
free(tmp);
exit(EXIT_SUCCESS);
}
}

View File

@@ -20,6 +20,13 @@ checkit() {
ret=0
fail_on_out() {
if [ -n "${out}" ]; then
eerror "Last command failed; failing"
exit 1
fi
}
ebegin "Checking exported symbols in libeinfo.so (data)"
checkit einfo.data $(
readelf -Ws ${libeinfo_builddir}/libeinfo.so \
@@ -74,6 +81,7 @@ out=$(cd ${top_srcdir}; find */ \
-exec grep -n -E '[[:space:]]+$' {} +)
[ -z "${out}" ]
eend $? "Trailing whitespace needs to be deleted:"$'\n'"${out}"
fail_on_out
ebegin "Checking trailing newlines in code"
out=$(cd ${top_srcdir};
@@ -82,6 +90,7 @@ out=$(cd ${top_srcdir};
done)
[ -z "${out}" ]
eend $? "Trailing newlines need to be deleted:"$'\n'"${out}"
fail_on_out
ebegin "Checking for obsolete functions"
out=$(cd ${top_srcdir}; find src -name '*.[ch]' \
@@ -89,6 +98,7 @@ out=$(cd ${top_srcdir}; find src -name '*.[ch]' \
-exec grep -n -E '\<(malloc|memory|sys/(errno|fcntl|signal|stropts|termios|unistd))\.h\>' {} +)
[ -z "${out}" ]
eend $? "Avoid these obsolete functions:"$'\n'"${out}"
fail_on_out
ebegin "Checking for x* func usage"
out=$(cd ${top_srcdir}; find src -name '*.[ch]' \
@@ -99,6 +109,7 @@ out=$(cd ${top_srcdir}; find src -name '*.[ch]' \
-e src/libeinfo/libeinfo.c)
[ -z "${out}" ]
eend $? "These need to be using the x* variant:"$'\n'"${out}"
fail_on_out
ebegin "Checking spacing style"
out=$(cd ${top_srcdir}; find src -name '*.[ch]' \
@@ -113,6 +124,7 @@ out=$(cd ${top_srcdir}; find src -name '*.[ch]' \
{} +)
[ -z "${out}" ]
eend $? "These lines violate style rules:"$'\n'"${out}"
fail_on_out
einfo "Running unit tests"
eindent

View File

@@ -7,44 +7,100 @@ terminates unexpectedly.
The following is a brief guide on using this capability.
## Use Default start, stop and status functions
* Use Default start, stop and status functions
If you write your own start, stop and status functions in your service
script, none of this will work. You must allow OpenRC to use the default
functions.
If you write your own start, stop and status functions in your service
script, none of this will work. You must allow OpenRC to use the default
functions.
* Daemons must not fork
Any deamon that you would like to have monitored by supervise-daemon
must not fork. Instead, it must stay in the foreground. If the daemon
forks, the supervisor will be unable to monitor it.
## Daemons must not fork
If the daemon can be configured to not fork, this should be done in the
daemon's configuration file, or by adding a command line option that
instructs it not to fork to the command_args_foreground variable shown
below.
Any deamon that you would like to have monitored by supervise-daemon
must not fork. Instead, it must stay in the foreground. If the daemon
itself forks, the supervisor will be unable to monitor it.
# Health Checks
If the daemon can be configured to not fork, this should be done in the
daemon's configuration file, or by adding a command line option that
instructs it not to fork to the command_args_foreground variable shown
below.
Health checks are a way to make sure a service monitored by
supervise-daemon stays healthy. To configure a health check for a
service, you need to write a healthcheck() function, and optionally an
unhealthy() function in the service script. Also, you will need to set
the healthcheck_timer and optionally healthcheck_delay variables.
## Variable Settings
## healthcheck() function
The healthcheck() function is run repeatedly based on the settings of
the healthcheck_* variables. This function should return zero if the
service is currently healthy or non-zero otherwise.
## unhealthy() function
If the healthcheck() function returns non-zero, the unhealthy() function
is run, then the service is restarted. Since the service will be
restarted by the supervisor, the unhealthy function should not try to
restart it; the purpose of the function is to allow any cleanup tasks
other than restarting the service to be run.
# Variable Settings
The most important setting is the supervisor variable. At the top of
your service script, you should set this variable as follows:
``` sh
supervisor=supervise-daemon
```
Several other variables affect the way services behave under
supervise-daemon. They are documented on the openrc-run man page, but I
will list them here for convenience:
pidfile=/pid/of/supervisor.pid
``` sh
command_args_foreground="arguments"
```
If you are using start-stop-daemon to monitor your scripts, the pidfile
is the path to the pidfile the daemon creates. If, on the other hand,
you are using supervise-daemon, this is the path to the pidfile the
supervisor creates.
command_args_foreground should be used if the daemon you want to monitor
This should be used if the daemon you want to monitor
forks and goes to the background by default. This should be set to the
command line option that instructs the daemon to stay in the foreground.
This is very early support, so feel free to file bugs if you have
issues.
``` sh
healthcheck_delay=seconds
```
This is the delay, in seconds, before the first health check is run.
If it is not set, we use the value of healthcheck_timer.
``` sh
healthcheck_timer=seconds
```
This is the number of seconds between health checks. If it is not set,
no health checks will be run.
``` sh
respawn_delay
```
This is the number of seconds to delay before attempting to respawn a
supervised process after it dies unexpectedly.
The default is to respawn immediately.
``` sh
respawn_max=x
```
This is the maximum number of times to respawn a supervised process
during the given respawn period. The default is unlimited.
``` sh
respawn_period=seconds
```
This works in conjunction with respawn_max and respawn_delay above to
decide if a process should not be respawned for some reason.
For example, if respawn_period is 60, respawn_max is 2 and respawn_delay
is 3 and a process dies more than 4 times, the process will not be
respawned and the supervisor will terminate.

23
test/travis.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/bin/bash
# Copyright (c) 2007-2018 The OpenRC Authors.
# See the Authors file at the top-level directory of this distribution and
# https://github.com/OpenRC/openrc/blob/master/AUTHORS
#
# This file is part of OpenRC. It is subject to the license terms in
# the LICENSE file found in the top-level directory of this
# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE
# This file may not be copied, modified, propagated, or distributed
# except according to the terms contained in the LICENSE file.
set -e
set -u
set -x
# These are steps to run on TravisCI under a containerized Ubuntu system.
# See $TOP/.travis.yml for more info about the TravisCI setup.
cpus=$(getconf _NPROCESSORS_CONF || echo 1)
# make on TravisCI doesn't support -O yet
make -j"${cpus}"
make test