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 ...)
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.
rc_hotplug="YES"
# Dynamic /dev managers can trigger coldplug events which cause services to
# 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
# Some people want a finer grain over hotplug. rc_plug_services is a
# 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
# anyway.
# default we allow services through as rc_hotplug has to be YES anyway.
# Example - rc_plug_services="net.wlan !net.*"
# This allows net.wlan and any service not matching net.* to be plugged.
rc_plug_services=""
# rc_logger launches a logging daemon to log the entire rc process to
# /var/log/rc.log
# NOTE: Linux systems require the devfs service to be started before
# logging can take place.
rc_logger="NO"
# By default we filter the environment for our running scripts. To allow other

View File

@ -1,7 +1,7 @@
NET_LO= net.lo
SRCS+= hwclock.in consolefont.in keymaps.in modules.in mtab.in numlock.in \
procfs.in termencoding.in
SRCS+= devfs.in dmesg.in hwclock.in consolefont.in keymaps.in modules.in \
mtab.in numlock.in procfs.in sysfs.in termencoding.in
.SUFFIXES: .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()
{
after clock modules
use dev clock modules
keyword nojail noopenvz noprefix notimeout novserver
}

View File

@ -6,6 +6,7 @@ description="Mounts misc filesystems in /proc."
depend()
{
use devfs
need localmount
keyword noopenvz noprefix novserver
}
@ -39,7 +40,7 @@ start()
# Setup Kernel Support for the NFS daemon status
if [ -d /proc/fs/nfsd ] && ! mountinfo -q /proc/fs/nfsd; then
if grep -qs nfsd /proc/filesystems; then
ebegin "Mounting nfsd filesystem"
ebegin "Mounting NFS filesystem"
mount -t nfsd -o nodev,noexec,nosuid \
nfsd /proc/fs/nfsd
eend $?
@ -56,26 +57,6 @@ start()
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
if [ -d /selinux ] && ! mountinfo -q /selinux; 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
LEVELDIR= ${DESTDIR}/${SYSCONFDIR}/runlevels
SYSINITDIR= ${LEVELDIR}/sysinit
BOOTDIR= ${LEVELDIR}/boot
DEFAULTDIR= ${LEVELDIR}/default
@ -17,6 +18,14 @@ include Makefile.${OS}
all:
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 \
${INSTALL} -d ${BOOTDIR} || exit $$?; \
for x in ${BOOT}; do \

View File

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

View File

@ -22,8 +22,4 @@ else
fi
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}

View File

@ -9,7 +9,8 @@
# tmpfs and ramfs are easy, so force one or the other.
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}
if grep -Eq "[[:space:]]+tmpfs$" /proc/filesystems; then
@ -56,17 +57,8 @@ mount_svcdir()
}
. /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
# 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!
# 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
@ -82,7 +74,6 @@ if [ -e /proc/uptime ]; then
einfo "/proc is already mounted, skipping"
mountproc=false
fi
unset up
fi
if ${mountproc}; then
@ -94,98 +85,5 @@ if ${mountproc}; then
fi
eend $?
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

View File

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

View File

