Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/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
- after bootmisc
- keyword -jail -vserver
- case "${IFACE}" in
- lo|lo0) provide lo;;
- *)
- 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:-5}}
- # 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
- sleep 1
- if _has_carrier; then
- [ "${efunc}" = "einfon" ] && echo
- eend 0
- return 0
- fi
- : $(( 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"
- for cmd in ${routes}; do
- unset IFS
- 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}";;
- *.*.*.*/32*) cmd="-host ${cmd}";;
- *.*.*.*/*|0.0.0.0|0.0.0.0" "*) cmd="-net ${cmd}";;
- default|default" "*) cmd="-net ${cmd}";;
- *) cmd="-host ${cmd}";;
- esac
- if ${hidefirstroute}; then
- _add_route ${cmd} >/dev/null 2>&1
- hidefirstroute=false
- else
- _add_route ${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()
- {
- 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
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement