DMSETUP="dmsetup"
FSTRIM="fstrim"
STAT="stat"
+BTRFS="/usr/sbin/btrfs"
FOTA_GUI="/usr/bin/fota_gui"
FOTA_GUI_ENABLE=
PART_USER=$("$BLKID" --match-token PARTLABEL=user -o device || "$BLKID" --match-token LABEL=user -o device)
}
+delete_btrfs_snapshot() {
+ PART="$1"
+ MNT_POINT="$2"
+ log "[Info] Deleting btrfs snapshot"
+ "$MOUNT" -o remount,rw "${MNT_POINT}"
+ "$BTRFS" subvolume delete "$MNT_POINT/fota/RO_update"
+ rm -rf -- "$MNT_POINT/fota"
+}
+
+restore_btrfs_snapshot() {
+ PART="$1"
+ MNT_POINT="$2"
+ if [ ! -d "$MNT_POINT/fota/RO_update" ]; then
+ log "[Info] btrfs snapshot not found"
+ return
+ fi
+ if "$BTRFS" subvolume list "$MNT_POINT/fota/RO_update"; then
+ log "[Info] Got previous snapshot."
+ # remove files from mountpoint because they will be restored from snapshot
+ # it is necessary otherwise files created during os-upgrade will be still there
+ for var in $(ls "$MNT_POINT" | grep -vE 'fota'); do
+ rm -rf -- "$MNT_POINT/$var"
+ done
+ # remove special directories /dev /proc /sys content
+ # it is needed because "btrfs subvolume snapshot" copies some fies from this directories
+ rm -rf -- "$MNT_POINT/fota/RO_update/dev/"* "$MNT_POINT/fota/RO_update/proc/"* "$MNT_POINT/fota/RO_update/sys/"*
+ # restore files from snapshot
+ cp -a -- "$MNT_POINT/fota/RO_update/"* "$MNT_POINT"
+ delete_btrfs_snapshot "$PART" "$MNT_POINT"
+ else
+ log "[Info] Removing leftover data from previous snapshot."
+ rm -rf -- "$MNT_POINT/fota"
+ fi
+
+}
+
+
#------------------------------------------------
# restore_checkpoint
#------------------------------------------------
restore_checkpoint() {
# Any existing checkpoint means that the RW update was unexpectedly
# aborded, so we must roll back the changes and update again.
- log "[Debug] Bow restore" "${INT_LOG_FILE}"
+ log "[Debug] Checkpoint restore" "${INT_LOG_FILE}"
PART="${1}"
-
- if [ "$(blkid -o value -s TYPE ${PART})" = "ext4" ]; then
+ DIRECTORY=${2}
+ FS_TYPE="$(blkid -o value -s TYPE "${PART}")"
+ if [ "$FS_TYPE" = "ext4" ]; then
"$BOW_RESTORE" "${PART}"
+ elif [ "$FS_TYPE" = "btrfs" ]; then
+ restore_btrfs_snapshot "${PART}" "${DIRECTORY}"
fi
}
log "[Debug] Mounted ${PARTITION} as F2FS checkpoint=disable" "${INT_LOG_FILE}"
}
-mount_checkpoint_partition() {
+mount_btrfs_partition() {
+ LABEL=${1}
+ PARTITION=${2}
+ DIRECTORY=${3}
+ if ! "${MOUNT}" -o rw "${PARTITION}" "${DIRECTORY}"; then
+ log "[Error] Cannot mount ${PARTITION} into ${DIRECTORY}"
+ return 1
+ fi
+ if ! "$MKDIR" -p "${DIRECTORY}/fota"; then
+ log "[Error] Cannot create directory for btrfs snapshot"
+ return 1
+ fi
+ log "[Debug] Mounted ${PARTITION} as btrfs" "${INT_LOG_FILE}"
+}
+
+restore_mount_checkpoint_partition() {
LABEL=${1}
PARTITION=${2}
DIRECTORY=${3}
FSTYPE=$(lsblk -o FSTYPE -n "${PARTITION}")
if [ "${FSTYPE}" = "ext4" ]; then
+ restore_checkpoint "${PARTITION}" "${DIRECTORY}"
if ! mount_bow_partition "${LABEL}" "${PARTITION}" "${DIRECTORY}" ; then
return 1
fi
elif [ "${FSTYPE}" = "f2fs" ]; then
+ restore_checkpoint "${PARTITION}" "${DIRECTORY}"
if ! mount_f2fs_partition "${LABEL}" "${PARTITION}" "${DIRECTORY}" ; then
return 1
fi
+ elif [ "${FSTYPE}" = "btrfs" ]; then
+ # btrfs has to be mounted to restore data
+ if ! mount_btrfs_partition "${LABEL}" "${PARTITION}" "${DIRECTORY}"; then
+ return 1
+ fi
+ restore_checkpoint "${PARTITION}" "${DIRECTORY}"
+ # restore deletes snapshot directory
+ "$MKDIR" -p "$DIRECTORY/fota"
+ "$BTRFS" subvolume snapshot "$DIRECTORY" "$DIRECTORY/fota/RO_update"
else
"${MOUNT}" "${PARTITION}" "${DIRECTORY}"
log "[Info] Unsupported filesystem ${FSTYPE} on ${PARTITION}" "${INT_LOG_FILE}"
log "[Info] Changes on partition ${LABEL} commited (f2fs)" "${INT_LOG_FILE}"
}
+commit_btrfs_partition()
+{
+ LABEL=${1}
+ MNT_POINT=${2}
+ PART_SYSTEM_DATA=$(blkid --match-token PARTLABEL="${LABEL}" -o device || blkid --match-token LABEL="${LABEL}" -o device)
+ delete_btrfs_snapshot "${PART_SYSTEM_DATA}" "${MNT_POINT}"
+ log "[Info] Changes on partition ${LABEL} commited (btrfs)" "${INT_LOG_FILE}"
+}
+
commit_partition()
{
LABEL=${1}
+ MNT_POINT=${2}
TYPE=$(blkid --match-token LABEL="${LABEL}" -o value -s TYPE | tail -n 1)
if [ "${TYPE}" = "ext4" ]; then
commit_bow_partition "${LABEL}"
elif [ "${TYPE}" = "f2fs" ]; then
commit_f2fs_partition "${LABEL}"
+ elif [ "$TYPE" = "btrfs" ]; then
+ commit_btrfs_partition "${LABEL}" "${MNT_POINT}"
else
log "[Info] Cannot commit ${LABEL}: Unsupported filesystem ${TYPE}" "${INT_LOG_FILE}"
fi
mount_partitions() {
get_partition_id
- restore_checkpoint "${PART_ROOTFS}"
- if ! mount_checkpoint_partition rootfs "${PART_ROOTFS}" "${FAKE_ROOT}" ; then
+ if ! restore_mount_checkpoint_partition rootfs "${PART_ROOTFS}" "${FAKE_ROOT}"; then
return 1
fi
- restore_checkpoint "${PART_SYSTEM_DATA}"
- if ! mount_checkpoint_partition system-data "${PART_SYSTEM_DATA}" "${FAKE_ROOT}/${SYSTEM_DATA_MNT}" ; then
+ if ! restore_mount_checkpoint_partition system-data "${PART_SYSTEM_DATA}" "${FAKE_ROOT}/${SYSTEM_DATA_MNT}"; then
return 1
fi
if [ ! "z${PART_USER}" = "z" ]; then
- restore_checkpoint "${PART_USER}"
- if ! mount_checkpoint_partition user "${PART_USER}" "${FAKE_ROOT}/${USER_MNT}" ; then
+ if ! restore_mount_checkpoint_partition user "${PART_USER}" "${FAKE_ROOT}/${USER_MNT}"; then
return 1
fi
fi
if [ ! "z${PART_USER}" = "z" ]; then
if [ "${UPGRADE_SUCCESS}" = "1" ]; then
- commit_partition user
+ commit_partition user "${FAKE_ROOT}/${USER_MNT}"
fi
umount_partition user "${FAKE_ROOT}/${USER_MNT}"
fi
if [ "${UPGRADE_SUCCESS}" = "1" ]; then
- commit_partition system-data
+ commit_partition system-data "${FAKE_ROOT}/${SYSTEM_DATA_MNT}"
fi
umount_partition system-data "${FAKE_ROOT}/${SYSTEM_DATA_MNT}"
if [ "${UPGRADE_SUCCESS}" = "1" ]; then
- commit_partition rootfs
+ commit_partition rootfs "${FAKE_ROOT}"
fi
umount_partition rootfs "${FAKE_ROOT}"
}