@ -84,10 +84,10 @@ RC_STRINGLIST *rc_config_list(const char *file)
size_t len = 0;
char *p;
char *token;
RC_STRINGLIST *list = NULL;
RC_STRINGLIST *list = rc_stringlist_new();
if (!(fp = fopen(file, "r")))
return NULL;
return list;
while ((rc_getline(&buffer, &len, fp))) {
p = buffer;
@ -104,8 +104,6 @@ RC_STRINGLIST *rc_config_list(const char *file)
if (token[strlen(token) - 1] == '\n')
token[strlen(token) - 1] = 0;
if (!list)
list = rc_stringlist_new();
rc_stringlist_add(list, token);
}
}
@ -131,9 +129,6 @@ RC_STRINGLIST *rc_config_load(const char *file)
char *p;
list = rc_config_list(file);
if (!list)
return NULL;
config = rc_stringlist_new();
TAILQ_FOREACH(line, list, entries) {
/* Get entry */
@ -203,9 +198,6 @@ char *rc_config_value(RC_STRINGLIST *list, const char *entry)
RC_STRING *line;
char *p;
if (!list)
return NULL;
TAILQ_FOREACH(line, list, entries) {
p = strchr(line->value, '=');
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_DIR 0x02
static RC_STRINGLIST *ls_dir(const char *dir, int options)
static RC_STRINGLIST *
ls_dir(const char *dir, int options)
{
DIR *dp;
struct dirent *d;
@ -77,15 +78,15 @@ static RC_STRINGLIST *ls_dir(const char *dir, int options)
char file[PATH_MAX];
int r;
list = rc_stringlist_new();
if ((dp = opendir(dir)) == NULL)
return NULL;
return list;
while (((d = readdir(dp)) != NULL)) {
if (d->d_name[0] != '.') {
if (options & LS_INITD) {
/* Check that our file really exists.
* This is important as a service maybe in a runlevel, but
* could also have been removed. */
* This is important as a service maybe in a
* runlevel, but could have been removed. */
snprintf(file, sizeof(file), "%s/%s",
dir, d->d_name);
r = stat(file, &buf);
@ -104,17 +105,15 @@ static RC_STRINGLIST *ls_dir(const char *dir, int options)
! S_ISDIR(buf.st_mode))
continue;
}
if (! list)
list = rc_stringlist_new();
rc_stringlist_add(list, d->d_name);
}
}
closedir(dp);
return list;
}
static bool rm_dir(const char *pathname, bool top)
static bool
rm_dir(const char *pathname, bool top)
{
DIR *dp;
struct dirent *d;
@ -127,14 +126,15 @@ static bool rm_dir(const char *pathname, bool top)
errno = 0;
while (((d = readdir(dp)) != NULL) && errno == 0) {
if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) {
snprintf(file, sizeof(file), "%s/%s", pathname, d->d_name);
if (strcmp(d->d_name, ".") != 0 &&
strcmp(d->d_name, "..") != 0)
{
snprintf(file, sizeof(file),
"%s/%s", pathname, d->d_name);
if (stat(file, &s) != 0) {
retval = false;
break;
}
if (S_ISDIR(s.st_mode)) {
if (!rm_dir(file, true))
{
@ -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 */
#ifdef __linux__
static bool file_regex(const char *file, const char *regex)
static bool
file_regex(const char *file, const char *regex)
{
FILE *fp;
char *line = NULL;
@ -197,8 +198,8 @@ static bool file_regex(const char *file, const char *regex)
}
#endif
const char *rc_sys(void)
const char *
rc_sys(void)
{
#ifdef PREFIX
return RC_SYS_PREFIX;
@ -242,7 +243,8 @@ const char *rc_sys(void)
}
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;
@ -250,17 +252,18 @@ static const char *rc_parse_service_state(RC_SERVICE state)
if (rc_service_state_names[i].state == state)
return rc_service_state_names[i].name;
}
return NULL;
}
bool rc_runlevel_starting(void)
bool
rc_runlevel_starting(void)
{
return exists(RC_STARTING);
}
librc_hidden_def(rc_runlevel_starting)
bool rc_runlevel_stopping(void)
bool
rc_runlevel_stopping(void)
{
return exists(RC_STOPPING);
}
@ -272,15 +275,17 @@ RC_STRINGLIST *rc_runlevel_list(void)
}
librc_hidden_def(rc_runlevel_list)
char *rc_runlevel_get(void)
char *
rc_runlevel_get(void)
{
FILE *fp;
char *runlevel = NULL;
size_t i;
if ((fp = fopen(RC_RUNLEVEL, "r"))) {
runlevel = xmalloc(sizeof(char) * PATH_MAX);
if (fgets(runlevel, PATH_MAX, fp)) {
int i = strlen(runlevel) - 1;
i = strlen(runlevel) - 1;
if (runlevel[i] == '\n')
runlevel[i] = 0;
} else
@ -297,7 +302,8 @@ char *rc_runlevel_get(void)
}
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");
@ -309,14 +315,14 @@ bool rc_runlevel_set(const char *runlevel)
}
librc_hidden_def(rc_runlevel_set)
bool rc_runlevel_exists(const char *runlevel)
bool
rc_runlevel_exists(const char *runlevel)
{
char path[PATH_MAX];
struct stat buf;
if (!runlevel)
return false;
snprintf(path, sizeof(path), "%s/%s", RC_RUNLEVELDIR, runlevel);
if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode))
return true;
@ -325,7 +331,8 @@ bool rc_runlevel_exists(const char *runlevel)
librc_hidden_def(rc_runlevel_exists)
/* 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 file[PATH_MAX];
@ -377,7 +384,8 @@ char *rc_service_resolve(const char *service)
}
librc_hidden_def(rc_service_resolve)
bool rc_service_exists(const char *service)
bool
rc_service_exists(const char *service)
{
char *file;
bool retval = false;
@ -406,7 +414,8 @@ bool rc_service_exists(const char *service)
librc_hidden_def(rc_service_exists)
#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 *cmd = NULL;
@ -421,7 +430,6 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service)
if (!(svc = rc_service_resolve(service)))
return NULL;
l = strlen(OPTSTR) + strlen(svc) + 1;
cmd = xmalloc(sizeof(char) * l);
snprintf(cmd, l, OPTSTR, svc);
@ -444,7 +452,8 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service)
librc_hidden_def(rc_service_extra_commands)
#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 *cmd;
@ -472,7 +481,8 @@ char *rc_service_description(const char *service, const char *option)
}
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];
@ -482,7 +492,8 @@ bool rc_service_in_runlevel(const char *service, const char *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];
int i = 0;
@ -500,7 +511,6 @@ bool rc_service_mark(const char *service, const RC_SERVICE state)
return false;
base = basename_c(service);
if (state != RC_SERVICE_STOPPED) {
if (!exists(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) {
snprintf(file, sizeof(file), RC_SVCDIR "/%s", "scheduled");
dirs = ls_dir(file, 0);
if (dirs) {
TAILQ_FOREACH(dir, dirs, entries) {
snprintf(was, sizeof(was), "%s/%s/%s",
file, dir->value, base);
unlink(was);
/* Try and remove the dir - we don't care about errors */
snprintf(was, sizeof(was), "%s/%s",
file, dir->value);
/* Try and remove the dir; we don't care about errors */
snprintf(was, sizeof(was), "%s/%s", file, dir->value);
serrno = errno;
rmdir(was);
errno = serrno;
}
rc_stringlist_free(dirs);
}
}
free(init);
return true;
}
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 state = RC_SERVICE_STOPPED;
@ -627,7 +634,6 @@ RC_SERVICE rc_service_state(const char *service)
if (state & RC_SERVICE_STOPPED) {
dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
if (dirs) {
TAILQ_FOREACH (dir, dirs, entries) {
snprintf(file, sizeof(file),
RC_SVCDIR "/scheduled/%s/%s",
@ -639,13 +645,13 @@ RC_SERVICE rc_service_state(const char *service)
}
rc_stringlist_free(dirs);
}
}
return 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;
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)
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)
{
FILE *fp;
@ -685,8 +692,8 @@ bool rc_service_value_set(const char *service, const char *option,
librc_hidden_def(rc_service_value_set)
bool rc_service_schedule_start(const char *service,
const char *service_to_start)
bool
rc_service_schedule_start(const char *service, const char *service_to_start)
{
char file[PATH_MAX];
char *p = file;
@ -703,15 +710,16 @@ bool rc_service_schedule_start(const char *service,
return false;
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);
free(init);
return retval;
}
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];
@ -723,10 +731,11 @@ bool rc_service_schedule_clear(const char *service)
}
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];
RC_STRINGLIST *list;
RC_STRINGLIST *list = NULL;
if (!runlevel) {
#ifdef RC_PKG_INITDIR
@ -739,36 +748,32 @@ RC_STRINGLIST *rc_services_in_runlevel(const char *runlevel)
list = ls_dir(RC_INITDIR, LS_INITD);
#ifdef RC_PKG_INITDIR
if (pkg) {
TAILQ_CONCAT(list, pkg, entries);
free(pkg);
}
#endif
#ifdef RC_LOCAL_INITDIR
if (local) {
TAILQ_CONCAT(list, local, entries);
free(local);
}
#endif
return list;
}
/* These special levels never contain any services */
if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0 ||
strcmp(runlevel, RC_LEVEL_SINGLE) == 0) {
return NULL;
}
if (strcmp(runlevel, RC_LEVEL_SINGLE) != 0) {
snprintf(dir, sizeof(dir), RC_RUNLEVELDIR "/%s", runlevel);
list = ls_dir(dir, LS_INITD);
}
if (!list)
list = rc_stringlist_new();
return list;
}
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 *list = NULL;
RC_STRINGLIST *list;
RC_STRINGLIST *dirs;
RC_STRING *d;
char dir[PATH_MAX];
@ -780,28 +785,26 @@ RC_STRINGLIST *rc_services_in_state(RC_SERVICE state)
if (state != RC_SERVICE_SCHEDULED)
return ls_dir(dir, LS_INITD);
dirs = ls_dir(dir, 0);
list = rc_stringlist_new();
if (! dirs)
return NULL;
return list;
TAILQ_FOREACH(d, dirs, entries) {
snprintf(p, sizeof(dir) - (p - dir), "/%s", d->value);
services = ls_dir(dir, LS_INITD);
if (! list)
services = list;
else if (services) {
if (services) {
TAILQ_CONCAT(list, services, entries);
free(services);
}
}
rc_stringlist_free(dirs);
return list;
}
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;
char *init;
@ -832,7 +835,6 @@ bool rc_service_add(const char *runlevel, const char *service)
if (!*p) {
free(init);
return false;
}
if (strcmp(path, RC_INITDIR) != 0) {
free(init);
@ -849,7 +851,8 @@ bool rc_service_add(const char *runlevel, const char *service)
}
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];
@ -861,32 +864,27 @@ bool rc_service_delete (const char *runlevel, const char *service)
}
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 *list = NULL;
RC_STRINGLIST *list = rc_stringlist_new();
RC_STRING *dir;
char file[PATH_MAX];
if (! dirs)
return NULL;
TAILQ_FOREACH (dir, dirs, entries) {
snprintf(file, sizeof(file), RC_SVCDIR "/scheduled/%s/%s",
dir->value, service);
if (exists(file)) {
if (! list)
list = rc_stringlist_new();
if (exists(file))
rc_stringlist_add(list, file);
}
}
rc_stringlist_free(dirs);
return list;
}
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];

