sysinit is now a real runlevel that handles things like udev, dmesg and

mounting various bits in /dev and /sys.
init.sh JUST mounts /lib/rc/init.d (and /proc for Linux systems)
To make development of this easier we now return an empty RC_STRINGLIST
instead of a NULL for empty things.

If you don't have a udev init script installed, don't reboot your box OR
roll back to an older OpenRC version.
This commit is contained in:
Roy Marples 2008-10-10 08:37:21 +00:00
parent 247766695c
commit d6da8e8c48
23 changed files with 777 additions and 926 deletions

View File

@ -1 +1 @@
CONF+= consolefont hwclock keymaps modules CONF+= consolefont dmesg hwclock keymaps modules

3
conf.d/dmesg Normal file
View File

@ -0,0 +1,3 @@
# Sets the level at which logging of messages is done to the
# console. See dmesg(8) for more info.
dmesg_level="1"

View File

@ -6,20 +6,3 @@
# consolefont, numlock, etc ...) # consolefont, numlock, etc ...)
rc_tty_number=12 rc_tty_number=12
# Use this variable to control the /dev management behavior.
# devfs - use devfs (requires sys-fs/devfsd)
# mdev - use mdev (requires sys-apps/busybox)
# udev - use udev (requires sys-fs/udev)
# static - let the user manage /dev (YOU need to create ALL device nodes)
# Leave it blank to let rc work it out (udev, mdev, devfs, static)
#rc_devices=""
# UDEV OPTION:
# Set to "yes" if you want to save /dev to a tarball on shutdown
# and restore it on startup. This is useful if you have a lot of
# custom device nodes that udev does not handle/know about.
rc_device_tarball="NO"
# Sets the level at which logging of messages is done to the
# console. See dmesg(8) for more info.
dmesg_level="1"

View File

@ -27,25 +27,17 @@ rc_depend_strict="YES"
# starting/stopping of the init.d service triggered by it. # starting/stopping of the init.d service triggered by it.
rc_hotplug="YES" rc_hotplug="YES"
# Dynamic /dev managers can trigger coldplug events which cause services to # Some people want a finer grain over hotplug. rc_plug_services is a
# start before we are ready for them. If this happens, we can defer these
# services to start in the boot runlevel. Set rc_coldplug="NO" if you don't
# want this.
# NOTE: This also affects module coldplugging in udev-096 and higher
# If you want module coldplugging but not coldplugging of services then you
# can set rc_coldplug="YES" and rc_plug_services="!*"
rc_coldplug="YES"
# Some people want a finer grain over hotplug/coldplug. rc_plug_services is a
# list of services that are matched in order, either allowing or not. By # list of services that are matched in order, either allowing or not. By
# default we allow services through as rc_coldplug/rc_hotplug has to be YES # default we allow services through as rc_hotplug has to be YES anyway.
# anyway.
# Example - rc_plug_services="net.wlan !net.*" # Example - rc_plug_services="net.wlan !net.*"
# This allows net.wlan and any service not matching net.* to be plugged. # This allows net.wlan and any service not matching net.* to be plugged.
rc_plug_services="" rc_plug_services=""
# rc_logger launches a logging daemon to log the entire rc process to # rc_logger launches a logging daemon to log the entire rc process to
# /var/log/rc.log # /var/log/rc.log
# NOTE: Linux systems require the devfs service to be started before
# logging can take place.
rc_logger="NO" rc_logger="NO"
# By default we filter the environment for our running scripts. To allow other # By default we filter the environment for our running scripts. To allow other

View File

@ -1,7 +1,7 @@
NET_LO= net.lo NET_LO= net.lo
SRCS+= hwclock.in consolefont.in keymaps.in modules.in mtab.in numlock.in \ SRCS+= devfs.in dmesg.in hwclock.in consolefont.in keymaps.in modules.in \
procfs.in termencoding.in mtab.in numlock.in procfs.in sysfs.in termencoding.in
.SUFFIXES: .Linux.in .SUFFIXES: .Linux.in
.Linux.in: .Linux.in:

36
init.d/devfs.in Normal file
View File

@ -0,0 +1,36 @@
#!@PREFIX@/sbin/runscript
# Copyright 2007-2008 Roy Marples <roy@marples.name>
# All rights reserved. Released under the 2-clause BSD license.
description="Mount system critical filesystems in /dev."
depend() {
use dev
keyword noprefix
}
start() {
# Mount required stuff as user may not have then in /etc/fstab
for x in \
"devpts /dev/pts 0755 ,gid=5,mode=0620 devpts" \
"tmpfs /dev/shm 1777 ,nodev shm" \
; do
set -- ${x}
grep -Eq "[[:space:]]+$1$" /proc/filesystems || continue
mountinfo -q "$2" && continue
if [ ! -d "$2" ]; then
mkdir -m "$3" -p "$2" >/dev/null 2>&1 || \
ewarn "Could not create $2!"
fi
if [ -d "$2" ]; then
ebegin "Mounting $2"
if ! fstabinfo --mount "$2"; then
mount -n -t "$1" -o noexec,nosuid"$4" "$5" "$2"
fi
eend $?
fi
done
return 0
}

17
init.d/dmesg.in Normal file
View File

@ -0,0 +1,17 @@
#!@PREFIX@/sbin/runscript
# Copyright 2007-2008 Roy Marples <roy@marples.name>
# All rights reserved. Released under the 2-clause BSD license.
description="Set the dmesg level for a cleaner boot"
depend()
{
before dev modules
}
start()
{
if [ -n "${dmesg_level}" ]; then
dmesg -n"${dmesg_level}"
fi
}

View File

@ -8,7 +8,7 @@ _IFS="
depend() depend()
{ {
after clock modules use dev clock modules
keyword nojail noopenvz noprefix notimeout novserver keyword nojail noopenvz noprefix notimeout novserver
} }

View File

@ -6,6 +6,7 @@ description="Mounts misc filesystems in /proc."
depend() depend()
{ {
use devfs
need localmount need localmount
keyword noopenvz noprefix novserver keyword noopenvz noprefix novserver
} }
@ -39,7 +40,7 @@ start()
# Setup Kernel Support for the NFS daemon status # Setup Kernel Support for the NFS daemon status
if [ -d /proc/fs/nfsd ] && ! mountinfo -q /proc/fs/nfsd; then if [ -d /proc/fs/nfsd ] && ! mountinfo -q /proc/fs/nfsd; then
if grep -qs nfsd /proc/filesystems; then if grep -qs nfsd /proc/filesystems; then
ebegin "Mounting nfsd filesystem" ebegin "Mounting NFS filesystem"
mount -t nfsd -o nodev,noexec,nosuid \ mount -t nfsd -o nodev,noexec,nosuid \
nfsd /proc/fs/nfsd nfsd /proc/fs/nfsd
eend $? eend $?
@ -56,26 +57,6 @@ start()
fi fi
fi fi
# Setup Kernel Support for securityfs
if [ -d /sys/kernel/security ] && ! mountinfo -q /sys/kernel/security; then
if grep -qs securityfs /proc/filesystems; then
ebegin "Mounting security filesystem"
mount -t securityfs -o nodev,noexec,nosuid \
securityfs /sys/kernel/security
eend $?
fi
fi
# Setup Kernel Support for debugfs
if [ -d /sys/kernel/debug ] && ! mountinfo -q /sys/kernel/debug; then
if grep -qs debugfs /proc/filesystems; then
ebegin "Mounting debug filesystem"
mount -t debugfs -o nodev,noexec,nosuid \
debugfs /sys/kernel/debug
eend $?
fi
fi
# Setup Kernel Support for SELinux # Setup Kernel Support for SELinux
if [ -d /selinux ] && ! mountinfo -q /selinux; then if [ -d /selinux ] && ! mountinfo -q /selinux; then
if grep -qs selinuxfs /proc/filesystems; then if grep -qs selinuxfs /proc/filesystems; then

63
init.d/sysfs.in Normal file
View File

@ -0,0 +1,63 @@
#!@PREFIX@/sbin/runscript
# Copyright 2007-2008 Roy Marples <roy@marples.name>
# All rights reserved. Released under the 2-clause BSD license.
description="Mount the sys filesystem."
depend()
{
keyword noprefix
}
mount_sys()
{
grep -Eq "[[:space:]]+sysfs$" /proc/filesystems || return 1
mountinfo -q /sys && return 0
if [ ! -d /sys ]; then
if ! mkdir -m 0755 /sys; then
ewarn "Could not create /sys!"
return 1
fi
fi
ebegin "Mounting /sys"
if ! fstabinfo --mount /sys; then
mount -n -t sysfs -o noexec,nosuid,nodev sysfs /sys
fi
eend $?
}
mount_misc()
{
# Setup Kernel Support for securityfs
if [ -d /sys/kernel/security ] && ! mountinfo -q /sys/kernel/security; then
if grep -qs securityfs /proc/filesystems; then
ebegin "Mounting security filesystem"
mount -t securityfs -o nodev,noexec,nosuid \
securityfs /sys/kernel/security
eend $?
fi
fi
# Setup Kernel Support for debugfs
if [ -d /sys/kernel/debug ] && ! mountinfo -q /sys/kernel/debug; then
if grep -qs debugfs /proc/filesystems; then
ebegin "Mounting debug filesystem"
mount -t debugfs -o nodev,noexec,nosuid \
debugfs /sys/kernel/debug
eend $?
fi
fi
}
start()
{
local retval
mount_sys
retval=$?
if [ ${retval} -eq 0 ]; then
mount_misc
fi
return ${retval}
}

View File

