Compare commits

..

10 Commits

Author SHA1 Message Date
William Hubbs
5df7ee0564 Update ChangeLog 2018-03-11 23:50:38 -05:00
William Hubbs
b731c02a38 Clean up cgroups v2 code
Remove the IFS manipulation and simplify the loop that processes the
settings.
2018-03-11 23:16:51 -05:00
Scall
c42916ea19 init.d: swap should always be started after root
Otherwise if a swap file is being used, and swap is started before
root, swapon may fail because of a read-only filesystem.
2018-03-11 23:16:51 -05:00
William Hubbs
f973354ccd version 0.35.3 2018-03-11 23:16:45 -05:00
William Hubbs
69349f7b57 Update ChangeLog 2018-03-01 19:29:17 -06:00
William Hubbs
1b1a70ecca version 0.35.2 2018-03-01 19:00:34 -06:00
Chris Cromer
05cfbb8348 openrc-run: fix memory size (#213)
Fixes #212
2018-03-01 19:33:02 -05:00
William Hubbs
a70b65f851 Update ChangeLog 2018-03-01 13:47:21 -06:00
William Hubbs
0660d2455d fix build on FreeBSD 2018-03-01 11:56:20 -06:00
William Hubbs
01c5b98d38 version 0.35.1 2018-03-01 11:55:55 -06:00
64 changed files with 1574 additions and 1824 deletions

1854
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,3 @@
NAME= openrc
VERSION= 0.39.2
VERSION= 0.35.3
PKG= ${NAME}-${VERSION}

51
NEWS.md
View File

@@ -4,57 +4,6 @@ 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.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
processes instead of files. These processes are defined by the
output_logger and error_logger variables in standard service scripts, or
by the -3/--output-logger or -4/--error-logger switches if you use
start-stop-daemon directly. For more information on this, see the
start-stop-daemon man page.
## OpenRC 0.36
In this release, the modules-load service has been combined into the
modules service since there is no reason I know of to keep them
separate. However, modules also provides modules-load in case you were
using modules-load in your dependencies.
The consolefont, keymaps, numlock and procfs service scripts no longer
have a dependency on localmount.
If you are a linux user and are still separaating / from /usr,
you will need to add the following line to the appropriate conf.d files:
rc_need="localmount"
## OpenRC 0.35
In this version, the cgroups mounting logic has been moved from the

View File

@@ -8,6 +8,11 @@
#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

@@ -19,10 +19,10 @@ SRCS-FreeBSD= hostid.in modules.in moused.in newsyslog.in pf.in rarpd.in \
rc-enabled.in rpcbind.in savecore.in syslogd.in
# These are FreeBSD specific
SRCS-FreeBSD+= adjkerntz.in devd.in dumpon.in encswap.in ipfw.in \
mixer.in nscd.in powerd.in syscons.in
modules-load.in mixer.in nscd.in powerd.in syscons.in
SRCS-Linux= agetty.in binfmt.in devfs.in cgroups.in dmesg.in hwclock.in \
consolefont.in keymaps.in killprocs.in modules.in \
consolefont.in keymaps.in killprocs.in modules.in modules-load.in \
mount-ro.in mtab.in numlock.in procfs.in net-online.in sysfs.in \
termencoding.in

View File

@@ -16,6 +16,7 @@ term_type="${term_type:-linux}"
command=/sbin/agetty
command_args_foreground="${agetty_options} ${port} ${baud} ${term_type}"
pidfile="/run/${RC_SVCNAME}.pid"
export EINFO_QUIET="${quiet:-yes}"
depend() {
after local
@@ -28,12 +29,5 @@ start_pre() {
eerror "symbolic links to it for the ports you want to start"
eerror "agetty on and add those to the appropriate runlevels."
return 1
else
export EINFO_QUIET="${quiet:-yes}"
fi
}
stop_pre()
{
export EINFO_QUIET="${quiet:-yes}"
}

View File

@@ -13,7 +13,7 @@ description="Sets a font for the consoles."
depend()
{
need termencoding
need localmount termencoding
after hotplug bootmisc modules
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
}

View File

@@ -13,7 +13,7 @@ description="Applies a keymap for the consoles."
depend()
{
need termencoding
need localmount termencoding
after bootmisc clock
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
}

72
init.d/modules-load.in Normal file
View File

@@ -0,0 +1,72 @@
#!@SBINDIR@/openrc-run
# Copyright (c) 2016 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.
description="Loads a list of modules from systemd-compatible locations."
depend()
{
keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver
}
find_modfiles()
{
local dirs="/usr/lib/modules-load.d /run/modules-load.d /etc/modules-load.d"
local basenames files fn x y
for x in $dirs; do
[ ! -d $x ] && continue
for y in $x/*.conf; do
[ -f $y ] && basenames="${basenames}\n${y##*/}"
done
done
basenames=$(printf "$basenames" | sort -u)
for x in $basenames; do
for y in $dirs; do
[ -r $y/$x ] &&
fn=$y/$x
done
files="$files $fn"
done
echo $files
}
load_modules()
{
local file m modules rc x
file=$1
[ -z "$file" ] && return 0
while read m x; do
case $m in
\;*) continue ;;
\#*) continue ;;
*) modules="$modules $m"
;;
esac
done < $file
for x in $modules; do
ebegin "Loading module $x"
case "$RC_UNAME" in
FreeBSD) kldload "$x"; rc=$? ;;
Linux) modprobe --use-blacklist -q "$x"; rc=$? ;;
*) ;;
esac
eend $rc "Failed to load $x"
done
}
start()
{
local x
files=$(find_modfiles)
for x in $files; do
load_modules $x
done
return 0
}

View File

@@ -14,66 +14,10 @@ description="Loads a user defined list of kernel modules."
depend()
{
use isapnp
provide modules-load
want modules-load
keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver
}
find_modfiles()
{
local dirs="/usr/lib/modules-load.d /run/modules-load.d /etc/modules-load.d"
local basenames files fn x y
for x in $dirs; do
[ ! -d $x ] && continue
for y in $x/*.conf; do
[ -f $y ] && basenames="${basenames}\n${y##*/}"
done
done
basenames=$(printf "$basenames" | sort -u)
for x in $basenames; do
for y in $dirs; do
[ -r $y/$x ] &&
fn=$y/$x
done
files="$files $fn"
done
echo $files
}
load_modules()
{
local file m modules rc x
file=$1
[ -z "$file" ] && return 0
while read m x; do
case $m in
\;*) continue ;;
\#*) continue ;;
*) modules="$modules $m"
;;
esac
done < $file
for x in $modules; do
ebegin "Loading module $x"
case "$RC_UNAME" in
FreeBSD) kldload "$x"; rc=$? ;;
Linux) modprobe --first-time -q --use-blacklist "$x"; rc=$? ;;
*) ;;
esac
eend $rc "Failed to load $x"
done
return 0
}
modules_load_d()
{
local x
files=$(find_modfiles)
for x in $files; do
load_modules $x
done
return 0
}
FreeBSD_modules()
{
local cnt=0 x
@@ -104,7 +48,7 @@ Linux_modules()
x=${x%.*}
done
local list= x= xx= y= args=
local list= x= xx= y= args= mpargs= a=
for x in $kv_variant_list ; do
eval list=\$modules_$(shell_var "$x")
[ -n "$list" ] && break
@@ -113,13 +57,24 @@ 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 --first-time --use-blacklist --verbose "$x" "$args"
eval modprobe --use-blacklist --verbose "$mpargs" "$x" "$args"
done
[ -n "$list" ] && eend
}
@@ -127,10 +82,7 @@ Linux_modules()
start()
{
case "$RC_UNAME" in
FreeBSD|Linux)
modules_load_d
${RC_UNAME}_modules
;;
FreeBSD|Linux) ${RC_UNAME}_modules ;;
*) ;;
esac
return 0

