openrc/init.d/net.lo.in
William Hubbs 1280b97749 oldnet: add support for shutdown_network from newnet
This setting, already in use in newnet, allows the user to control
whether network interfaces are stopped when the system shuts down. By
default, under newnet, they are not, so I am making oldnet have the same
default.

A side-affect of this is that in the default configuration this fixes
bugs like the one below.

Reported-by: jerryfleming2006@gmail.com
X-Gentoo-Bug: 259183
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=259183
2013-02-11 09:08:34 -06:00

787 lines
17 KiB
Plaintext

#!@PREFIX@/sbin/runscript
# Copyright (c) 2007-2009 Roy Marples <roy@marples.name>
# Released under the 2-clause BSD license.
MODULESDIR="${RC_LIBEXECDIR}/net"
MODULESLIST="${RC_SVCDIR}/nettree"
_config_vars="config routes"
[ -z "${IN_BACKGROUND}" ] && IN_BACKGROUND="NO"
description="Configures network interfaces."
# Handy var so we don't have to embed new lines everywhere for array splitting
__IFS="
"
depend()
{
local IFACE=${RC_SVCNAME#*.}
local IFVAR=$(shell_var "${IFACE}")
need localmount
if [ "$RC_UNAME" = Linux -a "$IFACE" != lo ]; then
need sysfs
fi
after bootmisc
keyword -jail -prefix -vserver
case "${IFACE}" in
lo|lo0) ;;
*)
after net.lo net.lo0 dbus
provide net
;;
esac
if [ "$(command -v "depend_${IFVAR}")" = "depend_${IFVAR}" ]; then
depend_${IFVAR}
fi
local dep= prov=
for dep in need use before after provide keyword; do
eval prov=\$rc_${dep}_${IFVAR}
if [ -n "${prov}" ]; then
${dep} ${prov}
ewarn "rc_${dep}_${IFVAR} is deprecated."
ewarn "Please use rc_net_${IFVAR}_${dep} instead."
fi
done
}
# Support bash arrays - sigh
_array_helper()
{
local _a=
eval _a=\$$1
_a=$(echo "${_a}" | sed -e 's:^[[:space:]]*::' -e 's:[[:space:]]*$::' -e '/^$/d' -e 's:[[:space:]]\{1,\}: :g')
[ -n "${_a}" ] && printf "%s\n" "${_a}"
}
_get_array()
{
local _a=
if [ -n "${BASH}" ]; then
case "$(declare -p "$1" 2>/dev/null)" in
"declare -a "*)
ewarn "You are using a bash array for $1."
ewarn "This feature will be removed in the future."
ewarn "Please see net.example for the correct format for $1."
eval "set -- \"\${$1[@]}\""
for _a; do
printf "%s\n" "${_a}"
done
return 0
;;
esac
fi
_array_helper $1
}
# Flatten bash arrays to simple strings
_flatten_array()
{
if [ -n "${BASH}" ]; then
case "$(declare -p "$1" 2>/dev/null)" in
"declare -a "*)
ewarn "You are using a bash array for $1."
ewarn "This feature will be removed in the future."
ewarn "Please see net.example for the correct format for $1."
eval "set -- \"\${$1[@]}\""
for x; do
printf "'%s' " "$(printf "$x" | sed "s:':'\\\'':g")"
done
return 0
;;
esac
fi
_array_helper $1
}
_wait_for_carrier()
{
local timeout= efunc=einfon
_has_carrier && return 0
eval timeout=\$carrier_timeout_${IFVAR}
timeout=${timeout:-${carrier_timeout:-0}}
# Incase users don't want this nice feature ...
[ ${timeout} -le 0 ] && return 0
yesno ${RC_PARALLEL} && efunc=einfo
${efunc} "Waiting for carrier (${timeout} seconds) "
while [ ${timeout} -gt 0 ]; do
if _has_carrier; then
[ "${efunc}" = "einfon" ] && echo
eend 0
return 0
fi
sleep 1
: $(( timeout -= 1 ))
[ "${efunc}" = "einfon" ] && printf "."
done
[ "${efunc}" = "einfon" ] && echo
eend 1
return 1
}
_netmask2cidr()
{
# Some shells cannot handle hex arithmetic, so we massage it slightly
# Buggy shells include FreeBSD sh, dash and busybox.
# bash and NetBSD sh don't need this.
case $1 in
0x*)
local hex=${1#0x*} quad=
while [ -n "${hex}" ]; do
local lastbut2=${hex#??*}
quad=${quad}${quad:+.}0x${hex%${lastbut2}*}
hex=${lastbut2}
done
set -- ${quad}
;;
esac
local i= len=
local IFS=.
for i in $1; do
while [ ${i} -ne 0 ]; do
: $(( len += i % 2 ))
: $(( i >>= 1 ))
done
done
echo "${len}"
}
_configure_variables()
{
local var= v= t=
for var in ${_config_vars}; do
local v=
for t; do
eval v=\$${var}_${t}
if [ -n "${v}" ]; then
eval ${var}_${IFVAR}=\$${var}_${t}
continue 2
fi
done
done
}
_which()
{
local i OIFS
# Empty
[ -z "$1" ] && return
# check paths
OIFS="$IFS"
IFS=:
for i in $PATH ; do
[ -x $i/$1 ] && echo $i/$1 && break
done
IFS=$OIFS
}
# Like _which, but also consider shell builtins, and multiple alternatives
_program_available()
{
[ -z "$1" ] && return 0
local x=
for x; do
case "${x}" in
/*) [ -x "${x}" ] && break;;
*) type "${x}" >/dev/null 2>&1 && break;;
esac
unset x
done
[ -n "${x}" ] && echo $x && return 0
return 1
}
_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= force=$1
if ! ${force} && [ -s "${MODULESLIST}" -a "${MODULESLIST}" -nt "${MODULESDIR}" ]; then
local update=false
for x in "${MODULESDIR}"/*.sh; 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; 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}"/*.sh; 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
printf "" > "${MODULESLIST}"
i=0
for MODULE in ${SORTED}; do
eval PROGRAM=\$${MODULE}_program
eval PROGRAM_START=\$${MODULE}_program_start
eval PROGRAM_STOP=\$${MODULE}_program_stop
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 += 1 ))
done
echo "module_${i}=" >> "${MODULESLIST}"
)
return 0
}
_load_modules()
{
local starting=$1 mymods=
# Ensure our list is up to date
_gen_module_list false
if ! . "${MODULESLIST}"; then
_gen_module_list true
. "${MODULESLIST}"
fi
MODULES=
if [ "${IFACE}" != "lo" -a "${IFACE}" != "lo0" ]; then
eval mymods=\$modules_${IFVAR}
[ -z "${mymods}" ] && mymods=${modules}
fi
local i=-1 x= mod= f= provides=
while true; do
: $(( i += 1 ))
eval mod=\$module_${i}
[ -z "${mod}" ] && break
[ -e "${MODULESDIR}/${mod}.sh" ] || continue
eval set -- \$module_${i}_program
if [ -n "$1" ]; then
if ! _program_available "$@" >/dev/null; then
vewarn "Skipping module $mod due to missing program: $@"
continue
fi
fi
if ${starting}; then
eval set -- \$module_${i}_program_start
else
eval set -- \$module_${i}_program_stop
fi
if [ -n "$1" ]; then
if ! _program_available "$@" >/dev/null; then
vewarn "Skipping module $mod due to missing program: $@"
continue
fi
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 "${RC_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}() { [ "$(command -v "${mod}_${f}")" = "${mod}_${f}" ] || 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}() { [ "$(command -v "${mod}_${f}")" = "${mod}_${f}" ] || 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()
{
local config="$(_get_array "config_${IFVAR}")"
local fallback="$(_get_array fallback_${IFVAR})"
config_index=0
local IFS="$__IFS"
set -- ${config}
# We should support a space separated array for cidr configs
# But only as long as they do not contain other parameters for the address
if [ $# = 1 ]; then
unset IFS
set -- ${config}
# Of course, we may have a single address added old style.
# If the NEXT argument is a v4 or v6 address, it's the next config.
# Otherwise, it's arguments to the first config...
if [ "${2#*.*}" = "${2}" -a "${2#*:*}" = "${2}" ]; then
# Not an IPv4/IPv6
local IFS="$__IFS"
set -- ${config}
fi
fi
# Ensure that loopback has the correct address
if [ "${IFACE}" = "lo" -o "${IFACE}" = "lo0" ]; then
if [ "$1" != "null" ]; then
config_0="127.0.0.1/8"
config_index=1
fi
else
if [ -z "$1" ]; then
ewarn "No configuration specified; defaulting to DHCP"
config_0="dhcp"
config_index=1
fi
fi
# We store our config in an array like vars
# so modules can influence it
for cmd; do
eval config_${config_index}="'${cmd}'"
: $(( config_index += 1 ))
done
# Terminate the list
eval config_${config_index}=
config_index=0
for cmd in ${fallback}; do
eval fallback_${config_index}="'${cmd}'"
: $(( 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
}
# Support functions
_run_if()
{
local cmd=$1 iface=$2 ifr=${IFACE} ifv=${IFVAR}
# Ensure that we don't stamp on real values
local IFACE= IFVAR=
shift
if [ -n "${iface}" ]; then
IFACE="${iface}"
[ "${iface}" != "${ifr}" ] && IFVAR=$(shell_var "${IFACE}")
else
IFACE=${ifr}
IFVAR=${ifv}
fi
${cmd}
}
interface_exists()
{
_run_if _exists "$@"
}
interface_up()
{
_run_if _up "$@"
}
interface_down()
{
_run_if _down "$@"
}
start()
{
local IFACE=${RC_SVCNAME#*.} oneworked=false fallback=false module=
local IFVAR=$(shell_var "${IFACE}") cmd= our_metric=
local metric=0 _up_before_preup
eval _up_before_preup="\$up_before_preup_${IFVAR}"
[ -z "${_up_before_preup}" ] && _up_before_preup=$up_before_preup
einfo "Bringing up interface ${IFACE}"
eindent
if [ -z "${MODULES}" ]; then
local MODULES=
_load_modules true
fi
# We up the iface twice if we have a preup to ensure it's up if
# available in preup and afterwards incase the user inadvertently
# brings it down
if [ "$(command -v preup)" = "preup" ]; then
yesno "${_up_before_preup:-yes}" && _up 2>/dev/null
ebegin "Running preup"
eindent
preup || return 1
eoutdent
fi
_up 2>/dev/null
for module in ${MODULES}; do
if [ "$(command -v "${module}_pre_start")" = "${module}_pre_start" ]; then
${module}_pre_start || exit $?
fi
done
if ! _exists; then
eerror "ERROR: interface ${IFACE} does not exist"
eerror "Ensure that you have loaded the correct kernel module for your hardware"
return 1
fi
if ! _wait_for_carrier; then
if service_started devd; then
ewarn "no carrier, but devd will start us when we have one"
mark_service_inactive "${RC_SVCNAME}"
else
eerror "no carrier"
fi
return 1
fi
local config= config_index=
_load_config
config_index=0
eval our_metric=\$metric_${IFVAR}
if [ -n "${our_metric}" ]; then
metric=${our_metric}
elif [ "${IFACE}" != "lo" -a "${IFACE}" != "lo0" ]; then
: $(( metric += $(_ifindex) ))
fi
while true; do
eval config=\$config_${config_index}
[ -z "${config}" ] && break
set -- ${config}
if [ "$1" != "null" -a "$1" != "noop" ]; then
ebegin "$1"
fi
eindent
case "$1" in
noop)
if [ -n "$(_get_inet_address)" ]; then
oneworked=true
break
fi
;;
null) :;;
[0-9]*|*:*) _add_address ${config};;
*)
if [ "$(command -v "${config}_start")" = "${config}_start" ]; then
"${config}"_start
else
eerror "nothing provides \`${config}'"
fi
;;
esac
if eend $?; then
oneworked=true
else
eval config=\$fallback_${config_index}
if [ -n "${config}" ]; then
fallback=true
eoutdent
ewarn "Trying fallback configuration ${config}"
eindent
eval config_${config_index}=\$config
unset fallback_${config_index}
: $(( config_index -= 1 ))
fi
fi
eoutdent
: $(( config_index += 1 ))
done
if ! ${oneworked}; then
if [ "$(command -v failup)" = "failup" ]; then
ebegin "Running failup"
eindent
failup
eoutdent
fi
return 1
fi
local hideFirstroute=false first=true routes=
if ${fallback}; then
routes="$(_get_array "fallback_routes_${IFVAR}")"
fi
if [ -z "${routes}" ]; then
routes="$(_get_array "routes_${IFVAR}")"
fi
if [ "${IFACE}" = "lo" -o "${IFACE}" = "lo0" ]; then
if [ "${config_0}" != "null" ]; then
routes="127.0.0.0/8 via 127.0.0.1
${routes}"
hideFirstroute=true
fi
fi
local OIFS="${IFS}" SIFS="${IFS-y}"
local IFS="$__IFS"
local fam
for cmd in ${routes}; do
unset IFS
if ${first}; then
first=false
einfo "Adding routes"
fi
case ${cmd} in
-6" "*) fam="-6"; cmd=${cmd#-6 };;
-4" "*) fam="-4"; cmd=${cmd#-4 };;
esac
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}";;
*.*.*.*/32*) cmd="-host ${cmd}";;
*.*.*.*/*|0.0.0.0|0.0.0.0" "*) cmd="-net ${cmd}";;
default|default" "*) cmd="-net ${cmd}";;
*:*/128*) cmd="-host ${cmd}";;
*:*/*) cmd="-net ${cmd}";;
*) cmd="-host ${cmd}";;
esac
if ${hideFirstroute}; then
_add_route ${fam} ${cmd} >/dev/null 2>&1
hideFirstroute=false
else
_add_route ${fam} ${cmd} >/dev/null
fi
eend $?
eoutdent
done
if [ "${SIFS}" = "y" ]; then
unset IFS
else
IFS="${OIFS}"
fi
for module in ${MODULES}; do
if [ "$(command -v "${module}_post_start")" = "${module}_post_start" ]; then
${module}_post_start || exit $?
fi
done
if [ "$(command -v postup)" = "postup" ]; then
ebegin "Running postup"
eindent
postup
eoutdent
fi
return 0
}
stop()
{
# Don't stop the network at shutdown.
# We don't use the noshutdown keyword so that we are started again
# correctly if we go back to multiuser.
yesno ${shutdown_network:-YES} && yesno $RC_GOINGDOWN && return 0
local IFACE=${RC_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 [ "$(command -v predown)" = "predown" ]; then
ebegin "Running predown"
eindent
predown || return 1
eoutdent
else
if is_net_fs /; then
eerror "root filesystem is network mounted -- can't stop ${IFACE}"
return 1
fi
fi
for module in ${MODULES}; do
if [ "$(command -v "${module}_pre_stop")" = "${module}_pre_stop" ]; then
${module}_pre_stop || exit $?
fi
done
for module in ${MODULES}; do
if [ "$(command -v "${module}_stop")" = "${module}_stop" ]; then
${module}_stop
fi
done
# Only delete addresses for interfaces that exist
if _exists; then
# PPP can manage it's own addresses when IN_BACKGROUND
# Important in case "demand" set on the ppp link
if ! (yesno ${IN_BACKGROUND} && is_ppp) ; then
_delete_addresses "${IFACE}"
fi
fi
for module in ${MODULES}; do
if [ "$(command -v "${module}_post_stop")" = "${module}_post_stop" ]; then
${module}_post_stop
fi
done
# If not in background, and not loopback then bring the interface down
# unless overridden.
if ! yesno ${IN_BACKGROUND} && \
[ "${IFACE}" != "lo" -a "${IFACE}" != "lo0" ]; then
eval module=\$ifdown_${IFVAR}
module=${module:-${ifdown:-YES}}
yesno ${module} && _down 2>/dev/null
fi
type resolvconf >/dev/null 2>&1 && resolvconf -d "${IFACE}" 2>/dev/null
if [ "$(command -v "postdown")" = "postdown" ]; then
ebegin "Running postdown"
eindent
postdown
eoutdent
fi
return 0
}