diff options
Diffstat (limited to 'lib/rcscripts/net.modules.d/helpers.d/functions')
-rw-r--r-- | lib/rcscripts/net.modules.d/helpers.d/functions | 526 |
1 files changed, 526 insertions, 0 deletions
diff --git a/lib/rcscripts/net.modules.d/helpers.d/functions b/lib/rcscripts/net.modules.d/helpers.d/functions new file mode 100644 index 0000000..f09d15d --- /dev/null +++ b/lib/rcscripts/net.modules.d/helpers.d/functions @@ -0,0 +1,526 @@ +#!/bin/bash +# Copyright (c) 2004-2005 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +# We will be loaded after conf.d/rc and conf.d/net so we can set a default +# here. +RC_AUTO_INTERFACE="${RC_AUTO_INTERFACE:-no}" + +netdir="/var/lib/net-scripts" +statedir="${netdir}/state" + +# Contributed by Roy Marples (uberlord@gentoo.org) + +# char* interface_device(char *iface) +# +# Gets the base device of the interface +# Can handle eth0:1 and eth0.1 +# Which returns eth0 in this case +interface_device() { + local dev="${1%%.*}" + [[ ${dev} == "$1" ]] && dev="${1%%:*}" + echo "${dev}" +} + +# char* interface_type(char* iface) +# +# Returns the base type of the interface +# eth, ippp, etc +interface_type() { + echo "${1%%[0-9]*}" +} + +# void save_state(char *interface) +# +# Saves state information regarding the interface +save_state() { + local iface="$1" + local d="${statedir}/${iface}" + + [[ ! -d ${d} ]] && mkdir -m 0755 -p "${d}" + cp -a /etc/resolv.conf /etc/ntp.conf /etc/yp.conf "${d}" 2>/dev/null +} + +# void remove_state(char *interface) +# +# Removes state information regarding the interface +remove_state() { + local d="${statedir}/$1" + + [[ -d ${d} ]] && rm -Rf "${d}" + [[ ! ${2:-true} ]] && mkdir -m 0755 -p "${d}" +} + +# void apply_state(char *interface) +# +# Apply's state information about the interface to the system +# If the files in the state dir are not links back to etc then +# we create them if RC_AUTO_INTERFACE="yes" +# +apply_state() { + local iface="$1" + + if [[ -z ${iface} ]]; then + iface=$( select_best_interface ) + [[ -z ${iface} ]] && return + fi + + local d="${statedir}/${iface}" + if [[ -d ${d} ]]; then + local files=$( ls "${d}" ) + if [[ -n ${files} ]] ; then + if [[ ${RC_AUTO_INTERFACE} == "yes" ]]; then + cp -aR "${d}"/* "${netdir}" + local file + for file in ${files} ; do + # Skip .sv files + [[ ${file} == *".sv" ]] && contine + local link=$( readlink "/etc/${file}" 2>/dev/null ) + if [[ ${link} != "${netdir}/${file}" ]]; then + [[ -e "/etc/${file}" ]] && rm -f "/etc/${file}" + ln -snf "${netdir}/${file}" "/etc/${file}" + fi + done + else + cp -ar "${d}"/* /etc + fi + fi + fi + + [[ ${RC_AUTO_INTERFACE} == "yes" ]] && merge_configs +} + +# char* order_interfaces(bool require_gateway) +# +# Lists the interfaces in route metric order that we have configured +# (ie a state dir exists) +# require_gateway defaults to false +order_interfaces() { + local ifaces + if [[ ${1:-false} == "true" ]]; then + ifaces=$(awk '$2!="Gateway" { print $7, $1 }' /proc/net/route \ + | sort -n | cut -d' ' -f2 | uniq) + else + ifaces=$(awk '$2=="00000000" { print $7, $1 }' /proc/net/route \ + | sort -n | cut -d' ' -f2 ) + fi + local i order + for i in ${ifaces}; do + [[ -d "${statedir}/${i}" ]] && order="${order}${i} " + done + + echo "${order}" +} + +# void merge_resolv() +# +# Merges the resolv.conf info from active interfaces +merge_resolv() { + local -a ifaces=( $(order_interfaces) ) + local i j f + + # We only work for ifaces with a resolv.conf + j=${#ifaces[@]} + for (( i=0; i<j; i++ )); do + [[ ! -e "${statedir}/${ifaces[i]}/resolv.conf" ]] && unset ifaces[i] + done + ifaces=( "${ifaces[@]}" ) + + # No point merging unless there are two or more interfaces + [[ ${#ifaces[@]} -lt 2 ]] && return + + veinfo "Merging resolv.conf from interfaces ${ifaces[@]}" + + local -a search srvs + j=0 + for (( i=0; i<${#ifaces[@]}; i++ )); do + f="${statedir}/${ifaces[i]}/resolv.conf" + srvs[i]=$( sed -n -e 's/^[ \t]*nameserver[ \t]*\([^#]\)/\1/p' "${f}" \ + | sed 2q ) + if [[ -z ${srvs[i]} ]]; then + unset srvs[i] + continue + fi + + search[i]=$( sed -n -e 's/^[ \t]*\(domain\|search\)[ \t]*\([^#]\)/\2/p' \ + "${f}" | sed -e '$!d' ) + + # No point in handling more than 3 interfaces due to libc limits + (( j++ )) + [[ ${j} -gt 2 ]] && break + done + srvs=( "${srvs[@]}" ) + search=( ${search[@]} ) + + local new_srvs + j=0 + # Add interface primary nameservers + for (( i=0;i<${#srvs[@]}; i++ )); do + local -a n=( ${srvs[i]} ) + if [[ " ${new_srvs} " != *" ${n[0]} "* ]]; then + new_srvs="${new_srvs} ${n[0]}" + # libc can only handle 3 name servers + (( j++ )) + [[ ${j} -gt 2 ]] && break + fi + done + + # Add interface secondary nameservers + if [[ ${j} -lt 3 ]]; then + for (( i=0;i<${#srvs[@]}; i++ )); do + local -a n=( ${srvs[i]} ) + [[ -z ${n[1]} ]] && continue + if [[ " ${new_srvs} " != *" ${n[1]} "* ]]; then + new_srvs="${new_srvs} ${n[1]}" + # libc can only handle 3 name servers + (( j++ )) + [[ ${j} -gt 2 ]] && break + fi + done + fi + + local new_search n_search=0 + for i in ${search[@]}; do + if [[ " ${new_search} " != *" ${i} "* ]]; then + new_search="${new_search} ${i}" + # lib limits us to 6 search domains + (( n_search++ )) + [[ ${n_search} -gt 5 ]] && break + fi + done + + # Now we create a new resolv.conf to use + local f="${netdir}/resolv.conf.$$" + echo "# Generated by net-scripts from interfaces ${ifaces[@]}" > "${f}" + chmod 644 "${f}" + for i in ${new_srvs[@]}; do + echo "nameserver ${i}" >> "${f}" + done + if [[ -n ${new_search} ]]; then + if [[ ${n_search} == "1" ]]; then + echo "domain${new_search}" >> "${f}" + else + echo "search${new_search}" >> "${f}" + fi + fi + mv "${f}" "${netdir}/resolv.conf" +} + + +# void merge_ntp() +# +# Merges the ntp.conf info from active interfaces +merge_ntp() { + local -a ifaces=( $(order_interfaces) ) + local i j f + + # We only work for ifaces with a ntp.conf + j=${#ifaces[@]} + for (( i=0; i<j; i++ )); do + [[ ! -e "${statedir}/${ifaces[i]}/ntp.conf" ]] && unset ifaces[i] + done + ifaces=( "${ifaces[@]}" ) + + # No point merging unless there are two or more interfaces + [[ ${#ifaces[@]} -lt 2 ]] && return + + veinfo "Merging ntp.conf from interfaces ${ifaces[@]}" + + local srvs + for (( i=0; i<${#ifaces[@]}; i++ )); do + f="${statedir}/${ifaces[i]}/ntp.conf" + srvs="${srvs} $( sed -n -e 's/^[ \t]*server[ \t]*\([^#]\)/\1/p' "${f}" )" + done + + # ntp does it's own preference list, so we just remove duplicates + sort_unique() { + set -- " ${@/%/\n}" + echo -e "$@" | sort -u + } + + srvs=$( sort_unique ${srvs} ) + + f="${netdir}/ntp.conf.$$" + echo "# Generated by net-scripts for interfaces ${ifaces[@]}" > "${f}" + chmod 644 "${f}" + + echo "restrict default noquery notrust nomodify" >> "${f}" + echo "restrict 127.0.0.1" >> "${f}" + + for i in ${srvs}; do + echo "restrict ${i} nomodify notrap noquery" >> "${f}" + echo "server ${i}" >> "${f}" + done + + echo "driftfile /var/lib/ntp/ntp.drift" >> "${f}" + echo "logfile /var/log/ntp.log" >> "${f}" + + mv "${f}" "${netdir}/ntp.conf" +} + +# void merge_configs() +# +# Merge config files together +merge_configs() { + merge_resolv + merge_ntp +} + +# char* select_best_interface() +# +# Selects the best interface to apply state information to +# This is currently based on routing metrics +select_best_interface() { + local -a ifs=( $(order_interfaces true) ) + + # We never select lo as the best interface + local x=" ${ifs[@]} " + ifs=( ${x// lo / } ) + + local iface + for iface in ${ifs[@]} ; do + if [[ -e "${statedir}/${iface}/resolv.conf" ]]; then + echo "${iface}" + return 0 + fi + done + + echo "${ifs[0]}" +} + +# int calculate_metric(char *interface) +# +# Calculates the best metric for the interface +# The Linux kernel does not use this at the moment, but we use it so that +# default routes remain and we can work out the "best" interface +calculate_metric() { + local iface="$1" exclude='$1!="Iface" && $1!="lo"' + + # Have we already got a metric? + local m=$( awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \ + /proc/net/route ) + if [[ -n ${m} ]]; then + echo "${m}" + return 0 + fi + + local itype=$( interface_type "${iface}" ) x i + + # If we're not a wireless device then exclude wireless from the + # routing table so we stay < 1000 + if [[ -e /proc/net/wireless ]]; then + if ! grep -q "^[ \t]*${iface}:[ \t]" /proc/net/wireless ; then + local i=$( sed -n -e 's/^[ \t]*\(.*\):.*/\1/p' /proc/net/wireless ) + for x in ${i} ; do + exclude="${exclude} && "'$1'"!=\"${x}\"" + done + fi + fi + + # Exclude ppp and ippp as well + local ix="ppp|ippp" + [[ ${itype} == "ppp" ]] && ix="ippp" + [[ ${itype} == "ippp" ]] && ix="ppp" + i=$( sed -n -e 's/^[ ]*\('${ix}'[0-9]*\):.*$/\1/p' /proc/net/dev ) + for x in ${i} ; do + exclude="${exclude} && "'$1'"!=\"${x}\"" + done + + local m=$( awk "${exclude} { print "'$7'" }" /proc/net/route \ + | sort -rn | head -n 1 | cut -d' ' -f2 ) + m="${m:--1}" + (( m ++ )) + + # If we're a wireless device then add 1000 so that wired interfaces take preference + if [[ -e /proc/net/wireless ]]; then + grep -q "^[ \t]*${iface}:[ \t]" /proc/net/wireless && (( m+= 1000 )) + fi + + # If we're a ppp device then we add 2000 for ISDN, otherwise 3000 + [[ ${itype} == "ippp" ]] && (( m+= 2000 )) + [[ ${itype} == "ppp" ]] && (( m+= 3000 )) + + echo "${m}" +} + +# int netmask2cidr(char *netmask) +# +# Returns the CIDR of a given netmask +netmask2cidr() { + local binary="" i bin + + for i in ${1//./ }; do + bin="" + while [[ ${i} != "0" ]]; do + bin=$[${i}%2]${bin} + (( i=i>>1 )) + done + binary="${binary}${bin}" + done + binary="${binary%%0*}" + echo "${#binary}" +} + +# char* netmask2cidr(int cidr) +# +# Returns the netmask of a given CIDR +cidr2netmask() { + local cidr="$1" netmask="" done=0 i sum=0 cur=128 + local octets frac + + (( octets=cidr/8 )) + (( frac=cidr%8 )) + while [[ octets -gt 0 ]]; do + netmask="${netmask}.255" + (( octets-- )) + (( done++ )) + done + + if [[ ${done} -lt 4 ]]; then + for (( i=0; i<${frac}; i++ )); do + (( sum+=cur )) + (( cur/=2 )) + done + netmask="${netmask}.${sum}" + (( done++ )) + + while [[ ${done} -lt 4 ]]; do + netmask="${netmask}.0" + (( done++ )) + done + fi + + echo "${netmask:1}" +} + +# char* ip_network(char *ip, char *netmask) +# +# Returns the network of the ip address +# ip can be 192.168.0.51/24 +# or +# ip can be 192.168.0.51 and netmask is 255.255.255.0 +ip_network() { + local ip="$1" mask="$2" i network x + + # If we didn't get parameter 2 then assume we have a CIDR + if [[ -z ${mask} ]]; then + mask="${ip##*/}" + [[ -z ${mask} || ${mask} == ${ip} ]] && return 1 + mask=$( cidr2netmask "${mask}" ) + ip="${ip%%/*}" + fi + + ip=( ${ip//./ } ) + mask=( ${mask//./ } ) + + for (( i=0; i<4; i++ )); do + (( x=ip[i] & mask[i] )) + network="${network}${x}" + [[ ${i} -lt 3 ]] && network="${network}." + done + + echo "${network}" +} + +# bool clean_pidfile(char *file) +# +# Removes the given pidfile if the process is not running +# Returns 1 if the process is still running otherwise 0 +clean_pidfile() { + local pidfile="$1" + + [[ ! -f ${pidfile} ]] && return 0 + local pid=$( < "${pidfile}" ) + + if [[ -n ${pid} ]]; then + local cmd="${pidfile##*/}" + cmd="${cmd%%-*}" + ps -p "${pid}" 2>/dev/null | grep -q "${cmd}" && return 1 + fi + + rm -f "${pidfile}" + return 0 +} + +# bool process_finished(int pid, char* cmd) +# +# We wait for 10 seconds until the command ${cmd} +# stops running on the process ${pid} +process_finished() { + local i pid="$1" cmd="$2" secs="${3:-9}" + + for (( i=0; i<secs; i++ )); do + ps -p "${pid}" 2>/dev/null | grep -q "${cmd}" || return 0 + sleep 1 + done + + return 1 +} + +# void function_wrap(char* source, char* target) +# +# wraps function calls - for example function_wrap(this, that) +# maps function names this_* to that_* +function_wrap() { + local i + + [[ $( type -t "${2}_provides" ) == "function" ]] && return + + for i in $( typeset -f | grep -o '^'"${1}"'_[^ ]*' ); do + eval "${2}${i#${1}}() { ${i} \"\$@\"; }" + done +} + +# char[] * expand_parameters(char *cmd) +# +# Returns an array after expanding parameters. For example +# "192.168.{1..3}.{1..3}/24 brd +" +# will return +# "192.168.1.1/24 brd +" +# "192.168.1.2/24 brd +" +# "192.168.1.3/24 brd +" +# "192.168.2.1/24 brd +" +# "192.168.2.2/24 brd +" +# "192.168.2.3/24 brd +" +# "192.168.3.1/24 brd +" +# "192.168.3.2/24 brd +" +# "192.168.3.3/24 brd +" +expand_parameters() { + local x="$( eval echo ${@// /_} )" + local -a a=( ${x} ) + + a=( "${a[@]/#/\"}" ) + a=( "${a[@]/%/\"}" ) + echo "${a[*]//_/ }" +} + +# void configure_variables(char *interface, char *option1, [char *option2]) +# +# Maps configuration options from <variable>_<option> to <variable>_<iface> +# option2 takes precedence over option1 +configure_variables() { + local iface="$1" option1="$2" option2="$3" + + local mod func x i + local -a ivars ovars1 ovars2 + local ifvar=$( bash_variable "${iface}" ) + + for mod in ${MODULES[@]}; do + func="${mod}_get_vars" + if [[ $( type -t ${func} ) == "function" ]]; then + ivars=( $( "${func}" "${ifvar}" ) ) + ovars1=( $( "${func}" "${option1}" ) ) + [[ -n ${option2} ]] && ovars2=( $( "${func}" "${option2}" ) ) + for ((i = 0; i<${#ivars[@]}; i++)); do + x="" + [[ -n ${ovars2[i]} ]] && eval x=( \"\$\{${ovars2[i]}\[@\]\}\" ) + [[ -z ${x} ]] && eval x=( \"\$\{${ovars1[i]}\[@\]\}\" ) + [[ -n ${x} ]] && eval "${ivars[i]}=( "\"\$\{x\[@\]\}\"" )" + done + fi + done + + return 0 +} + +# vim:ts=4 |