5af58b4514
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.
567 lines
12 KiB
Bash
Executable File
567 lines
12 KiB
Bash
Executable File
#!/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 :
|