root@OpenWrt_D2550:/usr/lib/lua/luci# cat /etc/banner
_________
/ /\ _ ___ ___ ___
/ LE / \ | | | __| \| __|
/ DE / \ | |__| _|| |) | _|
/________/ LE \ |____|___|___/|___|
\ \ DE /
\ LE \ / -------------------------------------------
\ DE \ / OpenWrt SNAPSHOT, r4415-8f2b0b86b
\________\/ -------------------------------------------
(下图)openwrt luci 界面的备份是通过 lua 调用 sysupgrade 实现的。
sysupgrade help
root@OpenWrt_D2550:/usr/lib/lua/luci# sysupgrade --help
Usage: /sbin/sysupgrade [<upgrade-option>...] <image file or URL>
/sbin/sysupgrade [-q] [-i] [-c] [-u] [-o] [-k] <backup-command> <file>
upgrade-option:
-f <config> restore configuration from .tar.gz (file or url)
-i interactive mode
-c attempt to preserve all changed files in /etc/
-o attempt to preserve all changed files in /, except those
from packages but including changed confs.
-u skip from backup files that are equal to those in /rom
-n do not save configuration over reflash
-p do not attempt to restore the partition table after flash.
-k include in backup a list of current installed packages at
/etc/backup/installed_packages.txt
-T | --test
Verify image and config .tar.gz but do not actually flash.
-F | --force
Flash image even if image checks fail, this is dangerous!
-q less verbose
-v more verbose
-h | --help display this help
backup-command:
-b | --create-backup <file>
create .tar.gz of files specified in sysupgrade.conf
then exit. Does not flash an image. If file is '-',
i.e. stdout, verbosity is set to 0 (i.e. quiet).
-r | --restore-backup <file>
restore a .tar.gz created with sysupgrade -b
then exit. Does not flash an image. If file is '-',
the archive is read from stdin.
-l | --list-backup
list the files that would be backed up when calling
sysupgrade -b. Does not create a backup file.
至于 sysupgrade 是一个 shell 脚本(位置在
/sbin/sysupgrade
)(300行代码)引用了
. /lib/functions.sh . /lib/functions/system.sh . /usr/share/libubox/jshn.sh
# 备份的 luci 界面
图
源码在 /usr/lib/lua/luci/controller/admin/system.lua
看懂源码只需要明白openwrt的mvc架构
参考:【笔记】openwrt - luci开发(资料整理)
https://lawsssscat.blog.csdn.net/article/details/103609225
其中,每个按钮的 action 如下:
# 首页
entry({"admin", "system", "flashops"}, call("action_flashops"), _("Backup / Flash Firmware"), 70)
# 执行重置
entry({"admin", "system", "flashops", "reset"}, post("action_reset"))
# 生成备份
entry({"admin", "system", "flashops", "backup"}, post("action_backup"))
entry({"admin", "system", "flashops", "backupmtdblock"}, post("action_backupmtdblock"))
entry({"admin", "system", "flashops", "backupfiles"}, form("admin_system/backupfiles"))
# 上传备份(同时执行配置还原)
-- call() instead of post() due to upload handling!
entry({"admin", "system", "flashops", "restore"}, call("action_restore"))
entry({"admin", "system", "flashops", "sysupgrade"}, call("action_sysupgrade"))
entry({"admin", "system", "reboot"}, template("admin_system/reboot"), _("Reboot"), 90)
entry({"admin", "system", "reboot", "call"}, post("action_reboot"))
下面对每个 action 的操作流程进行分析
# 生成备份
图
源码
entry({"admin", "system", "flashops", "backup"}, post("action_backup"))
function action_backup()
local reader = ltn12_popen("sysupgrade --create-backup - 2>/dev/null")
luci.http.header(
'Content-Disposition', 'attachment; filename="backup-%s-%s.tar.gz"' %{
luci.sys.hostname(),
os.date("%Y-%m-%d")
})
luci.http.prepare_content("application/x-targz")
luci.ltn12.pump.all(reader, luci.http.write)
end
-- nixio api
-- https://github.com/openwrt/luci/blob/master/libs/luci-lib-nixio/docsrc/nixio.lua
function ltn12_popen(command)
local fdi, fdo = nixio.pipe()
local pid = nixio.fork()
if pid > 0 then
fdo:close()
local close
return function()
local buffer = fdi:read(2048)
local wpid, stat = nixio.waitpid(pid, "nohang")
if not close and wpid and stat == "exited" then
close = true
end
if buffer and #buffer > 0 then
return buffer
elseif close then
fdi:close()
return nil
end
end
elseif pid == 0 then
nixio.dup(fdo, nixio.stdout)
fdi:close()
fdo:close()
nixio.exec("/bin/sh", "-c", command)
end
end
主要的命令就是
sysupgrade --create-backup - 2>/dev/null
把备份的配置传到(-
)管道(pipe)中,然后通过http传到前端
这里,需要注意的是 sysupgrade 备份的内容。它会读文件 /etc/sysupgrade.conf
和 /lib/upgrade/keep.d/*
对里面声明的内容进行备份,因此,我们可以把自定义的备份内容写到前者 sysupgrade.conf 中
下面是源码
# /sbin/sysupgrade 中的方法
list_static_conffiles() {
local filter=$1
find $(sed -ne '/^[[:space:]]*$/d; /^#/d; p' \
/etc/sysupgrade.conf /lib/upgrade/keep.d/* 2>/dev/null) \
\( -type f -o -type l \) $filter 2>/dev/null
}
# 执行重置
源码
entry({"admin", "system", "flashops", "reset"}, post("action_reset"))
function action_reset()
if supports_reset() then
luci.template.render("admin_system/applyreboot", {
title = luci.i18n.translate("Erasing..."),
msg = luci.i18n.translate("The system is erasing the configuration partition now and will reboot itself when finished."),
addr = "192.168.1.1"
})
fork_exec("sleep 1; killall dropbear uhttpd; sleep 1; jffs2reset -y && reboot")
return
end
http.redirect(luci.dispatcher.build_url('admin/system/flashops'))
end
local function supports_reset()
return (os.execute([[grep -sq "^overlayfs:/overlay / overlay " /proc/mounts]]) == 0)
end
主要的命令是
jffs2reset -y
root@OpenWrt_D2550:~# jffs2reset
This will erase all settings and remove any installed packages. Are you sure? [N/y]
它是一个二进制文件,作用就是直接把 upper 层删了
关于 upper 层
参考:
【笔记】openwrt 扩容 overlay文件系统
https://lawsssscat.blog.csdn.net/article/details/105237099
另外这里,一般我们重置配置用的 firstboot
其实也是调用的 jffs2reset
root@OpenWrt_D2550:~# cat /sbin/firstboot
#!/bin/sh
/sbin/jffs2reset $@
# 定期备份
前面了解了 luci 的备份命令,就可以写我们自己的定期备份脚本了。