openwrtv3/package/base-files/files/lib/functions.sh
Gabor Juhos b7914344ad base-files: add macaddr_canonicalize helper function
In commit r38690, the MAC address canonicalization
has been converted to use 'tr' instead of 'printf'.
This only works if with MAC addresses which uses
the 'xx:xx:xx:xx:xx:xx' format.

However on some boards, the MAC addresses are stored
in different format in the mtd partition. Some vendors
are using hyphens or dots as separators instead of
colons. Also the leading zeroes may be missing from the
individual octets or those are replaced with spaces.

Add a new function which can be used to convert these
into the 'xx:xx:xx:xx:xx:xx' format. Also update the
'mtd_get_mac_ascii' function to use the new helper.

The helper function is based on this code:
  http://isquared.nl/blog/2010/08/11/Bash-function-to-canonicalize-MAC-addresses/

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>

SVN-Revision: 38803
2013-11-14 17:44:42 +00:00

587 lines
12 KiB
Bash
Executable file

#!/bin/sh
# Copyright (C) 2006-2013 OpenWrt.org
# Copyright (C) 2006 Fokus Fraunhofer <carsten.tittel@fokus.fraunhofer.de>
# Copyright (C) 2010 Vertical Communications
debug () {
${DEBUG:-:} "$@"
}
# newline
N="
"
_C=0
NO_EXPORT=1
LOAD_STATE=1
LIST_SEP=" "
hotplug_dev() {
env -i ACTION=$1 INTERFACE=$2 /sbin/hotplug-call net
}
append() {
local var="$1"
local value="$2"
local sep="${3:- }"
eval "export ${NO_EXPORT:+-n} -- \"$var=\${$var:+\${$var}\${value:+\$sep}}\$value\""
}
list_contains() {
local var="$1"
local str="$2"
local val
eval "val=\" \${$var} \""
[ "${val%% $str *}" != "$val" ]
}
list_remove() {
local var="$1"
local remove="$2"
local val
eval "val=\" \${$var} \""
val1="${val%% $remove *}"
[ "$val1" = "$val" ] && return
val2="${val##* $remove }"
[ "$val2" = "$val" ] && return
val="${val1## } ${val2%% }"
val="${val%% }"
eval "export ${NO_EXPORT:+-n} -- \"$var=\$val\""
}
config_load() {
[ -n "$IPKG_INSTROOT" ] && return 0
uci_load "$@"
}
reset_cb() {
config_cb() { return 0; }
option_cb() { return 0; }
list_cb() { return 0; }
}
reset_cb
package() {
return 0
}
config () {
local cfgtype="$1"
local name="$2"
export ${NO_EXPORT:+-n} CONFIG_NUM_SECTIONS=$(($CONFIG_NUM_SECTIONS + 1))
name="${name:-cfg$CONFIG_NUM_SECTIONS}"
append CONFIG_SECTIONS "$name"
[ -n "$NO_CALLBACK" ] || config_cb "$cfgtype" "$name"
export ${NO_EXPORT:+-n} CONFIG_SECTION="$name"
export ${NO_EXPORT:+-n} "CONFIG_${CONFIG_SECTION}_TYPE=$cfgtype"
}
option () {
local varname="$1"; shift
local value="$*"
export ${NO_EXPORT:+-n} "CONFIG_${CONFIG_SECTION}_${varname}=$value"
[ -n "$NO_CALLBACK" ] || option_cb "$varname" "$*"
}
list() {
local varname="$1"; shift
local value="$*"
local len
config_get len "$CONFIG_SECTION" "${varname}_LENGTH" 0
[ $len = 0 ] && append CONFIG_LIST_STATE "${CONFIG_SECTION}_${varname}"
len=$(($len + 1))
config_set "$CONFIG_SECTION" "${varname}_ITEM$len" "$value"
config_set "$CONFIG_SECTION" "${varname}_LENGTH" "$len"
append "CONFIG_${CONFIG_SECTION}_${varname}" "$value" "$LIST_SEP"
list_cb "$varname" "$*"
}
config_rename() {
local OLD="$1"
local NEW="$2"
local oldvar
local newvar
[ -n "$OLD" -a -n "$NEW" ] || return
for oldvar in `set | grep ^CONFIG_${OLD}_ | \
sed -e 's/\(.*\)=.*$/\1/'` ; do
newvar="CONFIG_${NEW}_${oldvar##CONFIG_${OLD}_}"
eval "export ${NO_EXPORT:+-n} \"$newvar=\${$oldvar}\""
unset "$oldvar"
done
export ${NO_EXPORT:+-n} CONFIG_SECTIONS="$(echo " $CONFIG_SECTIONS " | sed -e "s, $OLD , $NEW ,")"
[ "$CONFIG_SECTION" = "$OLD" ] && export ${NO_EXPORT:+-n} CONFIG_SECTION="$NEW"
}
config_unset() {
config_set "$1" "$2" ""
}
config_clear() {
local SECTION="$1"
local oldvar
list_remove CONFIG_SECTIONS "$SECTION"
export ${NO_EXPORT:+-n} CONFIG_SECTIONS="${SECTION:+$CONFIG_SECTIONS}"
for oldvar in `set | grep ^CONFIG_${SECTION:+${SECTION}_} | \
sed -e 's/\(.*\)=.*$/\1/'` ; do
unset $oldvar
done
}
# config_get <variable> <section> <option> [<default>]
# config_get <section> <option>
config_get() {
case "$3" in
"") eval echo "\${CONFIG_${1}_${2}:-\${4}}";;
*) eval export ${NO_EXPORT:+-n} -- "${1}=\${CONFIG_${2}_${3}:-\${4}}";;
esac
}
# config_get_bool <variable> <section> <option> [<default>]
config_get_bool() {
local _tmp
config_get _tmp "$2" "$3" "$4"
case "$_tmp" in
1|on|true|enabled) _tmp=1;;
0|off|false|disabled) _tmp=0;;
*) _tmp="$4";;
esac
export ${NO_EXPORT:+-n} "$1=$_tmp"
}
config_set() {
local section="$1"
local option="$2"
local value="$3"
local old_section="$CONFIG_SECTION"
CONFIG_SECTION="$section"
option "$option" "$value"
CONFIG_SECTION="$old_section"
}
config_foreach() {
local ___function="$1"
[ "$#" -ge 1 ] && shift
local ___type="$1"
[ "$#" -ge 1 ] && shift
local section cfgtype
[ -z "$CONFIG_SECTIONS" ] && return 0
for section in ${CONFIG_SECTIONS}; do
config_get cfgtype "$section" TYPE
[ -n "$___type" -a "x$cfgtype" != "x$___type" ] && continue
eval "$___function \"\$section\" \"\$@\""
done
}
config_list_foreach() {
[ "$#" -ge 3 ] || return 0
local section="$1"; shift
local option="$1"; shift
local function="$1"; shift
local val
local len
local c=1
config_get len "${section}" "${option}_LENGTH"
[ -z "$len" ] && return 0
while [ $c -le "$len" ]; do
config_get val "${section}" "${option}_ITEM$c"
eval "$function \"\$val\" \"\$@\""
c="$(($c + 1))"
done
}
insert_modules() {
[ -d /etc/modules.d ] && {
cd /etc/modules.d
sed 's/^[^#]/insmod &/' $* | ash 2>&- || :
}
}
include() {
local file
for file in $(ls $1/*.sh 2>/dev/null); do
. $file
done
}
find_mtd_index() {
local PART="$(grep "\"$1\"" /proc/mtd | awk -F: '{print $1}')"
local INDEX="${PART##mtd}"
echo ${INDEX}
}
find_mtd_part() {
local INDEX=$(find_mtd_index "$1")
local PREFIX=/dev/mtdblock
[ -d /dev/mtdblock ] && PREFIX=/dev/mtdblock/
echo "${INDEX:+$PREFIX$INDEX}"
}
find_mtd_chardev() {
local INDEX=$(find_mtd_index "$1")
local PREFIX=/dev/mtd
[ -d /dev/mtd ] && PREFIX=/dev/mtd/
echo "${INDEX:+$PREFIX$INDEX}"
}
mtd_get_mac_ascii()
{
local mtdname="$1"
local key="$2"
local part
local mac_dirty
part=$(find_mtd_part "$mtdname")
if [ -z "$part" ]; then
echo "mtd_get_mac_ascii: partition $mtdname not found!" >&2
return
fi
mac_dirty=$(strings "$part" | sed -n 's/^'"$key"'=//p')
# "canonicalize" mac
[ -n "$mac_dirty" ] && macaddr_canonicalize "$mac_dirty"
}
mtd_get_mac_binary() {
local mtdname="$1"
local offset="$2"
local part
part=$(find_mtd_part "$mtdname")
if [ -z "$part" ]; then
echo "mtd_get_mac_binary: partition $mtdname not found!" >&2
return
fi
dd bs=1 skip=$offset count=6 if=$part 2>/dev/null | hexdump -v -n 6 -e '5/1 "%02x:" 1/1 "%02x"'
}
mtd_get_part_size() {
local part_name=$1
local first dev size erasesize name
while read dev size erasesize name; do
name=${name#'"'}; name=${name%'"'}
if [ "$name" = "$part_name" ]; then
echo $((0x$size))
break
fi
done < /proc/mtd
}
macaddr_add() {
local mac=$1
local val=$2
local oui=${mac%:*:*:*}
local nic=${mac#*:*:*:}
nic=$(printf "%06x" $((0x${nic//:/} + $val & 0xffffff)) | sed 's/^\(.\{2\}\)\(.\{2\}\)\(.\{2\}\)/\1:\2:\3/')
echo $oui:$nic
}
macaddr_setbit_la()
{
local mac=$1
printf "%02x:%s" $((0x${mac%%:*} | 0x02)) ${mac#*:}
}
macaddr_2bin()
{
local mac=$1
echo -ne \\x${mac//:/\\x}
}
macaddr_canonicalize()
{
local mac="$1"
local canon=""
[ ${#mac} -gt 17 ] && return
[ -n "${mac//[a-fA-F0-9\.: -]/}" ] && return
for octet in ${mac//[\.:-]/ }; do
case "${#octet}" in
1)
octet="0${octet}"
;;
2)
;;
4)
octet="${octet:0:2} ${octet:2:2}"
;;
12)
octet="${octet:0:2} ${octet:2:2} ${octet:4:2} ${octet:6:2} ${octet:8:2} ${octet:10:2}"
;;
*)
return
;;
esac
canon=${canon}${canon:+ }${octet}
done
[ ${#canon} -ne 17 ] && return
printf "%02x:%02x:%02x:%02x:%02x:%02x" 0x${canon// / 0x} 2>/dev/null
}
strtok() { # <string> { <variable> [<separator>] ... }
local tmp
local val="$1"
local count=0
shift
while [ $# -gt 1 ]; do
tmp="${val%%$2*}"
[ "$tmp" = "$val" ] && break
val="${val#$tmp$2}"
export ${NO_EXPORT:+-n} "$1=$tmp"; count=$((count+1))
shift 2
done
if [ $# -gt 0 -a -n "$val" ]; then
export ${NO_EXPORT:+-n} "$1=$val"; count=$((count+1))
fi
return $count
}
jffs2_mark_erase() {
local part="$(find_mtd_part "$1")"
[ -z "$part" ] && {
echo Partition not found.
return 1
}
echo -e "\xde\xad\xc0\xde" | mtd -qq write - "$1"
}
uci_apply_defaults() {
cd /etc/uci-defaults || return 0
files="$(ls)"
[ -z "$files" ] && return 0
mkdir -p /tmp/.uci
for file in $files; do
( . "./$(basename $file)" ) && rm -f "$file"
done
uci commit
}
group_add() {
local name="$1"
local gid="$2"
local rc
[ -f "${IPKG_INSTROOT}/etc/group" ] || return 1
[ -n "$IPKG_INSTROOT" ] || lock /var/lock/group
echo "${name}:x:${gid}:" >> ${IPKG_INSTROOT}/etc/group
rc=$?
[ -n "$IPKG_INSTROOT" ] || lock -u /var/lock/group
return $rc
}
group_exists() {
grep -qs "^${1}:" ${IPKG_INSTROOT}/etc/group
}
user_add() {
local name="${1}"
local uid="${2}"
local gid="${3:-$2}"
local desc="${4:-$1}"
local home="${5:-/var/run/$1}"
local shell="${6:-/bin/false}"
local rc
[ -f "${IPKG_INSTROOT}/etc/passwd" ] || return 1
[ -n "$IPKG_INSTROOT" ] || lock /var/lock/passwd
echo "${name}:x:${uid}:${gid}:${desc}:${home}:${shell}" >> ${IPKG_INSTROOT}/etc/passwd
echo "${name}:x:0:0:99999:7:::" >> ${IPKG_INSTROOT}/etc/shadow
rc=$?
[ -n "$IPKG_INSTROOT" ] || lock -u /var/lock/passwd
return $rc
}
user_exists() {
grep -qs "^${1}:" ${IPKG_INSTROOT}/etc/passwd
}
pi_include() {
if [ -f "/tmp/overlay/$1" ]; then
. "/tmp/overlay/$1"
elif [ -f "$1" ]; then
. "$1"
elif [ -d "/tmp/overlay/$1" ]; then
if [ -n "$(ls /tmp/overlay/$1/*.sh 2>/dev/null)" ]; then
for src_script in /tmp/overlay/$1/*.sh; do
. "$src_script"
done
fi
elif [ -d "$1" ]; then
if [ -n "$(ls $1/*.sh 2>/dev/null)" ]; then
for src_script in $1/*.sh; do
. "$src_script"
done
fi
else
echo "WARNING: $1 not found"
return 1
fi
return 0
}
boot_hook_splice_start() {
export -n PI_HOOK_SPLICE=1
}
boot_hook_splice_finish() {
local hook
for hook in $PI_STACK_LIST; do
local v; eval "v=\${${hook}_splice:+\$${hook}_splice }$hook"
export -n "${hook}=${v% }"
export -n "${hook}_splice="
done
export -n PI_HOOK_SPLICE=
}
boot_hook_init() {
local hook="${1}_hook"
export -n "PI_STACK_LIST=${PI_STACK_LIST:+$PI_STACK_LIST }$hook"
export -n "$hook="
}
boot_hook_add() {
local hook="${1}_hook${PI_HOOK_SPLICE:+_splice}"
local func="${2}"
[ -n "$func" ] && {
local v; eval "v=\$$hook"
export -n "$hook=${v:+$v }$func"
}
}
boot_hook_shift() {
local hook="${1}_hook"
local rvar="${2}"
local v; eval "v=\$$hook"
[ -n "$v" ] && {
local first="${v%% *}"
[ "$v" != "${v#* }" ] && \
export -n "$hook=${v#* }" || \
export -n "$hook="
export -n "$rvar=$first"
return 0
}
return 1
}
boot_run_hook() {
local hook="$1"
local func
while boot_hook_shift "$hook" func; do
local ran; eval "ran=\$PI_RAN_$func"
[ -n "$ran" ] || {
export -n "PI_RAN_$func=1"
$func "$1" "$2"
}
done
}
jffs2_ready() {
mtdpart="$(find_mtd_part rootfs_data)"
[ -z "$mtdpart" ] && return 1
magic=$(hexdump $mtdpart -n 4 -e '4/1 "%02x"')
[ "$magic" != "deadc0de" ]
}
dupe() { # <new_root> <old_root>
cd $1
echo -n "creating directories... "
{
cd $2
find . -xdev -type d
echo "./dev ./overlay ./mnt ./proc ./tmp"
# xdev skips mounted directories
cd $1
} | xargs mkdir -p
echo "done"
echo -n "setting up symlinks... "
for file in $(cd $2; find . -xdev -type f;); do
case "$file" in
./rom/note) ;; #nothing
./etc/config*|\
./usr/lib/opkg/info/*) cp -af $2/$file $file;;
*) ln -sf /rom/${file#./*} $file;;
esac
done
for file in $(cd $2; find . -xdev -type l;); do
cp -af $2/${file#./*} $file
done
echo "done"
}
pivot() { # <new_root> <old_root>
mount -o noatime,move /proc $1/proc && \
pivot_root $1 $1$2 && {
mount -o noatime,move $2/dev /dev
mount -o noatime,move $2/tmp /tmp
mount -o noatime,move $2/sys /sys 2>&-
mount -o noatime,move $2/overlay /overlay 2>&-
return 0
}
}
fopivot() { # <rw_root> <ro_root> <dupe?>
root=$1
{
if grep -q overlay /proc/filesystems; then
mount -o noatime,lowerdir=/,upperdir=$1 -t overlayfs "overlayfs:$1" /mnt && root=/mnt
elif grep -q mini_fo /proc/filesystems; then
mount -t mini_fo -o noatime,base=/,sto=$1 "mini_fo:$1" /mnt 2>&- && root=/mnt
else
mount --bind -o noatime / /mnt
mount --bind -o noatime,union "$1" /mnt && root=/mnt
fi
} || {
[ "$3" = "1" ] && {
mount | grep "on $1 type" 2>&- 1>&- || mount -o noatime,bind $1 $1
dupe $1 $rom
}
}
pivot $root $2
}
ramoverlay() {
mkdir -p /tmp/root
mount -t tmpfs -o noatime,mode=0755 root /tmp/root
fopivot /tmp/root /rom 1
}
[ -z "$IPKG_INSTROOT" -a -f /lib/config/uci.sh ] && . /lib/config/uci.sh