diff options
Diffstat (limited to 'sh')
-rw-r--r-- | sh/Makefile | 7 | ||||
-rw-r--r-- | sh/functions.sh | 157 | ||||
-rwxr-xr-x | sh/gendepends.sh | 58 | ||||
-rw-r--r-- | sh/init-common-post.sh | 22 | ||||
-rw-r--r-- | sh/init-functions.sh | 62 | ||||
-rwxr-xr-x | sh/net.sh | 566 | ||||
-rwxr-xr-x | sh/rc-functions.sh | 60 | ||||
-rwxr-xr-x | sh/rc-help.sh | 262 | ||||
-rw-r--r-- | sh/rc-mount.sh | 70 | ||||
-rwxr-xr-x | sh/runscript.sh | 74 |
10 files changed, 1338 insertions, 0 deletions
diff --git a/sh/Makefile b/sh/Makefile new file mode 100644 index 00000000..ac50fa90 --- /dev/null +++ b/sh/Makefile @@ -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 diff --git a/sh/functions.sh b/sh/functions.sh new file mode 100644 index 00000000..d1327ad5 --- /dev/null +++ b/sh/functions.sh @@ -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 : diff --git a/sh/gendepends.sh b/sh/gendepends.sh new file mode 100755 index 00000000..aa494f03 --- /dev/null +++ b/sh/gendepends.sh @@ -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 : diff --git a/sh/init-common-post.sh b/sh/init-common-post.sh new file mode 100644 index 00000000..ec535eb6 --- /dev/null +++ b/sh/init-common-post.sh @@ -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 : diff --git a/sh/init-functions.sh b/sh/init-functions.sh new file mode 100644 index 00000000..59f0eb6b --- /dev/null +++ b/sh/init-functions.sh @@ -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 : diff --git a/sh/net.sh b/sh/net.sh new file mode 100755 index 00000000..c839dd4c --- /dev/null +++ b/sh/net.sh @@ -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 : diff --git a/sh/rc-functions.sh b/sh/rc-functions.sh new file mode 100755 index 00000000..586471dd --- /dev/null +++ b/sh/rc-functions.sh @@ -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 : diff --git a/sh/rc-help.sh b/sh/rc-help.sh new file mode 100755 index 00000000..97ca53f4 --- /dev/null +++ b/sh/rc-help.sh @@ -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 diff --git a/sh/rc-mount.sh b/sh/rc-mount.sh new file mode 100644 index 00000000..67ea203f --- /dev/null +++ b/sh/rc-mount.sh @@ -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 : diff --git a/sh/runscript.sh b/sh/runscript.sh new file mode 100755 index 00000000..6b679c21 --- /dev/null +++ b/sh/runscript.sh @@ -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 : |