@ -3,6 +3,7 @@ BOOT= bootmisc fsck hostname localmount \
DEFAULT= local netmount DEFAULT= local netmount
LEVELDIR= ${DESTDIR}/${SYSCONFDIR}/runlevels LEVELDIR= ${DESTDIR}/${SYSCONFDIR}/runlevels
SYSINITDIR= ${LEVELDIR}/sysinit
BOOTDIR= ${LEVELDIR}/boot BOOTDIR= ${LEVELDIR}/boot
DEFAULTDIR= ${LEVELDIR}/default DEFAULTDIR= ${LEVELDIR}/default
@ -17,6 +18,14 @@ include Makefile.${OS}
all: all:
install: install:
if ! test -d "${SYSINITDIR}"; then \
${INSTALL} -d ${SYSINITDIR} || exit $$?; \
for x in ${SYSINIT}; do \
if test -n "${PREFIX}"; then \
grep -q "keyword .*noprefix" ${INITDIR}/"$$x" && continue; \
fi; \
ln -snf ${PREFIX}/etc/init.d/"$$x" ${SYSINITDIR}/"$$x" || exit $$?; done \
fi
if ! test -d "${BOOTDIR}"; then \ if ! test -d "${BOOTDIR}"; then \
${INSTALL} -d ${BOOTDIR} || exit $$?; \ ${INSTALL} -d ${BOOTDIR} || exit $$?; \
for x in ${BOOT}; do \ for x in ${BOOT}; do \

View File

@ -1,2 +1,2 @@
BOOT+= hwclock consolefont keymaps modules mtab net.lo procfs \ SYSINIT+= devfs dmesg
termencoding BOOT+= hwclock keymaps modules mtab net.lo procfs termencoding

View File

@ -22,8 +22,4 @@ else
fi fi
echo "sysinit" > "${RC_SVCDIR}/softlevel" echo "sysinit" > "${RC_SVCDIR}/softlevel"
# sysinit is now done, so allow init scripts to run normally
[ -e /dev/.rcsysinit ] && rm -f /dev/.rcsysinit
exit ${retval} exit ${retval}

View File

@ -9,7 +9,8 @@
# tmpfs and ramfs are easy, so force one or the other. # tmpfs and ramfs are easy, so force one or the other.
mount_svcdir() mount_svcdir()
{ {
local fs= fsopts="-o rw,noexec,nodev,nosuid" devdir="rc-svcdir" devtmp="none" x= local fs= fsopts="-o rw,noexec,nodev,nosuid"
local devdir="rc-svcdir" devtmp="none" x=
local svcsize=${rc_svcsize:-1024} local svcsize=${rc_svcsize:-1024}
if grep -Eq "[[:space:]]+tmpfs$" /proc/filesystems; then if grep -Eq "[[:space:]]+tmpfs$" /proc/filesystems; then
@ -56,17 +57,8 @@ mount_svcdir()
} }
. /etc/init.d/functions.sh . /etc/init.d/functions.sh
. "${RC_LIBDIR}"/sh/rc-functions.sh
[ -r /etc/conf.d/rc ] && . /etc/conf.d/rc
[ -r /etc/rc.conf ] && . /etc/rc.conf [ -r /etc/rc.conf ] && . /etc/rc.conf
# Set the console loglevel to 1 for a cleaner boot
# the logger should anyhow dump the ring-0 buffer at start to the
# logs, and that with dmesg can be used to check for problems
if [ -n "${dmesg_level}" -a "${RC_SYS}" != "VSERVER" ]; then
dmesg -n "${dmesg_level}"
fi
# By default VServer already has /proc mounted, but OpenVZ does not! # By default VServer already has /proc mounted, but OpenVZ does not!
# However, some of our users have an old proc image in /proc # However, some of our users have an old proc image in /proc
# NFC how they managed that, but the end result means we have to test if # NFC how they managed that, but the end result means we have to test if
@ -82,7 +74,6 @@ if [ -e /proc/uptime ]; then
einfo "/proc is already mounted, skipping" einfo "/proc is already mounted, skipping"
mountproc=false mountproc=false
fi fi
unset up
fi fi
if ${mountproc}; then if ${mountproc}; then
@ -94,98 +85,5 @@ if ${mountproc}; then
fi fi
eend $? eend $?
fi fi
unset mountproc
# Re-load RC_SYS if empty now we have /proc mounted
[ -z "${RC_SYS}" ] && export RC_SYS="$(rc --sys)"
# Read off the kernel commandline to see if there's any special settings
# especially check to see if we need to set the CDBOOT environment variable
# Note: /proc MUST be mounted
if [ -r /sbin/livecd-functions.sh ]; then
. /sbin/livecd-functions.sh
livecd_read_commandline
fi
if [ "${RC_UNAME}" != "GNU/kFreeBSD" \
-a "${RC_SYS}" != "VSERVER" ];
then
if grep -Eq "[[:space:]]+sysfs$" /proc/filesystems; then
if [ -d /sys ]; then
if ! mountinfo --quiet /sys; then
ebegin "Mounting /sys"
if ! fstabinfo --mount /sys; then
mount -n -t sysfs -o noexec,nosuid,nodev sysfs /sys
fi
eend $?
fi
else
ewarn "No /sys to mount sysfs needed in 2.6 and later kernels!"
fi
fi
fi
# Default OpenVZ to static devices
if [ "${RC_SYS}" = "OPENVZ" ]; then
rc_devices=${rc_devices:-static}
fi
# Try to figure out how the user wants /dev handled
if [ "${rc_devices}" = "static" \
-o "${RC_SYS}" = "VSERVER" \
-o "${RC_UNAME}" = "GNU/kFreeBSD" ]
then
ebegin "Using existing device nodes in /dev"
eend 0
else
case ${rc_devices} in
devfs) managers="devfs udev mdev";;
udev) managers="udev devfs mdev";;
mdev) managers="mdev udev devfs";;
*) managers="udev devfs mdev";;
esac
for m in ${managers}; do
# Check kernel params
if get_bootparam "no${m}" || ! has_addon ${m}-start; then
continue
fi
# Let's see if we can get this puppy rolling
start_addon ${m} && break
# Clean up
mountinfo -q /dev && umount -n /dev
done
fi
# Mount required stuff as user may not have then in /etc/fstab
for x in "devpts /dev/pts 0755 ,gid=5,mode=0620 devpts" "tmpfs /dev/shm 1777 ,nodev shm"
do
set -- ${x}
grep -Eq "[[:space:]]+$1$" /proc/filesystems || continue
mountinfo -q "$2" && continue
if [ ! -d "$2" ] && \
[ "${m}" = "devfs" -o "${m}" = "udev" ]; then
mkdir -m "$3" -p "$2" >/dev/null 2>&1 || \
ewarn "Could not create $2!"
fi
if [ -d "$2" ]; then
ebegin "Mounting $2"
if ! fstabinfo --mount "$2"; then
mount -n -t "$1" -o noexec,nosuid"$4" "$5" "$2"
fi
eend $?
fi
done
# If booting off CD, we want to update inittab before setting the runlevel
if [ -f /sbin/livecd-functions.sh -a -n "${CDBOOT}" ]; then
ebegin "Updating inittab"
livecd_fix_inittab
eend $?
telinit q &>/dev/null
fi
. "${RC_LIBDIR}"/sh/init-common-post.sh . "${RC_LIBDIR}"/sh/init-common-post.sh

View File

@ -143,7 +143,6 @@ char *rc_conf_value(const char *var);
bool rc_conf_yesno(const char *var); bool rc_conf_yesno(const char *var);
void env_filter(void); void env_filter(void);
void env_config(void); void env_config(void);
bool service_plugable(const char *service);
int signal_setup(int sig, void (*handler)(int)); int signal_setup(int sig, void (*handler)(int));
pid_t exec_service(const char *, const char *); pid_t exec_service(const char *, const char *);

View File

