summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rcscripts/net.modules.d/helpers.d/functions')
-rw-r--r--lib/rcscripts/net.modules.d/helpers.d/functions526
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