openrc/sh/net.sh
Roy Marples 5af58b4514 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.
2007-04-05 11:18:42 +00:00

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 :