#!/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>/dev/null [[ ! ${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 # Append lo if it's up if grep -q "^lo[ \t]*" /proc/net/route ; then ifaces="${ifaces} lo" 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 "${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 [[ -n ${new_sortlist} ]] && echo "sortlist${new_sortlist}" >> "${f}" # We seperated the options out using # in our sed call above # so we set IFS here. If you do any spliting futher down in this function # then you will need to reset IFS. local IFS="#" for i in ${new_opts}; do [[ -n ${i# } ]] && echo "options ${i# }" >> "${f}" done 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 "${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) ) # Move lo to the back of the pecking order of it's active local x=" ${ifs[@]} " [[ ${x// lo / } != "${x}" ]] && ifs=( ${x// lo / } 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 # We only work for IPv4 addresses [[ ${ip} != *.*.*.* ]] && return # 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/dev/null | grep -q "${cmd}" || return 0 sleep 1 done return 1 } # bool is_function(char* name) # # Returns 0 if the given name is a shell function, otherwise 1 is_function() { [[ -z $1 ]] && return 1 [[ $(type -t "$1") == "function" ]] } # 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 is_function "${2}_depend" && 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 _