本文简述了openwrt sdk的升级功能流程,从页面传入升级文件到升级文件检测,再到调用升级脚本进行升级,升级完成后,进行系统重启。最后简述了如何添加升级文件标识,标识包括自己定义的字段,以及升级软件的md5值。达到防止用户用其他openwrt sdk编译出来的固件刷新我们的系统,以及防止升级软件被破坏。

需要用到的文件及在sdk中的路径(某些文件路径可能随项目的不同而改动):

./package/ralink/ui/luci-mtk/src/modules/admin-full/luasrc/controller/admin/system.lua

./target/linux/ramips/image/ Makefile

./package/base-files/files/lib/upgrade/common.sh

./package/base-files/files/lib/functions.sh

./package/base-files/files/sbin/sysupgrade

./target/linux/ramips/base-files/lib/ramips.sh

./target/linux/ramips/base-files/lib/upgrade/platform.sh

sysupgrade脚本:

[html]  view plain  copy
  1. #!/bin/sh
  2. . /lib/functions.sh
  3. # initialize defaults
  4. RAMFS_COPY_BIN=""   # extra programs for temporary ramfs root
  5. RAMFS_COPY_DATA=""  # extra data files
  6. export INTERACTIVE=0
  7. export VERBOSE=1
  8. export SAVE_CONFIG=1
  9. export SAVE_OVERLAY=0
  10. export DELAY=
  11. export CONF_IMAGE=
  12. export CONF_BACKUP_LIST=0
  13. export CONF_BACKUP=
  14. export CONF_RESTORE=
  15. export NEED_IMAGE=
  16. export HELP=0
  17. export FORCE=0
  18. export TEST=0
  19. # parse options
  20. while [ -n "$1" ]; do
  21. case "$1" in
  22. -i) export INTERACTIVE=1;;
  23. -d) export DELAY="$2"; shift;;
  24. -v) export VERBOSE="$(($VERBOSE + 1))";;
  25. -q) export VERBOSE="$(($VERBOSE - 1))";;
  26. -n) export SAVE_CONFIG=0;;
  27. -c) export SAVE_OVERLAY=1;;
  28. -b|--create-backup) export CONF_BACKUP="$2" NEED_IMAGE=1; shift;;
  29. -r|--restore-backup) export CONF_RESTORE="$2" NEED_IMAGE=1; shift;;
  30. -l|--list-backup) export CONF_BACKUP_LIST=1; break;;
  31. -f) export CONF_IMAGE="$2"; shift;;
  32. -F|--force) export FORCE=1;;
  33. -T|--test) export TEST=1;;
  34. -h|--help) export HELP=1; break;;
  35. -*)
  36. echo "Invalid option: $1"
  37. exit 1
  38. ;;
  39. *) break;;
  40. esac
  41. shift;
  42. done
  43. export CONFFILES=/tmp/sysupgrade.conffiles
  44. export CONF_TAR=/tmp/sysupgrade.tgz
  45. export ARGV="$*"
  46. export ARGC="$#"
  47. [ -z "$ARGV" -a -z "$NEED_IMAGE" -o $HELP -gt 0 ] && {
  48. cat <<EOF
  49. Usage: $0 [<upgrade-option>...] <image file or URL>
  50. $0 [-q] [-i] <backup-command> <file>
  51. upgrade-option:
  52. -d <delay>   add a delay before rebooting
  53. -f <config>  restore configuration from .tar.gz (file or url)
  54. -i           interactive mode
  55. -c           attempt to preserve all changed files in /etc/
  56. -n           do not save configuration over reflash
  57. -T | --test
  58. Verify image and config .tar.gz but do not actually flash.
  59. -F | --force
  60. Flash image even if image checks fail, this is dangerous!
  61. -q           less verbose
  62. -v           more verbose
  63. -h | --help  display this help
  64. backup-command:
  65. -b | --create-backup <file>
  66. create .tar.gz of files specified in sysupgrade.conf
  67. then exit. Does not flash an image. If file is '-',
  68. i.e. stdout, verbosity is set to 0 (i.e. quiet).
  69. -r | --restore-backup <file>
  70. restore a .tar.gz created with sysupgrade -b
  71. then exit. Does not flash an image. If file is '-',
  72. the archive is read from stdin.
  73. -l | --list-backup
  74. list the files that would be backed up when calling
  75. sysupgrade -b. Does not create a backup file.
  76. EOF
  77. exit 1
  78. }
  79. [ -n "$ARGV" -a -n "$NEED_IMAGE" ] && {
  80. cat <<-EOF
  81. -b|--create-backup and -r|--restore-backup do not perform a firmware upgrade.
  82. Do not specify both -b|-r and a firmware image.
  83. EOF
  84. exit 1
  85. }
  86. # prevent messages from clobbering the tarball when using stdout
  87. [ "$CONF_BACKUP" = "-" ] && export VERBOSE=0
  88. add_uci_conffiles() {
  89. local file="$1"
  90. ( find $(sed -ne '/^[[:space:]]*$/d; /^#/d; p' \
  91. /etc/sysupgrade.conf /lib/upgrade/keep.d/* 2>/dev/null) \
  92. -type f 2>/dev/null;
  93. opkg list-changed-conffiles ) | sort -u > "$file"
  94. return 0
  95. }
  96. add_overlayfiles() {
  97. local file="$1"
  98. find /overlay/etc/ -type f | sed \
  99. -e 's,^/overlay/,/,' \
  100. -e '\,/META_[a-zA-Z0-9]*$,d' \
  101. -e '\,/functions.sh$,d' \
  102. -e '\,/[^/]*-opkg$,d' \
  103. > "$file"
  104. return 0
  105. }
  106. # hooks
  107. sysupgrade_image_check="platform_check_image"
  108. [ $SAVE_OVERLAY = 0 -o ! -d /overlay/etc ] && \
  109. sysupgrade_init_conffiles="add_uci_conffiles" || \
  110. sysupgrade_init_conffiles="add_overlayfiles"
  111. include /lib/upgrade
  112. do_save_conffiles() {
  113. local conf_tar="${1:-$CONF_TAR}"
  114. [ -z "$(rootfs_type)" ] && {
  115. echo "Cannot save config while running from ramdisk."
  116. ask_bool 0 "Abort" && exit
  117. return 0
  118. }
  119. run_hooks "$CONFFILES" $sysupgrade_init_conffiles
  120. ask_bool 0 "Edit config file list" && vi "$CONFFILES"
  121. v "Saving config files..."
  122. [ "$VERBOSE" -gt 1 ] && TAR_V="v" || TAR_V=""
  123. tar c${TAR_V}zf "$conf_tar" -T "$CONFFILES" 2>/dev/null
  124. rm -f "$CONFFILES"
  125. }
  126. if [ $CONF_BACKUP_LIST -eq 1 ]; then
  127. add_uci_conffiles "$CONFFILES"
  128. cat "$CONFFILES"
  129. rm -f "$CONFFILES"
  130. exit 0
  131. fi
  132. if [ -n "$CONF_BACKUP" ]; then
  133. do_save_conffiles "$CONF_BACKUP"
  134. exit $?
  135. fi
  136. if [ -n "$CONF_RESTORE" ]; then
  137. if [ "$CONF_RESTORE" != "-" ] && [ ! -f "$CONF_RESTORE" ]; then
  138. echo "Backup archive '$CONF_RESTORE' not found."
  139. exit 1
  140. fi
  141. [ "$VERBOSE" -gt 1 ] && TAR_V="v" || TAR_V=""
  142. tar -C / -x${TAR_V}zf "$CONF_RESTORE"
  143. exit $?
  144. fi
  145. type platform_check_image >/dev/null 2>/dev/null || {
  146. echo "Firmware upgrade is not implemented for this platform."
  147. exit 1
  148. }
  149. for check in $sysupgrade_image_check; do
  150. ( eval "$check \"\$ARGV\"" ) || {
  151. if [ $FORCE -eq 1 ]; then
  152. echo "Image check '$check' failed but --force given - will update anyway!"
  153. break
  154. else
  155. echo "Image check '$check' failed."
  156. exit 1
  157. fi
  158. }
  159. done
  160. if [ -n "$CONF_IMAGE" ]; then
  161. case "$(get_magic_word $CONF_IMAGE cat)" in
  162. # .gz files
  163. 1f8b) ;;
  164. *)
  165. echo "Invalid config file. Please use only .tar.gz files"
  166. exit 1
  167. ;;
  168. esac
  169. get_image "$CONF_IMAGE" "cat" > "$CONF_TAR"
  170. export SAVE_CONFIG=1
  171. elif ask_bool $SAVE_CONFIG "Keep config files over reflash"; then
  172. [ $TEST -eq 1 ] || do_save_conffiles
  173. export SAVE_CONFIG=1
  174. else
  175. export SAVE_CONFIG=0
  176. fi
  177. if [ $TEST -eq 1 ]; then
  178. exit 0
  179. fi
  180. #run_hooks "" $sysupgrade_pre_upgrade
  181. ubus call system upgrade
  182. touch /tmp/sysupgrade
  183. kill_remaining TERM
  184. sleep 3
  185. kill_remaining KILL
  186. if [ -n "$(rootfs_type)" ]; then
  187. v "Switching to ramdisk..."
  188. run_ramfs '. /lib/functions.sh; include /lib/upgrade; do_upgrade'
  189. else
  190. do_upgrade
  191. fi

1.从页面接受传过来的升级文件

作为整个流程的开始,功能实现在文件system.lua中。

这是一个lua文件,很容易在function index函数中找到系统升级功能的入口函数:action_flashops。在这个函数中首先通过fp = io.open(image_tmp, "w")打开升级临时文件:/tmp/firmware.img,打开后通过fp:write(chunk)写入页面传进来的升级文件。到这里,接受升级文件完成 。

2.检测升级文件的合法性

实现同样在文件system.lua中。

在函数image_supported()中进行检测,这个函数通过image magic number来检测升级文件是否合法。函数image_supported()会调用platform.sh脚本中的platform_check_image函数,

platform_check_image函数调用ramips.sh脚本中的ramips_board_name函数,获取boardname,ramips_board_name函数从文件 /tmp/sysinfo/board_name 中获取board name,若没有则为unknown,并返回给调用者,我用的板是ralink-soc。platform_check_image函数继续调用common.sh脚本中的get_magic_long函数,用以获取升级文件magic,就是升级文件前4位。get_magic_long函数调用common.sh脚本中的get_image函数用以获取文件/tmp/firmware.img内容,其实就是cat /tmp/firmware.img. 获取到的内容,通过dd bs=4count=1,来获取前4位,最后通过hexdump -v -n 4 -e '1/1 "%02x"'处理以十六进制编码返回调用者。获取到的升级文件magic,在platform_check_image函数中与27051956做对比,这个值是在固件编译的时候已经定好了的。如果相等,就是合法的升级文件,继续升级动作;不相等则为非法升级文件,做一些后续处理并终止升级动作。到这里检测升级文件合法性完成。

3.检测升级文件不合法后的处理

实现同样在文件system.lua中。

检测到不合法后,通过nixio.fs.unlink(image_tmp)来删除临时文件/tmp/firmware.img,并通过image_invalid= true,设置检测失败,用以通知页面显示提示信息。终止升级。处理完成。

4.检测升级文件合法后的处理

实现同样在文件system.lua中。

检测到升级文件合法后,会获取一些升级文件相关的信息,用以在页面显示:调用image_checksum(),获取checksum;调用storage_size(),获取可用空间大小;调用nixio.fs.stat(image_tmp).size,获取升级文件大小;以及页面传过来的是否保存配置的值;其中,image_checksum()函数用的是md5sum命令,storage_size()函数是在系统文件/proc/mtd中找到firmware分区大小。

接下来如果用户选择进行升级文件,则会现在页面上打印一些提示信息,用于提示用户:正在升级,不要断开电源等等。

文件system.lua最后的处理就是调用升级脚本:fork_exec("killall dropbear uhttpd; sleep 1; /sbin/sysupgrade%s %q" %{ keep, image_tmp })。

这条语句,先清除dropbear 和uhttpd进程,再等待1秒,最后调用升级脚本sysupgrade,传过去的参数就是keep:是否要保存配置;image_tmp:升级文件/tmp/firmware.img。

OK,到这里system.lua文件中关于升级前的准备工作都完成了,视线请转到升级脚本sysupgrade上。

5.运行升级脚本

实现在文件sysupgrade中。

脚本开始,像所有的主体处理程序一样,会对传进来的参数进行处理。下面对这些参数的介绍:

-i       开启交互模式

-d      重启前延迟,延迟秒数是传进来的

-v      会打印sysupgrade脚本中的一些信息,脚本中默认打印

-q      与-v相反

-n      升级后不保存配置,默认保存配置

-c      保存所有的改动配置文件到/etc/

-b      用sysupgrade.conf中指定的文件,创建.tar.gz格式备份文件

-r      用上步创建的.tar.gz文件,恢复配置

-l       列出将会备份的文件列表

-f       从.tar.gz恢复配置

-F      即使升级文件检测失败,也要升级,这个参数是危险的,慎用

-T      验证升级文件和.tar.gz配置文件,但不升级

-h      打印帮助信息

这些参数的使用在脚本中都有介绍,不再多讲。

接下来:[ -z "$ARGV" -a -z "$NEED_IMAGE" -o $HELP -gt 0],意思是:如果没有升级文件参数,且没有命令行参数-b(create-backup),-r(restore-backup),或者带有-h(help)参数,则打印帮助信息。这个条件为真的话,会在终端打印帮助信息,退出脚本。

接下来:[ -n "$ARGV" -a -n "$NEED_IMAGE" ],意思是:不要指定-b或-r(创建配置、恢复配置)的同时,指定升级文件。为真的话,打印提示信息,退出脚本。

接下来:[ "$CONF_BACKUP" = "-" ] && exportVERBOSE=0,意思是:选择备份配置但传进来的文件为“-”时,不打印备份文件时的过程。

下面展示一下-v选项的作用:

带-v时的升级过程:

root@OpenWrt:/# sysupgrade -i -v/tmp/firmware.img

Keep config files over reflash (Y/n): y

Edit config file list (y/N): n

Saving config files...

etc/config/dhcp

etc/config/dropbear

etc/config/firewall

etc/config/fstab

etc/config/luci

etc/config/network

etc/config/system

etc/config/ucitrack

etc/config/uhttpd

etc/config/wireless

etc/dropbear/dropbear_dss_host_key

etc/dropbear/dropbear_rsa_host_key

etc/group

etc/hosts

etc/inittab

etc/passwd

etc/profile

etc/rc.local

etc/shells

etc/sysctl.conf

Sending TERM to remaining processes ...dnsmasq ubusd btnd logd netifd uhttpd ntpd

Sending KILL to remaining processes ...

Switching to ramdisk...

Performing system upgrade...

Unlocking firmware ...

Writing from <stdin> to firmware...

Appending jffs2 data from/tmp/sysupgrade.tgz to firmware...

Writing from <stdin> to firmware...

Upgrade completed

Reboot (Y/n):

不带-v时的升级过程:

root@OpenWrt:/# sysupgrade -i/tmp/firmware.img

Keep config files over reflash (Y/n): y

Edit config file list (y/N): n

Saving config files...

Sending TERM to remaining processes ...dnsmasq ubusd btnd logd netifd uhttpd ntpd

Sending KILL to remaining processes ...

Switching to ramdisk...

Performing system upgrade...

Unlocking firmware ...

Writing from <stdin> to firmware...

Appending jffs2 data from/tmp/sysupgrade.tgz to firmware...

Writing from <stdin> to firmware...

Upgrade completed

Reboot (Y/n):

继续分析:

if [ $CONF_BACKUP_LIST -eq 1 ]; then

add_uci_conffiles"$CONFFILES"

cat"$CONFFILES"

rm-f "$CONFFILES"

exit0

fi

如果需要列出配置文件列表,就调用add_uci_conffiles函数生成列表,并打印到终端。函数add_uci_conffiles(),找出需要保存的配置文件。通过在文件/etc/sysupgrade.conf中,/lib/upgrade/keep.d/*目录下,以及命令opkg list-changed-conffiles的输出中,找出配置 文件,其中opkg list-changed-conffiles列出用户修改的配置文件。

接下来:

if [ -n "$CONF_BACKUP" ];then

do_save_conffiles"$CONF_BACKUP"

exit$?

fi

如果需要创建配置备份文件,则调用函数do_save_conffiles,生成配置文件。函数do_save_conffiles(),打包上一部列出的配置文件 。

接下来:

if [ -n "$CONF_RESTORE" ]; then###需要恢复配置

if[ "$CONF_RESTORE" != "-" ] && [ ! -f"$CONF_RESTORE" ]; then ###判断所需要的配置文件是否存在

echo"Backup archive '$CONF_RESTORE' not found."

exit1

fi

["$VERBOSE" -gt 1 ] && TAR_V="v" ||TAR_V=""

tar-C / -x${TAR_V}zf "$CONF_RESTORE"

exit$?

fi

经过一些判断,解压配置文件包。

接下来:

type platform_check_image,检测platform_check_image命令是否存在,为了 下步做准备。找不到的话,脚本 退出,升级终止。

接下来:

for check in $sysupgrade_image_check;

do( eval "$check\"\$ARGV\"" ) || {  ###通过board name 和image magicnumber来判断升级文件是否合法

if [ $FORCE -eq 1 ]; then  ####检测失败了,但是因为设置了-F选项,强制升级,停止检测

echo"Image check '$check' failed but --force given - will update anyway!"

break

else   ###检测失败,且不要求强制升级,脚本退出,停止升级

echo"Image check '$check' failed."

exit1

fi

}

done

做升级文件的检测,$sysupgrade_image_check就是platform_check_image,这个 检测在升级开始的 时候,已经做过了 ,这里又做了一遍。如果检测失败了,但是设置了-F选项,强制升级,如果没设置,就脚本退出,停止升级。

接下来:

if [ -n "$CONF_IMAGE" ];then  ####需要从文件中恢复配置

case"$(get_magic_word $CONF_IMAGE cat)" in   ####获取文件内容,并拷贝2个字节,且转换为16进制输出

#.gz files

1f8b);;  ###检测文件失败,退出脚本,停止升级

*)

echo"Invalid config file. Please use only .tar.gz files"

exit1

;;

esac

get_image"$CONF_IMAGE" "cat" > "$CONF_TAR"

exportSAVE_CONFIG=1

elif ask_bool $SAVE_CONFIG "Keepconfig files over reflash"; then ###默认升级保存配置

[$TEST -eq 1 ] || do_save_conffiles

exportSAVE_CONFIG=1

else

exportSAVE_CONFIG=0

fi

这段的意思是,如果需要从文件中恢复配置,就开始处理。这个文件是从命令行参数中传进来的。get_magic_word函数在文件common.sh中,这个函数与前面所讲的get_magic_long函数实现基本一样,所不同的是get_magic_word函数利用dd bs=2 count=1,获取头2个字节,而不是4个。

接下来“

if [ $TEST -eq 1 ]; then

exit0

fi

这段的意思是:如果设置了-T选项,因为只是做了升级文件和.tar.gz配置文件的检测,不需要升级,脚本退出,停止升级。

接下来:

run_hooks ""$sysupgrade_pre_upgrade

这句的意思是:运行函数sysupgrade_pre_upgrade。先介绍下run_hooks函数,定义在文件common.sh中。

run_hooks() {

localarg="$1"; shift

forfunc in "$@"; do

eval"$func $arg"

done

}

run_hooks函数是钩子函数,其中传过来的第一个参数是函数运行的参数,其余参数为要运行的函数。

再介绍sysupgrade_pre_upgrade函数。定义在platform.sh文件中。

#append sysupgrade_pre_upgrade  disable_watchdog

disable_watchdog() {

killallwatchdog

(ps | grep -v 'grep' | grep '/dev/watchdog' ) && {

echo'Could not disable watchdog'

return1

}

}

其实就是在升级前,去清除watchdog进程。不过这个函数被注释掉了,所以不用管。

接下来:

ubus call system upgrade

openwrt ubus:为了在OpenWrt中提供守护进程和应用程序间的通讯,开发了ubus项目工程。它包含了守护进程、库以及一些额外的帮助程序。

核心部分是ubusd守护进程,它提供了其他守护进程将自己注册以及发送消息的接口。因为这个,接口通过使用Unixsocket来实现,并使用TLV(type-length-value)消息。

用法:Usage: ubus [<options>] <command> [arguments...]

这句的意思是:调用注册到ubus进程的system路径下的update方法,update方法设置了upgrade_running变量值为1,使得在ubus上注册的服务退出时无需等待。

接下来:

kill_remaining TERM

sleep3

kill_remainingKILL

kill_remaining函数,这个函数定义在common.sh文件中,就是发送信号给一些应用层进程。

用以升级前清除进程。

接下来:

run_ramfs '. /lib/functions.sh; include/lib/upgrade; do_upgrade'

是sysupgrade脚本的最后一句。也是开始升级的地方。

run_ramfs函数定义在common.sh文件中,先是安装一些命令到/tmp/root下,再在/tmp/root下构建一个临时文件系统。最后调用exec /bin/busybox ash -c "$*",来调用do_upgrade函数。do_upgrade函数调用platform_do_upgrade函数,platform_do_upgrade函数调用default_do_upgrade函数。

default_do_upgrade() {

sync

if[ "$SAVE_CONFIG" -eq 1 ]; then

get_image"$1" | mtd $MTD_CONFIG_ARGS -j "$CONF_TAR" write -"${PART_NAME:-image}"

else

get_image"$1" | mtd write - "${PART_NAME:-image}"

fi

}

介绍一下这个函数,sync命令的作用是,将有关文件系统的存储器常驻信息送入物理介质内,以确保文件系统的完整性。然后就是根据是否需要保存配置去分别调用mtd命令,去完成升级。

接下来:

v "Upgrade completed"

[-n "$DELAY" ] && sleep "$DELAY"

ask_bool1 "Reboot" && {

v"Rebooting system..."

reboot-f

sleep5

echob 2>/dev/null >/proc/sysrq-trigger

升级完了,需要重启了。整个升级流程到这里,就完成了。

6.添加升级文件标识以及升级文件md5值

功能很简单,就是在升级文件前添加一个自定义的字段,以及升级软件的md5值。用以阻止刷机,以及升级文件被破坏。字段以及md5值添加在编译时进行的。字段、md5值取出,是在升级文件检测时进行的。

添加字段:

在Makefile(路径前面已经列出)文件中,最后生成升级文件的地方添加。

define MkImageSysupgrade/squashfs

$(evaloutput_name=$(IMG_PREFIX)-$(2)-$(1)-$(if $(4),$(4),sysupgrade).bin)

$(evaloutput_name_tmp=$(IMG_PREFIX)-$(2)-$(1)-$(if $(4),$(4),sysupgrade_tmp).bin)

cat$(KDIR)/vmlinux-$(2).uImage $(KDIR)/root.$(1) > $(KDIR)/$(output_name)

$(callprepare_generic_squashfs,$(KDIR)/$(output_name))

if[ `stat -c%s "$(KDIR)/$(output_name)"` -gt $(3) ]; then \

echo"Warning: $(KDIR)/$(output_name) is too big" >&2; \

else\

$(CP)$(KDIR)/$(output_name) $(BIN_DIR)/$(output_name_tmp); \

fi

+echo "100msh" > $(BIN_DIR)/mykey

+md5sum $(BIN_DIR)/$(output_name_tmp) | cut -d ' ' -f 1 >>$(BIN_DIR)/mykey

+cat $(BIN_DIR)/mykey $(BIN_DIR)/$(output_name_tmp) >$(BIN_DIR)/$(output_name)

+rm -rf $(BIN_DIR)/$(output_name_tmp)

+rm -rf $(BIN_DIR)/mykey

endef行前有+号的地方就是添加的代码。添加了”100msh“字段在升级文件前。

字段取出:

get_image() { # <source> [<command> ]

localfrom="$1"

localconc="$2"

localcmd

case"$from" in

http://*|ftp://*)cmd="wget -O- -q";;

*)cmd="cat";;

esac

if[ -z "$conc" ]; then

localmagic="$(eval $cmd $from 2>/dev/null | dd bs=2 count=1 2>/dev/null |hexdump -n 2 -e '1/1 "%02x"')"

case"$magic" in

1f8b)conc="zcat";;

425a)conc="bzcat";;

esac

fi

+eval "$cmd $from 2>/dev/null ${conc:+| $conc} > /tmp/myupfile"

+head -n 1 /tmp/myupfile > /tmp/check

+grep -q "100msh" /tmp/check &&

+ {

+  echo "OK" >/tmp/ok

+ }||

+  {

+ echo "Illegal platform" > /tmp/nok

+ exit 1

+  }

+sed -i "1d" /tmp/myupfile

+head -n 1 /tmp/myupfile > /tmp/check

+sed -i "1d" /tmp/myupfile

+md5sum /tmp/myupfile | cut -d ' ' -f 1 > /tmp/mymd5

+diff -r /tmp/check /tmp/mymd5

+if [ $? -ne 0 ] ; then

+ echo different

+ exit 1

+fi

+rm -rf /tmp/check  /tmp/mymd5

+cat /tmp/myupfile

+ }

行前有+号的地方,就是添加的代码。就是取出第一行,其他不变。

另外default_do_upgrade()函数中的get_image "$1",修改成cat /tmp/myupfile,因为在调用default_do_upgrade()函数时,get_image函数中有些命令已经不能再用。

openwrt web升级功能介绍相关推荐

  1. 安信可蓝牙模块TB系列实现远程OTA无线升级功能介绍,剖析整个实现原理和代码介绍。

    文章目录 一.BLE FOTA简介 二.BLE SLAVE FOTA实现流程 通过手机APP 完成BLE设备的OTA演示 联系我们 一.BLE FOTA简介 BLE SLAVE设备除了有线升级(比如串 ...

  2. 安信可PB-01/02蓝牙模组实现远程OTA无线升级功能介绍,剖析整个实现原理和代码介绍。

    文章目录 一.安信可PB-01/02蓝牙模组 OTA简介 二.安信可PB-01/02蓝牙模组 FOTA实现流程 三.通过手机APP 完成安信可PB-01/02蓝牙模组的OTA演示 联系我们 一.安信可 ...

  3. android10新功能,三星A80升级安卓10 更新One UI 2.0内容新功能介绍

    三星A80升级安卓10 更新One UI 2.0内容新功能介绍 据网友反馈,三星现已面向Galaxy A80用户推送One UI 2.0更新,升级Android 10. 此外,三星Galaxy A80 ...

  4. 阿里云播放器SDK的正确打开方式 | Aliplayer Web播放器介绍及功能实现(三)

    阿里云播放器SDK(ApsaraVideo for Player SDK)是阿里视频云端到云到端服务的重要一环,除了支持点播和直播的基础播放功能外,还深度融合视频云业务,支持视频的加密播放.安全下载. ...

  5. LayIM 3.9.1与ASP.NET SignalR实现Web聊天室快速入门(四)之ASP.NET SignalR核心功能介绍

    前言 本系列文章特点:使用ASP.NET SignalR和LayIM快速入门对接,实现一对一聊天,群聊,添加聊天群组,查找聊天记录等功能.源代码不包含LayIM的源代码,因为官方并没开源属于收费资源, ...

  6. 事业单位人事招聘考务管理系统+功能介绍+HRSaaS软件系统服务平台+系统5.0版升级上线

    一)系统介绍 系统简述 品格科技系统服务于事业单位人事招聘考试业务,覆盖人事招聘.考务管理.人才储备整套业务体系的SaaS软件系统,系统基于目前业界的云计算技术开发. 系统包含招聘公告发布.网上报名. ...

  7. web短信系统平台软件搭建后台功能介绍|移讯云短信系统

    国际短信系统平台软件搭建后台功能介绍|移讯云短信系统 平台外放接口介绍 支持接入CMPP接口,支持smpp通道接入,支持外放CMPP接口(其他平台可以通过CMPP接入我平台),支持HTTP API J ...

  8. 邮件服务器轻松组建 友旺MG1200功能介绍

    免费邮箱缺乏稳定性,并且受垃圾邮件的侵扰,使得越来越多的企业认识到自己假设公司邮件服务器的重要性,友旺科技的MG1200/MG2400的诞生正是为了满足架设完全专属于企业或机关的邮件服务器,不需再使用 ...

  9. docker omv 防火墙_我的软路由折腾之旅 篇三:在openmediavault上通过Docker实现OPENWRT旁路由功能...

    我的软路由折腾之旅 篇三:在openmediavault上通过Docker实现OPENWRT旁路由功能 2020-06-20 11:28:38 57点赞 415收藏 74评论 你是AMD Yes党?还 ...

最新文章

  1. 开源 免费 java CMS - FreeCMS-标签 channelList .
  2. Redis在C#中的使用及Redis的封装
  3. c语言 获得回车按键控制输入法,android调用输入软键盘回车键跟删除键
  4. 防火墙如可禁止tracert但允许ping
  5. @所有人,20 万大奖待领取!【全民找“BUG”】活动,等你!
  6. 常用API-2(字符串与数组)
  7. php join a.id b.id,mysql,sql_MySQL A left join B on B.cid=A.id 左链接查询失败,求解,mysql,sql - phpStudy...
  8. Jibx Jersey2集成
  9. 背景图片生成网站收集
  10. numpy维度交换_如何将2个不同维度的numpy数组相乘
  11. [转载] 算法竞赛中的JAVA使用笔记
  12. Delphi/C#之父:Anders Hejlsberg
  13. 收藏 | 损失函数实现数据扩增
  14. Linux内存管理之内存寻址:分段机制的实现方式
  15. C语言和设计模式(继承、封装、多态)
  16. 技术沙龙|实力赋能开发者,助力企业从容应对数字化转型难题
  17. 宝马i3自动停泊技术
  18. 在aws云将本地虚拟机镜像上传
  19. AcWing 860. 染色法判定二分图 (染色法)
  20. cloud云技术简介

热门文章

  1. 苏州新导化工厂人员定位系统功能真的如此强大?当然强大,定位准确
  2. arduino驱动LD3320语音识别模块
  3. 21秋期末考试工程项目管理10324k2 (2)
  4. 寒假每日一题 1 : 笨拙的手指 java
  5. JVM面试题整理-Java内存区域与内存溢出异常、垃圾收集器和内存分配策略
  6. Android FMRadio上层调试
  7. 手把手教你架设电影服务器
  8. 如何优雅地在Stack OverFlow 上进行编程问题搜索
  9. 这个高仿小米商城项目太惊艳了
  10. elementUI输入框只能输入数字解决方案