View File

@ -48,7 +48,8 @@
extern const char *applet;
RC_DEPTREE *_rc_deptree_load(int *regen) {
RC_DEPTREE *
_rc_deptree_load(int *regen) {
int fd;
int retval;
int serrno = errno;
@ -65,12 +66,10 @@ RC_DEPTREE *_rc_deptree_load(int *regen) {
if (regen)
*regen = 1;
ebegin("Caching service dependencies");
retval = rc_deptree_update();
eend (retval ? 0 : -1, "Failed to update the dependency tree");
}
return rc_deptree_load();
}
@ -96,7 +95,8 @@ static const char * const longopts_help[] = {
};
#include "_usage.c"
int rc_depend(int argc, char **argv)
int
rc_depend(int argc, char **argv)
{
RC_STRINGLIST *list;
RC_STRINGLIST *types;
@ -112,7 +112,6 @@ int rc_depend(int argc, char **argv)
char *token;
types = rc_stringlist_new();
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
{
@ -162,7 +161,8 @@ int rc_depend(int argc, char **argv)
errno = 0;
depends = rc_deptree_depends(deptree, NULL, list, runlevel, 0);
if (!depends && errno == ENOENT)
eerror("no dependency info for service `%s'", argv[optind]);
eerror("no dependency info for service `%s'",
argv[optind]);
else
rc_stringlist_add(services, argv[optind]);
@ -186,7 +186,8 @@ int rc_depend(int argc, char **argv)
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)) {
TAILQ_FOREACH(s, depends, entries) {

View File

@ -62,13 +62,15 @@ static RC_STRINGLIST *rc_conf = NULL;
extern char** environ;
#ifdef DEBUG_MEMORY
static void _free_rc_conf(void)
static void
_free_rc_conf(void)
{
rc_stringlist_free(rc_conf);
}
#endif
char *rc_conf_value(const char *setting)
char *
rc_conf_value(const char *setting)
{
RC_STRINGLIST *old;
RC_STRING *s;
@ -83,17 +85,13 @@ char *rc_conf_value(const char *setting)
/* Support old configs */
if (exists(RC_CONF_OLD)) {
old = rc_config_load(RC_CONF_OLD);
if (old) {
if (rc_conf) {
TAILQ_CONCAT(rc_conf, old, entries);
#ifdef DEBUG_MEMORY
free(old);
} else
rc_conf = old;
}
#endif
}
/* Convert old uppercase to lowercase */
if (rc_conf)
TAILQ_FOREACH(s, rc_conf, entries) {
p = s->value;
while (p && *p && *p != '=') {
@ -107,7 +105,8 @@ char *rc_conf_value(const char *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));
}
@ -122,10 +121,11 @@ static const char *const env_whitelist[] = {
NULL
};
void env_filter(void)
void
env_filter(void)
{
RC_STRINGLIST *env_allow;
RC_STRINGLIST *profile = NULL;
RC_STRINGLIST *profile;
RC_STRINGLIST *env_list;
RC_STRING *env;
char *e;
@ -133,7 +133,6 @@ void env_filter(void)
/* Add the user defined list of vars */
env_allow = rc_stringlist_split(rc_conf_value("rc_env_allow"), " ");
if (exists(PROFILE_ENV))
profile = rc_config_load(PROFILE_ENV);
/* 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 */
if (profile) {
TAILQ_FOREACH(env, profile, entries) {
e = strchr(env->value, '=');
*e = '\0';
if (!getenv(env->value))
setenv(env->value, e + 1, 1);
}
}
#ifdef DEBUG_MEMORY
rc_stringlist_free(env_list);
rc_stringlist_free(env_allow);
rc_stringlist_free(profile);
#endif
}
void env_config(void)
void
env_config(void)
{
size_t pplen = strlen(PATH_PREFIX);
char *path;
@ -203,7 +203,8 @@ void env_config(void)
e = p = xmalloc(sizeof(char) * l);
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, ":"))) {
np = npp = xstrdup(PATH_PREFIX);
while ((tok = strsep(&npp, ":")))
@ -259,48 +260,8 @@ void env_config(void)
setenv("EINFO_COLOR", "NO", 1);
}
bool service_plugable(const char *service)
{
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))
int
signal_setup(int sig, void (*handler)(int))
{
struct sigaction sa;
@ -310,7 +271,8 @@ int signal_setup(int sig, void (*handler)(int))
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 fifo[PATH_MAX];
@ -368,7 +330,6 @@ pid_t exec_service(const char *service, const char *arg)
sigprocmask(SIG_SETMASK, &old, NULL);
free(file);
return pid;
}

View File

@ -58,7 +58,8 @@ static const char * const longopts_help[] = {
};
#include "_usage.c"
int rc_service(int argc, char **argv)
int
rc_service(int argc, char **argv)
{
int opt;
char *service;
@ -75,17 +76,21 @@ int rc_service(int argc, char **argv)
case 'e':
service = rc_service_resolve(optarg);
opt = service ? EXIT_SUCCESS : EXIT_FAILURE;
#ifdef DEBUG_MEMORY
free(service);
#endif
return opt;
/* NOTREACHED */
case 'l':
list = rc_services_in_runlevel(NULL);
if (! list)
if (!TAILQ_FIRST(list))
return EXIT_FAILURE;
rc_stringlist_sort(&list);
TAILQ_FOREACH(s, list, entries)
printf("%s\n", s->value);
#ifdef DEBUG_MEMORY
rc_stringlist_free(list);
#endif
return EXIT_SUCCESS;
/* NOTREACHED */
case 'r':
@ -93,7 +98,9 @@ int rc_service(int argc, char **argv)
if (!service)
return EXIT_FAILURE;
printf("%s\n", service);
#ifdef DEBUG_MEMORY
free(service);
#endif
return EXIT_SUCCESS;
/* NOTREACHED */
@ -103,13 +110,10 @@ int rc_service(int argc, char **argv)
argc -= optind;
argv += optind;
if (!*argv)
eerrorx("%s: you need to specify a service", applet);
if (!(service = rc_service_resolve(*argv)))
eerrorx("%s: service `%s' does not exist", applet, *argv);
*argv = service;
execv(*argv, argv);
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/wait.h>
/* So we can coldplug net devices */
#ifdef BSD
# include <sys/socket.h>
# include <ifaddrs.h>
#endif
#ifdef __linux__
# include <asm/setup.h> /* for COMMAND_LINE_SIZE */
#endif
@ -519,115 +513,10 @@ static void handle_signal(int sig)
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)
{
struct utsname uts;
const char *sys;
#ifdef __linux__
char *cmd;
#endif
if (strcmp(newlevel, RC_LEVEL_SYSINIT) == 0
#ifndef PREFIX
@ -669,39 +558,13 @@ static void do_newlevel(const char *newlevel)
ecolor(ECOLOR_GOOD), ecolor(ECOLOR_NORMAL));
setenv("RC_RUNLEVEL", newlevel, 1);
rc_plugin_run(RC_HOOK_RUNLEVEL_START_IN, newlevel);
hook_out = RC_HOOK_RUNLEVEL_START_OUT;
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) {
#ifndef PREFIX
if (! RUNLEVEL ||
(strcmp(RUNLEVEL, "S") != 0 &&
strcmp(RUNLEVEL, "1") != 0))
{
/* Remember the current runlevel for when we come back */
set_krunlevel(runlevel);
single_user();
}
@ -883,7 +746,12 @@ interactive_option:
if (! parallel) {
rc_waitpid(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 */
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)))
newlevel = krunlevel;
} else if (! RUNLEVEL ||
@ -1135,21 +1004,11 @@ int main(int argc, char **argv)
* correct order for stopping them */
stop_services = rc_services_in_state(RC_SERVICE_STARTED);
tmplist = rc_services_in_state(RC_SERVICE_INACTIVE);
if (tmplist) {
if (stop_services) {
TAILQ_CONCAT(stop_services, tmplist, entries);
free(tmplist);
} else
stop_services = tmplist;
}
tmplist = rc_services_in_state(RC_SERVICE_STARTING);
if (tmplist) {
if (stop_services) {
TAILQ_CONCAT(stop_services, tmplist, entries);
free(tmplist);
} else
stop_services = tmplist;
}
if (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_REBOOT) != 0)
{
/* We need to include the boot runlevel services if we're not in it */
start_services = rc_services_in_runlevel(bootlevel);
if (strcmp (newlevel ? newlevel : runlevel, bootlevel) != 0) {
tmplist = rc_services_in_runlevel(newlevel ? newlevel : runlevel);
if (tmplist) {
if (start_services) {
start_services = rc_services_in_runlevel(RC_LEVEL_SYSINIT);
if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SYSINIT)
!= 0)
{
/* We need to include the boot runlevel 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);
free(tmplist);
} else
start_services = tmplist;
}
}
if (coldplugged_services) {
@ -1191,6 +1055,7 @@ int main(int argc, char **argv)
rc_stringlist_addu(start_services, service->value);
}
}
}
parallel = rc_conf_yesno("rc_parallel");
@ -1265,14 +1130,15 @@ int main(int argc, char **argv)
if (start_services) {
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_services();
}
rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, runlevel);
hook_out = 0;
#ifdef __linux__
/* mark any services skipped as stopped */
if (PREVLEVEL && strcmp(PREVLEVEL, "N") == 0) {
@ -1285,12 +1151,15 @@ int main(int argc, char **argv)
}
#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
* 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)
unlink(RC_DEPTREE_CACHE);
return EXIT_SUCCESS;
}

View File

@ -108,9 +108,8 @@ static RC_STRINGLIST *types_mua = NULL;
static void (*selinux_run_init_old)(void);
static void (*selinux_run_init_new)(int argc, char **argv);
static void setup_selinux(int argc, char **argv);
static void setup_selinux(int argc, char **argv)
static void
setup_selinux(int argc, char **argv)
{
void *lib_handle = NULL;
@ -141,7 +140,8 @@ static void setup_selinux(int argc, char **argv)
}
#endif
static void handle_signal(int sig)
static void
handle_signal(int sig)
{
int serrno = errno;
char signame[10] = { '\0' };
@ -155,7 +155,8 @@ static void handle_signal(int sig)
case SIGCHLD:
if (signal_pipe[1] > -1) {
if (write(signal_pipe[1], &sig, sizeof(sig)) == -1)
eerror("%s: send: %s", service, strerror(errno));
eerror("%s: send: %s",
service, strerror(errno));
} else
rc_waitpid(-1);
break;
@ -192,18 +193,17 @@ static void handle_signal(int sig)
errno = serrno;
}
static time_t get_mtime(const char *pathname, bool follow_link)
static time_t
get_mtime(const char *pathname, bool follow_link)
{
struct stat buf;
int retval;
if (!pathname)
return 0;
retval = follow_link ? stat(pathname, &buf) : lstat(pathname, &buf);
if (!retval)
return buf.st_mtime;
errno = 0;
return 0;
}
@ -211,7 +211,8 @@ static time_t get_mtime(const char *pathname, bool follow_link)
static const char *const tests[] = {
"starting", "started", "stopping", "inactive", "wasinactive", NULL
};
static bool in_control()
static bool
in_control()
{
char file[PATH_MAX];
time_t m;
@ -231,7 +232,8 @@ static bool in_control()
return false;
while (tests[i]) {
snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", tests[i], applet);
snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s",
tests[i], applet);
if (exists(file)) {
m = get_mtime(file, false);
if (mtime < m && m != 0)
@ -243,7 +245,8 @@ static bool in_control()
return true;
}
static void uncoldplug()
static void
uncoldplug()
{
char file[PATH_MAX];
@ -252,7 +255,9 @@ static void uncoldplug()
eerror("%s: unlink `%s': %s", applet, file, strerror(errno));
}
static void start_services(RC_STRINGLIST *list) {
static void
start_services(RC_STRINGLIST *list)
{
RC_STRING *svc;
RC_SERVICE state = rc_service_state (service);
@ -265,11 +270,14 @@ static void start_services(RC_STRINGLIST *list) {
state & RC_SERVICE_STARTED)
{
TAILQ_FOREACH(svc, list, entries) {
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) {
if (!(rc_service_state(svc->value) &
RC_SERVICE_STOPPED))
continue;
if (state & RC_SERVICE_INACTIVE ||
state & RC_SERVICE_WASINACTIVE)
{
rc_service_schedule_start(service, svc->value);
rc_service_schedule_start(service,
svc->value);
ewarn("WARNING: %s is scheduled to started"
" when %s has started",
svc->value, applet);
@ -278,15 +286,14 @@ static void start_services(RC_STRINGLIST *list) {
}
}
}
}
static void restore_state(void)
static void
restore_state(void)
{
RC_SERVICE state;
if (rc_in_plugin || !in_control())
return;
state = rc_service_state(applet);
if (state & RC_SERVICE_STOPPING) {
if (state & RC_SERVICE_WASINACTIVE)
@ -310,7 +317,8 @@ static void restore_state(void)
}
}
static void cleanup(void)
static void
cleanup(void)
{
restore_state();
@ -318,9 +326,11 @@ static void cleanup(void)
if (hook_out) {
rc_plugin_run(hook_out, applet);
if (hook_out == RC_HOOK_SERVICE_START_DONE)
rc_plugin_run(RC_HOOK_SERVICE_START_OUT, applet);
rc_plugin_run(RC_HOOK_SERVICE_START_OUT,
applet);
else if (hook_out == RC_HOOK_SERVICE_STOP_DONE)
rc_plugin_run(RC_HOOK_SERVICE_STOP_OUT, applet);
rc_plugin_run(RC_HOOK_SERVICE_STOP_OUT,
applet);
}
if (restart_services)
@ -353,7 +363,9 @@ static void cleanup(void)
unlink(mtime_test);
}
static int write_prefix(const char *buffer, size_t bytes, bool *prefixed) {
static int
write_prefix(const char *buffer, size_t bytes, bool *prefixed)
{
unsigned int i;
const char *ec = ecolor(ECOLOR_HILITE);
const char *ec_normal = ecolor(ECOLOR_NORMAL);
@ -389,11 +401,11 @@ static int write_prefix(const char *buffer, size_t bytes, bool *prefixed) {
/* Release the lock */
close(lock_fd);
return ret;
}
static bool svc_exec(const char *arg1, const char *arg2)
static bool
svc_exec(const char *arg1, const char *arg2)
{
bool execok;
int fdout = fileno(stdout);
@ -430,7 +442,6 @@ static bool svc_exec(const char *arg1, const char *arg2)
/* If the below call fails due to not enough ptys then we don't
* prefix the output, but we still work */
openpty(&master_tty, &slave_tty, NULL, &tt, &ws);
if (master_tty >= 0 &&
(flags = fcntl(master_tty, F_GETFD, 0)) == 0)
fcntl(master_tty, F_SETFD, flags | FD_CLOEXEC);
@ -450,13 +461,15 @@ static bool svc_exec(const char *arg1, const char *arg2)
}
if (exists(RC_SVCDIR "/runscript.sh")) {
execl(RC_SVCDIR "/runscript.sh", RC_SVCDIR "/runscript.sh",
execl(RC_SVCDIR "/runscript.sh",
RC_SVCDIR "/runscript.sh",
service, arg1, arg2, (char *) NULL);
eerror("%s: exec `" RC_SVCDIR "/runscript.sh': %s",
service, strerror(errno));
_exit(EXIT_FAILURE);
} else {
execl(RC_LIBDIR "/sh/runscript.sh", RC_LIBDIR "/sh/runscript.sh",
execl(RC_LIBDIR "/sh/runscript.sh",
RC_LIBDIR "/sh/runscript.sh",
service, arg1, arg2, (char *) NULL);
eerror("%s: exec `" RC_LIBDIR "/sh/runscript.sh': %s",
service, strerror(errno));
@ -474,7 +487,8 @@ static bool svc_exec(const char *arg1, const char *arg2)
if ((s = select(selfd, &rset, NULL, NULL, NULL)) == -1) {
if (errno != EINTR) {
eerror("%s: select: %s", service, strerror(errno));
eerror("%s: select: %s", service,
strerror(errno));
break;
}
}
@ -509,7 +523,8 @@ static bool svc_exec(const char *arg1, const char *arg2)
return execok;
}
static bool svc_wait(const char *svc)
static bool
svc_wait(const char *svc)
{
char fifo[PATH_MAX];
struct timespec ts;
@ -525,7 +540,8 @@ static bool svc_wait(const char *svc)
forever = true;
rc_stringlist_free(keywords);
snprintf(fifo, sizeof(fifo), RC_SVCDIR "/exclusive/%s", basename_c(svc));
snprintf(fifo, sizeof(fifo), RC_SVCDIR "/exclusive/%s",
basename_c(svc));
ts.tv_sec = 0;
ts.tv_nsec = WAIT_INTERVAL;
@ -554,7 +570,8 @@ static bool svc_wait(const char *svc)
return retval;
}
static RC_SERVICE svc_status(void)
static RC_SERVICE
svc_status(void)
{
char status[10];
int (*e) (const char *fmt, ...) EINFO_PRINTF(1, 2) = einfo;
@ -586,19 +603,21 @@ static RC_SERVICE svc_status(void)
return state;
}
static void make_exclusive(void)
static void
make_exclusive(void)
{
/* We create a fifo so that other services can wait until we complete */
if (!*exclusive)
snprintf(exclusive, sizeof(exclusive), RC_SVCDIR "/exclusive/%s",
applet);
snprintf(exclusive, sizeof(exclusive),
RC_SVCDIR "/exclusive/%s", applet);
if (mkfifo(exclusive, 0600) != 0 && errno != EEXIST &&
(errno != EACCES || geteuid () == 0))
eerrorx ("%s: unable to create fifo `%s': %s",
applet, exclusive, strerror(errno));
snprintf(mtime_test, sizeof(mtime_test), RC_SVCDIR "/exclusive/%s.%d", applet, getpid());
snprintf(mtime_test, sizeof(mtime_test),
RC_SVCDIR "/exclusive/%s.%d", applet, getpid());
if (exists(mtime_test) && unlink(mtime_test) != 0) {
eerror("%s: unlink `%s': %s",
@ -614,28 +633,28 @@ static void make_exclusive(void)
}
}
static void unlink_mtime_test(void)
static void
unlink_mtime_test(void)
{
if (unlink(mtime_test) != 0)
eerror("%s: unlink `%s': %s", applet, mtime_test, strerror(errno));
eerror("%s: unlink `%s': %s",
applet, mtime_test, strerror(errno));
*mtime_test = '\0';
}
static void get_started_services(void)
static void
get_started_services(void)
{
RC_STRINGLIST *tmp = rc_services_in_state(RC_SERVICE_INACTIVE);
rc_stringlist_free(restart_services);
restart_services = rc_services_in_state(RC_SERVICE_STARTED);
if (tmp) {
if (restart_services) {
TAILQ_CONCAT(restart_services, tmp, entries);
free(tmp);
} else
restart_services = tmp;
}
}
static void setup_types(void)
static void
setup_types(void)
{
types_b = rc_stringlist_new();
rc_stringlist_add(types_b, "broken");
@ -661,7 +680,8 @@ static void setup_types(void)
rc_stringlist_add(types_mua, "beforeme");
}
static void svc_start(bool deps)
static void
svc_start(bool deps)
{
bool started;
bool background = false;
@ -682,6 +702,10 @@ static void svc_start(bool deps)
! state & RC_SERVICE_STOPPED)
exit(EXIT_FAILURE);
background = true;
rc_service_mark(service, RC_SERVICE_COLDPLUGGED);
if (rc_runlevel_starting())
ewarnx("WARNING: %s will be started when the runlevel"
" has finished.", applet);
}
if (state & RC_SERVICE_STARTED) {
@ -692,7 +716,8 @@ static void svc_start(bool deps)
else if (state & RC_SERVICE_STOPPING)
ewarnx("WARNING: %s is stopping", applet);
else if (state & RC_SERVICE_INACTIVE && ! background)
ewarnx("WARNING: %s has already started, but is inactive", applet);
ewarnx("WARNING: %s has already started, but is inactive",
applet);
if (!rc_service_mark(service, RC_SERVICE_STARTING)) {
if (errno == EACCES)
@ -701,7 +726,6 @@ static void svc_start(bool deps)
}
make_exclusive();
hook_out = RC_HOOK_SERVICE_START_OUT;
rc_plugin_run(RC_HOOK_SERVICE_START_IN, applet);
@ -712,13 +736,12 @@ static void svc_start(bool deps)
if (deps) {
if (!deptree && ((deptree = _rc_deptree_load(NULL)) == NULL))
eerrorx("failed to load deptree");
if (!types_b)
setup_types();
services = rc_deptree_depends(deptree, types_b, applet_list,
runlevel, 0);
if (services && TAILQ_FIRST(services)) {
if (TAILQ_FIRST(services)) {
eerrorn("ERROR: `%s' needs ", applet);
first = true;
TAILQ_FOREACH(svc, services, entries) {
@ -733,12 +756,14 @@ static void svc_start(bool deps)
rc_stringlist_free(services);
services = NULL;
need_services = rc_deptree_depends(deptree, types_n, applet_list,
runlevel, depoptions);
use_services = rc_deptree_depends(deptree, types_nu, applet_list,
runlevel, depoptions);
need_services = rc_deptree_depends(deptree, types_n,
applet_list, runlevel,
depoptions);
use_services = rc_deptree_depends(deptree, types_nu,
applet_list, runlevel,
depoptions);
if (! rc_runlevel_starting() && use_services)
if (!rc_runlevel_starting()) {
TAILQ_FOREACH(svc, use_services, entries) {
state = rc_service_state(svc->value);
/* Don't stop failed services again.
@ -753,26 +778,27 @@ static void svc_start(bool deps)
rc_waitpid(pid);
}
}
}
/* Now wait for them to start */
services = rc_deptree_depends(deptree, types_nua, applet_list,
runlevel, depoptions);
if (services) {
/* We use tmplist to hold our scheduled by list */
tmplist = NULL;
tmplist = rc_stringlist_new();
TAILQ_FOREACH(svc, services, entries) {
state = rc_service_state(svc->value);
if (state & RC_SERVICE_STARTED)
continue;
/* Don't wait for services which went inactive but are now in
* starting state which we are after */
/* Don't wait for services which went inactive but are
* now in starting state which we are after */
if (state & RC_SERVICE_STARTING &&
state & RC_SERVICE_WASINACTIVE)
{
if (!rc_stringlist_find(need_services, svc->value) &&
!rc_stringlist_find(use_services, svc->value))
if (!rc_stringlist_find(need_services,
svc->value) &&
!rc_stringlist_find(use_services,
svc->value))
continue;
}
@ -786,17 +812,15 @@ static void svc_start(bool deps)
if (state & RC_SERVICE_INACTIVE ||
state & RC_SERVICE_WASINACTIVE)
{
if (! tmplist)
tmplist = rc_stringlist_new();
rc_stringlist_add(tmplist, svc->value);
} else if (!tmplist)
} else if (!TAILQ_FIRST(tmplist))
eerrorx("ERROR: cannot start %s as"
" %s would not start",
applet, svc->value);
}
}
if (tmplist && TAILQ_FIRST(tmplist)) {
if (TAILQ_FIRST(tmplist)) {
/* Set the state now, then unlink our exclusive so that
our scheduled list is preserved */
rc_service_mark(service, RC_SERVICE_STOPPED);
@ -808,14 +832,14 @@ static void svc_start(bool deps)
n = 0;
TAILQ_FOREACH(svc, tmplist, entries) {
rc_service_schedule_start(svc->value, service);
use_services = rc_deptree_depend(deptree, "iprovide",
use_services = rc_deptree_depend(deptree,
"iprovide",
svc->value);
if (use_services) {
TAILQ_FOREACH(svc2, use_services, entries)
rc_service_schedule_start(svc2->value, service);
rc_service_schedule_start(svc2->value,
service);
rc_stringlist_free(use_services);
use_services = NULL;
}
len += strlen(svc->value) + 2;
n++;
}
@ -825,19 +849,19 @@ static void svc_start(bool deps)
TAILQ_FOREACH(svc, tmplist, entries) {
if (p != tmp)
p += snprintf(p, len, ", ");
p += snprintf(p, len - (p - tmp), "%s", svc->value);
p += snprintf(p, len - (p - tmp),
"%s", svc->value);
}
rc_stringlist_free(tmplist);
tmplist = NULL;
ewarnx("WARNING: %s is scheduled to start when %s has started",
applet, tmp);
ewarnx("WARNING: %s is scheduled to start when "
"%s has started", applet, tmp);
free(tmp);
}
rc_stringlist_free(services);
services = NULL;
}
}
if (ibsave)
setenv("IN_BACKGROUND", ibsave, 1);
@ -852,9 +876,11 @@ static void svc_start(bool deps)
eerrorx("ERROR: %s failed to start", applet);
} else {
if (rc_service_state(service) & RC_SERVICE_INACTIVE)
ewarnx("WARNING: %s has started, but is inactive", applet);
ewarnx("WARNING: %s has started, but is inactive",
applet);
else
ewarnx("WARNING: %s not under our control, aborting", applet);
ewarnx("WARNING: %s not under our control, aborting",
applet);
}
rc_service_mark(service, RC_SERVICE_STARTED);
@ -865,29 +891,24 @@ static void svc_start(bool deps)
/* Now start any scheduled services */
services = rc_services_scheduled(service);
if (services) {
TAILQ_FOREACH(svc, services, entries)
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
service_start(svc->value);
rc_stringlist_free(services);
services = NULL;
}
/* Do the same for any services we provide */
if (deptree) {
tmplist = rc_deptree_depend(deptree, "iprovide", applet);
if (tmplist) {
TAILQ_FOREACH(svc, tmplist, entries) {
services = rc_services_scheduled(svc->value);
if (! services)
continue;
TAILQ_FOREACH(svc2, services, entries)
if (rc_service_state(svc2->value) & RC_SERVICE_STOPPED)
if (rc_service_state(svc2->value) &
RC_SERVICE_STOPPED)
service_start(svc2->value);
rc_stringlist_free(services);
services = NULL;
}
}
rc_stringlist_free(tmplist);
tmplist = NULL;
}
@ -896,15 +917,16 @@ static void svc_start(bool deps)
rc_plugin_run(RC_HOOK_SERVICE_START_OUT, applet);
}
static void svc_stop(bool deps)
static void
svc_stop(bool deps)
{
bool stopped;
RC_SERVICE state = rc_service_state(service);
int depoptions = RC_DEP_TRACE;
RC_STRING *svc;
if (rc_runlevel_stopping() &&
state & RC_SERVICE_FAILED)
if (rc_runlevel_stopping() && state & RC_SERVICE_FAILED)
exit(EXIT_FAILURE);
if (rc_yesno(getenv("IN_HOTPLUG")) || in_background)
@ -946,7 +968,7 @@ static void svc_stop(bool deps)
services = rc_deptree_depends(deptree, types_m, applet_list,
runlevel, depoptions);
if (services) {
tmplist = rc_stringlist_new();
TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) {
state = rc_service_state(svc->value);
/* Don't stop failed services again.
@ -966,45 +988,43 @@ static void svc_stop(bool deps)
pid_t pid = service_stop(svc->value);
if (!rc_conf_yesno("rc_parallel"))
rc_waitpid(pid);
if (! tmplist)
tmplist = rc_stringlist_new();
rc_stringlist_add(tmplist, svc->value);
}
}
}
rc_stringlist_free(services);
services = NULL;
}
if (tmplist) {
TAILQ_FOREACH(svc, tmplist, entries) {
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
continue;
svc_wait(svc->value);
if (! (rc_service_state(svc->value) & RC_SERVICE_STOPPED)) {
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
continue;
if (rc_runlevel_stopping()) {
/* If shutting down, we should stop even
* if a dependant failed */
if (runlevel &&
(strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
strcmp(runlevel, RC_LEVEL_REBOOT) == 0 ||
strcmp(runlevel, RC_LEVEL_SINGLE) == 0))
(strcmp(runlevel,
RC_LEVEL_SHUTDOWN) == 0 ||
strcmp(runlevel,
RC_LEVEL_REBOOT) == 0 ||
strcmp(runlevel,
RC_LEVEL_SINGLE) == 0))
continue;
rc_service_mark(service, RC_SERVICE_FAILED);
}
eerrorx("ERROR: cannot stop %s as %s is still up",
applet, svc->value);
}
eerrorx("ERROR: cannot stop %s as %s "
"is still up", applet, svc->value);
}
rc_stringlist_free(tmplist);
tmplist = NULL;
}
/* We now wait for other services that may use us and are stopping
This is important when a runlevel stops */
/* We now wait for other services that may use us and are
* stopping. This is important when a runlevel stops */
services = rc_deptree_depends(deptree, types_mua, applet_list,
runlevel, depoptions);
if (services) {
TAILQ_FOREACH(svc, services, entries) {
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
continue;
@ -1013,7 +1033,6 @@ static void svc_stop(bool deps)
rc_stringlist_free(services);
services = NULL;
}
}
/* If we're stopping localmount, set LC_ALL=C so that
* bash doesn't load anything blocking the unmounting of /usr */
@ -1047,16 +1066,20 @@ static void svc_stop(bool deps)
rc_plugin_run(RC_HOOK_SERVICE_STOP_OUT, applet);
}
static void svc_restart(bool deps)
static void
svc_restart(bool deps)
{
/* This is hairly and a better way needs to be found I think!
The issue is this - openvpn need net and dns. net can restart
dns via resolvconf, so you could have openvpn trying to restart dnsmasq
which in turn is waiting on net which in turn is waiting on dnsmasq.
The work around is for resolvconf to restart it's services with --nodeps
which means just that. The downside is that there is a small window when
our status is invalid.
One workaround would be to introduce a new status, or status locking. */
* The issue is this - openvpn need net and dns. net can restart
* dns via resolvconf, so you could have openvpn trying to restart
* dnsmasq which in turn is waiting on net which in turn is waiting
* on dnsmasq.
* The work around is for resolvconf to restart it's services with
* --nodeps which means just that.
* The downside is that there is a small window when our status is
* invalid.
* One workaround would be to introduce a new status,
* or status locking. */
if (!deps) {
RC_SERVICE state = rc_service_state(service);
if (state & RC_SERVICE_STARTED || state & RC_SERVICE_INACTIVE)
@ -1077,6 +1100,51 @@ static void svc_restart(bool deps)
restart_services = NULL;
}
static bool
service_plugable(void)
{
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(applet, token,
(size_t)(star - token)) == 0)
{
allow = truefalse;
break;
}
} else {
if (strcmp(applet, token) == 0) {
allow = truefalse;
break;
}
}
}
#ifdef DEBUG_MEMORY
free(list);
#endif
return allow;
}
#include "_usage.h"
#define getoptstring "dDsv" getoptstring_COMMON
#define extraopts "stop | start | restart | describe | zap"
@ -1094,7 +1162,8 @@ static const char * const longopts_help[] = {
};
#include "_usage.c"
int runscript(int argc, char **argv)
int
runscript(int argc, char **argv)
{
bool deps = true;
bool doneone = false;
@ -1165,20 +1234,6 @@ int runscript(int argc, char **argv)
/* Change dir to / to ensure all init scripts don't use stuff in pwd */
chdir("/");
#ifdef __linux__
/* coldplug events can trigger init scripts, but we don't want to run
* them until after rc sysinit has completed so we punt them to the
* boot runlevel */
if (exists("/dev/.rcsysinit")) {
eerror("%s: cannot run until sysvinit completes", applet);
if (mkdir("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
eerrorx("%s: mkdir `/dev/.rcboot': %s", applet, strerror(errno));
snprintf(exclusive, sizeof(exclusive), "/dev/.rcboot/%s", applet);
symlink(service, exclusive);
exit (EXIT_FAILURE);
}
#endif
if ((runlevel = xstrdup (getenv ("RC_RUNLEVEL"))) == NULL) {
env_filter();
env_config();
@ -1198,7 +1253,6 @@ int runscript(int argc, char **argv)
if (rc_conf_yesno("rc_parallel")) {
/* Get the longest service name */
services = rc_services_in_runlevel(NULL);
if (services) {
TAILQ_FOREACH(svc, services, entries) {
ll = strlen(svc->value);
if (ll > l)
@ -1206,7 +1260,9 @@ int runscript(int argc, char **argv)
}
rc_stringlist_free(services);
services = NULL;
} else l = strlen(applet);
ll = strlen(applet);
if (ll > l)
l = ll;
/* Make our prefix string */
prefix = xmalloc(sizeof(char) * l + 1);
@ -1227,7 +1283,8 @@ int runscript(int argc, char **argv)
argv++;
/* Right then, parse any options there may be */
while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1)
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *)0)) != -1)
switch (opt) {
case 'd':
setenv("RC_DEBUG", "yes", 1);
@ -1251,7 +1308,7 @@ int runscript(int argc, char **argv)
}
if (rc_yesno(getenv("IN_HOTPLUG"))) {
if (! rc_conf_yesno("rc_hotplug") || ! service_plugable(applet))
if (!rc_conf_yesno("rc_hotplug") || !service_plugable())
eerrorx("%s: not allowed to be hotplugged", applet);
}
@ -1304,25 +1361,25 @@ int runscript(int argc, char **argv)
strcmp(optarg, "iprovide") == 0)
{
errno = 0;
if (rc_conf_yesno("rc_depend_strict") || errno == ENOENT)
if (rc_conf_yesno("rc_depend_strict") ||
errno == ENOENT)
depoptions |= RC_DEP_STRICT;
if (! deptree && ((deptree = _rc_deptree_load(NULL)) == NULL))
if (!deptree &&
((deptree = _rc_deptree_load(NULL)) == NULL))
eerrorx("failed to load deptree");
tmplist = rc_stringlist_new();
rc_stringlist_add(tmplist, optarg);
services = rc_deptree_depends(deptree, tmplist, applet_list,
services = rc_deptree_depends(deptree, tmplist,
applet_list,
runlevel, depoptions);
rc_stringlist_free(tmplist);
tmplist = NULL;
if (services) {
TAILQ_FOREACH(svc, services, entries)
printf("%s ", svc->value);
printf ("\n");
rc_stringlist_free(services);
services = NULL;
}
} else if (strcmp (optarg, "status") == 0) {
RC_SERVICE r = svc_status();
retval = (int) r;
@ -1332,7 +1389,8 @@ int runscript(int argc, char **argv)
if (strcmp(optarg, "conditionalrestart") == 0 ||
strcmp(optarg, "condrestart") == 0)
{
if (rc_service_state(service) & RC_SERVICE_STARTED)
if (rc_service_state(service) &
RC_SERVICE_STARTED)
svc_restart(deps);
} else if (strcmp(optarg, "restart") == 0) {
svc_restart (deps);
@ -1341,32 +1399,39 @@ int runscript(int argc, char **argv)
} else if (strcmp(optarg, "stop") == 0) {
if (deps && in_background)
get_started_services();
svc_stop(deps);
if (deps) {
if (! in_background &&
! rc_runlevel_stopping() &&
rc_service_state(service) & RC_SERVICE_STOPPED)
rc_service_state(service) &
RC_SERVICE_STOPPED)
uncoldplug();
if (in_background &&
rc_service_state(service) & RC_SERVICE_INACTIVE)
rc_service_state(service) &
RC_SERVICE_INACTIVE)
{
TAILQ_FOREACH(svc, restart_services, entries)
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
TAILQ_FOREACH(svc,
restart_services,
entries)
if (rc_service_state(svc->value) &
RC_SERVICE_STOPPED)
rc_service_schedule_start(service, svc->value);
}
}
} else if (strcmp(optarg, "zap") == 0) {
einfo("Manually resetting %s to stopped state", applet);
if (!rc_service_mark(applet, RC_SERVICE_STOPPED))
eerrorx("rc_service_mark: %s", strerror(errno));
einfo("Manually resetting %s to stopped state",
applet);
if (!rc_service_mark(applet,
RC_SERVICE_STOPPED))
eerrorx("rc_service_mark: %s",
strerror(errno));
uncoldplug();
} else
svc_exec(optarg, NULL);
/* We should ensure this list is empty after an action is done */
/* We should ensure this list is empty after
* an action is done */
rc_stringlist_free(restart_services);
restart_services = NULL;
}