Rewrite the core parts in C. We now provide librc so other programs can

query runlevels, services and state without using bash. We also provide
libeinfo so other programs can easily use our informational functions.

As such, we have dropped the requirement of using bash as the init script
shell. We now use /bin/sh and have strived to make the scripts as portable
as possible. Shells that work are bash and dash. busybox works provided
you disable s-s-d. If you have WIPE_TMP set to yes in conf.d/bootmisc you
should disable find too.
zsh and ksh do not work at this time.

Networking support is currently being re-vamped also as it was heavily bash
array based. As such, a new config format is available like so
config_eth0="1.2.3.4/24 5.6.7.8/16"
or like so
config_eth0="'1.2.3.4 netmask 255.255.255.0' '5.6.7.8 netmask 255.255.0.0'"

We will still support the old bash array format provided that /bin/sh IS
a link it bash.

ChangeLog for baselayout-1 can be found in our SVN repo.
This commit is contained in:
Roy Marples
2007-04-05 11:18:42 +00:00
commit 5af58b4514
169 changed files with 20917 additions and 0 deletions

7
sh/Makefile Normal file
View File

@@ -0,0 +1,7 @@
DIR = /$(LIB)/rcscripts/sh
FILES = functions.sh init-functions.sh init-common-post.sh \
rc-functions.sh rc-mount.sh
EXES = gendepends.sh net.sh rc-mount.sh rc-help.sh runscript.sh
TOPDIR = ..
include $(TOPDIR)/default.mk

157
sh/functions.sh Normal file
View File

@@ -0,0 +1,157 @@
# Copyright 1999-2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# Please keep this useable by every shell in portage
RC_GOT_FUNCTIONS="yes"
eindent() {
if [ -n "${RC_EBUFFER}" ] ; then
"${RC_LIBDIR}"/bin/eindent
else
RC_EINDENT=$((${RC_EINDENT:-0} + 2))
[ "${RC_EINDENT}" -gt 40 ] && RC_EINDENT=40
export RC_EINDENT
fi
}
eoutdent() {
if [ -n "${RC_EBUFFER}" ] ; then
"${RC_LIBDIR}"/bin/eoutdent
else
RC_EINDENT=$((${RC_EINDENT:-0} - 2))
[ "${RC_EINDENT}" -lt 0 ] && RC_EINDENT=0
fi
return 0
}
# void esyslog(char* priority, char* tag, char* message)
#
# use the system logger to log a message
#
esyslog() {
local pri= tag=
if [ -x /usr/bin/logger ] ; then
pri="$1"
tag="$2"
shift 2
[ -z "$*" ] && return 0
/usr/bin/logger -p "${pri}" -t "${tag}" -- "$*"
fi
return 0
}
# Safer way to list the contents of a directory,
# as it do not have the "empty dir bug".
#
# char *dolisting(param)
#
# print a list of the directory contents
#
# NOTE: quote the params if they contain globs.
# also, error checking is not that extensive ...
#
dolisting() {
local x= y= mylist= mypath="$*"
# Here we use file globbing instead of ls to save on forking
for x in ${mypath} ; do
[ ! -e "${x}" ] && continue
if [ -L "${x}" -o -f "${x}" ] ; then
mylist="${mylist} "${x}
elif [ -d "${x}" ] ; then
[ "${x%/}" != "${x}" ] && x=${x%/}
for y in "${x}"/* ; do
[ -e "${y}" ] && mylist="${mylist} ${y}"
done
fi
done
echo "${mylist# *}"
}
# bool is_older_than(reference, files/dirs to check)
#
# return 0 if any of the files/dirs are newer than
# the reference file
#
# EXAMPLE: if is_older_than a.out *.o ; then ...
is_older_than() {
local x= ref="$1"
shift
for x in "$@" ; do
[ -e "${x}" ] || continue
# We need to check the mtime if it's a directory too as the
# contents may have changed.
[ "${x}" -nt "${ref}" ] && return 0
[ -d "${x}" ] && is_older_than "${ref}" "${x}"/* && return 0
done
return 1
}
uniqify() {
local result=
while [ -n "$1" ] ; do
case " ${result} " in
*" $1 "*) ;;
*) result="${result} $1" ;;
esac
shift
done
echo "${result# *}"
}
KV_to_int() {
[ -z $1 ] && return 1
local KV_MAJOR=${1%%.*}
local x=${1#*.}
local KV_MINOR=${x%%.*}
x=${1#*.*.}
local KV_MICRO=${x%%-*}
local KV_int=$((${KV_MAJOR} * 65536 + ${KV_MINOR} * 256 + ${KV_MICRO} ))
# We make version 2.2.0 the minimum version we will handle as
# a sanity check ... if its less, we fail ...
[ "${KV_int}" -lt 131584 ] && return 1
echo "${KV_int}"
}
# Setup a basic $PATH. Just add system default to existing.
# This should solve both /sbin and /usr/sbin not present when
# doing 'su -c foo', or for something like: PATH= rcscript start
case "${PATH}" in
/lib/rcscripts/bin:/bin:/sbin:/usr/bin:/usr/sbin) ;;
/lib/rcscripts/bin:/bin:/sbin:/usr/bin:/usr/sbin:*) ;;
*) export PATH="/lib/rcscripts/bin:/bin:/sbin:/usr/bin:/usr/sbin:${PATH}" ;;
esac
for arg in "$@" ; do
case "${arg}" in
--nocolor|--nocolour)
export RC_NOCOLOR="yes"
;;
esac
done
if [ "${RC_NOCOLOR}" != "yes" -a -z "${GOOD}" ] ; then
if color_terminal ; then
GOOD=$'\e[32;01m'
WARN=$'\e[33;01m'
BAD=$'\e[31;01m'
HILITE=$'\e[36;01m'
BRACKET=$'\e[34;01m'
NORMAL=$'\e[0m'
fi
fi
# vim: set ts=4 :

58
sh/gendepends.sh Executable file
View File

@@ -0,0 +1,58 @@
#!/bin/sh
# Shell wrapper to list our dependencies
# Copyright 2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
. /etc/init.d/functions.sh
need() {
[ -n "$*" ] && echo "${SVCNAME} ineed $*"
}
use() {
[ -n "$*" ] && echo "${SVCNAME} iuse $*"
}
before() {
[ -n "$*" ] && echo "${SVCNAME} ibefore $*"
}
after() {
[ -n "$*" ] && echo "${SVCNAME} iafter $*"
}
provide() {
[ -n "$*" ] && echo "${SVCNAME} iprovide $*"
}
depend() {
:
}
cd /etc/init.d
for SVCNAME in * ; do
[ -x "${SVCNAME}" ] || continue
case "${SVCNAME}" in
*.sh) continue ;;
esac
SVCNAME=${SVCNAME##*/}
(
if . /etc/init.d/"${SVCNAME}" ; then
rc_c=${SVCNAME%%.*}
if [ -n "${rc_c}" -a "${rc_c}" != "${SVCNAME}" ] ; then
[ -e /etc/conf.d/"${rc_c}" ] && . /etc/conf.d/"${rc_c}"
fi
unset rc_c
[ -e /etc/conf.d/"${SVCNAME}" ] && . /etc/conf.d/"${SVCNAME}"
echo "${SVCNAME}"
depend
# Add any user defined depends
need ${RC_NEED}
use ${RC_USE}
before ${RC_BEFORE}
after ${RC_AFTER}
provide ${RC_PROVIDE}
fi
)
done
# vim: set ts=4 :

