functions.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. #!/bin/sh
  2. # Copyright (C) 2006-2013 OpenWrt.org
  3. # Copyright (C) 2006 Fokus Fraunhofer <[email protected]>
  4. # Copyright (C) 2010 Vertical Communications
  5. debug () {
  6. ${DEBUG:-:} "$@"
  7. }
  8. # newline
  9. N="
  10. "
  11. _C=0
  12. NO_EXPORT=1
  13. LOAD_STATE=1
  14. LIST_SEP=" "
  15. hotplug_dev() {
  16. env -i ACTION=$1 INTERFACE=$2 /sbin/hotplug-call net
  17. }
  18. append() {
  19. local var="$1"
  20. local value="$2"
  21. local sep="${3:- }"
  22. eval "export ${NO_EXPORT:+-n} -- \"$var=\${$var:+\${$var}\${value:+\$sep}}\$value\""
  23. }
  24. list_contains() {
  25. local var="$1"
  26. local str="$2"
  27. local val
  28. eval "val=\" \${$var} \""
  29. [ "${val%% $str *}" != "$val" ]
  30. }
  31. list_remove() {
  32. local var="$1"
  33. local remove="$2"
  34. local val
  35. eval "val=\" \${$var} \""
  36. val1="${val%% $remove *}"
  37. [ "$val1" = "$val" ] && return
  38. val2="${val##* $remove }"
  39. [ "$val2" = "$val" ] && return
  40. val="${val1## } ${val2%% }"
  41. val="${val%% }"
  42. eval "export ${NO_EXPORT:+-n} -- \"$var=\$val\""
  43. }
  44. config_load() {
  45. [ -n "$IPKG_INSTROOT" ] && return 0
  46. uci_load "$@"
  47. }
  48. reset_cb() {
  49. config_cb() { return 0; }
  50. option_cb() { return 0; }
  51. list_cb() { return 0; }
  52. }
  53. reset_cb
  54. package() {
  55. return 0
  56. }
  57. config () {
  58. local cfgtype="$1"
  59. local name="$2"
  60. export ${NO_EXPORT:+-n} CONFIG_NUM_SECTIONS=$(($CONFIG_NUM_SECTIONS + 1))
  61. name="${name:-cfg$CONFIG_NUM_SECTIONS}"
  62. append CONFIG_SECTIONS "$name"
  63. [ -n "$NO_CALLBACK" ] || config_cb "$cfgtype" "$name"
  64. export ${NO_EXPORT:+-n} CONFIG_SECTION="$name"
  65. export ${NO_EXPORT:+-n} "CONFIG_${CONFIG_SECTION}_TYPE=$cfgtype"
  66. }
  67. option () {
  68. local varname="$1"; shift
  69. local value="$*"
  70. export ${NO_EXPORT:+-n} "CONFIG_${CONFIG_SECTION}_${varname}=$value"
  71. [ -n "$NO_CALLBACK" ] || option_cb "$varname" "$*"
  72. }
  73. list() {
  74. local varname="$1"; shift
  75. local value="$*"
  76. local len
  77. config_get len "$CONFIG_SECTION" "${varname}_LENGTH" 0
  78. [ $len = 0 ] && append CONFIG_LIST_STATE "${CONFIG_SECTION}_${varname}"
  79. len=$(($len + 1))
  80. config_set "$CONFIG_SECTION" "${varname}_ITEM$len" "$value"
  81. config_set "$CONFIG_SECTION" "${varname}_LENGTH" "$len"
  82. append "CONFIG_${CONFIG_SECTION}_${varname}" "$value" "$LIST_SEP"
  83. list_cb "$varname" "$*"
  84. }
  85. config_rename() {
  86. local OLD="$1"
  87. local NEW="$2"
  88. local oldvar
  89. local newvar
  90. [ -n "$OLD" -a -n "$NEW" ] || return
  91. for oldvar in `set | grep ^CONFIG_${OLD}_ | \
  92. sed -e 's/\(.*\)=.*$/\1/'` ; do
  93. newvar="CONFIG_${NEW}_${oldvar##CONFIG_${OLD}_}"
  94. eval "export ${NO_EXPORT:+-n} \"$newvar=\${$oldvar}\""
  95. unset "$oldvar"
  96. done
  97. export ${NO_EXPORT:+-n} CONFIG_SECTIONS="$(echo " $CONFIG_SECTIONS " | sed -e "s, $OLD , $NEW ,")"
  98. [ "$CONFIG_SECTION" = "$OLD" ] && export ${NO_EXPORT:+-n} CONFIG_SECTION="$NEW"
  99. }
  100. config_unset() {
  101. config_set "$1" "$2" ""
  102. }
  103. config_clear() {
  104. local SECTION="$1"
  105. local oldvar
  106. list_remove CONFIG_SECTIONS "$SECTION"
  107. export ${NO_EXPORT:+-n} CONFIG_SECTIONS="${SECTION:+$CONFIG_SECTIONS}"
  108. for oldvar in `set | grep ^CONFIG_${SECTION:+${SECTION}_} | \
  109. sed -e 's/\(.*\)=.*$/\1/'` ; do
  110. unset $oldvar
  111. done
  112. }
  113. # config_get <variable> <section> <option> [<default>]
  114. # config_get <section> <option>
  115. config_get() {
  116. case "$3" in
  117. "") eval echo "\${CONFIG_${1}_${2}:-\${4}}";;
  118. *) eval export ${NO_EXPORT:+-n} -- "${1}=\${CONFIG_${2}_${3}:-\${4}}";;
  119. esac
  120. }
  121. # config_get_bool <variable> <section> <option> [<default>]
  122. config_get_bool() {
  123. local _tmp
  124. config_get _tmp "$2" "$3" "$4"
  125. case "$_tmp" in
  126. 1|on|true|enabled) _tmp=1;;
  127. 0|off|false|disabled) _tmp=0;;
  128. *) _tmp="$4";;
  129. esac
  130. export ${NO_EXPORT:+-n} "$1=$_tmp"
  131. }
  132. config_set() {
  133. local section="$1"
  134. local option="$2"
  135. local value="$3"
  136. local old_section="$CONFIG_SECTION"
  137. CONFIG_SECTION="$section"
  138. option "$option" "$value"
  139. CONFIG_SECTION="$old_section"
  140. }
  141. config_foreach() {
  142. local ___function="$1"
  143. [ "$#" -ge 1 ] && shift
  144. local ___type="$1"
  145. [ "$#" -ge 1 ] && shift
  146. local section cfgtype
  147. [ -z "$CONFIG_SECTIONS" ] && return 0
  148. for section in ${CONFIG_SECTIONS}; do
  149. config_get cfgtype "$section" TYPE
  150. [ -n "$___type" -a "x$cfgtype" != "x$___type" ] && continue
  151. eval "$___function \"\$section\" \"\$@\""
  152. done
  153. }
  154. config_list_foreach() {
  155. [ "$#" -ge 3 ] || return 0
  156. local section="$1"; shift
  157. local option="$1"; shift
  158. local function="$1"; shift
  159. local val
  160. local len
  161. local c=1
  162. config_get len "${section}" "${option}_LENGTH"
  163. [ -z "$len" ] && return 0
  164. while [ $c -le "$len" ]; do
  165. config_get val "${section}" "${option}_ITEM$c"
  166. eval "$function \"\$val\" \"\$@\""
  167. c="$(($c + 1))"
  168. done
  169. }
  170. insert_modules() {
  171. [ -d /etc/modules.d ] && {
  172. cd /etc/modules.d
  173. sed 's/^[^#]/insmod &/' $* | ash 2>&- || :
  174. }
  175. }
  176. include() {
  177. local file
  178. for file in $(ls $1/*.sh 2>/dev/null); do
  179. . $file
  180. done
  181. }
  182. find_mtd_index() {
  183. local PART="$(grep "\"$1\"" /proc/mtd | awk -F: '{print $1}')"
  184. local INDEX="${PART##mtd}"
  185. echo ${INDEX}
  186. }
  187. find_mtd_part() {
  188. local INDEX=$(find_mtd_index "$1")
  189. local PREFIX=/dev/mtdblock
  190. [ -d /dev/mtdblock ] && PREFIX=/dev/mtdblock/
  191. echo "${INDEX:+$PREFIX$INDEX}"
  192. }
  193. find_mtd_chardev() {
  194. local INDEX=$(find_mtd_index "$1")
  195. local PREFIX=/dev/mtd
  196. [ -d /dev/mtd ] && PREFIX=/dev/mtd/
  197. echo "${INDEX:+$PREFIX$INDEX}"
  198. }
  199. mtd_get_mac_ascii()
  200. {
  201. local mtdname="$1"
  202. local key="$2"
  203. local part
  204. local mac_dirty
  205. . /lib/functions.sh
  206. part=$(find_mtd_part "$mtdname")
  207. if [ -z "$part" ]; then
  208. echo "mtd_get_mac_ascii: partition $mtdname not found!" >&2
  209. return
  210. fi
  211. mac_dirty=$(strings "$part" | sed -n 's/'"$key"'=//p')
  212. # "canonicalize" mac
  213. printf "%02x:%02x:%02x:%02x:%02x:%02x" 0x${mac_dirty//:/ 0x}
  214. }
  215. mtd_get_mac_binary() {
  216. local mtdname="$1"
  217. local offset="$2"
  218. local part
  219. part=$(find_mtd_part "$mtdname")
  220. if [ -z "$part" ]; then
  221. echo "mtd_get_mac_binary: partition $mtdname not found!" >&2
  222. return
  223. fi
  224. dd bs=1 skip=$offset count=6 if=$part 2>/dev/null | hexdump -v -n 6 -e '5/1 "%02x:" 1/1 "%02x"'
  225. }
  226. macaddr_add() {
  227. local mac=$1
  228. local val=$2
  229. local oui=${mac%:*:*:*}
  230. local nic=${mac#*:*:*:}
  231. nic=$(printf "%06x" $((0x${nic//:/} + $val & 0xffffff)) | sed 's/^\(.\{2\}\)\(.\{2\}\)\(.\{2\}\)/\1:\2:\3/')
  232. echo $oui:$nic
  233. }
  234. macaddr_setbit_la()
  235. {
  236. local mac=$1
  237. printf "%02x:%s" $((0x${mac%%:*} | 0x02)) ${mac#*:}
  238. }
  239. macaddr_2bin()
  240. {
  241. local mac=$1
  242. echo -ne \\x${mac//:/\\x}
  243. }
  244. strtok() { # <string> { <variable> [<separator>] ... }
  245. local tmp
  246. local val="$1"
  247. local count=0
  248. shift
  249. while [ $# -gt 1 ]; do
  250. tmp="${val%%$2*}"
  251. [ "$tmp" = "$val" ] && break
  252. val="${val#$tmp$2}"
  253. export ${NO_EXPORT:+-n} "$1=$tmp"; count=$((count+1))
  254. shift 2
  255. done
  256. if [ $# -gt 0 -a -n "$val" ]; then
  257. export ${NO_EXPORT:+-n} "$1=$val"; count=$((count+1))
  258. fi
  259. return $count
  260. }
  261. jffs2_mark_erase() {
  262. local part="$(find_mtd_part "$1")"
  263. [ -z "$part" ] && {
  264. echo Partition not found.
  265. return 1
  266. }
  267. echo -e "\xde\xad\xc0\xde" | mtd -qq write - "$1"
  268. }
  269. uci_apply_defaults() {
  270. cd /etc/uci-defaults || return 0
  271. files="$(ls)"
  272. [ -z "$files" ] && return 0
  273. mkdir -p /tmp/.uci
  274. for file in $files; do
  275. ( . "./$(basename $file)" ) && rm -f "$file"
  276. done
  277. uci commit
  278. }
  279. group_add() {
  280. local name="$1"
  281. local gid="$2"
  282. local rc
  283. [ -f "${IPKG_INSTROOT}/etc/group" ] || return 1
  284. [ -n "$IPKG_INSTROOT" ] || lock /var/lock/group
  285. echo "${name}:x:${gid}:" >> ${IPKG_INSTROOT}/etc/group
  286. rc=$?
  287. [ -n "$IPKG_INSTROOT" ] || lock -u /var/lock/group
  288. return $rc
  289. }
  290. group_exists() {
  291. grep -qs "^${1}:" ${IPKG_INSTROOT}/etc/group
  292. }
  293. user_add() {
  294. local name="${1}"
  295. local uid="${2}"
  296. local gid="${3:-$2}"
  297. local desc="${4:-$1}"
  298. local home="${5:-/var/run/$1}"
  299. local shell="${6:-/bin/false}"
  300. local rc
  301. [ -f "${IPKG_INSTROOT}/etc/passwd" ] || return 1
  302. [ -n "$IPKG_INSTROOT" ] || lock /var/lock/passwd
  303. echo "${name}:x:${uid}:${gid}:${desc}:${home}:${shell}" >> ${IPKG_INSTROOT}/etc/passwd
  304. echo "${name}:x:0:0:99999:7:::" >> ${IPKG_INSTROOT}/etc/shadow
  305. rc=$?
  306. [ -n "$IPKG_INSTROOT" ] || lock -u /var/lock/passwd
  307. return $rc
  308. }
  309. user_exists() {
  310. grep -qs "^${1}:" ${IPKG_INSTROOT}/etc/passwd
  311. }
  312. pi_include() {
  313. if [ -f "/tmp/overlay/$1" ]; then
  314. . "/tmp/overlay/$1"
  315. elif [ -f "$1" ]; then
  316. . "$1"
  317. elif [ -d "/tmp/overlay/$1" ]; then
  318. if [ -n "$(ls /tmp/overlay/$1/*.sh 2>/dev/null)" ]; then
  319. for src_script in /tmp/overlay/$1/*.sh; do
  320. . "$src_script"
  321. done
  322. fi
  323. elif [ -d "$1" ]; then
  324. if [ -n "$(ls $1/*.sh 2>/dev/null)" ]; then
  325. for src_script in $1/*.sh; do
  326. . "$src_script"
  327. done
  328. fi
  329. else
  330. echo "WARNING: $1 not found"
  331. return 1
  332. fi
  333. return 0
  334. }
  335. boot_hook_splice_start() {
  336. export -n PI_HOOK_SPLICE=1
  337. }
  338. boot_hook_splice_finish() {
  339. local hook
  340. for hook in $PI_STACK_LIST; do
  341. local v; eval "v=\${${hook}_splice:+\$${hook}_splice }$hook"
  342. export -n "${hook}=${v% }"
  343. export -n "${hook}_splice="
  344. done
  345. export -n PI_HOOK_SPLICE=
  346. }
  347. boot_hook_init() {
  348. local hook="${1}_hook"
  349. export -n "PI_STACK_LIST=${PI_STACK_LIST:+$PI_STACK_LIST }$hook"
  350. export -n "$hook="
  351. }
  352. boot_hook_add() {
  353. local hook="${1}_hook${PI_HOOK_SPLICE:+_splice}"
  354. local func="${2}"
  355. [ -n "$func" ] && {
  356. local v; eval "v=\$$hook"
  357. export -n "$hook=${v:+$v }$func"
  358. }
  359. }
  360. boot_hook_shift() {
  361. local hook="${1}_hook"
  362. local rvar="${2}"
  363. local v; eval "v=\$$hook"
  364. [ -n "$v" ] && {
  365. local first="${v%% *}"
  366. [ "$v" != "${v#* }" ] && \
  367. export -n "$hook=${v#* }" || \
  368. export -n "$hook="
  369. export -n "$rvar=$first"
  370. return 0
  371. }
  372. return 1
  373. }
  374. boot_run_hook() {
  375. local hook="$1"
  376. local func
  377. while boot_hook_shift "$hook" func; do
  378. local ran; eval "ran=\$PI_RAN_$func"
  379. [ -n "$ran" ] || {
  380. export -n "PI_RAN_$func=1"
  381. $func "$1" "$2"
  382. }
  383. done
  384. }
  385. jffs2_ready() {
  386. mtdpart="$(find_mtd_part rootfs_data)"
  387. [ -z "$mtdpart" ] && return 1
  388. magic=$(hexdump $mtdpart -n 4 -e '4/1 "%02x"')
  389. [ "$magic" != "deadc0de" ]
  390. }
  391. dupe() { # <new_root> <old_root>
  392. cd $1
  393. echo -n "creating directories... "
  394. {
  395. cd $2
  396. find . -xdev -type d
  397. echo "./dev ./overlay ./mnt ./proc ./tmp"
  398. # xdev skips mounted directories
  399. cd $1
  400. } | xargs mkdir -p
  401. echo "done"
  402. echo -n "setting up symlinks... "
  403. for file in $(cd $2; find . -xdev -type f;); do
  404. case "$file" in
  405. ./rom/note) ;; #nothing
  406. ./etc/config*|\
  407. ./usr/lib/opkg/info/*) cp -af $2/$file $file;;
  408. *) ln -sf /rom/${file#./*} $file;;
  409. esac
  410. done
  411. for file in $(cd $2; find . -xdev -type l;); do
  412. cp -af $2/${file#./*} $file
  413. done
  414. echo "done"
  415. }
  416. pivot() { # <new_root> <old_root>
  417. mount -o noatime,move /proc $1/proc && \
  418. pivot_root $1 $1$2 && {
  419. mount -o noatime,move $2/dev /dev
  420. mount -o noatime,move $2/tmp /tmp
  421. mount -o noatime,move $2/sys /sys 2>&-
  422. mount -o noatime,move $2/overlay /overlay 2>&-
  423. return 0
  424. }
  425. }
  426. fopivot() { # <rw_root> <ro_root> <dupe?>
  427. root=$1
  428. {
  429. if grep -q overlay /proc/filesystems; then
  430. mount -o noatime,lowerdir=/,upperdir=$1 -t overlayfs "overlayfs:$1" /mnt && root=/mnt
  431. elif grep -q mini_fo /proc/filesystems; then
  432. mount -t mini_fo -o noatime,base=/,sto=$1 "mini_fo:$1" /mnt 2>&- && root=/mnt
  433. else
  434. mount --bind -o noatime / /mnt
  435. mount --bind -o noatime,union "$1" /mnt && root=/mnt
  436. fi
  437. } || {
  438. [ "$3" = "1" ] && {
  439. mount | grep "on $1 type" 2>&- 1>&- || mount -o noatime,bind $1 $1
  440. dupe $1 $rom
  441. }
  442. }
  443. pivot $root $2
  444. }
  445. ramoverlay() {
  446. mkdir -p /tmp/root
  447. mount -t tmpfs -o noatime,mode=0755 root /tmp/root
  448. fopivot /tmp/root /rom 1
  449. }
  450. [ -z "$IPKG_INSTROOT" -a -f /lib/config/uci.sh ] && . /lib/config/uci.sh