Add a new shutdown runlevel, Gentoo #224537.

Split halt.sh into halt, killprocs, romount and savecache services.
The reboot runlevel is removed but mapped to shutdown.
The halt script should be moved to the sysvinit package.
This commit is contained in:
Roy Marples 2008-11-03 15:31:01 +00:00
parent 895c4f4149
commit 0af7d5bc20
19 changed files with 199 additions and 210 deletions

View File

@ -1,6 +1,8 @@
DIR= ${SYSCONFDIR}
CONF= rc.conf
CLEANFILES+= rc.conf
MK= ../mk
include ${MK}/os.mk
include Makefile.${OS}

5
init.d/.gitignore vendored
View File

@ -2,12 +2,15 @@ bootmisc
devfs
dmesg
fsck
halt.sh
halt
hostname
killprocs
local
localmount
netmount
romount
root
savecache
swap
sysctl
urandom

View File

@ -1,6 +1,6 @@
DIR= ${INITDIR}
SRCS= bootmisc.in fsck.in halt.sh.in hostname.in local.in localmount.in \
netmount.in root.in swap.in sysctl.in urandom.in
SRCS= bootmisc.in fsck.in hostname.in local.in localmount.in \
netmount.in root.in savecache.in swap.in sysctl.in urandom.in
BIN= ${OBJS}
INSTALLAFTER= _installafter

View File

@ -1,7 +1,11 @@
NET_LO= net.lo
SRCS+= devfs.in dmesg.in hwclock.in consolefont.in keymaps.in modules.in \
mtab.in numlock.in procfs.in sysfs.in termencoding.in
SRCS+= devfs.in dmesg.in hwclock.in consolefont.in keymaps.in killprocs.in \
modules.in mtab.in numlock.in procfs.in romount.in sysfs.in \
termencoding.in
# This really belongs with sysvinit
SRCS+= halt.in
.SUFFIXES: .Linux.in
.Linux.in:

23
init.d/halt.in Normal file
View File

@ -0,0 +1,23 @@
#!@PREFIX@/sbin/runscript
# Copyright 2007-2008 Roy Marples <roy@marples.name>
# All rights reserved. Released under the 2-clause BSD license.
# This script really belongs with the Linux sysvinit package
depend()
{
after *
use romount
}
start()
{
case "${RUNLEVEL}" in
0) runlevel=shutdown;;
6) runlevel=reboot;;
*) eerror "Unknown runlevel ${RUNLEVEL}"; return 1
esac
. /etc/init.d/"${runlevel}".sh
return 0
}

View File