22
sh/init-common-post.sh Normal file
View File

@@ -0,0 +1,22 @@
# Copyright 1999-2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# mount $svcdir as something we can write to if it's not rw
# On vservers, / is always rw at this point, so we need to clean out
# the old service state data
if touch "${RC_SVCDIR}/.test" 2>/dev/null ; then
rm -rf "${RC_SVCDIR}/.test" \
$(ls -d1 "${RC_SVCDIR:-/lib/rcscripts/init.d}"/* 2>/dev/null | \
grep -Ev "/(deptree|ksoftlevel)$")
else
mount_svcdir
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 0
# vim: set ts=4 :

62
sh/init-functions.sh Normal file
View File

@@ -0,0 +1,62 @@
# Copyright 1999-2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# void try(command)
#
# Try to execute 'command', if it fails, drop to a shell.
#
try() {
local errstr
local retval=0
if [ -c /dev/null ] ; then
errstr=$(eval $* 2>&1 >/dev/null)
else
errstr=$(eval $* 2>&1)
fi
retval=$?
if [ ${retval} -ne 0 ] ; then
#splash "critical" &
eend 1
eerror "The \"$*\" command failed with error:"
eerror " ${errstr#*: }"
echo
eerror "Since this is a critical task, startup cannot continue."
echo
single_user
fi
return ${retval}
}
# bool check_statedir(dir)
#
# Check that 'dir' exists, if not, drop to a shell.
#
check_statedir() {
[ -z "$1" ] && return 0
if [ ! -d "$1" ] ; then
if ! mkdir -p "$1" &>/dev/null ; then
#splash "critical" &
echo
eerror "For Gentoo to function properly, \"$1\" needs to exist."
if [ "${RC_FORCE_AUTO}" = "yes" ] ; then
eerror "Attempting to create \"$1\" for you ..."
mount -o remount,rw /
mkdir -p "$1"
fi
if [ ! -d "$1" ] ; then
eerror "Please mount your root partition read/write, and execute:"
echo
eerror " # mkdir -p $1"
echo; echo
single_user
fi
fi
fi
return 0
}
# vim: set ts=4 :

566
sh/net.sh Executable file
View File

@@ -0,0 +1,566 @@
#!/sbin/runscript
# Copyright 1999-2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
MODULESDIR="${RC_LIBDIR}/net"
MODULESLIST="${RC_SVCDIR}/nettree"
_config_vars="config"
[ -z "${IN_BACKGROUND}" ] && IN_BACKGROUND=false
depend() {
local IFACE=${SVCNAME#*.}
local IFVAR=$(echo -n "${IFACE}" | sed -e 's/[^[:alnum:]]/_/g')
need localmount
after bootmisc
provide net
case "${IFACE}" in
lo|lo0) ;;
*)
after net.lo net.lo0
local prov=
eval prov=\$RC_NEED_${IFVAR}
[ -n "${prov}" ] && need ${prov}
eval prov=\$RC_USE_${IFVAR}
[ -n "${prov}" ] && use ${prov}
eval prov=\$RC_BEFORE_${IFVAR}
[ -n "${prov}" ] && before ${prov}
eval prov=\$RC_AFTER_${IFVAR}
[ -n "${prov}" ] && after ${prov}
eval prov=\$RC_PROVIDE_${IFVAR}
[ -n "${prov}" ] && provide ${prov}
;;
esac
}
_shell_var() {
echo -n "$1" | sed -e 's/[^[:alnum:]]/_/g'
}
# Credit to David Leverton for this function which handily maps a bash array
# structure to positional parameters so existing configs work :)
# We'll deprecate arrays at some point though.
_get_array() {
if [ -n "${BASH}" ] ; then
case "$(declare -p "$1" 2>/dev/null)" in
"declare -a "*)
echo "set -- \"\${$1[@]}\""
return
;;
esac
fi
echo "eval set -- \"\$$1\""
}
_wait_for_carrier() {
local timeout= efunc=einfon
_has_carrier && return 0
eval timeout=\$carrier_timeout_${IF_VAR}
timeout=${timeout:-5}
[ -n "${RC_EBUFFER}" ] && efunc=einfo
${efunc} "Waiting for carrier (${timeout} seconds) "
while [ ${timeout} -gt 0 ] ; do
sleep 1
if _has_carrier ; then
[ -z "${RC_EBUFFER}" ] && echo
return 0
fi
timeout=$((${timeout} - 1))
[ -z "${RC_EBUFFER}" ] && echo -n "."
done
echo
return 1
}
_netmask2cidr() {
local i= len=0
local IFS=.
for i in $1; do
while [ ${i} != "0" ] ; do
len=$((${len} + 1))
i=$((${i} >> 1))
done
done
echo "${len}"
}
_configure_variables() {
local var= v= t=
for var in ${_config_vars} ; do
local v=
for t in "$@" ; do
eval v=\$${var}_${t}
if [ -n "${v}" ] ; then
eval ${var}_${IFVAR}=\$${var}_${t}
continue 2
fi
done
done
}
_show_address() {
einfo "received address $(_get_inet_address "${IFACE}")"
}
# Basically sorts our modules into order and saves the list
_gen_module_list() {
local x= f=
if [ -s "${MODULESLIST}" -a "${MODULESLIST}" -nt "${MODULESDIR}" ] ; then
local update=false
for x in "${MODULESDIR}"/* ; do
[ -e "${x}" ] || continue
if [ "${x}" -nt "${MODULESLIST}" ] ; then
update=true
break
fi
done
${update} || return 0
fi
einfo "Caching network module dependencies"
# Run in a subshell to protect the main script
(
after() {
eval ${MODULE}_after="\"\${${MODULE}_after}\${${MODULE}_after:+ }$*\""
}
before() {
local mod=${MODULE}
local MODULE=
for MODULE in "$@" ; do
after "${mod}"
done
}
program() {
if [ "$1" = "start" -o "$1" = "stop" ] ; then
local s="$1"
shift
eval ${MODULE}_program_${s}="\"\${${MODULE}_program_${s}}\${${MODULE}_program_${s}:+ }$*\""
else
eval ${MODULE}_program="\"\${${MODULE}_program}\${${MODULE}_program:+ }$*\""
fi
}
provide() {
eval ${MODULE}_provide="\"\${${MODULE}_provide}\${${MODULE}_provide:+ }$*\""
local x
for x in $* ; do
eval ${x}_providedby="\"\${${MODULE}_providedby}\${${MODULE}_providedby:+ }${MODULE}\""
done
}
for MODULE in "${MODULESDIR}"/* ; do
sh -n "${MODULE}" || continue
. "${MODULE}" || continue
MODULE=${MODULE#${MODULESDIR}/}
MODULE=${MODULE%.sh}
eval ${MODULE}_depend
MODULES="${MODULES} ${MODULE}"
done
VISITED=
SORTED=
visit() {
case " ${VISITED} " in
*" $1 "*) return ;;
esac
VISITED="${VISITED} $1"
eval AFTER=\$${1}_after
for MODULE in ${AFTER} ; do
eval PROVIDEDBY=\$${MODULE}_providedby
if [ -n "${PROVIDEDBY}" ] ; then
for MODULE in ${PROVIDEDBY} ; do
visit "${MODULE}"
done
else
visit "${MODULE}"
fi
done
eval PROVIDE=\$${1}_provide
for MODULE in ${PROVIDE} ; do
visit "${MODULE}"
done
eval PROVIDEDBY=\$${1}_providedby
[ -z "${PROVIDEDBY}" ] && SORTED="${SORTED} $1"
}
for MODULE in ${MODULES} ; do
visit "${MODULE}"
done
> "${MODULESLIST}"
i=0
for MODULE in ${SORTED} ; do
eval PROGRAM=\$${MODULE}_program
eval PROGRAM_START=\$${MODULE}_program_start
eval PROGRAM_STOP=\$${MODULE}_program_stop
#for x in ${PROGRAM} ; do
# [ -x "${x}" ] || continue 2
#done
eval PROVIDE=\$${MODULE}_provide
echo "module_${i}='${MODULE}'" >> "${MODULESLIST}"
echo "module_${i}_program='${PROGRAM}'" >> "${MODULESLIST}"
echo "module_${i}_program_start='${PROGRAM_START}'" >> "${MODULESLIST}"
echo "module_${i}_program_stop='${PROGRAM_STOP}'" >> "${MODULESLIST}"
echo "module_${i}_provide='${PROVIDE}'" >> "${MODULESLIST}"
i=$((${i} + 1))
done
echo "module_${i}=" >> "${MODULESLIST}"
)
return 0
}
_load_modules() {
# Ensure our list is up to date
_gen_module_list
local starting=$1 mymods=
MODULES=
if [ "${IFACE}" != "lo" -a "${IFACE}" != "lo0" ] ; then
eval mymods=\$modules_${IFVAR}
[ -z "${mymods}" ] && mymods=${modules}
fi
. "${MODULESLIST}"
local i=-1 x= mod= f= provides=
while true ; do
i=$((${i} + 1))
eval mod=\$module_${i}
[ -z "${mod}" ] && break
[ -e "${MODULESDIR}/${mod}.sh" ] || continue
eval set -- \$module_${i}_program
if [ -n "$1" ] ; then
x=
for x in "$@" ; do
[ -x "${x}" ] && break
done
[ -x "${x}" ] || continue
fi
if ${starting} ; then
eval set -- \$module_${i}_program_start
else
eval set -- \$module_${i}_program_stop
fi
if [ -n "$1" ] ; then
x=
for x in "$@" ; do
[ -x "${x}" ] && break
done
[ -x "${x}" ] || continue
fi
eval provides=\$module_${i}_provide
if ${starting} ; then
case " ${mymods} " in
*" !${mod} "*) continue ;;
*" !${provides} "*) [ -n "${provides}" ] && continue ;;
esac
fi
MODULES="${MODULES}${MODULES:+ }${mod}"
# Now load and wrap our functions
if ! . "${MODULESDIR}/${mod}.sh" ; then
eend 1 "${SVCNAME}: error loading module \`${mod}'"
exit 1
fi
[ -z "${provides}" ] && continue
# Wrap our provides
local f=
for f in pre_start start post_start ; do
eval "${provides}_${f}() { type ${mod}_${f} >/dev/null 2>/dev/null || return 0; ${mod}_${f} \"\$@\"; }"
done
eval module_${mod}_provides="${provides}"
eval module_${provides}_providedby="${mod}"
done
# Wrap our preferred modules
for mod in ${mymods} ; do
case " ${MODULES} " in
*" ${mod} "*)
eval x=\$module_${mod}_provides
[ -z "${x}" ] && continue
for f in pre_start start post_start ; do
eval "${x}_${f}() { type ${mod}_${f} >/dev/null 2>/dev/null || return 0; ${mod}_${f} \"\$@\"; }"
done
eval module_${x}_providedby="${mod}"
;;
esac
done
# Finally remove any duplicated provides from our list if we're starting
# Otherwise reverse the list
local LIST="${MODULES}" p=
MODULES=
if ${starting} ; then
for mod in ${LIST} ; do
eval x=\$module_${mod}_provides
if [ -n "${x}" ] ; then
eval p=\$module_${x}_providedby
[ "${mod}" != "${p}" ] && continue
fi
MODULES="${MODULES}${MODULES:+ }${mod}"
done
else
for mod in ${LIST} ; do
MODULES="${mod}${MODULES:+ }${MODULES}"
done
fi
veinfo "Loaded modules: ${MODULES}"
}
_load_config() {
eval "$(_get_array "config_${IFVAR}")"
if [ "${IFACE}" = "lo" -o "${IFACE}" = "lo0" ] ; then
set -- "127.0.0.1/8" "$@"
else
if [ $# -eq 0 ] ; then
ewarn "No configuration specified; defaulting to DHCP"
set -- "dhcp"
fi
fi
# We store our config in an array like vars
# so modules can influence it
config_index=0
for cmd in "$@" ; do
eval config_${config_index}="'${cmd}'"
config_index=$((${config_index} + 1))
done
# Terminate the list
eval config_${config_index}=
config_index=0
eval $(_get_array fallback_${IFVAR})
for cmd in "$@" ; do
eval fallback_${config_index}="'${cmd}'"
config_index=$((${config_index} + 1))
done
# Terminate the list
eval fallback_${config_index}=
# Don't set to zero, so any net modules don't have to do anything extra
config_index=-1
}
start() {
local IFACE=${SVCNAME#*.} oneworked=false module=
local IFVAR=$(_shell_var "${IFACE}") cmd= metric=0 our_metric=$metric
einfo "Bringing up interface ${IFACE}"
eindent
if [ -z "${MODULES}" ] ; then
local MODULES=
_load_modules true
fi
_up 2>/dev/null
if type preup >/dev/null 2>/dev/null ; then
ebegin "Running preup"
eindent
preup || return 1
eoutdent
fi
for module in ${MODULES} ; do
if type "${module}_pre_start" >/dev/null 2>/dev/null ; then
if ! ${module}_pre_start ; then
eend 1
exit 1
fi
fi
done
local config= config_index=
_load_config
config_index=0
if [ -n "${our_metric}" ] ; then
metric=${our_metric}
elif [ "${IFACE}" != "lo" -a "${IFACE}" != "lo0" ] ; then
metric=$((${metric} + $(_ifindex)))
fi
while true ; do
eval config=\$config_${config_index}
[ -z "${config}" ] && break
set -- "${config}"
ebegin "$1"
eindent
case "$1" in
noop)
if [ -n "$(_get_inet_address)" ] ; then
oneworked=true
break
fi
;;
null) : ;;
[0-9]*|*:*) _add_address ${config} ;;
*)
if type "${config}_start" >/dev/null 2>/dev/null ; then
"${config}"_start
else
eerror "nothing provides \`${config}'"
fi
;;
esac
if eend $? ; then
oneworked=true
else
eval config=\$fallback_${IFVAR}
if [ -n "${config}" ] ; then
einfo "Trying fallback configuration"
eval config_${config_index}=\$fallback_${IFVAR}
eval fallback_${config_index}=
config_index=$((${config_index} - 1))
fi
fi
eoutdent
config_index=$((${config_index} + 1))
done
if ! ${oneworked} ; then
if type failup >/dev/null 2>/dev/null ; then
ebegin "Running failup"
eindent
failup
eoutdent
fi
return 1
fi
local hidefirstroute=false first=true routes=
eval "$(_get_array "routes_${IFVAR}")"
if [ "${IFACE}" = "lo" -o "${IFACE}" = "lo0" ] ; then
set -- "127.0.0.0/8 via 127.0.0.1" "$@"
hidefirstroute=true
fi
for cmd in "$@" ; do
if ${first} ; then
first=false
einfo "Adding routes"
fi
eindent
ebegin "${cmd}"
# Work out if we're a host or a net if not told
case "${cmd}" in
*" -net "*|*" -host "*) ;;
*" netmask "*) cmd="-net ${cmd}" ;;
*)
case "${cmd%% *}" in
*.*.*.*/32) cmd="-host ${cmd}" ;;
*.*.*.*/*|0.0.0.0|default) cmd="-net ${cmd}" ;;
*) cmd="-host ${cmd}" ;;
esac
;;
esac
if ${hidefirstroute} ; then
_add_route ${cmd} >/dev/null 2>/dev/null
hidefirstroute=false
else
_add_route ${cmd} >/dev/null
fi
eend $?
eoutdent
done
for module in ${MODULES} ; do
if type "${module}_post_start" >/dev/null 2>/dev/null ; then
if ! ${module}_post_start ; then
eend 1
exit 1
fi
fi
done
if type postup >/dev/null 2>/dev/null ; then
ebegin "Running postup"
eindent
postup
eoutdent
fi
return 0
}
stop() {
local IFACE=${SVCNAME#*.} module=
local IFVAR=$(_shell_var "${IFACE}") opts=
einfo "Bringing down interface ${IFACE}"
eindent
if [ -z "${MODULES}" ] ; then
local MODULES=
_load_modules false
fi
if type predown >/dev/null 2>/dev/null ; then
ebegin "Running predown"
eindent
predown || return 1
eoutdent
fi
for module in ${MODULES} ; do
if type "${module}_pre_stop" >/dev/null 2>/dev/null ; then
if ! ${module}_pre_stop ; then
eend 1
exit 1
fi
fi
done
for module in ${MODULES} ; do
if type "${module}_stop" >/dev/null 2>/dev/null ; then
${module}_stop
fi
done
_delete_addresses "${IFACE}"
for module in ${MODULES} ; do
if type "${module}_post_stop" >/dev/null 2>/dev/null ; then
${module}_post_stop
fi
done
[ "${IN_BACKGROUND}" != "true" ] && \
[ "${IFACE}" != "lo" -a "${IFACE}" != "lo0" ] && \
_down 2>/dev/null
[ -x /sbin/resolvconf ] && resolvconf -d "${IFACE}"
if type predown >/dev/null 2>/dev/null ; then
ebegin "Running postdown"
eindent
postdown
eoutdent
fi
return 0
}
# vim: set ts=4 :

60
sh/rc-functions.sh Executable file
View File

@@ -0,0 +1,60 @@
# Copyright 2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
has_addon() {
[ -e "${RC_LIBDIR}/addons/$1.sh" ]
}
import_addon() {
if has_addon "$1" ; then
. "${RC_LIBDIR}/addons/$1.sh"
return 0
fi
return 1
}
start_addon() {
( import_addon "$1-start" )
}
stop_addon() {
( import_addon "$1-stop" )
}
is_net_fs() {
[ -z "$1" ] && return 1
local t=$(mountinfo --fstype "$1" )
for x in ${RC_NET_FS_LIST} ; do
[ "${x}" = "${t}" ] && return 0
done
return 1
}
is_union_fs() {
[ ! -x /sbin/unionctl ] && return 1
unionctl "$1" --list >/dev/null 2>/dev/null
}
get_bootparam() {
local match="$1"
[ -z "${match}" -o ! -r /proc/cmdline ] && return 1
set -- $(cat /proc/cmdline)
while [ -n "$1" ] ; do
case "$1" in
gentoo=*)
local params="${1##*=}"
local IFS=, x=
for x in ${params} ; do
[ "${x}" = "${match}" ] && return 0
done
;;
esac
shift
done
return 1
}
# vim: set ts=4 :

262
sh/rc-help.sh Executable file
View File

@@ -0,0 +1,262 @@
#!/bin/sh
# Copyright 1999-2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
if [ "${RC_NOCOLOR}" = "yes" ] ; then
unset BLUE GREEN OFF CYAN
else
BLUE="\033[34;01m"
GREEN="\033[32;01m"
OFF="\033[0m"
CYAN="\033[36;01m"
fi
myscript=$1
if [ -z "${myscript}" ] ; then
echo "Please execute an init.d script"
exit 1
fi
if [ -L "${myscript}" ] ; then
SERVICE=$(readlink "${myscript}")
else
SERVICE=${myscript}
fi
SERVICE=${SERVICE##*/}
if [ "$2" = "help" ] ; then
BE_VERBOSE="yes"
NL="\n"
else
BE_VERBOSE="no"
NL=
fi
default_opts="start stop restart pause zap"
extra_opts="$(. "${myscript}" 2>/dev/null ; echo "${opts}")"
if [ "${BE_VERBOSE}" = "yes" ] ; then
printf "
${GREEN}Gentoo RC-Scripts; ${BLUE}http://www.gentoo.org/${OFF}
Copyright 1999-2007 Gentoo Foundation; Distributed under the GPL
"
fi
printf "Usage: ${CYAN}${SERVICE}${OFF} [ ${GREEN}flags${OFF} ] < ${GREEN}options${OFF} >
${CYAN}Normal Options:${OFF}"
if [ "${BE_VERBOSE}" = "yes" ] ; then
printf "
${GREEN}start${OFF}
Start service, as well as the services it depends on (if not already
started).
${GREEN}stop${OFF}
Stop service, as well as the services that depend on it (if not already
stopped).
${GREEN}restart${OFF}
Restart service, as well as the services that depend on it.
Note to developers: If this function is replaced with a custom one,
'svc_start' and 'svc_stop' should be used instead of 'start' and
'stop' to restart the service. This is so that the dependencies
can be handled correctly. Refer to the portmap rc-script for an
example.
${GREEN}conditionalrestart|condrestart${OFF}
Same as 'restart', but only if the service has already been started.
${GREEN}pause${OFF}
Same as 'stop', but the services that depends on it, will not be
stopped. This is useful for stopping a network interface without
stopping all the network services that depend on 'net'.
${GREEN}zap${OFF}
Reset a service that is currently stopped, but still marked as started,
to the stopped state. Basically for killing zombie services.
${GREEN}status${OFF}
Prints \"status: started\" if the service is running, else it
prints \"status: stopped\".
Note that if the '--quiet' flag is given, it will return true if the
service is running, else false.
${GREEN}ineed|iuse${OFF}
List the services this one depends on. Consult the section about
dependencies for more info on the different types of dependencies.
${GREEN}needsme|usesme${OFF}
List the services that depend on this one. Consult the section about
dependencies for more info on the different types of dependencies.
${GREEN}broken${OFF}
List the missing or broken dependencies of type 'need' this service
depends on.
"
else
printf " ${GREEN}${default_opts}${OFF}
Default init.d options.
"
fi
if [ -n "${extra_opts}" ] ; then
printf "
${CYAN}Additional Options:${OFF}${NL}
${GREEN}${extra_opts}${OFF}
Extra options supported by this init.d script.
"
fi
printf "
${CYAN}Flags:${OFF}${NL}
${GREEN}--ifstarted${OFF} Only do actions if service started
${GREEN}--nodeps${OFF} Don't stop or start any dependencies
${GREEN}--quiet${OFF}
Suppress output to stdout, except if:${NL}
1) It is a warning, then output to stdout
2) It is an error, then output to stderr${NL}
${GREEN}--verbose${OFF} Output extra information
${GREEN}--debug${OFF} Output debug information
${GREEN}--nocolor${OFF} Suppress the use of colors
"
if [ "${BE_VERBOSE}" = "yes" ] ; then
printf "
${CYAN}Dependencies:${OFF}
This is the heart of the Gentoo RC-Scripts, as it determines the order
in which services gets started, and also to some extend what services
get started in the first place.
The following example demonstrates how to use dependencies in
rc-scripts:
depend() {
need foo bar
use ray
}
Here we have foo and bar as dependencies of type 'need', and ray of
type 'use'. You can have as many dependencies of each type as needed, as
long as there is only one entry for each type, listing all its dependencies
on one line only.
${GREEN}need${OFF}
These are all the services needed for this service to start. If any
service in the 'need' line is not started, it will be started even if it
is not in the current, or 'boot' runlevel, and then this service will be
started. If any services in the 'need' line fails to start or is
missing, this service will never be started.
${GREEN}use${OFF}
This can be seen as representing optional services this service depends on
that are not critical for it to start. For any service in the 'use' line,
it must be added to the 'boot' or current runlevel to be considered a
valid 'use' dependency. It can also be used to determine startup order.
${GREEN}before${OFF}
This, together with the 'after' dependency type, can be used to control
startup order. In core, 'before' and 'after' do not denote a dependency,
but should be used for order changes that will only be honoured during
a change of runlevel. All services listed will get started *after* the
current service. In other words, this service will get started *before*
all listed services.
${GREEN}after${OFF}
All services listed will be started *before* the current service. Have a
look at 'before' for more info.
${GREEN}provide${OFF}
This is not really a dependency type, rather it will enable you to create
virtual services. This is useful if there is more than one version of
a specific service type, system loggers or crons for instance. Just
have each system logger provide 'logger', and make all services in need
of a system logger depend on 'logger'. This should make things much more
generic.
Note that the 'need', 'use', 'before', and 'after' dependency types accept
an '*' as an argument. Having:
depend() {
before *
}
will make the service start first in the current runlevel, and:
depend() {
after *
}
will make the service the last to start.
You should however be careful how you use this, as I really will not
recommend using it with the 'need' or 'use' dependency type ... you have
been warned!
${CYAN}'net' Dependency and 'net.*' Services:${OFF}
Example:
depend() {
need net
}
This is a special dependency of type 'need'. It represents a state where
a network interface or interfaces besides lo is up and active. Any service
starting with 'net.' will be treated as a part of the 'net' dependency,
if:
1. It is part of the 'boot' runlevel
2. It is part of the current runlevel
A few examples are the /etc/init.d/net.eth0 and /etc/init.d/net.lo services.
"
fi
printf "
${CYAN}Configuration files:${OFF}
"
if [ "${BE_VERBOSE}" = "yes" ] ; then
printf "
There are two files which will be sourced for possible configuration by
the rc-scripts. They are (sourced from top to bottom):
"
fi
printf " /etc/conf.d/${SERVICE}${NL} /etc/rc.conf"
if [ "${BE_VERBOSE}" = "yes" ] ; then
printf "
You can add extra dependencies to ${SERVICE} by adding some variables to
/etc/conf.d/${SERVICE}
RC_NEED=\"openvpn ntpd\"
RC_USE=\"dns\"
This makes ${SERVICE} need openvpn and ntpd, while it just uses dns.
A good example of this is nfsmount needing openvpn if the nfs mounts in
/etc/fstab are over the vpn link.
"
fi
if [ "${BE_VERBOSE}" = "yes" ] ; then
printf "\n
${CYAN}Management:${OFF}
Services are added and removed via the 'rc-update' tool. Running it without
arguments should give sufficient help.
"
else
printf "\n
For more info, please run '${myscript} help'.
"
fi
exit 0