View File

@@ -13,7 +13,7 @@ description="Delays until the network is online or a specific timeout"
depend()
{
after modules net
after modules
need sysfs
provide network-online
keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn -uml -vserver

View File

@@ -15,6 +15,7 @@ ttyn=${rc_tty_number:-${RC_TTY_NUMBER:-12}}
depend()
{
need localmount
keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver
}

View File

@@ -16,6 +16,7 @@ depend()
after clock
use devfs
want modules
need localmount
keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver
}

View File

@@ -49,7 +49,7 @@ start()
fi
ebegin "Saving dependency cache"
local rc=0 save=
for x in depconfig deptree rc.log shutdowntime softlevel; do
for x in shutdowntime softlevel rc.log; do
[ -e "$RC_SVCDIR/$x" ] && save="$save $RC_SVCDIR/$x"
done
if [ -n "$save" ]; then

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 ${sysfs_opts} \
mount -n -t efivarfs -o ro \
efivarfs /sys/firmware/efi/efivars 2> /dev/null
eend 0
fi

View File

@@ -119,9 +119,6 @@ The amount of time, in milliseconds, s6-svc should wait for the service
to go down when stopping the service. The default is 60000.
.It Ar start_stop_daemon_args
List of arguments passed to start-stop-daemon when starting the daemon.
.It Ar supervise_daemon_args
List of arguments passed to supervise-daemon when starting the daemon.
If undefined, start_stop_daemon_args is used as a fallback.
.It Ar command
Daemon to start or stop via
.Nm start-stop-daemon
@@ -173,23 +170,6 @@ variable is set.
The same thing as
.Pa output_log
but for the standard error output.
.It Ar output_logger
This is a process which will be used to log the standard output from the
service. If you are starting this service with
.Xr start-stop-daemon 8 ,
, you must set
.Pa command_background
to true. Keep in mind that this command must be executable as a shell
command inside the chroot if the
.Pa chroot
variable is set. Keep in mind also that this command works by accepting
the stdout of the service on stdin.
An example of a command that can be run this way is logger if you want
your service output to go to syslog.
.It Ar error_logger
The same thing as
.Pa output_logger
but for the standard error output.
.It Ar directory
.Xr start-stop-daemon 8
and
@@ -614,7 +594,7 @@ rc_net_tap1_provide="!net"
# It's also possible to negate keywords. This is mainly useful for prefix
# users testing OpenRC.
rc_keyword="!-prefix"
# This can also be used to block a script from running in all
# This can also be used to block a script from runining in all
# containers except one or two
rc_keyword="!-containers !-docker"
.Ed

View File

@@ -16,7 +16,6 @@
.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
@@ -33,8 +32,6 @@ 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

@@ -20,14 +20,6 @@
.Ar service cmd
.Op Ar ...
.Nm
.Fl d , -debug
.Ar service cmd
.Op Ar ...
.Nm
.Fl D , -nodeps
.Ar service cmd
.Op Ar ...
.Nm
.Op Fl i , -ifexists
.Ar service cmd
.Op Ar ...
@@ -40,21 +32,9 @@
.Ar service cmd
.Op Ar ...
.Nm
.Op Fl s , -ifstarted
.Ar service cmd
.Op Ar ...
.Nm
.Op Fl S , -ifstopped
.Ar service cmd
.Op Ar ...
.Nm
.Fl e , -exists
.Ar service
.Nm
.Fl Z , -dry-run
.Ar service cmd
.Op Ar ...
.Nm
.Fl l , -list
.Nm
.Fl r , -resolve
@@ -88,15 +68,6 @@ return 0 if it can find
otherwise -1.
.Fl r , -resolve
does the same and also prints the full path of the service to stdout.
.Pp
.Fl d , -debug
sets -x when running the service script(s).
.Pp
.Fl D , -nodeps
ignores dependencies when running the service.
.Pp
.Fl Z , -dry-run
displays commands rather than executing them.
.Sh SEE ALSO
.Xr openrc 8 ,
.Xr stdout 3

View File

@@ -131,34 +131,9 @@ Modifies the scheduling priority of the daemon.
.It Fl 1 , -stdout Ar logfile
Redirect the standard output of the process to logfile when started with
.Fl background .
The logfile Must be an absolute pathname, but relative to the path
optionally given with
Must be an absolute pathname, but relative to the path optionally given with
.Fl r , -chroot .
The logfile can also be a named pipe.
.It Fl 2 , -stderr Ar logfile
Redirect the standard error of the process to logfile when started with
.Fl background .
The logfile must be an absolute pathname, but relative to the path
optionally given with
.Fl r , -chroot .
The logfile can also be a named pipe.
.It Fl 3 , -stdout-logger Ar cmd
Run cmd as a child process redirecting the standard output to the
standard input of cmd when started with
.Fl background .
Cmd must be an absolute pathname, but relative to the path optionally given with
.Fl r , -chroot .
This process must be prepared to accept input on stdin and be able to
log it or send it to another location.
.It Fl 4 , -stderr-logger Ar cmd
Run cmd as a child process and
Redirect the standard error of the process to the standard input of cmd
when started with
.Fl background .
Cmd must be an absolute pathname, but relative to the path optionally given with
.Fl r , -chroot .
This process must be prepared to accept input on stdin and be able to
log it or send it to another location.
.It Fl w , -wait Ar milliseconds
Wait
.Ar milliseconds
@@ -176,7 +151,6 @@ These options are only used for stopping daemons:
.It Fl R , -retry Ar timeout | Ar signal Ns / Ns Ar timeout
The retry specification can be either a timeout in seconds or multiple
signal/timeout pairs (like SIGTERM/5).
If this option is not given, the default is SIGTERM/5.
.El
.Sh ENVIRONMENT
.Va SSD_IONICELEVEL

View File

@@ -16,10 +16,6 @@
.Nd starts a daemon and restarts it if it crashes
.Sh SYNOPSIS
.Nm
.Fl a , -healthcheck-timer
.Ar seconds
.Fl A , -healthcheck-delay
.Ar seconds
.Fl D , -respawn-delay
.Ar seconds
.Fl d , -chdir
@@ -94,11 +90,6 @@ 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.
@@ -129,7 +120,6 @@ 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
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.

View File

@@ -12,4 +12,4 @@
include ${MK}/os-BSD.mk
CPPFLAGS+= -D_BSD_SOURCE
CPPFLAGS+= -D_WITH_GETLINE

View File