@ -187,12 +187,21 @@ valid_service(const char *runlevel, const char *service, const char *type)
strcmp(type, "needsme") == 0) strcmp(type, "needsme") == 0)
return true; return true;
if (rc_service_in_runlevel(service, runlevel))
return true;
if (strcmp(runlevel, RC_LEVEL_SYSINIT) != 0 &&
strcmp(runlevel, bootlevel) != 0)
{
if (rc_service_in_runlevel(service, bootlevel))
return true;
}
state = rc_service_state(service); state = rc_service_state(service);
return ((strcmp(runlevel, bootlevel) != 0 && if (state & RC_SERVICE_COLDPLUGGED ||
rc_service_in_runlevel(service, bootlevel)) || state & RC_SERVICE_STARTED)
rc_service_in_runlevel(service, runlevel) || return true;
state & RC_SERVICE_COLDPLUGGED ||
state & RC_SERVICE_STARTED); return false;
} }
static bool static bool
@ -344,7 +353,7 @@ get_provided(const RC_DEPINFO *depinfo, const char *runlevel, int options)
static void static void
visit_service(const RC_DEPTREE *deptree, visit_service(const RC_DEPTREE *deptree,
const RC_STRINGLIST *types, const RC_STRINGLIST *types,
RC_STRINGLIST **sorted, RC_STRINGLIST *sorted,
RC_STRINGLIST *visited, RC_STRINGLIST *visited,
const RC_DEPINFO *depinfo, const RC_DEPINFO *depinfo,
const char *runlevel, int options) const char *runlevel, int options)
@ -373,9 +382,7 @@ visit_service(const RC_DEPTREE *deptree,
if (!(options & RC_DEP_TRACE) || if (!(options & RC_DEP_TRACE) ||
strcmp(type->value, "iprovide") == 0) strcmp(type->value, "iprovide") == 0)
{ {
if (!*sorted) rc_stringlist_add(sorted, service->value);
*sorted = rc_stringlist_new();
rc_stringlist_add(*sorted, service->value);
continue; continue;
} }
@ -420,11 +427,9 @@ visit_service(const RC_DEPTREE *deptree,
/* We've visited everything we need, so add ourselves unless we /* We've visited everything we need, so add ourselves unless we
are also the service calling us or we are provided by something */ are also the service calling us or we are provided by something */
svcname = getenv("RC_SVCNAME"); svcname = getenv("RC_SVCNAME");
if (!svcname || strcmp(svcname, depinfo->service) != 0) if (!svcname || strcmp(svcname, depinfo->service) != 0) {
if (!get_deptype(depinfo, "providedby")) { if (!get_deptype(depinfo, "providedby"))
if (!*sorted) rc_stringlist_add(sorted, depinfo->service);
*sorted = rc_stringlist_new();
rc_stringlist_add(*sorted, depinfo->service);
} }
} }
@ -437,15 +442,15 @@ rc_deptree_depend(const RC_DEPTREE *deptree,
RC_STRINGLIST *svcs; RC_STRINGLIST *svcs;
RC_STRING *svc; RC_STRING *svc;
svcs = rc_stringlist_new();
if (!(di = get_depinfo(deptree, service)) || if (!(di = get_depinfo(deptree, service)) ||
!(dt = get_deptype(di, type))) !(dt = get_deptype(di, type)))
{ {
errno = ENOENT; errno = ENOENT;
return NULL; return svcs;
} }
/* For consistency, we copy the array */ /* For consistency, we copy the array */
svcs = rc_stringlist_new();
TAILQ_FOREACH(svc, dt->services, entries) TAILQ_FOREACH(svc, dt->services, entries)
rc_stringlist_add(svcs, svc->value); rc_stringlist_add(svcs, svc->value);
return svcs; return svcs;
@ -458,7 +463,7 @@ rc_deptree_depends(const RC_DEPTREE *deptree,
const RC_STRINGLIST *services, const RC_STRINGLIST *services,
const char *runlevel, int options) const char *runlevel, int options)
{ {
RC_STRINGLIST *sorted = NULL; RC_STRINGLIST *sorted = rc_stringlist_new();
RC_STRINGLIST *visited = rc_stringlist_new(); RC_STRINGLIST *visited = rc_stringlist_new();
RC_DEPINFO *di; RC_DEPINFO *di;
const RC_STRING *service; const RC_STRING *service;
@ -472,7 +477,7 @@ rc_deptree_depends(const RC_DEPTREE *deptree,
continue; continue;
} }
if (types) if (types)
visit_service(deptree, types, &sorted, visited, visit_service(deptree, types, sorted, visited,
di, runlevel, options); di, runlevel, options);
} }
rc_stringlist_free(visited); rc_stringlist_free(visited);
@ -499,42 +504,25 @@ rc_deptree_order(const RC_DEPTREE *deptree, const char *runlevel, int options)
{ {
list = rc_services_in_state(RC_SERVICE_STARTED); list = rc_services_in_state(RC_SERVICE_STARTED);
list2 = rc_services_in_state(RC_SERVICE_INACTIVE); list2 = rc_services_in_state(RC_SERVICE_INACTIVE);
if (list2) {
if (list) {
TAILQ_CONCAT(list, list2, entries); TAILQ_CONCAT(list, list2, entries);
free(list2); free(list2);
} else
list = list2;
}
list2 = rc_services_in_state(RC_SERVICE_STARTING); list2 = rc_services_in_state(RC_SERVICE_STARTING);
if (list2) {
if (list) {
TAILQ_CONCAT(list, list2, entries); TAILQ_CONCAT(list, list2, entries);
free(list2); free(list2);
} else
list = list2;
}
} else { } else {
list = rc_services_in_runlevel(runlevel); list = rc_services_in_runlevel(RC_LEVEL_SYSINIT);
/* Add coldplugged services */ if (strcmp(runlevel, RC_LEVEL_SYSINIT) != 0) {
list2 = rc_services_in_state(RC_SERVICE_COLDPLUGGED); list2 = rc_services_in_runlevel(runlevel);
if (list2) { TAILQ_CONCAT(list, list2, entries);
if (list) { free(list2);
list2 = rc_services_in_state(RC_SERVICE_COLDPLUGGED);
TAILQ_CONCAT(list, list2, entries); TAILQ_CONCAT(list, list2, entries);
free(list2); free(list2);
} else
list = list2;
}
/* If we're not the boot runlevel then add that too */ /* If we're not the boot runlevel then add that too */
if (strcmp(runlevel, bootlevel) != 0) { if (strcmp(runlevel, bootlevel) != 0) {
list2 = rc_services_in_runlevel (bootlevel); list2 = rc_services_in_runlevel(bootlevel);
if (list2) {
if (list) {
TAILQ_CONCAT(list, list2, entries); TAILQ_CONCAT(list, list2, entries);
free(list2); free(list2);
} else
list = list2;
} }
} }
} }
@ -683,7 +671,6 @@ rc_deptree_update_needed(void)
/* Some init scripts dependencies change depending on config files /* Some init scripts dependencies change depending on config files
* outside of baselayout, like syslog-ng, so we check those too. */ * outside of baselayout, like syslog-ng, so we check those too. */
config = rc_config_list(RC_DEPCONFIG); config = rc_config_list(RC_DEPCONFIG);
if (config) {
TAILQ_FOREACH(s, config, entries) { TAILQ_FOREACH(s, config, entries) {
if (!rc_newer_than(RC_DEPTREE_CACHE, s->value)) { if (!rc_newer_than(RC_DEPTREE_CACHE, s->value)) {
newer = true; newer = true;
@ -691,7 +678,6 @@ rc_deptree_update_needed(void)
} }
} }
rc_stringlist_free(config); rc_stringlist_free(config);
}
return newer; return newer;
} }
librc_hidden_def(rc_deptree_update_needed) librc_hidden_def(rc_deptree_update_needed)
@ -907,13 +893,11 @@ rc_deptree_update(void)
deptype = get_deptype(depinfo, "ibefore"); deptype = get_deptype(depinfo, "ibefore");
if (!deptype) if (!deptype)
continue; continue;
sorted = NULL; sorted = rc_stringlist_new();
visited = rc_stringlist_new(); visited = rc_stringlist_new();
visit_service(deptree, types, &sorted, visited, depinfo, visit_service(deptree, types, sorted, visited, depinfo,
NULL, 0); NULL, 0);
rc_stringlist_free(visited); rc_stringlist_free(visited);
if (!sorted)
continue;
TAILQ_FOREACH_SAFE(s2, deptype->services, entries, s2_np) { TAILQ_FOREACH_SAFE(s2, deptype->services, entries, s2_np) {
TAILQ_FOREACH(s3, sorted, entries) { TAILQ_FOREACH(s3, sorted, entries) {
di = get_depinfo(deptree, s3->value); di = get_depinfo(deptree, s3->value);

View File

@ -84,10 +84,10 @@ RC_STRINGLIST *rc_config_list(const char *file)
size_t len = 0; size_t len = 0;
char *p; char *p;
char *token; char *token;
RC_STRINGLIST *list = NULL; RC_STRINGLIST *list = rc_stringlist_new();
if (!(fp = fopen(file, "r"))) if (!(fp = fopen(file, "r")))
return NULL; return list;
while ((rc_getline(&buffer, &len, fp))) { while ((rc_getline(&buffer, &len, fp))) {
p = buffer; p = buffer;
@ -104,8 +104,6 @@ RC_STRINGLIST *rc_config_list(const char *file)
if (token[strlen(token) - 1] == '\n') if (token[strlen(token) - 1] == '\n')
token[strlen(token) - 1] = 0; token[strlen(token) - 1] = 0;
if (!list)
list = rc_stringlist_new();
rc_stringlist_add(list, token); rc_stringlist_add(list, token);
} }
} }
@ -131,9 +129,6 @@ RC_STRINGLIST *rc_config_load(const char *file)
char *p; char *p;
list = rc_config_list(file); list = rc_config_list(file);
if (!list)
return NULL;
config = rc_stringlist_new(); config = rc_stringlist_new();
TAILQ_FOREACH(line, list, entries) { TAILQ_FOREACH(line, list, entries) {
/* Get entry */ /* Get entry */
@ -203,9 +198,6 @@ char *rc_config_value(RC_STRINGLIST *list, const char *entry)
RC_STRING *line; RC_STRING *line;
char *p; char *p;
if (!list)
return NULL;
TAILQ_FOREACH(line, list, entries) { TAILQ_FOREACH(line, list, entries) {
p = strchr(line->value, '='); p = strchr(line->value, '=');
if (p && if (p &&

View File

@ -67,7 +67,8 @@ static const rc_service_state_name_t rc_service_state_names[] = {
#define LS_INITD 0x01 #define LS_INITD 0x01
#define LS_DIR 0x02 #define LS_DIR 0x02
static RC_STRINGLIST *ls_dir(const char *dir, int options) static RC_STRINGLIST *
ls_dir(const char *dir, int options)
{ {
DIR *dp; DIR *dp;
struct dirent *d; struct dirent *d;
@ -77,15 +78,15 @@ static RC_STRINGLIST *ls_dir(const char *dir, int options)
char file[PATH_MAX]; char file[PATH_MAX];
int r; int r;
list = rc_stringlist_new();
if ((dp = opendir(dir)) == NULL) if ((dp = opendir(dir)) == NULL)
return NULL; return list;
while (((d = readdir(dp)) != NULL)) { while (((d = readdir(dp)) != NULL)) {
if (d->d_name[0] != '.') { if (d->d_name[0] != '.') {
if (options & LS_INITD) { if (options & LS_INITD) {
/* Check that our file really exists. /* Check that our file really exists.
* This is important as a service maybe in a runlevel, but * This is important as a service maybe in a
* could also have been removed. */ * runlevel, but could have been removed. */
snprintf(file, sizeof(file), "%s/%s", snprintf(file, sizeof(file), "%s/%s",
dir, d->d_name); dir, d->d_name);
r = stat(file, &buf); r = stat(file, &buf);
@ -104,17 +105,15 @@ static RC_STRINGLIST *ls_dir(const char *dir, int options)
! S_ISDIR(buf.st_mode)) ! S_ISDIR(buf.st_mode))
continue; continue;
} }
if (! list)
list = rc_stringlist_new();
rc_stringlist_add(list, d->d_name); rc_stringlist_add(list, d->d_name);
} }
} }
closedir(dp); closedir(dp);
return list; return list;
} }
static bool rm_dir(const char *pathname, bool top) static bool
rm_dir(const char *pathname, bool top)
{ {
DIR *dp; DIR *dp;
struct dirent *d; struct dirent *d;
@ -127,16 +126,17 @@ static bool rm_dir(const char *pathname, bool top)
errno = 0; errno = 0;
while (((d = readdir(dp)) != NULL) && errno == 0) { while (((d = readdir(dp)) != NULL) && errno == 0) {
if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) { if (strcmp(d->d_name, ".") != 0 &&
snprintf(file, sizeof(file), "%s/%s", pathname, d->d_name); strcmp(d->d_name, "..") != 0)
{
snprintf(file, sizeof(file),
"%s/%s", pathname, d->d_name);
if (stat(file, &s) != 0) { if (stat(file, &s) != 0) {
retval = false; retval = false;
break; break;
} }
if (S_ISDIR(s.st_mode)) { if (S_ISDIR(s.st_mode)) {
if (! rm_dir(file, true)) if (!rm_dir(file, true))
{ {
retval = false; retval = false;
break; break;
@ -151,7 +151,7 @@ static bool rm_dir(const char *pathname, bool top)
} }
closedir(dp); closedir(dp);
if (! retval) if (!retval)
return false; return false;
if (top && rmdir(pathname) != 0) if (top && rmdir(pathname) != 0)
@ -162,7 +162,8 @@ static bool rm_dir(const char *pathname, bool top)
/* Other systems may need this at some point, but for now it's Linux only */ /* Other systems may need this at some point, but for now it's Linux only */
#ifdef __linux__ #ifdef __linux__
static bool file_regex(const char *file, const char *regex) static bool
file_regex(const char *file, const char *regex)
{ {
FILE *fp; FILE *fp;
char *line = NULL; char *line = NULL;
@ -171,12 +172,12 @@ static bool file_regex(const char *file, const char *regex)
bool retval = false; bool retval = false;
int result; int result;
if (! (fp = fopen(file, "r"))) if (!(fp = fopen(file, "r")))
return false; return false;
if ((result = regcomp(&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) { if ((result = regcomp(&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) {
fclose(fp); fclose(fp);
line = xmalloc(sizeof (char) * BUFSIZ); line = xmalloc(sizeof(char) * BUFSIZ);
regerror(result, &re, line, BUFSIZ); regerror(result, &re, line, BUFSIZ);
fprintf(stderr, "file_regex: %s", line); fprintf(stderr, "file_regex: %s", line);
free(line); free(line);
@ -197,8 +198,8 @@ static bool file_regex(const char *file, const char *regex)
} }
#endif #endif
const char *
const char *rc_sys(void) rc_sys(void)
{ {
#ifdef PREFIX #ifdef PREFIX
return RC_SYS_PREFIX; return RC_SYS_PREFIX;
@ -242,7 +243,8 @@ const char *rc_sys(void)
} }
librc_hidden_def(rc_sys) librc_hidden_def(rc_sys)
static const char *rc_parse_service_state(RC_SERVICE state) static const char *
rc_parse_service_state(RC_SERVICE state)
{ {
int i; int i;
@ -250,17 +252,18 @@ static const char *rc_parse_service_state(RC_SERVICE state)
if (rc_service_state_names[i].state == state) if (rc_service_state_names[i].state == state)
return rc_service_state_names[i].name; return rc_service_state_names[i].name;
} }
return NULL; return NULL;
} }
bool rc_runlevel_starting(void) bool
rc_runlevel_starting(void)
{ {
return exists(RC_STARTING); return exists(RC_STARTING);
} }
librc_hidden_def(rc_runlevel_starting) librc_hidden_def(rc_runlevel_starting)
bool rc_runlevel_stopping(void) bool
rc_runlevel_stopping(void)
{ {
return exists(RC_STOPPING); return exists(RC_STOPPING);
} }
@ -272,15 +275,17 @@ RC_STRINGLIST *rc_runlevel_list(void)
} }
librc_hidden_def(rc_runlevel_list) librc_hidden_def(rc_runlevel_list)
char *rc_runlevel_get(void) char *
rc_runlevel_get(void)
{ {
FILE *fp; FILE *fp;
char *runlevel = NULL; char *runlevel = NULL;
size_t i;
if ((fp = fopen(RC_RUNLEVEL, "r"))) { if ((fp = fopen(RC_RUNLEVEL, "r"))) {
runlevel = xmalloc(sizeof(char) * PATH_MAX); runlevel = xmalloc(sizeof(char) * PATH_MAX);
if (fgets(runlevel, PATH_MAX, fp)) { if (fgets(runlevel, PATH_MAX, fp)) {
int i = strlen(runlevel) - 1; i = strlen(runlevel) - 1;
if (runlevel[i] == '\n') if (runlevel[i] == '\n')
runlevel[i] = 0; runlevel[i] = 0;
} else } else
@ -288,7 +293,7 @@ char *rc_runlevel_get(void)
fclose(fp); fclose(fp);
} }
if (! runlevel || ! *runlevel) { if (!runlevel || !*runlevel) {
free(runlevel); free(runlevel);
runlevel = xstrdup(RC_LEVEL_SYSINIT); runlevel = xstrdup(RC_LEVEL_SYSINIT);
} }
@ -297,11 +302,12 @@ char *rc_runlevel_get(void)
} }
librc_hidden_def(rc_runlevel_get) librc_hidden_def(rc_runlevel_get)
bool rc_runlevel_set(const char *runlevel) bool
rc_runlevel_set(const char *runlevel)
{ {
FILE *fp = fopen(RC_RUNLEVEL, "w"); FILE *fp = fopen(RC_RUNLEVEL, "w");
if (! fp) if (!fp)
return false; return false;
fprintf(fp, "%s", runlevel); fprintf(fp, "%s", runlevel);
fclose(fp); fclose(fp);
@ -309,14 +315,14 @@ bool rc_runlevel_set(const char *runlevel)
} }
librc_hidden_def(rc_runlevel_set) librc_hidden_def(rc_runlevel_set)
bool rc_runlevel_exists(const char *runlevel) bool
rc_runlevel_exists(const char *runlevel)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
struct stat buf; struct stat buf;
if (! runlevel) if (!runlevel)
return false; return false;
snprintf(path, sizeof(path), "%s/%s", RC_RUNLEVELDIR, runlevel); snprintf(path, sizeof(path), "%s/%s", RC_RUNLEVELDIR, runlevel);
if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)) if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode))
return true; return true;
@ -325,14 +331,15 @@ bool rc_runlevel_exists(const char *runlevel)
librc_hidden_def(rc_runlevel_exists) librc_hidden_def(rc_runlevel_exists)
/* Resolve a service name to it's full path */ /* Resolve a service name to it's full path */
char *rc_service_resolve(const char *service) char *
rc_service_resolve(const char *service)
{ {
char buffer[PATH_MAX]; char buffer[PATH_MAX];
char file[PATH_MAX]; char file[PATH_MAX];
int r; int r;
struct stat buf; struct stat buf;
if (! service) if (!service)
return NULL; return NULL;
if (service[0] == '/') if (service[0] == '/')
@ -377,14 +384,15 @@ char *rc_service_resolve(const char *service)
} }
librc_hidden_def(rc_service_resolve) librc_hidden_def(rc_service_resolve)
bool rc_service_exists(const char *service) bool
rc_service_exists(const char *service)
{ {
char *file; char *file;
bool retval = false; bool retval = false;
int len; int len;
struct stat buf; struct stat buf;
if (! service) if (!service)
return false; return false;
len = strlen(service); len = strlen(service);
@ -395,7 +403,7 @@ bool rc_service_exists(const char *service)
service[len - 1] == 'h') service[len - 1] == 'h')
return false; return false;
if (! (file = rc_service_resolve(service))) if (!(file = rc_service_resolve(service)))
return false; return false;
if (stat(file, &buf) == 0 && buf.st_mode & S_IXUGO) if (stat(file, &buf) == 0 && buf.st_mode & S_IXUGO)
@ -406,7 +414,8 @@ bool rc_service_exists(const char *service)
librc_hidden_def(rc_service_exists) librc_hidden_def(rc_service_exists)
#define OPTSTR ". '%s'; echo \"${opts}\"" #define OPTSTR ". '%s'; echo \"${opts}\""
RC_STRINGLIST *rc_service_extra_commands(const char *service) RC_STRINGLIST *
rc_service_extra_commands(const char *service)
{ {
char *svc; char *svc;
char *cmd = NULL; char *cmd = NULL;
@ -418,10 +427,9 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service)
FILE *fp; FILE *fp;
size_t l; size_t l;
if (! (svc = rc_service_resolve(service))) if (!(svc = rc_service_resolve(service)))
return NULL; return NULL;
l = strlen(OPTSTR) + strlen(svc) + 1; l = strlen(OPTSTR) + strlen(svc) + 1;
cmd = xmalloc(sizeof(char) * l); cmd = xmalloc(sizeof(char) * l);
snprintf(cmd, l, OPTSTR, svc); snprintf(cmd, l, OPTSTR, svc);
@ -431,7 +439,7 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service)
rc_getline(&buffer, &len, fp); rc_getline(&buffer, &len, fp);
p = buffer; p = buffer;
while ((token = strsep(&p, " "))) { while ((token = strsep(&p, " "))) {
if (! commands) if (!commands)
commands = rc_stringlist_new(); commands = rc_stringlist_new();
rc_stringlist_add(commands, token); rc_stringlist_add(commands, token);
} }
@ -444,7 +452,8 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service)
librc_hidden_def(rc_service_extra_commands) librc_hidden_def(rc_service_extra_commands)
#define DESCSTR ". '%s'; echo \"${description%s%s}\"" #define DESCSTR ". '%s'; echo \"${description%s%s}\""
char *rc_service_description(const char *service, const char *option) char *
rc_service_description(const char *service, const char *option)
{ {
char *svc; char *svc;
char *cmd; char *cmd;
@ -453,7 +462,7 @@ char *rc_service_description(const char *service, const char *option)
FILE *fp; FILE *fp;
size_t l; size_t l;
if (! (svc = rc_service_resolve(service))) if (!(svc = rc_service_resolve(service)))
return NULL; return NULL;
if (!option) if (!option)
@ -472,7 +481,8 @@ char *rc_service_description(const char *service, const char *option)
} }
librc_hidden_def(rc_service_description) librc_hidden_def(rc_service_description)
bool rc_service_in_runlevel(const char *service, const char *runlevel) bool
rc_service_in_runlevel(const char *service, const char *runlevel)
{ {
char file[PATH_MAX]; char file[PATH_MAX];
@ -482,7 +492,8 @@ bool rc_service_in_runlevel(const char *service, const char *runlevel)
} }
librc_hidden_def(rc_service_in_runlevel) librc_hidden_def(rc_service_in_runlevel)
bool rc_service_mark(const char *service, const RC_SERVICE state) bool
rc_service_mark(const char *service, const RC_SERVICE state)
{ {
char file[PATH_MAX]; char file[PATH_MAX];
int i = 0; int i = 0;
@ -496,11 +507,10 @@ bool rc_service_mark(const char *service, const RC_SERVICE state)
RC_STRING *dir; RC_STRING *dir;
int serrno; int serrno;
if (! init) if (!init)
return false; return false;
base = basename_c(service); base = basename_c(service);
if (state != RC_SERVICE_STOPPED) { if (state != RC_SERVICE_STOPPED) {
if (!exists(init)) { if (!exists(init)) {
free(init); free(init);
@ -583,29 +593,26 @@ bool rc_service_mark(const char *service, const RC_SERVICE state)
if (state == RC_SERVICE_STARTED || state == RC_SERVICE_STOPPED) { if (state == RC_SERVICE_STARTED || state == RC_SERVICE_STOPPED) {
snprintf(file, sizeof(file), RC_SVCDIR "/%s", "scheduled"); snprintf(file, sizeof(file), RC_SVCDIR "/%s", "scheduled");
dirs = ls_dir(file, 0); dirs = ls_dir(file, 0);
if (dirs) {
TAILQ_FOREACH(dir, dirs, entries) { TAILQ_FOREACH(dir, dirs, entries) {
snprintf(was, sizeof(was), "%s/%s/%s", snprintf(was, sizeof(was), "%s/%s/%s",
file, dir->value, base); file, dir->value, base);
unlink(was); unlink(was);
/* Try and remove the dir - we don't care about errors */ /* Try and remove the dir; we don't care about errors */
snprintf(was, sizeof(was), "%s/%s", snprintf(was, sizeof(was), "%s/%s", file, dir->value);
file, dir->value);
serrno = errno; serrno = errno;
rmdir(was); rmdir(was);
errno = serrno; errno = serrno;
} }
rc_stringlist_free(dirs); rc_stringlist_free(dirs);
} }
}
free(init); free(init);
return true; return true;
} }
librc_hidden_def(rc_service_mark) librc_hidden_def(rc_service_mark)
RC_SERVICE rc_service_state(const char *service) RC_SERVICE
rc_service_state(const char *service)
{ {
int i; int i;
int state = RC_SERVICE_STOPPED; int state = RC_SERVICE_STOPPED;
@ -627,7 +634,6 @@ RC_SERVICE rc_service_state(const char *service)
if (state & RC_SERVICE_STOPPED) { if (state & RC_SERVICE_STOPPED) {
dirs = ls_dir(RC_SVCDIR "/scheduled", 0); dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
if (dirs) {
TAILQ_FOREACH (dir, dirs, entries) { TAILQ_FOREACH (dir, dirs, entries) {
snprintf(file, sizeof(file), snprintf(file, sizeof(file),
RC_SVCDIR "/scheduled/%s/%s", RC_SVCDIR "/scheduled/%s/%s",
@ -639,13 +645,13 @@ RC_SERVICE rc_service_state(const char *service)
} }
rc_stringlist_free(dirs); rc_stringlist_free(dirs);
} }
}
return state; return state;
} }
librc_hidden_def(rc_service_state) librc_hidden_def(rc_service_state)
char *rc_service_value_get(const char *service, const char *option) char *
rc_service_value_get(const char *service, const char *option)
{ {
FILE *fp; FILE *fp;
char *line = NULL; char *line = NULL;
@ -663,7 +669,8 @@ char *rc_service_value_get(const char *service, const char *option)
} }
librc_hidden_def(rc_service_value_get) librc_hidden_def(rc_service_value_get)
bool rc_service_value_set(const char *service, const char *option, bool
rc_service_value_set(const char *service, const char *option,
const char *value) const char *value)
{ {
FILE *fp; FILE *fp;
@ -685,8 +692,8 @@ bool rc_service_value_set(const char *service, const char *option,
librc_hidden_def(rc_service_value_set) librc_hidden_def(rc_service_value_set)
bool rc_service_schedule_start(const char *service, bool
const char *service_to_start) rc_service_schedule_start(const char *service, const char *service_to_start)
{ {
char file[PATH_MAX]; char file[PATH_MAX];
char *p = file; char *p = file;
@ -703,32 +710,34 @@ bool rc_service_schedule_start(const char *service,
return false; return false;
init = rc_service_resolve(service_to_start); init = rc_service_resolve(service_to_start);
snprintf(p, sizeof(file) - (p - file), "/%s", basename_c(service_to_start)); snprintf(p, sizeof(file) - (p - file),
"/%s", basename_c(service_to_start));
retval = (exists(file) || symlink(init, file) == 0); retval = (exists(file) || symlink(init, file) == 0);
free(init); free(init);
return retval; return retval;
} }
librc_hidden_def(rc_service_schedule_start) librc_hidden_def(rc_service_schedule_start)
bool rc_service_schedule_clear(const char *service) bool
rc_service_schedule_clear(const char *service)
{ {
char dir[PATH_MAX]; char dir[PATH_MAX];
snprintf(dir, sizeof(dir), RC_SVCDIR "/scheduled/%s", snprintf(dir, sizeof(dir), RC_SVCDIR "/scheduled/%s",
basename_c(service)); basename_c(service));
if (! rm_dir(dir, true) && errno == ENOENT) if (!rm_dir(dir, true) && errno == ENOENT)
return true; return true;
return false; return false;
} }
librc_hidden_def(rc_service_schedule_clear) librc_hidden_def(rc_service_schedule_clear)
RC_STRINGLIST *rc_services_in_runlevel(const char *runlevel) RC_STRINGLIST *
rc_services_in_runlevel(const char *runlevel)
{ {
char dir[PATH_MAX]; char dir[PATH_MAX];
RC_STRINGLIST *list; RC_STRINGLIST *list = NULL;
if (! runlevel) { if (!runlevel) {
#ifdef RC_PKG_INITDIR #ifdef RC_PKG_INITDIR
RC_STRINGLIST *pkg = ls_dir(RC_PKG_INITDIR, LS_INITD); RC_STRINGLIST *pkg = ls_dir(RC_PKG_INITDIR, LS_INITD);
#endif #endif
@ -739,36 +748,32 @@ RC_STRINGLIST *rc_services_in_runlevel(const char *runlevel)
list = ls_dir(RC_INITDIR, LS_INITD); list = ls_dir(RC_INITDIR, LS_INITD);
#ifdef RC_PKG_INITDIR #ifdef RC_PKG_INITDIR
if (pkg) {
TAILQ_CONCAT(list, pkg, entries); TAILQ_CONCAT(list, pkg, entries);
free(pkg); free(pkg);
}
#endif #endif
#ifdef RC_LOCAL_INITDIR #ifdef RC_LOCAL_INITDIR
if (local) {
TAILQ_CONCAT(list, local, entries); TAILQ_CONCAT(list, local, entries);
free(local); free(local);
}
#endif #endif
return list; return list;
} }
/* These special levels never contain any services */ /* These special levels never contain any services */
if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0 || if (strcmp(runlevel, RC_LEVEL_SINGLE) != 0) {
strcmp(runlevel, RC_LEVEL_SINGLE) == 0) {
return NULL;
}
snprintf(dir, sizeof(dir), RC_RUNLEVELDIR "/%s", runlevel); snprintf(dir, sizeof(dir), RC_RUNLEVELDIR "/%s", runlevel);
list = ls_dir(dir, LS_INITD); list = ls_dir(dir, LS_INITD);
}
if (!list)
list = rc_stringlist_new();
return list; return list;
} }
librc_hidden_def(rc_services_in_runlevel) librc_hidden_def(rc_services_in_runlevel)
RC_STRINGLIST *rc_services_in_state(RC_SERVICE state) RC_STRINGLIST *
rc_services_in_state(RC_SERVICE state)
{ {
RC_STRINGLIST *services; RC_STRINGLIST *services;
RC_STRINGLIST *list = NULL; RC_STRINGLIST *list;
RC_STRINGLIST *dirs; RC_STRINGLIST *dirs;
RC_STRING *d; RC_STRING *d;
char dir[PATH_MAX]; char dir[PATH_MAX];
@ -780,28 +785,26 @@ RC_STRINGLIST *rc_services_in_state(RC_SERVICE state)
if (state != RC_SERVICE_SCHEDULED) if (state != RC_SERVICE_SCHEDULED)
return ls_dir(dir, LS_INITD); return ls_dir(dir, LS_INITD);
dirs = ls_dir(dir, 0); dirs = ls_dir(dir, 0);
list = rc_stringlist_new();
if (! dirs) if (! dirs)
return NULL; return list;
TAILQ_FOREACH(d, dirs, entries) { TAILQ_FOREACH(d, dirs, entries) {
snprintf(p, sizeof(dir) - (p - dir), "/%s", d->value); snprintf(p, sizeof(dir) - (p - dir), "/%s", d->value);
services = ls_dir(dir, LS_INITD); services = ls_dir(dir, LS_INITD);
if (! list) if (services) {
services = list;
else if (services) {
TAILQ_CONCAT(list, services, entries); TAILQ_CONCAT(list, services, entries);
free(services); free(services);
} }
} }
rc_stringlist_free(dirs); rc_stringlist_free(dirs);
return list; return list;
} }
librc_hidden_def(rc_services_in_state) librc_hidden_def(rc_services_in_state)
bool rc_service_add(const char *runlevel, const char *service) bool
rc_service_add(const char *runlevel, const char *service)
{ {
bool retval; bool retval;
char *init; char *init;
@ -811,7 +814,7 @@ bool rc_service_add(const char *runlevel, const char *service)
char binit[PATH_MAX]; char binit[PATH_MAX];
char *i; char *i;
if (! rc_runlevel_exists(runlevel)) { if (!rc_runlevel_exists(runlevel)) {
errno = ENOENT; errno = ENOENT;
return false; return false;
} }
@ -827,12 +830,11 @@ bool rc_service_add(const char *runlevel, const char *service)
/* We need to ensure that only things in /etc/init.d are added /* We need to ensure that only things in /etc/init.d are added
* to the boot runlevel */ * to the boot runlevel */
if (strcmp (runlevel, RC_LEVEL_BOOT) == 0) { if (strcmp(runlevel, RC_LEVEL_BOOT) == 0) {
p = realpath(dirname(init), path); p = realpath(dirname(init), path);
if (! *p) { if (!*p) {
free(init); free(init);
return false; return false;
} }
if (strcmp(path, RC_INITDIR) != 0) { if (strcmp(path, RC_INITDIR) != 0) {
free(init); free(init);
@ -849,7 +851,8 @@ bool rc_service_add(const char *runlevel, const char *service)
} }
librc_hidden_def(rc_service_add) librc_hidden_def(rc_service_add)
bool rc_service_delete (const char *runlevel, const char *service) bool
rc_service_delete(const char *runlevel, const char *service)
{ {
char file[PATH_MAX]; char file[PATH_MAX];
@ -861,32 +864,27 @@ bool rc_service_delete (const char *runlevel, const char *service)
} }
librc_hidden_def(rc_service_delete) librc_hidden_def(rc_service_delete)
RC_STRINGLIST *rc_services_scheduled_by(const char *service) RC_STRINGLIST *
rc_services_scheduled_by(const char *service)
{ {
RC_STRINGLIST *dirs = ls_dir(RC_SVCDIR "/scheduled", 0); RC_STRINGLIST *dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
RC_STRINGLIST *list = NULL; RC_STRINGLIST *list = rc_stringlist_new();
RC_STRING *dir; RC_STRING *dir;
char file[PATH_MAX]; char file[PATH_MAX];
if (! dirs)
return NULL;
TAILQ_FOREACH (dir, dirs, entries) { TAILQ_FOREACH (dir, dirs, entries) {
snprintf(file, sizeof(file), RC_SVCDIR "/scheduled/%s/%s", snprintf(file, sizeof(file), RC_SVCDIR "/scheduled/%s/%s",
dir->value, service); dir->value, service);
if (exists(file)) { if (exists(file))
if (! list)
list = rc_stringlist_new();
rc_stringlist_add(list, file); rc_stringlist_add(list, file);
} }
}
rc_stringlist_free(dirs); rc_stringlist_free(dirs);
return list; return list;
} }
librc_hidden_def(rc_services_scheduled_by) librc_hidden_def(rc_services_scheduled_by)
RC_STRINGLIST *rc_services_scheduled(const char *service) RC_STRINGLIST *
rc_services_scheduled(const char *service)
{ {
char dir[PATH_MAX]; char dir[PATH_MAX];

View File

@ -48,7 +48,8 @@
extern const char *applet; extern const char *applet;
RC_DEPTREE *_rc_deptree_load(int *regen) { RC_DEPTREE *
_rc_deptree_load(int *regen) {
int fd; int fd;
int retval; int retval;
int serrno = errno; int serrno = errno;
@ -65,12 +66,10 @@ RC_DEPTREE *_rc_deptree_load(int *regen) {
if (regen) if (regen)
*regen = 1; *regen = 1;
ebegin("Caching service dependencies"); ebegin("Caching service dependencies");
retval = rc_deptree_update(); retval = rc_deptree_update();
eend (retval ? 0 : -1, "Failed to update the dependency tree"); eend (retval ? 0 : -1, "Failed to update the dependency tree");
} }
return rc_deptree_load(); return rc_deptree_load();
} }
@ -96,7 +95,8 @@ static const char * const longopts_help[] = {
}; };
#include "_usage.c" #include "_usage.c"
int rc_depend(int argc, char **argv) int
rc_depend(int argc, char **argv)
{ {
RC_STRINGLIST *list; RC_STRINGLIST *list;
RC_STRINGLIST *types; RC_STRINGLIST *types;
@ -112,7 +112,6 @@ int rc_depend(int argc, char **argv)
char *token; char *token;
types = rc_stringlist_new(); types = rc_stringlist_new();
while ((opt = getopt_long(argc, argv, getoptstring, while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1) longopts, (int *) 0)) != -1)
{ {
@ -145,14 +144,14 @@ int rc_depend(int argc, char **argv)
ebegin("Caching service dependencies"); ebegin("Caching service dependencies");
update = rc_deptree_update(); update = rc_deptree_update();
eend(update ? 0 : -1, "%s: %s", applet, strerror(errno)); eend(update ? 0 : -1, "%s: %s", applet, strerror(errno));
if (! update) if (!update)
eerrorx("Failed to update the dependency tree"); eerrorx("Failed to update the dependency tree");
} }
if (! (deptree = _rc_deptree_load(NULL))) if (!(deptree = _rc_deptree_load(NULL)))
eerrorx("failed to load deptree"); eerrorx("failed to load deptree");
if (! runlevel) if (!runlevel)
runlevel = rc_runlevel_get(); runlevel = rc_runlevel_get();
services = rc_stringlist_new(); services = rc_stringlist_new();
@ -161,8 +160,9 @@ int rc_depend(int argc, char **argv)
rc_stringlist_add(list, argv[optind]); rc_stringlist_add(list, argv[optind]);
errno = 0; errno = 0;
depends = rc_deptree_depends(deptree, NULL, list, runlevel, 0); depends = rc_deptree_depends(deptree, NULL, list, runlevel, 0);
if (! depends && errno == ENOENT) if (!depends && errno == ENOENT)
eerror("no dependency info for service `%s'", argv[optind]); eerror("no dependency info for service `%s'",
argv[optind]);
else else
rc_stringlist_add(services, argv[optind]); rc_stringlist_add(services, argv[optind]);
@ -170,7 +170,7 @@ int rc_depend(int argc, char **argv)
rc_stringlist_free(list); rc_stringlist_free(list);
optind++; optind++;
} }
if (! TAILQ_FIRST(services)) { if (!TAILQ_FIRST(services)) {
rc_stringlist_free(services); rc_stringlist_free(services);
rc_stringlist_free(types); rc_stringlist_free(types);
rc_deptree_free(deptree); rc_deptree_free(deptree);
@ -181,12 +181,13 @@ int rc_depend(int argc, char **argv)
} }
/* If we don't have any types, then supply some defaults */ /* If we don't have any types, then supply some defaults */
if (! TAILQ_FIRST(types)) { if (!TAILQ_FIRST(types)) {
rc_stringlist_add(types, "ineed"); rc_stringlist_add(types, "ineed");
rc_stringlist_add(types, "iuse"); rc_stringlist_add(types, "iuse");
} }
depends = rc_deptree_depends(deptree, types, services, runlevel, options); depends = rc_deptree_depends(deptree, types, services,
runlevel, options);
if (TAILQ_FIRST(depends)) { if (TAILQ_FIRST(depends)) {
TAILQ_FOREACH(s, depends, entries) { TAILQ_FOREACH(s, depends, entries) {

View File

@ -62,13 +62,15 @@ static RC_STRINGLIST *rc_conf = NULL;
extern char** environ; extern char** environ;
#ifdef DEBUG_MEMORY #ifdef DEBUG_MEMORY
static void _free_rc_conf(void) static void
_free_rc_conf(void)
{ {
rc_stringlist_free(rc_conf); rc_stringlist_free(rc_conf);
} }
#endif #endif
char *rc_conf_value(const char *setting) char *
rc_conf_value(const char *setting)
{ {
RC_STRINGLIST *old; RC_STRINGLIST *old;
RC_STRING *s; RC_STRING *s;
@ -83,17 +85,13 @@ char *rc_conf_value(const char *setting)
/* Support old configs */ /* Support old configs */
if (exists(RC_CONF_OLD)) { if (exists(RC_CONF_OLD)) {
old = rc_config_load(RC_CONF_OLD); old = rc_config_load(RC_CONF_OLD);
if (old) {
if (rc_conf) {
TAILQ_CONCAT(rc_conf, old, entries); TAILQ_CONCAT(rc_conf, old, entries);
#ifdef DEBUG_MEMORY
free(old); free(old);
} else #endif
rc_conf = old;
}
} }
/* Convert old uppercase to lowercase */ /* Convert old uppercase to lowercase */
if (rc_conf)
TAILQ_FOREACH(s, rc_conf, entries) { TAILQ_FOREACH(s, rc_conf, entries) {
p = s->value; p = s->value;
while (p && *p && *p != '=') { while (p && *p && *p != '=') {
@ -107,7 +105,8 @@ char *rc_conf_value(const char *setting)
return rc_config_value(rc_conf, setting); return rc_config_value(rc_conf, setting);
} }
bool rc_conf_yesno(const char *setting) bool
rc_conf_yesno(const char *setting)
{ {
return rc_yesno(rc_conf_value (setting)); return rc_yesno(rc_conf_value (setting));
} }
@ -122,10 +121,11 @@ static const char *const env_whitelist[] = {
NULL NULL
}; };
void env_filter(void) void
env_filter(void)
{ {
RC_STRINGLIST *env_allow; RC_STRINGLIST *env_allow;
RC_STRINGLIST *profile = NULL; RC_STRINGLIST *profile;
RC_STRINGLIST *env_list; RC_STRINGLIST *env_list;
RC_STRING *env; RC_STRING *env;
char *e; char *e;
@ -133,7 +133,6 @@ void env_filter(void)
/* Add the user defined list of vars */ /* Add the user defined list of vars */
env_allow = rc_stringlist_split(rc_conf_value("rc_env_allow"), " "); env_allow = rc_stringlist_split(rc_conf_value("rc_env_allow"), " ");
if (exists(PROFILE_ENV))
profile = rc_config_load(PROFILE_ENV); profile = rc_config_load(PROFILE_ENV);
/* Copy the env and work from this so we can manipulate it safely */ /* Copy the env and work from this so we can manipulate it safely */
@ -163,21 +162,22 @@ void env_filter(void)
} }
/* Now add anything missing from the profile */ /* Now add anything missing from the profile */
if (profile) {
TAILQ_FOREACH(env, profile, entries) { TAILQ_FOREACH(env, profile, entries) {
e = strchr(env->value, '='); e = strchr(env->value, '=');
*e = '\0'; *e = '\0';
if (!getenv(env->value)) if (!getenv(env->value))
setenv(env->value, e + 1, 1); setenv(env->value, e + 1, 1);
} }
}
#ifdef DEBUG_MEMORY
rc_stringlist_free(env_list); rc_stringlist_free(env_list);
rc_stringlist_free(env_allow); rc_stringlist_free(env_allow);
rc_stringlist_free(profile); rc_stringlist_free(profile);
#endif
} }
void env_config(void) void
env_config(void)
{ {
size_t pplen = strlen(PATH_PREFIX); size_t pplen = strlen(PATH_PREFIX);
char *path; char *path;
@ -203,7 +203,8 @@ void env_config(void)
e = p = xmalloc(sizeof(char) * l); e = p = xmalloc(sizeof(char) * l);
p += snprintf(p, l, "%s", PATH_PREFIX); p += snprintf(p, l, "%s", PATH_PREFIX);
/* Now go through the env var and only add bits not in our PREFIX */ /* Now go through the env var and only add bits not in our
* PREFIX */
while ((token = strsep(&path, ":"))) { while ((token = strsep(&path, ":"))) {
np = npp = xstrdup(PATH_PREFIX); np = npp = xstrdup(PATH_PREFIX);
while ((tok = strsep(&npp, ":"))) while ((tok = strsep(&npp, ":")))
@ -259,48 +260,8 @@ void env_config(void)
setenv("EINFO_COLOR", "NO", 1); setenv("EINFO_COLOR", "NO", 1);
} }
bool service_plugable(const char *service) int
{ signal_setup(int sig, void (*handler)(int))
char *list;
char *p;
char *star;
char *token;
bool allow = true;
char *match = rc_conf_value("rc_plug_services");
bool truefalse;
if (! match)
return true;
list = xstrdup(match);
p = list;
while ((token = strsep(&p, " "))) {
if (token[0] == '!') {
truefalse = false;
token++;
} else
truefalse = true;
star = strchr(token, '*');
if (star) {
if (strncmp(service, token, (size_t)(star - token)) == 0)
{
allow = truefalse;
break;
}
} else {
if (strcmp(service, token) == 0) {
allow = truefalse;
break;
}
}
}
free(list);
return allow;
}
int signal_setup(int sig, void (*handler)(int))
{ {
struct sigaction sa; struct sigaction sa;
@ -310,7 +271,8 @@ int signal_setup(int sig, void (*handler)(int))
return sigaction(sig, &sa, NULL); return sigaction(sig, &sa, NULL);
} }
pid_t exec_service(const char *service, const char *arg) pid_t
exec_service(const char *service, const char *arg)
{ {
char *file; char *file;
char fifo[PATH_MAX]; char fifo[PATH_MAX];
@ -320,7 +282,7 @@ pid_t exec_service(const char *service, const char *arg)
struct sigaction sa; struct sigaction sa;
file = rc_service_resolve(service); file = rc_service_resolve(service);
if (! exists(file)) { if (!exists(file)) {
rc_service_mark(service, RC_SERVICE_STOPPED); rc_service_mark(service, RC_SERVICE_STOPPED);
free(file); free(file);
return 0; return 0;
@ -368,7 +330,6 @@ pid_t exec_service(const char *service, const char *arg)
sigprocmask(SIG_SETMASK, &old, NULL); sigprocmask(SIG_SETMASK, &old, NULL);
free(file); free(file);
return pid; return pid;
} }

View File

@ -58,7 +58,8 @@ static const char * const longopts_help[] = {
}; };
#include "_usage.c" #include "_usage.c"
int rc_service(int argc, char **argv) int
rc_service(int argc, char **argv)
{ {
int opt; int opt;
char *service; char *service;
@ -75,17 +76,21 @@ int rc_service(int argc, char **argv)
case 'e': case 'e':
service = rc_service_resolve(optarg); service = rc_service_resolve(optarg);
opt = service ? EXIT_SUCCESS : EXIT_FAILURE; opt = service ? EXIT_SUCCESS : EXIT_FAILURE;
#ifdef DEBUG_MEMORY
free(service); free(service);
#endif
return opt; return opt;
/* NOTREACHED */ /* NOTREACHED */
case 'l': case 'l':
list = rc_services_in_runlevel(NULL); list = rc_services_in_runlevel(NULL);
if (! list) if (!TAILQ_FIRST(list))
return EXIT_FAILURE; return EXIT_FAILURE;
rc_stringlist_sort(&list); rc_stringlist_sort(&list);
TAILQ_FOREACH(s, list, entries) TAILQ_FOREACH(s, list, entries)
printf("%s\n", s->value); printf("%s\n", s->value);
#ifdef DEBUG_MEMORY
rc_stringlist_free(list); rc_stringlist_free(list);
#endif
return EXIT_SUCCESS; return EXIT_SUCCESS;
/* NOTREACHED */ /* NOTREACHED */
case 'r': case 'r':
@ -93,7 +98,9 @@ int rc_service(int argc, char **argv)
if (!service) if (!service)
return EXIT_FAILURE; return EXIT_FAILURE;
printf("%s\n", service); printf("%s\n", service);
#ifdef DEBUG_MEMORY
free(service); free(service);
#endif
return EXIT_SUCCESS; return EXIT_SUCCESS;
/* NOTREACHED */ /* NOTREACHED */
@ -103,13 +110,10 @@ int rc_service(int argc, char **argv)
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (!*argv) if (!*argv)
eerrorx("%s: you need to specify a service", applet); eerrorx("%s: you need to specify a service", applet);
if (!(service = rc_service_resolve(*argv))) if (!(service = rc_service_resolve(*argv)))
eerrorx("%s: service `%s' does not exist", applet, *argv); eerrorx("%s: service `%s' does not exist", applet, *argv);
*argv = service; *argv = service;
execv(*argv, argv); execv(*argv, argv);
eerrorx("%s: %s", applet, strerror(errno)); eerrorx("%s: %s", applet, strerror(errno));

View File

@ -43,12 +43,6 @@ const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
#include <sys/utsname.h> #include <sys/utsname.h>
#include <sys/wait.h> #include <sys/wait.h>
/* So we can coldplug net devices */
#ifdef BSD
# include <sys/socket.h>
# include <ifaddrs.h>
#endif
#ifdef __linux__ #ifdef __linux__
# include <asm/setup.h> /* for COMMAND_LINE_SIZE */ # include <asm/setup.h> /* for COMMAND_LINE_SIZE */
#endif #endif
@ -519,115 +513,10 @@ static void handle_signal(int sig)
errno = serrno; errno = serrno;
} }
static void do_coldplug(void)
{
size_t l;
DIR *dp;
struct dirent *d;
char *service;
RC_STRING *s;
#ifdef BSD
struct ifaddrs *ifap;
struct ifaddrs *ifa;
char *p;
#endif
errno = 0;
if (!rc_conf_yesno("rc_coldplug") && errno != ENOENT)
return;
/* We need to ensure our state dirs exist.
* We should have a better call than this, but oh well. */
rc_deptree_update_needed();
#ifdef BSD
if (getifaddrs(&ifap) == 0) {
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr->sa_family != AF_LINK)
continue;
l = strlen("net.") + strlen(ifa->ifa_name) + 1;
service = xmalloc(sizeof (char) * l);
snprintf(service, l, "net.%s", ifa->ifa_name);
if (rc_service_exists(service) &&
service_plugable(service))
rc_service_mark(service, RC_SERVICE_COLDPLUGGED);
free(service);
}
freeifaddrs (ifap);
}
/* The mice are a little more tricky.
* If we coldplug anything else, we'll probably do it here. */
if ((dp = opendir("/dev"))) {
while ((d = readdir(dp))) {
if (strncmp(d->d_name, "psm", 3) == 0 ||
strncmp(d->d_name, "ums", 3) == 0)
{
p = d->d_name + 3;
if (p && isdigit((unsigned char)*p)) {
l = strlen("moused.") + strlen(d->d_name) + 1;
service = xmalloc(sizeof(char) * l);
snprintf (service, l, "moused.%s", d->d_name);
if (rc_service_exists (service) &&
service_plugable (service))
rc_service_mark (service, RC_SERVICE_COLDPLUGGED);
free(service);
}
}
}
closedir (dp);
}
#else
/* udev likes to start services before we're ready when it does
* its coldplugging thing. runscript knows when we're not ready so it
* stores a list of coldplugged services in DEVBOOT for us to pick up
* here when we are ready for them */
if ((dp = opendir(DEVBOOT))) {
while ((d = readdir(dp))) {
if (d->d_name[0] == '.' &&
(d->d_name[1] == '\0' ||
(d->d_name[1] == '.' && d->d_name[2] == '\0')))
continue;
if (rc_service_exists(d->d_name) &&
service_plugable(d->d_name))
rc_service_mark(d->d_name, RC_SERVICE_COLDPLUGGED);
l = strlen(DEVBOOT "/") + strlen(d->d_name) + 1;
service = xmalloc(sizeof (char) * l);
snprintf(service, l, DEVBOOT "/%s", d->d_name);
if (unlink(service))
eerror("%s: unlink `%s': %s", applet, service,
strerror(errno));
free(service);
}
closedir(dp);
rmdir(DEVBOOT);
}
#endif
if (rc_yesno(getenv("EINFO_QUIET")))
return;
/* Load our list of coldplugged services and display them */
einfon("Device initiated services:%s", ecolor(ECOLOR_HILITE));
coldplugged_services = rc_services_in_state(RC_SERVICE_COLDPLUGGED);
if (coldplugged_services)
TAILQ_FOREACH(s, coldplugged_services, entries)
printf(" %s", s->value);
printf("%s\n", ecolor(ECOLOR_NORMAL));
}
static void do_newlevel(const char *newlevel) static void do_newlevel(const char *newlevel)
{ {
struct utsname uts; struct utsname uts;
const char *sys; const char *sys;
#ifdef __linux__
char *cmd;
#endif
if (strcmp(newlevel, RC_LEVEL_SYSINIT) == 0 if (strcmp(newlevel, RC_LEVEL_SYSINIT) == 0
#ifndef PREFIX #ifndef PREFIX
@ -669,39 +558,13 @@ static void do_newlevel(const char *newlevel)
ecolor(ECOLOR_GOOD), ecolor(ECOLOR_NORMAL)); ecolor(ECOLOR_GOOD), ecolor(ECOLOR_NORMAL));
setenv("RC_RUNLEVEL", newlevel, 1); setenv("RC_RUNLEVEL", newlevel, 1);
rc_plugin_run(RC_HOOK_RUNLEVEL_START_IN, newlevel);
hook_out = RC_HOOK_RUNLEVEL_START_OUT;
run_program(INITSH); run_program(INITSH);
#ifdef __linux__
/* If we requested a runlevel, save it now */
if ((cmd = proc_getent("rc_runlevel"))) {
set_krunlevel(cmd);
free(cmd);
} else if ((cmd = proc_getent("softlevel"))) {
set_krunlevel(cmd);
free(cmd);
} else
set_krunlevel(NULL);
#endif
/* Setup our coldplugged services now */
do_coldplug();
rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, newlevel);
hook_out = 0;
if (want_interactive())
mark_interactive();
exit(EXIT_SUCCESS);
} else if (strcmp(newlevel, RC_LEVEL_SINGLE) == 0) { } else if (strcmp(newlevel, RC_LEVEL_SINGLE) == 0) {
#ifndef PREFIX #ifndef PREFIX
if (! RUNLEVEL || if (! RUNLEVEL ||
(strcmp(RUNLEVEL, "S") != 0 && (strcmp(RUNLEVEL, "S") != 0 &&
strcmp(RUNLEVEL, "1") != 0)) strcmp(RUNLEVEL, "1") != 0))
{ {
/* Remember the current runlevel for when we come back */
set_krunlevel(runlevel); set_krunlevel(runlevel);
single_user(); single_user();
} }
@ -883,7 +746,12 @@ interactive_option:
if (! parallel) { if (! parallel) {
rc_waitpid(pid); rc_waitpid(pid);
remove_pid(pid); remove_pid(pid);
/* Attempt to open the logger as a service may
* mount the needed /dev/pts for this to work */
if (rc_logger_tty == -1)
rc_logger_open(runlevel);
} }
} }
} }
@ -1076,7 +944,8 @@ int main(int argc, char **argv)
{ {
/* Try not to join boot and krunlevels together */ /* Try not to join boot and krunlevels together */
if (! newlevel || if (! newlevel ||
strcmp(newlevel, getenv("RC_BOOTLEVEL")) != 0) (strcmp(newlevel, getenv("RC_BOOTLEVEL")) != 0 &&
strcmp(newlevel, RC_LEVEL_SYSINIT) != 0))
if (get_krunlevel(krunlevel, sizeof(krunlevel))) if (get_krunlevel(krunlevel, sizeof(krunlevel)))
newlevel = krunlevel; newlevel = krunlevel;
} else if (! RUNLEVEL || } else if (! RUNLEVEL ||
@ -1135,21 +1004,11 @@ int main(int argc, char **argv)
* correct order for stopping them */ * correct order for stopping them */
stop_services = rc_services_in_state(RC_SERVICE_STARTED); stop_services = rc_services_in_state(RC_SERVICE_STARTED);
tmplist = rc_services_in_state(RC_SERVICE_INACTIVE); tmplist = rc_services_in_state(RC_SERVICE_INACTIVE);
if (tmplist) {
if (stop_services) {
TAILQ_CONCAT(stop_services, tmplist, entries); TAILQ_CONCAT(stop_services, tmplist, entries);
free(tmplist); free(tmplist);
} else
stop_services = tmplist;
}
tmplist = rc_services_in_state(RC_SERVICE_STARTING); tmplist = rc_services_in_state(RC_SERVICE_STARTING);
if (tmplist) {
if (stop_services) {
TAILQ_CONCAT(stop_services, tmplist, entries); TAILQ_CONCAT(stop_services, tmplist, entries);
free(tmplist); free(tmplist);
} else
stop_services = tmplist;
}
if (stop_services) if (stop_services)
rc_stringlist_sort(&stop_services); rc_stringlist_sort(&stop_services);
@ -1171,17 +1030,22 @@ int main(int argc, char **argv)
strcmp(newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 && strcmp(newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 &&
strcmp(newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0) strcmp(newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0)
{ {
/* We need to include the boot runlevel services if we're not in it */ start_services = rc_services_in_runlevel(RC_LEVEL_SYSINIT);
start_services = rc_services_in_runlevel(bootlevel); if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SYSINIT)
if (strcmp (newlevel ? newlevel : runlevel, bootlevel) != 0) { != 0)
tmplist = rc_services_in_runlevel(newlevel ? newlevel : runlevel); {
if (tmplist) { /* We need to include the boot runlevel services */
if (start_services) { tmplist = rc_services_in_runlevel(bootlevel);
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); TAILQ_CONCAT(start_services, tmplist, entries);
free(tmplist); free(tmplist);
} else
start_services = tmplist;
}
} }
if (coldplugged_services) { if (coldplugged_services) {
@ -1191,6 +1055,7 @@ int main(int argc, char **argv)
rc_stringlist_addu(start_services, service->value); rc_stringlist_addu(start_services, service->value);
} }
} }
}
parallel = rc_conf_yesno("rc_parallel"); parallel = rc_conf_yesno("rc_parallel");
@ -1265,14 +1130,15 @@ int main(int argc, char **argv)
if (start_services) { if (start_services) {
do_start_services(parallel); do_start_services(parallel);
/* FIXME: If we skip the boot runlevel and go straight
* to default from sysinit, we should now re-evaluate our
* start services + coldplugged services and call
* do_start_services a second time. */
/* Wait for our services to finish */ /* Wait for our services to finish */
wait_for_services(); wait_for_services();
} }
rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, runlevel);
hook_out = 0;
#ifdef __linux__ #ifdef __linux__
/* mark any services skipped as stopped */ /* mark any services skipped as stopped */
if (PREVLEVEL && strcmp(PREVLEVEL, "N") == 0) { if (PREVLEVEL && strcmp(PREVLEVEL, "N") == 0) {
@ -1285,12 +1151,15 @@ int main(int argc, char **argv)
} }
#endif #endif
rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, runlevel);
hook_out = 0;
/* If we're in the boot runlevel and we regenerated our dependencies /* If we're in the boot runlevel and we regenerated our dependencies
* we need to delete them so that they are regenerated again in the * we need to delete them so that they are regenerated again in the
* default runlevel as they may depend on things that are now available */ * default runlevel as they may depend on things that are now
* available */
if (regen && strcmp(runlevel, bootlevel) == 0) if (regen && strcmp(runlevel, bootlevel) == 0)
unlink(RC_DEPTREE_CACHE); unlink(RC_DEPTREE_CACHE);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

File diff suppressed because it is too large Load Diff