70
sh/rc-mount.sh Normal file
View File

@@ -0,0 +1,70 @@
# Copyright 2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# bool do_unmount(char *cmd, char *no_unmounts, char *nodes, char *fslist)
# Handy function to handle all our unmounting needs
# find-mount is a C program to actually find our mounts on our supported OS's
do_unmount() {
local cmd="$1" retval=0 retry=
local f_opts="-m -c" f_kill="-s " mnt=
if [ "${RC_UNAME}" = "Linux" ] ; then
f_opts="-c"
f_kill="-"
fi
local mnts="$(mountinfo ${2:+--skip-regex} $2 ${3:+--node-regex} $3 ${4:+--fstype-regex} $4 --reverse \
| sed -e "s/'/'\\\\''/g" -e "s/^/'/g" -e "s/$/'/g")"
eval set -- ${mnts}
for mnt in "$@" ; do
case "${cmd}" in
umount*)
# If we're using the mount (probably /usr) then don't unmount us
local pids="$(fuser ${f_opts} "${mnt}" 2>/dev/null)"
case " ${pids} " in
*" $$ "*)
ewarn "We are using ${mnt}, not unmounting"
continue
;;
esac
ebegin "Unmounting ${mnt}"
;;
*)
ebegin "Remounting ${mnt}"
;;
esac
retry=3
while ! ${cmd} "${mnt}" 2>/dev/null ; do
# Don't kill if it's us (/ and possibly /usr)
local pids="$(fuser ${f_opts} "${mnt}" 2>/dev/null)"
case " ${pids} " in
*" $$ "*) retry=0 ;;
" ") eend 1 "in use but fuser finds nothing"; retry=0 ;;
*)
local sig="KILL"
[ ${retry} -gt 0 ] && sig="TERM"
fuser ${f_kill}${sig} -k ${f_opts} "${mnt}" \
>/dev/null 2>/dev/null
sleep 1
retry=$((${retry} - 1))
;;
esac
# OK, try forcing things
if [ ${retry} -le 0 ] ; then
${cmd} -f "${mnt}" || retry=-999
retry=-999
break
fi
done
if [ ${retry} -eq -999 ] ; then
eend 1
retval=1
else
eend 0
fi
done
return ${retval}
}
# vim: set ts=4 :