@@ -13,6 +13,6 @@
SFX= .GNU-kFreeBSD.in
PKG_PREFIX?= /usr
CPPFLAGS+= -D_BSD_SOURCE
CPPFLAGS+= -D_BSD_SOURCE -D_XOPEN_SOURCE=700
LIBDL= -Wl,-Bdynamic -ldl
LIBKVM?=

View File

@@ -11,5 +11,5 @@
SFX= .GNU.in
PKG_PREFIX?= /usr
CPPFLAGS+= -D_DEFAULT_SOURCE -DMAXPATHLEN=4096 -DPATH_MAX=4096
CPPFLAGS+= -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700 -DMAXPATHLEN=4096 -DPATH_MAX=4096
LIBDL= -Wl,-Bdynamic -ldl

View File

@@ -11,7 +11,7 @@
SFX= .Linux.in
PKG_PREFIX?= /usr
CPPFLAGS+= -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L
CPPFLAGS+= -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700
LIBDL= -Wl,-Bdynamic -ldl
ifeq (${MKSELINUX},yes)

View File

@@ -45,20 +45,20 @@ SBINDIR?= ${PREFIX}/sbin
SBINMODE?= 0755
INCDIR?= ${UPREFIX}/include
INCMODE?= 0644
INCMODE?= 0444
_LIBNAME_SH= case `readlink /lib` in /lib64|lib64) echo "lib64";; *) echo "lib";; esac
_LIBNAME:= $(shell ${_LIBNAME_SH})
LIBNAME?= ${_LIBNAME}
LIBDIR?= ${UPREFIX}/${LIBNAME}
LIBMODE?= 0644
LIBMODE?= 0444
SHLIBDIR?= ${PREFIX}/${LIBNAME}
LIBEXECDIR?= ${PREFIX}/libexec/rc
MANPREFIX?= ${UPREFIX}/share
MANDIR?= ${MANPREFIX}/man
MANMODE?= 0644
MANMODE?= 0444
BASHCOMPDIR?= ${UPREFIX}/share/bash-completion/completions

View File

@@ -29,9 +29,7 @@ Not using this interpreter will break the use of dependencies and is not
supported. (iow: if you insist on using `#!/bin/sh` you're on your own)
A `depend` function declares the dependencies of this service script.
All scripts must have start/stop/status functions, but defaults are
provided and should be used unless you have a very strong reason not to
use them.
All scripts must have start/stop/status functions, but defaults are provided and should be used unless you have a very strong reason not to use them.
Extra functions can be added easily:

1
sh/.gitignore vendored
View File

@@ -1,5 +1,6 @@
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 ${SRCS-${OS}}
openrc-run.sh.in rc-functions.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

@@ -133,10 +133,11 @@ _status()
elif service_inactive; then
ewarn "status: inactive"
return 16
elif service_crashed; then
eerror "status: crashed"
return 32
elif service_started; then
if service_crashed; then
eerror "status: crashed"
return 32
fi
einfo "status: started"
return 0
else

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,6 +2,42 @@
# 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,10 +38,6 @@ ssd_start()
service_inactive && _inactive=true
mark_service_inactive
fi
[ -n "$output_logger" ] &&
output_logger_arg="--stdout-logger \"$output_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"
# to work properly.
@@ -51,8 +47,6 @@ ssd_start()
${directory:+--chdir} $directory \
${output_log+--stdout} $output_log \
${error_log+--stderr} $error_log \
${output_logger_arg} \
${error_logger_arg} \
${procname:+--name} $procname \
${pidfile:+--pidfile} $pidfile \
${command_user+--user} $command_user \

View File

@@ -10,8 +10,6 @@
# 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
@@ -34,11 +32,9 @@ 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}} \
$supervise_daemon_args \
$command \
-- $command_args $command_args_foreground
rc=$?
@@ -102,13 +98,3 @@ supervise_status()
return 3
fi
}
healthcheck()
{
return 0
}
unhealthy()
{
return 0
}

View File

@@ -66,6 +66,9 @@ int parse_mode(mode_t *, char *);
/* Handy function so we can wrap einfo around our deptree */
RC_DEPTREE *_rc_deptree_load (int, int *);
/* Test to see if we can see pid 1 or not */
bool _rc_can_find_pids(void);
RC_SERVICE lookup_service_state(const char *service);
void from_time_t(char *time_string, time_t tv);
time_t to_time_t(char *timestring);

View File

@@ -883,7 +883,7 @@ eindent(void)
{
char *env = getenv("EINFO_INDENT");
int amount = 0;
char *num;
char num[10];
if (env) {
errno = 0;
@@ -894,9 +894,8 @@ eindent(void)
amount += INDENT_WIDTH;
if (amount > INDENT_MAX)
amount = INDENT_MAX;
xasprintf(&num, "%08d", amount);
snprintf(num, 10, "%08d", amount);
setenv("EINFO_INDENT", num, 1);
free(num);
}
hidden_def(eindent)
@@ -904,7 +903,7 @@ void eoutdent(void)
{
char *env = getenv("EINFO_INDENT");
int amount = 0;
char *num = NULL;
char num[10];
int serrno = errno;
if (!env)
@@ -918,9 +917,8 @@ void eoutdent(void)
if (amount <= 0)
unsetenv("EINFO_INDENT");
else {
xasprintf(&num, "%08d", amount);
snprintf(num, 10, "%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 = NULL;
char buffer[32];
FILE *fp;
int c;
bool retval = false;
exec = basename_c(exec);
xasprintf(&buffer, "/proc/%d/stat", pid);
snprintf(buffer, sizeof(buffer), "/proc/%d/stat", pid);
if ((fp = fopen(buffer, "r"))) {
while ((c = getc(fp)) != EOF && c != '(')
;
@@ -41,27 +41,23 @@ 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 = NULL;
char cmdline[32];
int fd;
char buffer[PATH_MAX];
char *p;
ssize_t bytes;
xasprintf(&cmdline, "/proc/%u/cmdline", pid);
if ((fd = open(cmdline, O_RDONLY)) < 0) {
free(cmdline);
snprintf(cmdline, sizeof(cmdline), "/proc/%u/cmdline", pid);
if ((fd = open(cmdline, O_RDONLY)) < 0)
return false;
}
bytes = read(fd, buffer, sizeof(buffer));
close(fd);
free(cmdline);
if (bytes == -1)
return false;
@@ -92,7 +88,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 = NULL;
char buffer[PATH_MAX];
struct stat sb;
pid_t openrc_pid = 0;
char *pp;
@@ -153,22 +149,18 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
continue;
if (pid != 0 && pid != p)
continue;
xasprintf(&buffer, "/proc/%d/ns/pid", p);
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';
}
free(buffer);
if (strlen(my_ns) && strlen (proc_ns) && strcmp(my_ns, proc_ns))
continue;
if (uid) {
xasprintf(&buffer, "/proc/%d", p);
if (stat(buffer, &sb) != 0 || sb.st_uid != uid) {
free(buffer);
snprintf(buffer, sizeof(buffer), "/proc/%d", p);
if (stat(buffer, &sb) != 0 || sb.st_uid != uid)
continue;
}
free(buffer);
}
if (exec && !pid_is_exec(p, exec))
continue;
@@ -177,10 +169,9 @@ 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) {
xasprintf(&buffer, "/proc/%d/status", p);
snprintf(buffer, sizeof(buffer), "/proc/%d/status", p);
if (exists(buffer)) {
fp = fopen(buffer, "r");
free(buffer);
if (! fp)
continue;
while (! feof(fp)) {
@@ -324,13 +315,12 @@ _match_daemon(const char *path, const char *file, RC_STRINGLIST *match)
{
char *line = NULL;
size_t len = 0;
char *ffile = NULL;
char ffile[PATH_MAX];
FILE *fp;
RC_STRING *m;
xasprintf(&ffile, "%s/%s", path, file);
snprintf(ffile, sizeof(ffile), "%s/%s", path, file);
fp = fopen(ffile, "r");
free(ffile);
if (!fp)
return false;
@@ -356,22 +346,29 @@ _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) {
xasprintf(&m, "exec=%s", exec);
l = strlen(exec) + 6;
m = xmalloc(sizeof(char) * l);
snprintf(m, l, "exec=%s", exec);
rc_stringlist_add(match, m);
free(m);
}
while (argv && argv[i]) {
xasprintf(&m, "argv_0=%s", argv[i++]);
l = strlen(*argv) + strlen("argv_=") + 16;
m = xmalloc(sizeof(char) * l);
snprintf(m, l, "argv_0=%s", argv[i++]);
rc_stringlist_add(match, m);
free(m);
}
if (pidfile) {
xasprintf(&m, "pidfile=%s", pidfile);
l = strlen(pidfile) + 9;
m = xmalloc(sizeof(char) * l);
snprintf(m, l, "pidfile=%s", pidfile);
rc_stringlist_add(match, m);
free(m);
}
@@ -384,8 +381,8 @@ rc_service_daemon_set(const char *service, const char *exec,
const char *const *argv,
const char *pidfile, bool started)
{
char *dirpath = NULL;
char *file = NULL;
char dirpath[PATH_MAX];
char file[PATH_MAX];
int nfiles = 0;
char oldfile[PATH_MAX] = { '\0' };
bool retval = false;
@@ -400,7 +397,8 @@ rc_service_daemon_set(const char *service, const char *exec,
return false;
}
xasprintf(&dirpath, RC_SVCDIR "/daemons/%s", basename_c(service));
snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s",
basename_c(service));
/* Regardless, erase any existing daemon info */
if ((dp = opendir(dirpath))) {
@@ -409,7 +407,8 @@ rc_service_daemon_set(const char *service, const char *exec,
if (d->d_name[0] == '.')
continue;
xasprintf(&file, "%s/%s", dirpath, d->d_name);
snprintf(file, sizeof(file), "%s/%s",
dirpath, d->d_name);
nfiles++;
if (!*oldfile) {
@@ -422,7 +421,6 @@ 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);
@@ -431,7 +429,8 @@ rc_service_daemon_set(const char *service, const char *exec,
/* Now store our daemon info */
if (started) {
if (mkdir(dirpath, 0755) == 0 || errno == EEXIST) {
xasprintf(&file, "%s/%03d", dirpath, nfiles + 1);
snprintf(file, sizeof(file), "%s/%03d",
dirpath, nfiles + 1);
if ((fp = fopen(file, "w"))) {
fprintf(fp, "exec=");
if (exec)
@@ -447,12 +446,10 @@ 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)
@@ -461,8 +458,8 @@ bool
rc_service_started_daemon(const char *service,
const char *exec, const char *const *argv, int indx)
{
char *dirpath = NULL;
char *file = NULL;
char dirpath[PATH_MAX];
char file[16];
RC_STRINGLIST *match;
bool retval = false;
DIR *dp;
@@ -471,13 +468,13 @@ rc_service_started_daemon(const char *service,
if (!service || !exec)
return false;
xasprintf(&dirpath, RC_SVCDIR "/daemons/%s", basename_c(service));
snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s",
basename_c(service));
match = _match_list(exec, argv, NULL);
if (indx > 0) {
xasprintf(&file, "%03d", indx);
snprintf(file, sizeof(file), "%03d", indx);
retval = _match_daemon(dirpath, file, match);
free(file);
} else {
if ((dp = opendir(dirpath))) {
while ((d = readdir(dp))) {
@@ -492,7 +489,6 @@ 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,9 +237,13 @@ static void rc_config_set_value(RC_STRINGLIST *config, char *value)
if (token[i] == '\n')
token[i] = 0;
xasprintf(&newline, "%s=%s", entry, token);
i = strlen(entry) + strlen(token) + 2;
newline = xmalloc(sizeof(char) * i);
snprintf(newline, i, "%s=%s", entry, token);
} else {
xasprintf(&newline, "%s=", entry);
i = strlen(entry) + 2;
newline = xmalloc(sizeof(char) * i);
snprintf(newline, i, "%s=", entry);
}
replaced = false;
@@ -296,7 +300,8 @@ static RC_STRINGLIST *rc_config_kcl(RC_STRINGLIST *config)
if (value != NULL) {
len = varlen + strlen(value) + 2;
xasprintf(&tmp, "%s=%s", override->value, value);
tmp = xmalloc(sizeof(char) * len);
snprintf(tmp, len, "%s=%s", override->value, value);
}
/*

View File

@@ -50,7 +50,6 @@ static const rc_service_state_name_t rc_service_state_names[] = {
{ RC_SERVICE_HOTPLUGGED, "hotplugged" },
{ RC_SERVICE_FAILED, "failed" },
{ RC_SERVICE_SCHEDULED, "scheduled"},
{ RC_SERVICE_CRASHED, "crashed"},
{ 0, NULL}
};
@@ -849,10 +848,6 @@ rc_service_state(const char *service)
}
}
if (state & RC_SERVICE_STARTED) {
if (rc_service_daemons_crashed(service) && errno != EACCES)
state |= RC_SERVICE_CRASHED;
}
if (state & RC_SERVICE_STOPPED) {
dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
TAILQ_FOREACH(dir, dirs, entries) {

View File

@@ -188,8 +188,7 @@ typedef enum
/* Optional states service could also be in */
RC_SERVICE_FAILED = 0x0200,
RC_SERVICE_SCHEDULED = 0x0400,
RC_SERVICE_WASINACTIVE = 0x0800,
RC_SERVICE_CRASHED = 0x1000,
RC_SERVICE_WASINACTIVE = 0x0800
} RC_SERVICE;
/*! Add the service to the runlevel

1
src/rc/.gitignore vendored
View File

@@ -56,7 +56,6 @@ mark_service_inactive
mark_service_wasinactive
mark_service_hotplugged
mark_service_failed
mark_service_crashed
rc-abort
rc
openrc

View File

@@ -5,8 +5,8 @@ include ${MK}/os.mk
SRCS= checkpath.c do_e.c do_mark_service.c do_service.c \
do_value.c fstabinfo.c is_newer_than.c is_older_than.c \
mountinfo.c openrc-run.c rc-abort.c rc.c \
rc-depend.c rc-logger.c rc-misc.c rc-pipes.c \
rc-plugin.c rc-service.c rc-status.c rc-update.c \
rc-depend.c rc-logger.c rc-misc.c rc-plugin.c \
rc-service.c rc-status.c rc-update.c \
shell_var.c start-stop-daemon.c supervise-daemon.c swclock.c _usage.c
ifeq (${MKSELINUX},yes)
@@ -14,7 +14,7 @@ SRCS+= rc-selinux.c
endif
ifeq (${OS},Linux)
SRCS+= kill_all.c openrc-init.c openrc-shutdown.c broadcast.c rc-wtmp.c
SRCS+= kill_all.c openrc-init.c openrc-shutdown.c rc-wtmp.c
endif
CLEANFILES= version.h rc-selinux.o
@@ -41,7 +41,6 @@ RC_SBINPROGS= mark_service_starting mark_service_started \
mark_service_stopping mark_service_stopped \
mark_service_inactive mark_service_wasinactive \
mark_service_hotplugged mark_service_failed \
mark_service_crashed \
rc-abort swclock
ifeq (${OS},Linux)
@@ -124,8 +123,7 @@ is_older_than: is_older_than.o rc-misc.o
mark_service_starting mark_service_started \
mark_service_stopping mark_service_stopped \
mark_service_inactive mark_service_wasinactive \
mark_service_hotplugged mark_service_failed \
mark_service_crashed: do_mark_service.o rc-misc.o
mark_service_hotplugged mark_service_failed: do_mark_service.o rc-misc.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
mountinfo: mountinfo.o _usage.o rc-misc.o
@@ -134,7 +132,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 rc-misc.o _usage.o broadcast.o rc-wtmp.o
openrc-shutdown: openrc-shutdown.o _usage.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
@@ -158,10 +156,10 @@ rc-service: rc-service.o _usage.o rc-misc.o
rc-update: rc-update.o _usage.o rc-misc.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
start-stop-daemon: start-stop-daemon.o _usage.o rc-misc.o rc-pipes.o rc-schedules.o
start-stop-daemon: start-stop-daemon.o _usage.o rc-misc.o rc-schedules.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
supervise-daemon: supervise-daemon.o _usage.o rc-misc.o rc-plugin.o rc-schedules.o
supervise-daemon: supervise-daemon.o _usage.o rc-misc.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

View File

@@ -1,209 +0,0 @@
/*
* 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;
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);
}

View File

@@ -1,16 +0,0 @@
/*
* 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,13 +269,11 @@ 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

@@ -68,7 +68,9 @@ int main(int argc, char **argv)
ok = rc_service_started_daemon(service, exec, NULL, idx);
} else if (strcmp(applet, "service_crashed") == 0) {
ok = ( rc_service_daemons_crashed(service) && errno != EACCES);
ok = (_rc_can_find_pids() &&
rc_service_daemons_crashed(service) &&
errno != EACCES);
} else
eerrorx("%s: unknown applet", applet);

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,7 +24,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -45,7 +44,7 @@ static pid_t do_openrc(const char *runlevel)
sigset_t signals;
pid = fork();
switch (pid) {
switch(pid) {
case -1:
perror("fork");
break;
@@ -97,15 +96,12 @@ 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);
ts.tv_sec = 3;
ts.tv_nsec = 0;
nanosleep(&ts, NULL);
sleep(3);
printf("Sending the final kill signal\n");
kill(-1, SIGKILL);
sync();
@@ -139,7 +135,7 @@ static void reap_zombies(void)
static void signal_handler(int sig)
{
switch (sig) {
switch(sig) {
case SIGINT:
handle_shutdown("reboot", RB_AUTOBOOT);
break;

View File

@@ -1268,9 +1268,6 @@ int main(int argc, char **argv)
case_RC_COMMON_GETOPT
}
if (rc_yesno(getenv("RC_NODEPS")))
deps = false;
/* If we're changing runlevels and not called by rc then we cannot
work with any dependencies */
if (deps && getenv("RC_PID") == NULL &&
@@ -1285,8 +1282,6 @@ int main(int argc, char **argv)
unsetenv("IN_BACKGROUND");
}
if (rc_yesno(getenv("IN_DRYRUN")))
dry_run = true;
if (rc_yesno(getenv("IN_HOTPLUG"))) {
if (!service_plugable())
eerrorx("%s: not allowed to be hotplugged", applet);

View File

@@ -25,24 +25,20 @@
#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 = "cdDfFHKpRrsw" getoptstring_COMMON;
const char *getoptstring = "dDHKpRrsw" 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'},
@@ -55,7 +51,6 @@ 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",
@@ -69,12 +64,8 @@ const char * const longopts_help[] = {
};
const char *usagestring = NULL;
const char *exclusive = "Select one of "
"--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";
"--halt, --kexec, --poweroff, --reexec, --reboot, --single or --write-only";
static bool do_cancel = false;
static bool do_dryrun = false;
static bool do_halt = false;
static bool do_kexec = false;
@@ -85,40 +76,6 @@ 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;
@@ -142,59 +99,16 @@ 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)
{
/* use the sig parameter so the compiler will not complain */
if (sig == SIGINT)
;
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;
@@ -203,17 +117,14 @@ 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':
@@ -222,12 +133,10 @@ 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':
@@ -237,91 +146,12 @@ int main(int argc, char **argv)
case_RC_COMMON_GETOPT
}
}
if (geteuid() != 0)
if (geteuid() != 0 && ! do_dryrun)
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)
@@ -330,6 +160,10 @@ 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

@@ -87,8 +87,6 @@ write_log(int logfd, const char *buffer, size_t bytes)
}
if (!in_escape) {
if (!isprint((int) *p) && *p != '\n')
goto cont;
if (write(logfd, p++, 1) == -1)
eerror("write: %s", strerror(errno));
continue;

View File

@@ -51,8 +51,7 @@ rc_conf_yesno(const char *setting)
static const char *const env_whitelist[] = {
"EERROR_QUIET", "EINFO_QUIET",
"IN_BACKGROUND", "IN_DRYRUN", "IN_HOTPLUG",
"RC_DEBUG", "RC_NODEPS",
"IN_BACKGROUND", "IN_HOTPLUG",
"LANG", "LC_MESSAGES", "TERM",
"EINFO_COLOR", "EINFO_VERBOSE",
NULL
@@ -411,6 +410,34 @@ RC_DEPTREE * _rc_deptree_load(int force, int *regen)
return rc_deptree_load();
}
bool _rc_can_find_pids(void)
{
RC_PIDLIST *pids;
RC_PID *pid;
RC_PID *pid2;
bool retval = false;
if (geteuid() == 0)
return true;
/* If we cannot see process 1, then we don't test to see if
* services crashed or not */
pids = rc_find_pids(NULL, NULL, 0, 1);
if (pids) {
pid = LIST_FIRST(pids);
if (pid) {
retval = true;
while (pid) {
pid2 = LIST_NEXT(pid, entries);
free(pid);
pid = pid2;
}
}
free(pids);
}
return retval;
}
static const struct {
const char * const name;
RC_SERVICE bit;
@@ -423,7 +450,6 @@ static const struct {
{ "service_hotplugged", RC_SERVICE_HOTPLUGGED, },
{ "service_wasinactive", RC_SERVICE_WASINACTIVE, },
{ "service_failed", RC_SERVICE_FAILED, },
{ "service_crashed", RC_SERVICE_CRASHED, },
};
RC_SERVICE lookup_service_state(const char *service)

View File

@@ -1,56 +0,0 @@
/*
* rc-pipes.c
* Helper to handle spawning processes and connecting them to pipes.
*/
/*
* Copyright (c) 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.
*/
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include "rc-pipes.h"
static const int pipe_read_end = 0;
static const int pipe_write_end = 1;
/*
* Starts a command with stdin redirected from a pipe
* Returns the write end of the pipe or -1
*/
int rc_pipe_command(char *cmd)
{
int pfd[2];
pid_t pid;
if (pipe(pfd) < 0)
return -1;
pid = fork();
if (pid > 0) {
/* parent */
close(pfd[pipe_read_end]);
return pfd[pipe_write_end];
} else if (pid == 0) {
/* child */
close(pfd[pipe_write_end]);
if (pfd[pipe_read_end] != STDIN_FILENO) {
if (dup2(pfd[pipe_read_end], STDIN_FILENO) < 0)
exit(1);
close(pfd[pipe_read_end]);
}
execl("/bin/sh", "sh", "-c", cmd, NULL);
exit(1);
}
return -1;
}

View File

@@ -1,18 +0,0 @@
/*
* Copyright (c) 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.
*/
#ifndef RC_PIPES_H
#define RC_PIPES_H
int rc_pipe_command(char *cmd);
#endif

View File

@@ -351,9 +351,8 @@ int run_stop_schedule(const char *applet,
tkilled += nkilled;
break;
case SC_FOREVER:
case SC_TIMEOUT:
if (item->type == SC_TIMEOUT && item->value < 1) {
if (item->value < 1) {
item = NULL;
break;
}
@@ -361,7 +360,7 @@ int run_stop_schedule(const char *applet,
ts.tv_sec = 0;
ts.tv_nsec = POLL_INTERVAL;
for (nsecs = 0; item->type == SC_FOREVER || nsecs < item->value; nsecs++) {
for (nsecs = 0; nsecs < item->value; nsecs++) {
for (nloops = 0;
nloops < ONE_SECOND / POLL_INTERVAL;
nloops++)

View File

@@ -29,35 +29,25 @@
const char *applet = NULL;
const char *extraopts = NULL;
const char *getoptstring = "cdDe:ilr:INsSZ" getoptstring_COMMON;
const char *getoptstring = "ce:ilr:IN" getoptstring_COMMON;
const struct option longopts[] = {
{ "debug", 0, NULL, 'd' },
{ "nodeps", 0, NULL, 'D' },
{ "exists", 1, NULL, 'e' },
{ "ifcrashed", 0, NULL, 'c' },
{ "ifexists", 0, NULL, 'i' },
{ "ifinactive", 0, NULL, 'I' },
{ "ifnotstarted", 0, NULL, 'N' },
{ "ifstarted", 0, NULL, 's' },
{ "ifstopped", 0, NULL, 'S' },
{ "list", 0, NULL, 'l' },
{ "resolve", 1, NULL, 'r' },
{ "dry-run", 0, NULL, 'Z' },
longopts_COMMON
};
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 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",
"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",
"list all available services",
"resolve the service name to an init script",
"dry run (show what would happen)",
longopts_help_COMMON
};
const char *usagestring = "" \
@@ -77,8 +67,6 @@ int main(int argc, char **argv)
bool if_exists = false;
bool if_inactive = false;
bool if_notstarted = false;
bool if_started = false;
bool if_stopped = false;
applet = basename_c(argv[0]);
/* Ensure that we are only quiet when explicitly told to be */
@@ -88,12 +76,6 @@ int main(int argc, char **argv)
longopts, (int *) 0)) != -1)
{
switch (opt) {
case 'd':
setenv("RC_DEBUG", "yes", 1);
break;
case 'D':
setenv("RC_NODEPS", "yes", 1);
break;
case 'e':
service = rc_service_resolve(optarg);
opt = service ? EXIT_SUCCESS : EXIT_FAILURE;
@@ -130,15 +112,6 @@ int main(int argc, char **argv)
free(service);
return EXIT_SUCCESS;
/* NOTREACHED */
case 's':
if_started = true;
break;
case 'S':
if_stopped = true;
break;
case 'Z':
setenv("IN_DRYRUN", "yes", 1);
break;
case_RC_COMMON_GETOPT
}
@@ -160,10 +133,6 @@ int main(int argc, char **argv)
return 0;
if (if_notstarted && (state & RC_SERVICE_STARTED))
return 0;
if (if_started && ! (state & RC_SERVICE_STARTED))
return 0;
if (if_stopped && ! (state & RC_SERVICE_STOPPED))
return 0;
*argv = service;
execv(*argv, argv);
eerrorx("%s: %s", applet, strerror(errno));

View File

@@ -54,6 +54,7 @@ const char *usagestring = "" \
"Usage: rc-status [options] <runlevel>...\n" \
" or: rc-status [options] [-a | -c | -l | -m | -r | -s | -u]";
static bool test_crashed = false;
static RC_DEPTREE *deptree;
static RC_STRINGLIST *types;
@@ -75,7 +76,7 @@ print_level(const char *prefix, const char *level)
printf("%s\n", level);
}
static char *get_uptime(const char *service)
static void get_uptime(const char *service, char *uptime, int uptime_size)
{
RC_SERVICE state = rc_service_state(service);
char *start_count;
@@ -87,8 +88,8 @@ static char *get_uptime(const char *service)
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,24 +111,23 @@ static char *get_uptime(const char *service)
diff_secs %= diff_mins * (time_t) 60;
}
if (diff_days > 0)
xasprintf(&uptime,
snprintf(uptime, uptime_size,
"%ld day(s) %02ld:%02ld:%02ld (%s)",
diff_days, diff_hours, diff_mins, diff_secs,
start_count);
else
xasprintf(&uptime,
snprintf(uptime, uptime_size,
"%02ld:%02ld:%02ld (%s)",
diff_hours, diff_mins, diff_secs, start_count);
}
}
return uptime;
}
static void
print_service(const char *service)
{
char *status = NULL;
char *uptime = NULL;
char status[60];
char uptime [40];
char *child_pid = NULL;
char *start_time = NULL;
int cols = printf(" %s", service);
@@ -136,45 +136,42 @@ print_service(const char *service)
ECOLOR color = ECOLOR_BAD;
if (state & RC_SERVICE_STOPPING)
xasprintf(&status, "stopping ");
snprintf(status, sizeof(status), "stopping ");
else if (state & RC_SERVICE_STARTING) {
xasprintf(&status, "starting ");
snprintf(status, sizeof(status), "starting ");
color = ECOLOR_WARN;
} else if (state & RC_SERVICE_INACTIVE) {
xasprintf(&status, "inactive ");
snprintf(status, sizeof(status), "inactive ");
color = ECOLOR_WARN;
} else if (state & RC_SERVICE_STARTED) {
errno = 0;
if (rc_service_daemons_crashed(service) && errno != EACCES)
if (test_crashed &&
rc_service_daemons_crashed(service) &&
errno != EACCES)
{
child_pid = rc_service_value_get(service, "child_pid");
start_time = rc_service_value_get(service, "start_time");
if (start_time && child_pid)
xasprintf(&status, " unsupervised ");
snprintf(status, sizeof(status), " unsupervised ");
else
xasprintf(&status, " crashed ");
snprintf(status, sizeof(status), " crashed ");
free(child_pid);
free(start_time);
} else {
uptime = get_uptime(service);
if (uptime) {
xasprintf(&status, " started %s", uptime);
free(uptime);
} else
xasprintf(&status, " started ");
get_uptime(service, uptime, 40);
snprintf(status, sizeof(status), " started %s", uptime);
color = ECOLOR_GOOD;
}
} else if (state & RC_SERVICE_SCHEDULED) {
xasprintf(&status, "scheduled");
snprintf(status, sizeof(status), "scheduled");
color = ECOLOR_WARN;
} else
xasprintf(&status, " stopped ");
snprintf(status, sizeof(status), " stopped ");
errno = 0;
if (c && *c && isatty(fileno(stdout)))
printf("\n");
ebracket(cols, color, status);
free(status);
}
static void
@@ -243,6 +240,8 @@ int main(int argc, char **argv)
char *p, *runlevel = NULL;
int opt, retval = 0;
test_crashed = _rc_can_find_pids();
applet = basename_c(argv[0]);
while ((opt = getopt_long(argc, argv, getoptstring, longopts,
(int *) 0)) != -1)

View File

@@ -62,7 +62,7 @@ add(const char *runlevel, const char *service)
if (!rc_service_exists(service)) {
if (errno == ENOEXEC)
eerror("%s: service `%s' is not executable",
eerror("%s: service `%s' is not executeable",
applet, service);
else
eerror("%s: service `%s' does not exist",

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

@@ -59,14 +59,13 @@ static struct pam_conv conv = { NULL, NULL};
#include "queue.h"
#include "rc.h"
#include "rc-misc.h"
#include "rc-pipes.h"
#include "rc-schedules.h"
#include "_usage.h"
#include "helpers.h"
const char *applet = NULL;
const char *extraopts = NULL;
const char *getoptstring = "I:KN:PR:Sa:bc:d:e:g:ik:mn:op:s:tu:r:w:x:1:2:3:4:" \
const char *getoptstring = "I:KN:PR:Sa:bc:d:e:g:ik:mn:op:s:tu:r:w:x:1:2:" \
getoptstring_COMMON;
const struct option longopts[] = {
{ "ionice", 1, NULL, 'I'},
@@ -94,8 +93,6 @@ const struct option longopts[] = {
{ "exec", 1, NULL, 'x'},
{ "stdout", 1, NULL, '1'},
{ "stderr", 1, NULL, '2'},
{ "stdout-logger",1, NULL, '3'},
{ "stderr-logger",1, NULL, '4'},
{ "progress", 0, NULL, 'P'},
longopts_COMMON
};
@@ -125,8 +122,6 @@ const char * const longopts_help[] = {
"Binary to start/stop",
"Redirect stdout to file",
"Redirect stderr to file",
"Redirect stdout to process",
"Redirect stderr to process",
"Print dots each second while waiting",
longopts_help_COMMON
};
@@ -167,20 +162,20 @@ handle_signal(int sig)
{
int status;
int serrno = errno;
char *signame = NULL;
char signame[10] = { '\0' };
switch (sig) {
case SIGINT:
if (!signame)
xasprintf(&signame, "SIGINT");
if (!signame[0])
snprintf(signame, sizeof(signame), "SIGINT");
/* FALLTHROUGH */
case SIGTERM:
if (!signame)
xasprintf(&signame, "SIGTERM");
if (!signame[0])
snprintf(signame, sizeof(signame), "SIGTERM");
/* FALLTHROUGH */
case SIGQUIT:
if (!signame)
xasprintf(&signame, "SIGQUIT");
if (!signame[0])
snprintf(signame, sizeof(signame), "SIGQUIT");
eerrorx("%s: caught %s, aborting", applet, signame);
/* NOTREACHED */
@@ -199,9 +194,6 @@ handle_signal(int sig)
eerror("%s: caught unknown signal %d", applet, sig);
}
/* free signame */
free(signame);
/* Restore errno */
errno = serrno;
}
@@ -210,6 +202,7 @@ static char *
expand_home(const char *home, const char *path)
{
char *opath, *ppath, *p, *nh;
size_t len;
struct passwd *pw;
if (!path || *path != '~')
@@ -240,7 +233,9 @@ expand_home(const char *home, const char *path)
return xstrdup(home);
}
xasprintf(&nh, "%s%s", home, ppath);
len = strlen(ppath) + strlen(home) + 1;
nh = xmalloc(len);
snprintf(nh, len, "%s%s", home, ppath);
free(opath);
return nh;
}
@@ -281,8 +276,6 @@ int main(int argc, char **argv)
int tid = 0;
char *redirect_stderr = NULL;
char *redirect_stdout = NULL;
char *stderr_process = NULL;
char *stdout_process = NULL;
int stdin_fd;
int stdout_fd;
int stderr_fd;
@@ -386,7 +379,6 @@ 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;
@@ -508,14 +500,6 @@ int main(int argc, char **argv)
redirect_stderr = optarg;
break;
case '3': /* --stdout-logger "command to run for stdout logging" */
stdout_process = optarg;
break;
case '4': /* --stderr-logger "command to run for stderr logging" */
stderr_process = optarg;
break;
case_RC_COMMON_GETOPT
}
@@ -567,9 +551,6 @@ int main(int argc, char **argv)
if (redirect_stdout || redirect_stderr)
eerrorx("%s: --stdout and --stderr are only relevant"
" with --start", applet);
if (stdout_process || stderr_process)
eerrorx("%s: --stdout-logger and --stderr-logger are only relevant"
" with --start", applet);
if (start_wait)
ewarn("using --wait with --stop has no effect,"
" use --retry instead");
@@ -582,15 +563,6 @@ int main(int argc, char **argv)
if ((redirect_stdout || redirect_stderr) && !background)
eerrorx("%s: --stdout and --stderr are only relevant"
" with --background", applet);
if ((stdout_process || stderr_process) && !background)
eerrorx("%s: --stdout-logger and --stderr-logger are only relevant"
" with --background", applet);
if (redirect_stdout && stdout_process)
eerrorx("%s: do not use --stdout and --stdout-logger together",
applet);
if (redirect_stderr && stderr_process)
eerrorx("%s: do not use --stderr and --stderr-logger together",
applet);
}
/* Expand ~ */
@@ -631,6 +603,7 @@ int main(int argc, char **argv)
*exec_file ? exec_file : exec);
free(exec_file);
exit(EXIT_FAILURE);
}
if (start && retry)
ewarn("using --retry with --start has no effect,"
@@ -688,7 +661,7 @@ int main(int argc, char **argv)
parse_schedule(applet, NULL, sig);
if (pidfile) {
pid = get_pid(applet, pidfile);
if (pid == -1 && errno != ENOENT)
if (pid == -1)
exit(EXIT_FAILURE);
} else {
pid = 0;
@@ -913,12 +886,6 @@ int main(int argc, char **argv)
eerrorx("%s: unable to open the logfile"
" for stdout `%s': %s",
applet, redirect_stdout, strerror(errno));
}else if (stdout_process) {
stdout_fd = rc_pipe_command(stdout_process);
if (stdout_fd == -1)
eerrorx("%s: unable to open the logging process"
" for stdout `%s': %s",
applet, stdout_process, strerror(errno));
}
if (redirect_stderr) {
if ((stderr_fd = open(redirect_stderr,
@@ -927,21 +894,13 @@ int main(int argc, char **argv)
eerrorx("%s: unable to open the logfile"
" for stderr `%s': %s",
applet, redirect_stderr, strerror(errno));
}else if (stderr_process) {
stderr_fd = rc_pipe_command(stderr_process);
if (stderr_fd == -1)
eerrorx("%s: unable to open the logging process"
" for stderr `%s': %s",
applet, stderr_process, strerror(errno));
}
if (background)
dup2(stdin_fd, STDIN_FILENO);
if (background || redirect_stdout || stdout_process
|| rc_yesno(getenv("EINFO_QUIET")))
if (background || redirect_stdout || rc_yesno(getenv("EINFO_QUIET")))
dup2(stdout_fd, STDOUT_FILENO);
if (background || redirect_stderr || stderr_process
|| rc_yesno(getenv("EINFO_QUIET")))
if (background || redirect_stderr || rc_yesno(getenv("EINFO_QUIET")))
dup2(stderr_fd, STDERR_FILENO);
for (i = getdtablesize() - 1; i >= 3; --i)

View File

@@ -61,18 +61,15 @@ 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 = "A:a:D:d:e:g:H:I:Kk:m:N:p:R:r:Su:1:2:3" \
const char *getoptstring = "D:d:e:g:I:Kk:m:N:p:R:r: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'},
@@ -94,8 +91,6 @@ 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",
@@ -118,9 +113,6 @@ 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 int nicelevel = 0;
static int ionicec = -1;
static int ioniced = 0;
@@ -191,25 +183,10 @@ static void handle_signal(int sig)
re_exec_supervisor();
}
static void healthcheck(int sig)
{
if (sig == SIGALRM)
do_healthcheck = 1;
}
static void reap_zombies(int sig)
{
int serrno;
(void) sig;
serrno = errno;
while (waitpid((pid_t)(-1), NULL, WNOHANG) > 0) {}
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 != '~')
@@ -240,7 +217,9 @@ static char * expand_home(const char *home, const char *path)
return xstrdup(home);
}
xasprintf(&nh, "%s%s", home, ppath);
len = strlen(ppath) + strlen(home) + 1;
nh = xmalloc(len);
snprintf(nh, len, "%s%s", home, ppath);
free(opath);
return nh;
}
@@ -253,8 +232,8 @@ static char *make_cmdline(char **argv)
for (c = argv; c && *c; c++)
len += (strlen(*c) + 1);
cmdline = xmalloc(len+1);
memset(cmdline, 0, len+1);
cmdline = xmalloc(len);
memset(cmdline, 0, len);
for (c = argv; c && *c; c++) {
strcat(cmdline, *c);
strcat(cmdline, " ");
@@ -447,14 +426,10 @@ static void child_process(char *exec, char **argv)
static void supervisor(char *exec, char **argv)
{
FILE *fp;
pid_t wait_pid;
int i;
int nkilled;
struct timespec ts;
time_t respawn_now= 0;
time_t first_spawn= 0;
pid_t health_pid;
int health_status;
#ifndef RC_DEBUG
signal_setup_restart(SIGHUP, handle_signal);
@@ -467,7 +442,6 @@ static void supervisor(char *exec, char **argv)
signal_setup_restart(SIGPIPE, handle_signal);
signal_setup_restart(SIGALRM, handle_signal);
signal_setup(SIGTERM, handle_signal);
signal_setup(SIGCHLD, reap_zombies);
signal_setup_restart(SIGUSR1, handle_signal);
signal_setup_restart(SIGUSR2, handle_signal);
signal_setup_restart(SIGBUS, handle_signal);
@@ -516,88 +490,44 @@ static void supervisor(char *exec, char **argv)
* Supervisor main loop
*/
i = 0;
if (healthcheckdelay) {
signal_setup(SIGALRM, healthcheck);
alarm(healthcheckdelay);
} else if (healthchecktimer) {
signal_setup(SIGALRM, healthcheck);
alarm(healthchecktimer);
}
while (!exiting) {
wait_pid = wait(&i);
if (wait_pid == -1) {
if (do_healthcheck) {
do_healthcheck = 0;
alarm(0);
syslog(LOG_DEBUG, "running health check for %s", svcname);
health_pid = exec_service(svcname, "healthcheck");
health_status = rc_waitpid(health_pid);
if (WIFEXITED(health_status) && !WEXITSTATUS(health_status)) {
alarm(healthchecktimer);
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;
} else {
syslog(LOG_WARNING, "health check for %s failed", svcname);
health_pid = exec_service(svcname, "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, "killed %d processes", nkilled);
else if (errno != 0)
syslog(LOG_INFO, "Unable to kill %d: %s",
child_pid, strerror(errno));
}
} else if (exiting ) {
alarm(0);
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);
continue;
}
} else 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));
} else
continue;
ts.tv_sec = respawn_delay;
ts.tv_nsec = 0;
nanosleep(&ts, NULL);
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;
}
}
alarm(0);
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
if (child_pid == 0)
child_process(exec, argv);
if (healthcheckdelay) {
signal_setup(SIGALRM, healthcheck);
alarm(healthcheckdelay);
} else if (healthchecktimer) {
signal_setup(SIGALRM, healthcheck);
alarm(healthchecktimer);
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
if (child_pid == 0)
child_process(exec, argv);
}
}
@@ -682,16 +612,6 @@ 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)
@@ -748,11 +668,6 @@ 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'",
@@ -920,7 +835,7 @@ int main(int argc, char **argv)
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,
"than %d to avoid infinite respawning", applet,
respawn_delay * respawn_max);
if (retry) {
@@ -948,13 +863,10 @@ 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));
@@ -982,7 +894,6 @@ 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

View File

@@ -7,109 +7,44 @@ terminates unexpectedly.
The following is a brief guide on using this capability.
* 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.
## Use Default start, stop and status 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.
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 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.
## Daemons must not fork
# Health Checks
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 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.
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.
## 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
## 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:
``` sh
pidfile=/pid/of/supervisor.pid
```
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.
``` sh
command_args_foreground="arguments"
```
This should be used if the daemon you want to monitor
command_args_foreground 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.
``` 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.
This is very early support, so feel free to file bugs if you have
issues.

View File

@@ -90,8 +90,8 @@ the service script by hand.
FIXME: Document stacked runlevels
The default startup uses the runlevels `sysinit`, `boot`, and `default`,
in that order. Shutdown uses the `shutdown` runlevel.
The default startup uses the runlevels `boot`, `sysinit` and `default`, in that
order. Shutdown uses the `shutdown` runlevel.
# The Magic of `conf.d`
@@ -162,6 +162,7 @@ stopped, by using:
The `rc_cgroup_cleanup` setting can be changed to yes to make this
happen automatically when the service is stopped.
# Caching
For performance reasons OpenRC keeps a cache of pre-parsed service metadata