@ -1,112 +0,0 @@
#!@SHELL@
# Copyright 2007-2008 Roy Marples <roy@marples.name>
# All rights reserved. Released under the 2-clause BSD license.
. @SYSCONFDIR@/init.d/functions.sh
. "${RC_LIBDIR}"/sh/rc-functions.sh
[ -r @SYSCONFDIR@/conf.d/localmount ] && . @SYSCONFDIR@/conf.d/localmount
[ -r @SYSCONFDIR@/rc.conf ] && . @SYSCONFDIR@/rc.conf
# Really kill things off before unmounting
if [ -x /sbin/killall5 ]; then
killall5 -15
killall5 -9
fi
# Flush all pending disk writes now
sync; sync
# If we are in a VPS, we don't need anything below here, because
# 1) we don't need (and by default can't) umount anything (VServer) or
# 2) the host utils take care of all umounting stuff (OpenVZ)
if [ "${RC_SYS}" = "VSERVER" -o "${RC_SYS}" = "OPENVZ" ]; then
[ "${RC_SYS}" = "OPENVZ" -a "$1" = "reboot" ] && echo "" > /reboot
if [ -e @SYSCONFDIR@/init.d/"$1".sh ]; then
. @SYSCONFDIR@/init.d/"$1".sh
else
exit 0
fi
fi
# If $svcdir is still mounted, preserve it if we can
mnt=$(mountinfo --node "${RC_SVCDIR}")
if [ -n "${mnt}" ] && \
rm -rf "${RC_LIBDIR}/tmp.$$" && \
mkdir -p "${RC_LIBDIR}/tmp.$$" 2>/dev/null \
; then
rmdir "${RC_LIBDIR}/tmp.$$"
f_opts="-m -c"
[ "${RC_UNAME}" = "Linux" ] && f_opts="-c"
if type fuser >/dev/null 2>&1; then
if [ -n "$(fuser ${f_opts} "${svcdir}" 2>/dev/null)" ]; then
fuser -k ${f_opts} "${svcdir}" >/dev/null 2>&1
sleep 2
fi
fi
cp -p "${RC_SVCDIR}"/deptree "${RC_SVCDIR}"/depconfig \
"${RC_SVCDIR}"/softlevel "${RC_SVCDIR}"/nettree \
"${RC_SVCDIR}"/rc.log \
"${RC_LIBDIR}" 2>/dev/null
umount "${RC_SVCDIR}"
rm -rf "${RC_SVCDIR}"/*
# Pipe errors to /dev/null as we may have future timestamps
cp -p "${RC_LIBDIR}"/deptree "${RC_LIBDIR}"/depconfig \
"${RC_LIBDIR}"/softlevel "${RC_LIBDIR}"/nettree \
"${RC_LIBDIR}"/rc.log \
"${RC_SVCDIR}" 2>/dev/null
rm -f "${RC_LIBDIR}"/deptree "${RC_LIBDIR}"/depconfig \
"${RC_LIBDIR}"/softlevel "${RC_LIBDIR}"/nettree \
"${RC_LIBDIR}"/rc.log
# Release the memory disk if we used it
case "${mnt}" in
"/dev/md"[0-9]*) mdconfig -d -u "${mnt#/dev/md*}";;
esac
fi
unmounted=0
# Remount the remaining filesystems read-only
# Most BSD's don't need this as the kernel handles it nicely
if [ "${RC_UNAME}" = "Linux" ]; then
ebegin "Remounting remaining filesystems read-only"
# We need the do_unmount function
. "${RC_LIBDIR}"/sh/rc-mount.sh
eindent
no_umounts_r="/dev|/dev/.*|${RC_SVCDIR}"
# RC_NO_UMOUNTS is an env var that can be set by plugins
OIFS=${IFS} SIFS=${IFS-y}
IFS=$IFS:
for x in ${no_umounts} ${RC_NO_UMOUNTS}; do
no_umounts_r="${no_umounts_r}|${x}"
done
if [ "${SIFS}" = "y" ]; then
IFS=$OIFS
else
unset IFS
fi
no_umounts_r="${no_umounts_r}|/proc|/proc/.*|/sys|/sys/.*"
no_umounts_r="^(${no_umounts_r})$"
fs=
for x in ${net_fs_list}; do
fs="${fs}${fs:+|}${x}"
done
[ -n "${fs}" ] && fs="^(${fs})$"
do_unmount "mount -n -o remount,ro" \
--skip-point-regex "${no_umounts_r}" \
${fs:+--skip-fstype-regex} ${fs} --nonetdev
eoutdent
eend $?
unmounted=$?
fi
if [ ${unmounted} -ne 0 ]; then
if [ -x /sbin/sulogin ]; then
ewarn "$1 timeout in 30 seconds"
sulogin -t 30 /dev/console
fi
fi
# Load the final script - not needed on BSD so they should not exist
[ -e @SYSCONFDIR@/init.d/"$1".sh ] && . @SYSCONFDIR@/init.d/"$1".sh
# Always exit 0 here
exit 0

15
init.d/killprocs.in Normal file
View File

@ -0,0 +1,15 @@
#!@PREFIX@/sbin/runscript
# Copyright 2007-2008 Roy Marples <roy@marples.name>
# All rights reserved. Released under the 2-clause BSD license.
start()
{
ebegin "Terminating remaining processes"
killall5 -15
sleep 1
eend 0
ebegin "Killing remaining processes"
killall5 -9
sleep 1
eend 0
}

43
init.d/romount.in Normal file
View File

@ -0,0 +1,43 @@
#!@PREFIX@/sbin/runscript
# Copyright 2007-2008 Roy Marples <roy@marples.name>
# All rights reserved. Released under the 2-clause BSD license.
depend()
{
need killprocs savecache
keywords noopenvz novserver
}
start()
{
# Flush all pending disk writes now
sync; sync
ebegin "Remounting remaining filesystems read-only"
# We need the do_unmount function
. "${RC_LIBDIR}"/sh/rc-mount.sh
eindent
local m="/dev|/dev/.*|/proc|/proc.*|/sys|/sys/.*|${RC_SVCDIR}" x= fs=
# RC_NO_UMOUNTS is an env var that can be set by plugins
local OIFS=$IFS SIFS=${IFS-y} IFS=$IFS
IFS=$IFS:
for x in ${no_umounts} ${RC_NO_UMOUNTS}; do
m="${m}|${x}"
done
if [ "${SIFS}" = y ]; then
IFS=$OIFS
else
unset IFS
fi
m="^(${m})$"
fs=
for x in ${net_fs_list}; do
fs="${fs}${fs:+|}${x}"
done
[ -n "${fs}" ] && fs="^(${fs})$"
do_unmount "mount -n -o remount,ro" \
--skip-point-regex "${m}" \
${fs:+--skip-fstype-regex} ${fs} --nonetdev
eoutdent
eend $?
}

25
init.d/savecache.in Normal file
View File

@ -0,0 +1,25 @@
#!@PREFIX@/sbin/runscript
# Copyright 2007-2008 Roy Marples <roy@marples.name>
# All rights reserved. Released under the 2-clause BSD license.
description="Saves the caches OpenRC uses to non volatile storage"
start()
{
ebegin "Saving dependency cache"
if [ ! -d "${RC_LIBDIR}"/cache ]; then
rm -rf "${RC_LIBDIR}"/cache
if ! mkdir "${RC_LIBDIR}"/cache; then
eend $?
return $?
fi
fi
local save=
for x in deptree depconfig softlevel nettree rc.log; do
[ -e "${RC_SVCDIR}/${x}" ] && save="${save} ${RC_SVCDIR}/${x}"
done
if [ -n "${save}" ]; then
cp -p ${save} "${RC_LIBDIR}"/cache 2>/devnull
fi
eend $?
}

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd October 27, 2008
.Dd November 03, 2008
.Dt RC 8 SMM
.Os OpenRC
.Sh NAME
@ -65,8 +65,6 @@ All services in the boot and sysinit runlevels are automatically included
in all other runlevels except for those listed here.
.It Ar single
Stops all services except for those in the sysinit runlevel.
.It Ar reboot
Changes to the single runlevel and then reboots the host.
.It Ar shutdown
Changes to the single runlevel and then halts the host.
.El

View File

@ -1,11 +1,13 @@
BOOT= bootmisc fsck hostname localmount \
root swap sysctl urandom
DEFAULT= local netmount
SHUTDOWN= savecache
LEVELDIR= ${DESTDIR}/${SYSCONFDIR}/runlevels
SYSINITDIR= ${LEVELDIR}/sysinit
BOOTDIR= ${LEVELDIR}/boot
DEFAULTDIR= ${LEVELDIR}/default
SHUTDOWNDIR= ${LEVELDIR}/shutdown
INITDIR= ../init.d
@ -44,6 +46,14 @@ install:
fi; \
ln -snf ${PREFIX}/etc/init.d/"$$x" ${DEFAULTDIR}/"$$x" || exit $$?; done \
fi
if ! test -d "${SHUTDOWNDIR}"; then \
${INSTALL} -d ${SHUTDOWNDIR} || exit $$?; \
for x in ${SHUTDOWN}; do \
if test -n "${PREFIX}"; then \
grep -q "keyword .*noprefix" ${INITDIR}/"$$x" && continue; \
fi; \
ln -snf ${PREFIX}/etc/init.d/"$$x" ${SHUTDOWNDIR}/"$$x" || exit $$?; done \
fi
check test::

View File

@ -1,2 +1,6 @@
SYSINIT+= devfs dmesg
BOOT+= hwclock keymaps modules mtab net.lo procfs termencoding
SHUTDOWN+= killprocs romount
# This really belongs with sysvinit
SHUTDOWN+= halt

View File

@ -9,17 +9,15 @@ retval=0
RC_SVCDIR=${RC_SVCDIR:-/@LIB@/rc/init.d}
if [ "${RC_SVCDIR}" != "/" ] && mkdir "${RC_SVCDIR}/.test.$$" 2>/dev/null; then
rmdir "${RC_SVCDIR}/.test.$$"
for x in ${RC_SVCDIR}/*; do
[ -e "${x}" ] || continue
case ${x##*/} in
depconfig|deptree|ksoftlevel|rc.log);;
*) rm -rf "${x}";;
esac
done
rm -rf "${RC_SVCDIR}"/*
else
mount_svcdir
retval=$?
fi
if [ -e "${RC_LIBDIR}"/cache/deptree ]; then
cp -p "${RC_LIBDIR}"/cache/* "${RC_SVCDIR}" 2>/dev/null
fi
echo "sysinit" > "${RC_SVCDIR}/softlevel"
exit ${retval}

View File

@ -10,18 +10,6 @@
# FreeBSD-7 supports tmpfs now :)
mount_svcdir()
{
local dotmp=false release=false retval=0
if [ -e "${RC_SVCDIR}"/deptree ]; then
dotmp=true
if ! mount -t tmpfs none "${RC_LIBDIR}"/tmp 2>/dev/null; then
mdconfig -a -t malloc -s 1m -u 1
newfs /dev/md1
mount /dev/md1 "${RC_LIBDIR}"/tmp
release=true
fi
cp -p "${RC_SVCDIR}"/deptree "${RC_SVCDIR}"/depconfig \
"${RC_SVCDIR}"/nettree "${RC_LIBDIR}"/tmp 2>/dev/null
fi
if ! fstabinfo --mount "${RC_SVCDIR}"; then
if ! mount -t tmpfs -o rw,noexec,nosuid none "${RC_SVCDIR}" 2>/dev/null; then
mdconfig -a -t malloc -s "${rc_svcsize:-1024}"k -u 0
@ -29,15 +17,6 @@ mount_svcdir()
mount -o rw,noexec,nosuid /dev/md0 "${RC_SVCDIR}"
fi
fi
retval=$?
if ${dotmp}; then
cp -p "${RC_LIBDIR}"/tmp/deptree "${RC_LIBDIR}"/tmp/depconfig \
"${RC_LIBDIR}"/tmp/nettree "${RC_SVCDIR}" 2>/dev/null
umount "${RC_LIBDIR}"/tmp
${release} && mdconfig -d -u 1
fi
return ${retval}
}
. "${RC_LIBDIR}"/sh/functions.sh

View File

@ -3,14 +3,13 @@
# Copyright 2007-2008 Roy Marples <roy@marples.name>
# All rights reserved. Released under the 2-clause BSD license.
# This basically mounts $RC_SVCDIR as a ramdisk, but preserving its content
# which allows us to store service state and generate dependencies if needed.
# This basically mounts $RC_SVCDIR as a ramdisk.
# The tricky part is finding something our kernel supports
# tmpfs and ramfs are easy, so force one or the other.
mount_svcdir()
{
local fs= fsopts="-o rw,noexec,nodev,nosuid"
local devdir="rc-svcdir" devtmp="none" x=
local devdir="rc-svcdir" x=
local svcsize=${rc_svcsize:-1024}
if grep -Eq "[[:space:]]+tmpfs$" /proc/filesystems; then
@ -19,41 +18,24 @@ mount_svcdir()
elif grep -Eq "[[:space:]]+ramfs$" /proc/filesystems; then
fs="ramfs"
# ramfs has no special options
elif [ -e /dev/ram0 -a -e /dev/ram1 ] \
elif [ -e /dev/ram0 ] \
&& grep -Eq "[[:space:]]+ext2$" /proc/filesystems; then
devdir="/dev/ram0"
devtmp="/dev/ram1"
fs="ext2"
for x in ${devdir} ${devtmp}; do
dd if=/dev/zero of="${x}" bs=1k count="${svcsize}"
mkfs -t "${fs}" -i 1024 -vm0 "${x}" "${svcsize}"
done
dd if=/dev/zero of="${devdir}" bs=1k count="${svcsize}"
mkfs -t "${fs}" -i 1024 -vm0 "${devdir}" "${svcsize}"
else
echo
eerror "OpenRC requires tmpfs, ramfs or 2 ramdisks + ext2"
eerror "OpenRC requires tmpfs, ramfs or a ramdisk + ext2"
eerror "compiled into the kernel"
echo
return 1
fi
local dotmp=false
if [ -e "${RC_SVCDIR}"/deptree ]; then
dotmp=true
mount -n -t "${fs}" -o rw "${devtmp}" "${RC_LIBDIR}"/tmp
cp -p "${RC_SVCDIR}"/deptree "${RC_SVCDIR}"/depconfig \
"${RC_SVCDIR}"/nettree "${RC_LIBDIR}"/tmp 2>/dev/null
fi
# If we have no entry in fstab for $RC_SVCDIR, provide our own
if ! fstabinfo --mount "${RC_SVCDIR}"; then
mount -n -t "${fs}" ${fsopts} "${devdir}" "${RC_SVCDIR}"
fi
if ${dotmp}; then
cp -p "${RC_LIBDIR}"/tmp/deptree "${RC_LIBDIR}"/tmp/depconfig \
"${RC_LIBDIR}"/tmp/nettree "${RC_SVCDIR}" 2>/dev/null
umount -n "${RC_LIBDIR}"/tmp
fi
}
. /etc/init.d/functions.sh

View File

@ -189,7 +189,8 @@ valid_service(const char *runlevel, const char *service, const char *type)
if (rc_service_in_runlevel(service, runlevel))
return true;
if (strcmp(runlevel, RC_LEVEL_SYSINIT) != 0 &&
if (strcmp(runlevel, RC_LEVEL_SHUTDOWN) != 0 &&
strcmp(runlevel, RC_LEVEL_SYSINIT) != 0 &&
strcmp(runlevel, bootlevel) != 0)
{
if (rc_service_in_runlevel(service, bootlevel))
@ -499,8 +500,7 @@ rc_deptree_order(const RC_DEPTREE *deptree, const char *runlevel, int options)
/* When shutting down, list all running services */
if (strcmp(runlevel, RC_LEVEL_SINGLE) == 0 ||
strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
strcmp(runlevel, RC_LEVEL_REBOOT) == 0)
strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0)
{
list = rc_services_in_state(RC_SERVICE_STARTED);
list2 = rc_services_in_state(RC_SERVICE_INACTIVE);

View File

@ -70,7 +70,6 @@ typedef TAILQ_HEAD(rc_stringlist, rc_string) RC_STRINGLIST;
#define RC_LEVEL_SYSINIT "sysinit"
#define RC_LEVEL_SINGLE "single"
#define RC_LEVEL_SHUTDOWN "shutdown"
#define RC_LEVEL_REBOOT "reboot"
/*! Return the current runlevel.
* @return the current runlevel */

View File

@ -831,6 +831,11 @@ main(int argc, char **argv)
}
newlevel = argv[optind++];
/* For compat with old system */
if (newlevel) {
if (strcmp(newlevel, "reboot") == 0)
newlevel = UNCONST(RC_LEVEL_SHUTDOWN);
}
/* Enable logging */
setenv("EINFO_LOG", "rc", 1);
@ -875,8 +880,7 @@ main(int argc, char **argv)
set_krunlevel(NULL);
if (newlevel &&
(strcmp(newlevel, RC_LEVEL_REBOOT) == 0 ||
strcmp(newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
(strcmp(newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
strcmp(newlevel, RC_LEVEL_SINGLE) == 0))
{
going_down = true;
@ -887,9 +891,9 @@ main(int argc, char **argv)
#ifdef __FreeBSD__
/* FIXME: we shouldn't have todo this */
/* For some reason, wait_for_services waits for the logger proccess
* to finish as well, but only on FreeBSD. We cannot allow this so
* we stop logging now. */
/* For some reason, wait_for_services waits for the logger
* proccess to finish as well, but only on FreeBSD.
* We cannot allow this so we stop logging now. */
rc_logger_close();
#endif
@ -944,29 +948,30 @@ main(int argc, char **argv)
}
/* Load our list of hotplugged services */
hotplugged_services = rc_services_in_state(RC_SERVICE_HOTPLUGGED);
if (!going_down ||
strcmp(newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) == 0)
start_services = rc_services_in_runlevel(RC_LEVEL_SYSINIT);
if (!going_down &&
start_services = rc_services_in_runlevel(newlevel ?
newlevel : runlevel);
if (strcmp(newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 &&
strcmp(newlevel ? newlevel : runlevel, RC_LEVEL_SYSINIT) != 0)
{
/* We need to include the boot runlevel services */
tmplist = rc_services_in_runlevel(bootlevel);
tmplist = rc_services_in_runlevel(RC_LEVEL_SYSINIT);
TAILQ_CONCAT(start_services, tmplist, entries);
free(tmplist);
if (strcmp (newlevel ? newlevel : runlevel, bootlevel) != 0) {
tmplist = rc_services_in_runlevel(newlevel ?
newlevel : runlevel);
TAILQ_CONCAT(start_services, tmplist, entries);
free(tmplist);
}
if (hotplugged_services) {
if (!start_services)
start_services = rc_stringlist_new();
TAILQ_FOREACH(service, hotplugged_services, entries)
rc_stringlist_addu(start_services, service->value);
if (strcmp(newlevel ? runlevel : runlevel,
RC_LEVEL_SINGLE) != 0)
{
if (strcmp(newlevel ? newlevel : runlevel,
bootlevel) != 0)
{
tmplist = rc_services_in_runlevel(bootlevel);
TAILQ_CONCAT(start_services, tmplist, entries);
free(tmplist);
}
if (hotplugged_services) {
TAILQ_FOREACH(service, hotplugged_services,
entries)
rc_stringlist_addu(start_services,
service->value);
}
}
}
@ -994,15 +999,12 @@ main(int argc, char **argv)
setenv("RC_RUNLEVEL", runlevel, 1);
}
/* Run the halt script if needed */
if (strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
strcmp(runlevel, RC_LEVEL_REBOOT) == 0)
{
#ifdef __linux__
/* We can't log beyond this point as the shutdown runlevel
* will mount / readonly. */
if (strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0)
rc_logger_close();
execl(HALTSH, HALTSH, runlevel, (char *) NULL);
eerrorx("%s: unable to exec `%s': %s",
applet, HALTSH, strerror(errno));
}
#endif
mkdir(RC_STARTING, 0755);
rc_plugin_run(RC_HOOK_RUNLEVEL_START_IN, runlevel);
@ -1064,5 +1066,18 @@ main(int argc, char **argv)
if (regen && strcmp(runlevel, bootlevel) == 0)
unlink(RC_DEPTREE_CACHE);
#ifdef __linux__
/* Run our halt script if it exists
* We only do this for compat with Gentoo sysvinit which
* should run halt.sh itself. */
if (exists(HALTSH)) {
if (strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0) {
execl(HALTSH, HALTSH, (char *) NULL);
eerrorx("%s: unable to exec `%s': %s",
applet, HALTSH, strerror(errno));
}
}
#endif
return EXIT_SUCCESS;
}

View File

@ -519,6 +519,9 @@ svc_exec(const char *arg1, const char *arg2)
}
execok = rc_waitpid(service_pid) == 0 ? true : false;
if (!execok && errno == ECHILD)
/* killall5 -9 could cause this */
execok = true;
service_pid = 0;
return execok;
@ -1008,8 +1011,6 @@ svc_stop(bool deps)
if (runlevel &&
(strcmp(runlevel,
RC_LEVEL_SHUTDOWN) == 0 ||
strcmp(runlevel,
RC_LEVEL_REBOOT) == 0 ||
strcmp(runlevel,
RC_LEVEL_SINGLE) == 0))
continue;