From 5ba6f0a62817f6031936b8880a15c404840924bb Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Tue, 29 Apr 2008 10:25:45 +0000 Subject: We need to ensure that the init script started is correct, translating symlinks. This has a new rule - multiplexed services must exist in the same dir as the master sript. So we need to ensuret that net.lo(0) is the real script and not a symlink itself. This fixes Gentoo #219526. --- init.d/.gitignore | 4 + init.d/Makefile | 7 + init.d/Makefile.FreeBSD | 2 + init.d/Makefile.Linux | 2 + init.d/Makefile.NetBSD | 2 + init.d/net.lo.in | 680 ++++++++++++++++++++++++++++++++++++++++++++++++ mk/scripts.mk | 4 +- sh/.gitignore | 2 + sh/Makefile | 6 +- sh/Makefile.FreeBSD | 2 - sh/Makefile.Linux | 1 - sh/Makefile.NetBSD | 1 - sh/net.sh.in | 680 ------------------------------------------------ src/rc/runscript.c | 77 ++++-- 14 files changed, 760 insertions(+), 710 deletions(-) create mode 100644 init.d/net.lo.in delete mode 100644 sh/net.sh.in diff --git a/init.d/.gitignore b/init.d/.gitignore index e04a53f7..10872127 100644 --- a/init.d/.gitignore +++ b/init.d/.gitignore @@ -26,3 +26,7 @@ mixer nscd powerd syscons +net.lo +ttys +swap-blk +wscons diff --git a/init.d/Makefile b/init.d/Makefile index a9f62e25..b670eacb 100644 --- a/init.d/Makefile +++ b/init.d/Makefile @@ -3,7 +3,14 @@ SRCS= bootmisc.in fsck.in halt.sh.in hostname.in local.in localmount.in \ netmount.in root.in swap.in sysctl.in urandom.in BIN= ${OBJS} +INSTALLAFTER= _installafter +CLEANFILES+= net.lo +TARGETS+= net.lo + MK= ../mk include ${MK}/os.mk include Makefile.${OS} include ${MK}/scripts.mk + +_installafter: net.lo + ${INSTALL} -m ${BINMODE} net.lo ${DESTDIR}/${INITDIR}/${NET_LO} diff --git a/init.d/Makefile.FreeBSD b/init.d/Makefile.FreeBSD index 8bcb9694..3cd6feb6 100644 --- a/init.d/Makefile.FreeBSD +++ b/init.d/Makefile.FreeBSD @@ -1,3 +1,5 @@ +NET_LO= net.lo0 + # Generic BSD scripts SRCS+= hostid.in moused.in newsyslog.in pf.in rarpd.in rc-enabled.in \ rpcbind.in savecore.in syslogd.in diff --git a/init.d/Makefile.Linux b/init.d/Makefile.Linux index 0e476b57..ae9e6ba4 100644 --- a/init.d/Makefile.Linux +++ b/init.d/Makefile.Linux @@ -1,3 +1,5 @@ +NET_LO= net.lo + SRCS+= hwclock.in consolefont.in keymaps.in modules.in mtab.in numlock.in \ procfs.in termencoding.in diff --git a/init.d/Makefile.NetBSD b/init.d/Makefile.NetBSD index 0bf2f657..2d1141bd 100644 --- a/init.d/Makefile.NetBSD +++ b/init.d/Makefile.NetBSD @@ -1,3 +1,5 @@ +NET_LO= net.lo0 + # Generic BSD scripts SRCS+= hostid.in moused.in newsyslog.in pf.in rarpd.in rc-enabled.in \ rpcbind.in savecore.in syslogd.in diff --git a/init.d/net.lo.in b/init.d/net.lo.in new file mode 100644 index 00000000..8f53a86c --- /dev/null +++ b/init.d/net.lo.in @@ -0,0 +1,680 @@ +#!@PREFIX@/sbin/runscript +# Copyright 2007-2008 Roy Marples +# All rights reserved. Released under the 2-clause BSD license. + +MODULESDIR="${RC_LIBDIR}/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 + provide net + keyword nojail noprefix novserver + + case "${IFACE}" in + lo|lo0);; + *) after net.lo net.lo0;; + 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} + fi + done +} + +# Support bash arrays - sigh +_get_array() +{ + local _a= + if [ -n "${BASH}" ]; then + case "$(declare -p "$1" 2>/dev/null)" in + "declare -a "*) + eval "set -- \"\${$1[@]}\"" + for _a; do + printf "%s\n" "${_a}" + done + return 0 + ;; + esac + fi + + eval _a=\$$1 + printf "%s" "${_a}" + printf "\n" + [ -n "${_a}" ] +} + +# Flatten bash arrays to simple strings +_flatten_array() +{ + if [ -n "${BASH}" ]; then + case "$(declare -p "$1" 2>/dev/null)" in + "declare -a "*) + eval "set -- \"\${$1[@]}\"" + for x; do + printf "'%s' " "$(printf "$x" | sed "s:':'\\\'':g")" + done + return 0 + ;; + esac + fi + + eval _a=\$$1 + printf "%s" "${_a}" + printf "\n" + [ -n "${_a}" ] +} + +_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=$((${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} != "0" ]; do + len=$((${len} + ${i} % 2)) + i=$((${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 +} + +_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=$((${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=$((${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; 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; do + case "${x}" in + /*) [ -x "${x}" ] && break;; + *) type "${x}" >/dev/null 2>&1 && break;; + esac + unset x + done + [ -n "${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 "${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 + if [ $# = 1 ]; then + unset IFS + set -- ${config} + # Of course, we may have a single address added old style. + case "$2" in + netmask|broadcast|brd|brd+) + local IFS="$__IFS" + set -- ${config} + ;; + esac + 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=$((${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=$((${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=${RC_SVCNAME#*.} oneworked=false module= + local IFVAR=$(shell_var "${IFACE}") cmd= our_metric= + local metric=0 + + 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 + _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=$((${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 [ "$(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 + eoutdent + ewarn "Trying fallback configuration ${config}" + eindent + eval config_${config_index}=\$config + unset fallback_${config_index} + config_index=$((${config_index} - 1)) + fi + fi + eoutdent + config_index=$((${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 + local routes="$(_get_array "routes_${IFVAR}")" + 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" "*|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 non PPP interfaces + if ! [ "$(command -v is_ppp)" = "is_ppp" ] || ! is_ppp; then + _delete_addresses "${IFACE}" + fi + + for module in ${MODULES}; do + if [ "$(command -v "${module}_post_stop")" = "${module}_post_stop" ]; then + ${module}_post_stop + fi + done + + ! yesno ${IN_BACKGROUND} && \ + [ "${IFACE}" != "lo" -a "${IFACE}" != "lo0" ] && \ + _down 2>/dev/null + + 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 +} diff --git a/mk/scripts.mk b/mk/scripts.mk index ced18441..f65c1422 100644 --- a/mk/scripts.mk +++ b/mk/scripts.mk @@ -22,9 +22,9 @@ SED_REPLACE= -e 's:@SHELL@:${SH}:g' -e 's:@LIB@:${LIBNAME}:g' -e 's:@SYSCONFDIR .in: ${SED} ${SED_REPLACE} ${SED_EXTRA} $< > $@ -all: ${OBJS} +all: ${OBJS} ${TARGETS} -realinstall: ${BIN} ${CONF} ${CONF_APPEND} +realinstall: ${BIN} ${CONF} ${INC} @if test -n "${DIR}"; then \ ${ECHO} ${INSTALL} -d ${DESTDIR}/${DIR}; \ ${INSTALL} -d ${DESTDIR}/${DIR} || exit $$?; \ diff --git a/sh/.gitignore b/sh/.gitignore index 91d8a146..028281d4 100644 --- a/sh/.gitignore +++ b/sh/.gitignore @@ -4,3 +4,5 @@ net.sh rc-functions.sh runscript.sh init.sh +ifwatchd-carrier.sh +ifwatchd-nocarrier.sh diff --git a/sh/Makefile b/sh/Makefile index cc4aa35f..efca9800 100644 --- a/sh/Makefile +++ b/sh/Makefile @@ -1,8 +1,8 @@ DIR= ${PREFIX}/${RC_LIB}/sh -SRCS= functions.sh.in gendepends.sh.in net.sh.in \ +SRCS= functions.sh.in gendepends.sh.in \ rc-functions.sh.in runscript.sh.in INC= init-common-post.sh rc-mount.sh functions.sh rc-functions.sh -BIN= gendepends.sh init.sh net.sh runscript.sh +BIN= gendepends.sh init.sh runscript.sh INSTALLAFTER= _installafter @@ -13,8 +13,6 @@ include ${MK}/scripts.mk _installafter: ${INSTALL} -d ${DESTDIR}/${INITDIR} - @# Provide an init script for the loopback interface - ln -snf ${PREFIX}/${RC_LIB}/sh/net.sh ${DESTDIR}/${INITDIR}/${NET_LO} || exit $$? @# Put functions.sh into the init.d dir so 3rd party apps don't have to @# be multilib aware ln -snf ${PREFIX}/${RC_LIB}/sh/functions.sh ${DESTDIR}/${INITDIR} || exit $$? diff --git a/sh/Makefile.FreeBSD b/sh/Makefile.FreeBSD index 93a00a01..d4e6b866 100644 --- a/sh/Makefile.FreeBSD +++ b/sh/Makefile.FreeBSD @@ -1,7 +1,5 @@ SRCS+= init.sh.in -NET_LO= net.lo0 - .SUFFIXES: .sh.BSD.in .sh.BSD.in.sh: ${SED} ${SED_REPLACE} ${SED_EXTRA} $< > $@ diff --git a/sh/Makefile.Linux b/sh/Makefile.Linux index b73b4665..bb48f42e 100644 --- a/sh/Makefile.Linux +++ b/sh/Makefile.Linux @@ -1,4 +1,3 @@ -NET_LO= net.lo SRCS+= init.sh.in init-early.sh.in BIN+= init-early.sh diff --git a/sh/Makefile.NetBSD b/sh/Makefile.NetBSD index 0e4200aa..bd443934 100644 --- a/sh/Makefile.NetBSD +++ b/sh/Makefile.NetBSD @@ -1,6 +1,5 @@ SRCS+= init.sh.in -NET_LO= net.lo0 SRCS+= ifwatchd-carrier.sh.in ifwatchd-nocarrier.sh.in BIN+= ifwatchd-carrier.sh ifwatchd-nocarrier.sh diff --git a/sh/net.sh.in b/sh/net.sh.in deleted file mode 100644 index 8f53a86c..00000000 --- a/sh/net.sh.in +++ /dev/null @@ -1,680 +0,0 @@ -#!@PREFIX@/sbin/runscript -# Copyright 2007-2008 Roy Marples -# All rights reserved. Released under the 2-clause BSD license. - -MODULESDIR="${RC_LIBDIR}/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 - provide net - keyword nojail noprefix novserver - - case "${IFACE}" in - lo|lo0);; - *) after net.lo net.lo0;; - 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} - fi - done -} - -# Support bash arrays - sigh -_get_array() -{ - local _a= - if [ -n "${BASH}" ]; then - case "$(declare -p "$1" 2>/dev/null)" in - "declare -a "*) - eval "set -- \"\${$1[@]}\"" - for _a; do - printf "%s\n" "${_a}" - done - return 0 - ;; - esac - fi - - eval _a=\$$1 - printf "%s" "${_a}" - printf "\n" - [ -n "${_a}" ] -} - -# Flatten bash arrays to simple strings -_flatten_array() -{ - if [ -n "${BASH}" ]; then - case "$(declare -p "$1" 2>/dev/null)" in - "declare -a "*) - eval "set -- \"\${$1[@]}\"" - for x; do - printf "'%s' " "$(printf "$x" | sed "s:':'\\\'':g")" - done - return 0 - ;; - esac - fi - - eval _a=\$$1 - printf "%s" "${_a}" - printf "\n" - [ -n "${_a}" ] -} - -_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=$((${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} != "0" ]; do - len=$((${len} + ${i} % 2)) - i=$((${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 -} - -_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=$((${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=$((${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; 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; do - case "${x}" in - /*) [ -x "${x}" ] && break;; - *) type "${x}" >/dev/null 2>&1 && break;; - esac - unset x - done - [ -n "${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 "${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 - if [ $# = 1 ]; then - unset IFS - set -- ${config} - # Of course, we may have a single address added old style. - case "$2" in - netmask|broadcast|brd|brd+) - local IFS="$__IFS" - set -- ${config} - ;; - esac - 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=$((${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=$((${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=${RC_SVCNAME#*.} oneworked=false module= - local IFVAR=$(shell_var "${IFACE}") cmd= our_metric= - local metric=0 - - 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 - _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=$((${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 [ "$(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 - eoutdent - ewarn "Trying fallback configuration ${config}" - eindent - eval config_${config_index}=\$config - unset fallback_${config_index} - config_index=$((${config_index} - 1)) - fi - fi - eoutdent - config_index=$((${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 - local routes="$(_get_array "routes_${IFVAR}")" - 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" "*|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 non PPP interfaces - if ! [ "$(command -v is_ppp)" = "is_ppp" ] || ! is_ppp; then - _delete_addresses "${IFACE}" - fi - - for module in ${MODULES}; do - if [ "$(command -v "${module}_post_stop")" = "${module}_post_stop" ]; then - ${module}_post_stop - fi - done - - ! yesno ${IN_BACKGROUND} && \ - [ "${IFACE}" != "lo" -a "${IFACE}" != "lo0" ] && \ - _down 2>/dev/null - - 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 -} diff --git a/src/rc/runscript.c b/src/rc/runscript.c index 4ecf305d..af140d62 100644 --- a/src/rc/runscript.c +++ b/src/rc/runscript.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -707,7 +708,8 @@ static void svc_start(bool deps) hook_out = RC_HOOK_SERVICE_START_OUT; rc_plugin_run(RC_HOOK_SERVICE_START_IN, applet); - if (rc_conf_yesno("rc_depend_strict")) + errno = 0; + if (rc_conf_yesno("rc_depend_strict") || errno == ENOENT) depoptions |= RC_DEP_STRICT; if (deps) { @@ -933,8 +935,8 @@ static void svc_stop(bool deps) ewarn ("WARNING: you are stopping a boot service"); if (deps && ! (state & RC_SERVICE_WASINACTIVE)) { - - if (rc_conf_yesno("rc_depend_strict")) + errno = 0; + if (rc_conf_yesno("rc_depend_strict") || errno == ENOENT) depoptions |= RC_DEP_STRICT; if (! deptree && ((deptree = _rc_deptree_load(NULL)) == NULL)) @@ -1102,39 +1104,73 @@ int runscript(int argc, char **argv) int retval; int opt; RC_STRING *svc; - char dir[PATH_MAX]; + char path[PATH_MAX]; + char lnk[PATH_MAX]; size_t l = 0; size_t ll; - char *save; + char *dir, *save; + const char *file; int depoptions = RC_DEP_TRACE; + struct stat stbuf; /* Show help if insufficient args */ if (argc < 2 || ! exists(argv[1])) { - fprintf(stderr, "runscript is not meant to be to run directly\n"); + fprintf(stderr, "runscript should not be run directly\n"); exit(EXIT_FAILURE); } - applet = basename_c(argv[1]); - if (argc < 3) - usage(EXIT_FAILURE); - - if (*argv[1] == '/') - service = xstrdup(argv[1]); - else { - getcwd(dir, sizeof(dir)); - l = strlen(dir) + strlen(argv[1]) + 2; - service = xmalloc(sizeof (char) * l); - snprintf(service, l, "%s/%s", dir, argv[1]); + if (stat(argv[1], &stbuf) != 0) { + fprintf(stderr, "runscript `%s': %s\n", + argv[1], strerror(errno)); + exit(EXIT_FAILURE); } atexit(cleanup); + /* We need to work out the real full path to our service. + * This works fine, provided that we ONLY allow mulitplexed services + * to exist in the same directory as the master link. + * Also, the master link as to be a real file in the init dir. */ + if (!realpath(argv[1], path)) { + fprintf(stderr, "realpath: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + memset(lnk, 0, sizeof(lnk)); + if (readlink(argv[1], lnk, sizeof(lnk)-1)) { + dir = dirname(path); + if (strchr(lnk, '/')) { + save = xstrdup(dir); + dir = dirname(lnk); + if (strcmp(dir, save) == 0) + file = basename_c(argv[1]); + else + file = basename_c(lnk); + free(save); + dir = dirname(path); + } else + file = basename_c(argv[1]); + ll = strlen(dir) + strlen(file) + 2; + service = xmalloc(ll); + snprintf(service, ll, "%s/%s", dir, file); + if (stat(service, &stbuf) != 0) { + free(service); + service = xstrdup(lnk); + } + } + if (!service) + service = xstrdup(path); + applet = basename_c(service); + + if (argc < 3) + usage(EXIT_FAILURE); + /* Change dir to / to ensure all init scripts don't use stuff in pwd */ chdir("/"); #ifdef __linux__ - /* coldplug events can trigger init scripts, but we don't want to run them - until after rc sysinit has completed so we punt them to the boot runlevel */ + /* coldplug events can trigger init scripts, but we don't want to run + * them until after rc sysinit has completed so we punt them to the + * boot runlevel */ if (exists("/dev/.rcsysinit")) { eerror("%s: cannot run until sysvinit completes", applet); if (mkdir("/dev/.rcboot", 0755) != 0 && errno != EEXIST) @@ -1264,7 +1300,8 @@ int runscript(int argc, char **argv) strcmp(optarg, "ibefore") == 0 || strcmp(optarg, "iprovide") == 0) { - if (rc_conf_yesno("rc_depend_strict")) + errno = 0; + if (rc_conf_yesno("rc_depend_strict") || errno == ENOENT) depoptions |= RC_DEP_STRICT; if (! deptree && ((deptree = _rc_deptree_load(NULL)) == NULL)) -- cgit v1.2.3