221 lines
6.6 KiB
Bash
Executable File
221 lines
6.6 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
TMP_SELF_COPY=/var/run/cloned-overlay-backup
|
|
|
|
action=${1}
|
|
shift
|
|
|
|
has_overlay() {
|
|
[ -d "/overlay/upper" ] || return 1
|
|
[ "overlay" = "$(/bin/mount | awk '($3 ~ /^\/$/) && ($5 !~ /rootfs/) { print $5 }')" ] || return 1
|
|
|
|
return 0
|
|
}
|
|
|
|
has_ext_overlay() {
|
|
[ -d "/ext_overlay/upper" ] || return 1
|
|
grep '^overlayfs:/overlay / ' /proc/mounts | grep -Fq 'upperdir=/ext_overlay/upper' || return 1
|
|
|
|
return 0
|
|
}
|
|
|
|
backup() {
|
|
if ! has_overlay; then
|
|
echo "only supports squashfs firmware"
|
|
exit 1
|
|
fi
|
|
if [ -z "$1" ]; then
|
|
echo "input backup path is null"
|
|
exit 1
|
|
fi
|
|
local BACKUP_PATH="$1"
|
|
|
|
if echo "$BACKUP_PATH" | grep -q -e '^/overlay/upper' -e '^/ext_overlay/upper' ; then
|
|
echo "can not backup to /overlay/upper, /ext_overlay/upper"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -d "${BACKUP_PATH}" ] && ! mkdir -p "${BACKUP_PATH}" ; then
|
|
echo "backup path does not exist and can not be create"
|
|
exit 1
|
|
fi
|
|
|
|
local realpath="$(cd "${BACKUP_PATH}"; pwd -P)"
|
|
if [ -z "$realpath" ]; then
|
|
echo "cannot get absolute path of ${BACKUP_PATH}"
|
|
exit 1
|
|
fi
|
|
|
|
local mountpoint=$(findmnt -T $realpath -o TARGET | sed -n 2p)
|
|
# while read -r; do
|
|
# if [[ "x$realpath" == "x$REPLY" || "x${realpath#$REPLY/}" != "x$realpath" ]]; then
|
|
# mountpoint="$REPLY"
|
|
# break
|
|
# fi
|
|
# done < <(
|
|
# cat /proc/mounts | grep -v '^overlay ' | awk 'NR>1 {print $2}' | grep -v '^/$' | \
|
|
# sort -u | \
|
|
# while read -r; do printf "%b\n" "$REPLY" ; done | \
|
|
# awk '{print length, $0}' | sort -nr | cut -d' ' -f2-
|
|
# )
|
|
|
|
if [ "/" = "$mountpoint" ]; then
|
|
echo "can not backup to /"
|
|
exit 1
|
|
else
|
|
echo "found mount point $mountpoint"
|
|
fi
|
|
|
|
local filename_suffix=
|
|
local tar_extra_args=
|
|
if has_ext_overlay; then
|
|
tar_extra_args="$tar_extra_args ext_overlay/upper"
|
|
filename_suffix="${filename_suffix}.s"
|
|
fi
|
|
|
|
local hostname=$(cat /proc/sys/kernel/hostname)
|
|
local fwver=$(. /etc/openwrt_release; echo $DISTRIB_ID-$DISTRIB_RELEASE)
|
|
|
|
local date=$(date +%Y-%m%d-%H%M)
|
|
local backup_name="backup_overlay_${hostname}_${fwver}_${date}${filename_suffix}.overlay.tar.gz"
|
|
local backup_full_path="$BACKUP_PATH/$backup_name"
|
|
echo "writing backup to $backup_full_path"
|
|
if tar -C / -cz overlay/upper $tar_extra_args > "$backup_full_path" ; then
|
|
sync "$BACKUP_PATH"
|
|
echo "backup success"
|
|
return 0
|
|
else
|
|
rm -f "$backup_full_path"
|
|
echo "backup failed"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
patch_sandbox_device() {
|
|
local overlay="$1"
|
|
local ucidir="$overlay/upper/etc/config"
|
|
local uci_section=$(uci -c "$ucidir" -q show fstab | grep '^fstab\.@mount\[[0-9]*\]\.target='"'/overlay'\$" | head -1 | grep -o '^fstab\.@mount\[[0-9]*\]')
|
|
if [ -n "$uci_section" ]; then
|
|
if [ "x1" = "x$(uci -c "$ucidir" get "$uci_section.enabled")" ]; then
|
|
uci -c "$ucidir" -q delete "$uci_section.uuid"
|
|
uci -c "$ucidir" -q delete "$uci_section.label"
|
|
uci -c "$ucidir" -q delete "$uci_section.device"
|
|
if [ -n "$SANDBOX_UUID" ]; then
|
|
uci -c "$ucidir" set "$uci_section.uuid=$SANDBOX_UUID"
|
|
elif [ -n "$SANDBOX_LABEL" ]; then
|
|
uci -c "$ucidir" set "$uci_section.label=$SANDBOX_LABEL"
|
|
else
|
|
uci -c "$ucidir" set "$uci_section.device=$SANDBOX_DEVICE"
|
|
fi
|
|
uci -c "$ucidir" commit fstab
|
|
echo "found and patched $overlay"
|
|
return 0
|
|
fi
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
restore() {
|
|
if ! has_overlay; then
|
|
echo "only supports squashfs firmware"
|
|
exit 1
|
|
fi
|
|
if [ -z "$1" ]; then
|
|
echo "input backup path is null"
|
|
exit 1
|
|
fi
|
|
local BACKUP_PATH_FILE="$1"
|
|
|
|
if [ ! -f "${BACKUP_PATH_FILE}" ]; then
|
|
echo "invalid backup file, can not restore"
|
|
exit 1
|
|
fi
|
|
|
|
# prevent uci cache
|
|
rm -rf /var/run/uci
|
|
|
|
local tar_extra_args=overlay/upper
|
|
if has_ext_overlay; then
|
|
tar_extra_args=
|
|
local uuid label device line
|
|
local uci_section=$(uci -c /overlay/upper/etc/config show fstab | grep '^fstab\.@mount\[[0-9]*\]\.target='"'/overlay'\$" | head -1 | grep -o '^fstab\.@mount\[[0-9]*\]')
|
|
while read line; do
|
|
export -n "$line"
|
|
done < <(
|
|
uci -c /overlay/upper/etc/config show "$uci_section" | sed -e '/^fstab\.[^\.]*=/d' -e 's/^fstab\.[^\.]*\.//g' | grep -e '^uuid=' -e '^label=' -e '^device=' | sed "s/'//g"
|
|
)
|
|
SANDBOX_UUID=$uuid
|
|
SANDBOX_LABEL=$label
|
|
SANDBOX_DEVICE=$device
|
|
fi
|
|
|
|
sync /
|
|
echo "restoring from ${BACKUP_PATH_FILE}"
|
|
if tar -C / -xz $tar_extra_args < "${BACKUP_PATH_FILE}" ; then
|
|
if [ -n "$SANDBOX_UUID" -o -n "$SANDBOX_LABEL" -o -n "$SANDBOX_DEVICE" ]; then
|
|
echo "patch sandbox device ${SANDBOX_UUID}${SANDBOX_LABEL}${SANDBOX_DEVICE}"
|
|
patch_sandbox_device /overlay && patch_sandbox_device /ext_overlay
|
|
fi
|
|
sync /overlay /ext_overlay
|
|
echo "restore success"
|
|
echo "schedule to restart after 5 seconds!"
|
|
/etc/init.d/tasks task_add reboot 'reboot -d 5'
|
|
return 0
|
|
else
|
|
echo "restore failed"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
supports_overlay_backup() {
|
|
has_overlay || return 1
|
|
echo "overlay"
|
|
has_ext_overlay && echo "ext_overlay"
|
|
return 0
|
|
}
|
|
|
|
get_backup_file_list() {
|
|
local backup_file
|
|
if [ -n "$1" ]; then
|
|
for backup_file in `cd $1 && ls backup_overlay_*.overlay.tar.gz`; do
|
|
echo "${backup_file}"
|
|
done
|
|
else
|
|
echo "input backup path is null"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
usage() {
|
|
echo "usage: overlay-backup sub-command [arguments...]"
|
|
echo "where sub-command is one of:"
|
|
echo " backup [dir] Backup all installed package(s) to [directory]"
|
|
echo " restore [dir] Restore package(s) by [directory]"
|
|
echo " supports_overlay_backup check system supports overlay backup"
|
|
echo " get_backup_file_list [dir] get local available backup file list in [dir]"
|
|
}
|
|
|
|
case $action in
|
|
"supports_overlay_backup")
|
|
supports_overlay_backup
|
|
;;
|
|
"backup")
|
|
backup "$@"
|
|
;;
|
|
"restore")
|
|
if [ "$0" = "$TMP_SELF_COPY" ]; then
|
|
restore "$@"
|
|
else
|
|
echo "copy self $0 to $TMP_SELF_COPY when restore"
|
|
cp -af "$0" "$TMP_SELF_COPY"
|
|
exec "$TMP_SELF_COPY" restore "$@"
|
|
fi
|
|
;;
|
|
"get_available_backup_file_list")
|
|
get_backup_file_list "$@"
|
|
;;
|
|
*)
|
|
usage
|
|
;;
|
|
esac
|