Chet Ramey wrote:
Maybe you should post your script so readers can take a look. It's
unlikely that there is a bug in here-documents, but it's possible.
----
If you ask for it... I "inlined" the needed library functions,
so should run standalone.
FWIW, this script DOES work interactively in normal operation.
Just when the system is in pre-single-user state and not
much in the way of resources is available that it blows.
Right now only have 'start' implemented, as there is little call
for deconstructing network configs when the system is going down.
'ifmap' by itself should show current eth-dev mappings.
Note, buried in this code are absolute numbers (MAC addrs),
so to test on another machine they would need to be changed.
Have intended to put "site-local" info in a config file, but
as it doesn't work....haven't spent alot of time on expanding it.
--- ifmap -------------------------------------------------------------
#!/bin/bash
### BEGIN INIT INFO
# Provides: net-devices
# Required-Start: boot.udev boot.device-mapper boot.localfs
# Required-Stop: $null
# Default-Start: B
# Default-Stop:
# Short-Description: order net devices
# Description: order net devs if needed
### END INIT INFO
#
# assign network names as rc-script
# L A Walsh, (free to use/modify/distribute to nice people) (c) 2013-2014
#
#include standard template:
# gvim=:SetNumberAndWidth
echo "assign_netif_names=$0 $@"
_prgpth=${0:?}; _prgpth=${_prgpth#-} _prg=${_prgpth##*/};
_prgdr=${_prgpth%/$_prg}
[[ -z $_prgdr || $_prg == $_prgdr ]] && _prgdr="$PWD"
#if ! typeset -f include >&/dev/null ;then
# source ${_LOCAL_DIR:=/etc/local}/bash_env.sh;
#fi
export PATH="/etc/local/bin:/etc/local/lib:$PATH"
export
PS4='>>${BASH_SOURCE:+${BASH_SOURCE[0]}}#${LINENO}${FUNCNAME:+(${FUNCNAME[0]})}> '
#include stdalias (needed entries included below)
shopt -s extglob expand_aliases
alias dcl=declare sub=function
alias int=dcl\ -i map=dcl\ -A hash=dcl\ -A array=dcl\ -a
alias lower=dcl\ -l upper=dcl\ -u string=dcl my=dcl
alias map2int=dcl\ -Ai intArray=dcl\ -ia
#include rc.status -- essential funcs included below:
int rc_status=0
sub rc_reset { rc_status=0; }
sub rc_status {
rc_status=$?;
if ((rc_status)) && { (($#)) && [[ $1 = -v ]] ; }; then
echo "Abnormal rc_status was $rc_status)."
elif (($#)) && [[ $1 = -v ]] ; then
echo "rc_status: ok"
fi
}
sub rc_exit {
rc_status=$?;
rc_status
exit $rc_status
}
# need to list commands here:
# modprobe
sub warn () { local msg="Warning: ${1:-"general"}"
echo "$msg" >&2
}
sub die () { int stat=$?; local msg="Error. ${1:-"unknown"}"
echo "$msg (errno=$stat)" >&2
(exit $stat);
rc_status -v
rc_exit
exit $stat
}
if [[ -z $(type -P modprobe) ]]; then
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:$PATH
fi
if [[ -n $(type -P modprobe) ]]; then
alias modprobe="$(type -P modprobe)"
else
#delay failure until use
alias modprobe="die 'cannot load required modules'"
fi
if [[ -z $(type -P ip ) ]]; then
die "Cannot find 'ip' util -- needed for network setup"
fi
alias ip="$(type -P ip)"
sub varflags() {
my var="${1:-""}"
read out <<<$(declare -p "$var" )
[[ $out =~ /^declare.*=.*$/ ]] || die "no such variable"
out="${out%% +([^-])=*}"
out="${out#declare }"
[[ ${out:0:1} == - ]] || { echo ""; return 0 ; }
echo "${out#-}"
}
sub isarray() {
my name="${1:-""}"
flags=$(varflags $name)
[[ $flags =~ a ]] && return 0
return 1
}
sub ipcmd () {
my ipcmd="${1:?}"; shift; array tmpbuff
my outbuff="${2:-tmpbuff}"
}
sysfs=/sys
sysnet=$sysfs/class/net
sys_modules=$sysfs/module
sub rev () {
(($#==0)) && { echo ""; return 0 ;}
my element=${1:?}; shift;
(($#==0)) && { echo "$element"; return 0;}
echo "$(rev "$@") $element"
}
sub rename_if () {
my old_name=${1:?} new_name=${2:?}
echo ip link set name "$new_name" dev "$old_name"
}
sub down_if () {
my if_name=${1:?}
echo ip link set down dev "$if_name"
}
sub set_links_down() { # can't operate on up links
down_if eth2 down
down_if eth3 down
down_if eth4 down
down_if eth5 down
}
map act_hw2if=() #actual values (to be read in)
map act_if2hw=()
map XIF=() #tmp array to hold exchanged IF's
##inline data (should be in external file)
map hw2if=( [00:15:17:bf:be:b2]=eth0 [00:15:17:bf:be:b3]=eth1
[00:26:b9:48:71:e2]=eth2 [00:26:b9:48:71:e4]=eth3
[a0:36:9f:15:c9:c0]=eth4 [a0:36:9f:15:c9:c2]=eth5 )
map if2hw=( [eth0]=00:15:17:bf:be:b2 [eth1]=00:15:17:bf:be:b3
[eth2]=00:26:b9:48:71:e2 [eth3]=00:26:b9:48:71:e4
[eth4]=a0:36:9f:15:c9:c0 [eth5]=a0:36:9f:15:c9:c2 )
#
#needed_drivers=(e1000e bnx2 ixgbe bonding)
needed_drivers=(e1000e bnx2 ixgbe)
sub vrfy_drivers () {
int errors=0;
for i in ${needed_drivers[@]} ; do
if [[ ! -d $sys_modules/$i ]]; then
modprobe "$i" || {
warn "Module $i is not in kernel and can't be loaded"
errors+=1
}
fi
done
return $errors
}
sub get_net_IFnames_hwaddrs () {
vrfy_drivers
array pseudo_devs=(br bond ifb team)
string pseudo_RE='^(?:'"$(echo "${pseudo_devs[@]}"|tr " " "|")"')\d+$'
string netdev_pat="+([_0-9a-z])+([0-9])"
( cd "$sysnet" &&
for nm in $(eval "echo $netdev_pat" | tr ' ' "\n" |
sort | grep -Pv "$pseudo_RE"); do
echo "$nm $(<$nm/address)"
done )
}
sub read_actuals () {
my ifname hwaddr
while read ifname hwaddr; do
printf "ifname=%s, hwaddr=%s\n" "$ifname" "$hwaddr"
act_hw2if["$hwaddr"]="$ifname"
act_if2hw["$ifname"]="$hwaddr"
done <<<"$(get_net_IFnames_hwaddrs)"
}
sub ifaddr_cmd () {
if ((${#act_hw2if[@]:-0}==0)) ;then read_actuals; fi
my hwaddr
for ifname in $(printf "%s\n" "${act_hw2if[@]}"|sort|tr "\n" " ") ; do
my first_ifn="$ifname"
if [[ $ifname =~ \+ ]] ; then
first_ifn="${ifname%%+*}"
fi
printf "%s\t%s\n" "$ifname" "${act_if2hw["$first_ifn"]}"
done
}
sub ifmap_cmd () {
ifaddr_cmd "$@"
}
sub remap_cmd () {
if ((${#act_hw2if[@]}==0)); then read_actuals; fi
my key ifname
int count=0
map XIF act_hw2if act_if2hw
array ifnames=$(printf "%s\n" "${!if2hw[@]}"|sort|
grep -P '^[^~+]*$' |tr "\n" " ")
array rev_ifns=($(rev "${ifnames[@]}" ))
for key in "${rev_ifns[@]}"; do
int is_regex=0;
ifname="$key"
if [[ ${key:0:1} == ~ ]];then ifname=${key:1}; is_regex=1; fi
my hwaddr="${if2hw["$key"]:-""}"
my actual_hw="${act_if2hw["$ifname"]:-""}"
my actual_if="${act_hw2if["$actual_hw"]:-""}" ##line 233
if [[ ${actual_hw:-""} && ! $actual_hw =~ \+ ]]; then ##
if ((is_regex)); then [[ $actual_hw =~ $hwaddr ]] && continue
else [[ $actual_hw == $hwaddr ]] && continue; fi
if [[ ! ${act_if2hw["$ifname"]:-} ]]; then
#Nobody has the name, use it
down_if "$actual_hw"
rename_if "$actual_hw" "$ifname" ; count+=1
else
rename_if "$actual_if" "X$ifname"; #don't count temp renames 2x
XIF["X$ifname"]="$hwaddr"
fi
fi
done
if ((${#XIF[@]}==0)); then
echo "HW interfaces appear to be in order."; return 0; fi
int count=0
for ifname in "${!XIF[@]}"; do
hwaddr=${XIF[$ifname]};
ifname=${ifname#X}
my destname=${hw2if[$hwaddr]}
rename_if "$ifname" "$destname" ; count+=1
done
printf "%d interface%s renamed\n" $count "$( (($count!=1)) && echo "s" )"
}
sub start_cmd () {
remap_cmd "$@"
}
hash switches=([ifmap]=1 [remap]=1 [start]=1)
sub help () {
echo "$_prg:"
echo "Options: ifmap - show current hw# -> IF map"
echo " remap - verify & remap ifnames if needed"
return 1
}
if (($#)) ; then
dcl op="${1#:-}"
if [[ ${switches[$op]:-} ]]; then
cmd="${op}_cmd"
shift
$cmd "$@"
else
echo "Unknown switch :-$op"
fi
else
help
fi