74
sh/runscript.sh Executable file
View File

@@ -0,0 +1,74 @@
#!/bin/sh
# Shell wrapper for runscript
# Copyright 1999-2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
. /etc/init.d/functions.sh
. "${RC_LIBDIR}"/sh/rc-functions.sh
# Support LiveCD foo
if [ -r /sbin/livecd-functions.sh ] ; then
. /sbin/livecd-functions.sh
livecd_read_commandline
fi
if [ -z "$1" -o -z "$2" ] ; then
eerror "${SVCNAME}: not enough arguments"
exit 1
fi
[ "${RC_DEBUG}" = "yes" ] && set -x
# If we're net.eth0 or openvpn.work then load net or openvpn config
rc_c=${SVCNAME%%.*}
if [ -n "${rc_c}" -a "${rc_c}" != "${SVCNAME}" ] ; then
if [ -e "/etc/conf.d/${rc_c}.${RC_SOFTLEVEL}" ] ; then
. "/etc/conf.d/${rc_c}.${RC_SOFTLEVEL}"
elif [ -e "/etc/conf.d/${rc_c}" ] ; then
. "/etc/conf.d/${rc_c}"
fi
fi
unset rc_c
# Overlay with our specific config
if [ -e "/etc/conf.d/${SVCNAME}.${RC_SOFTLEVEL}" ] ; then
. "/etc/conf.d/${SVCNAME}.${RC_SOFTLEVEL}"
elif [ -e "/etc/conf.d/${SVCNAME}" ] ; then
. "/etc/conf.d/${SVCNAME}"
fi
# Load any system overrides
[ -e /etc/rc.conf ] && . /etc/rc.conf
# Apply any ulimit defined
[ -n "${RC_ULIMIT}" ] && ulimit ${RC_ULIMIT}
# Load our script
. $1
shift
while [ -n "$1" ] ; do
# See if we have the required function and run it
for rc_x in start stop ${opts} ; do
if [ "${rc_x}" = "$1" ] ; then
if type "$1" >/dev/null 2>/dev/null ; then
unset rc_x
"$1" || exit $?
shift
continue 2
else
if [ "${rc_x}" = "start" -o "${rc_x}" = "stop" ] ; then
exit 0
else
eerror "${SVCNAME}: function \`$1' defined but does not exist"
exit 1
fi
fi
fi
done
eerror "${SVCNAME}: unknown function \`$1'"
exit 1
done
# vim: set ts=4 :