diff --git a/Documentation/partition.md b/Documentation/partition.md index 8cc52da13..bb7d9294e 100644 --- a/Documentation/partition.md +++ b/Documentation/partition.md @@ -51,10 +51,13 @@ Log in as `root` to get to the Home Assistant CLI and then enter `login` to cont Confirm your USB SSD/HD is connected and recognized using `fdisk -l`. -Make sure the drive has no partition named `hassos-data` (or no partition at all). With the drive, use the below command (again, replacing XXX with your drive) +With the drive connected, use the following command (replacing sdx with your drive, without a partition number): ```sh -$ datactl move /dev/xxx +$ datactl move /dev/sdx ``` -Hit any key to continue, and then the move will happen after the next reboot. Once complete, the external drive will be owned and used by the system. +Enter "yes" to confirm the operation. This will prepare the disk, however, the +actual move will be running on next reboot. Once complete, the external drive +will contain the data and will need to be plugged in to successfully boot Home +Assistant OS. diff --git a/buildroot-external/configs/intel_nuc_defconfig b/buildroot-external/configs/intel_nuc_defconfig index db791a537..a70275a21 100644 --- a/buildroot-external/configs/intel_nuc_defconfig +++ b/buildroot-external/configs/intel_nuc_defconfig @@ -34,6 +34,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_LINUX_FIRMWARE=y diff --git a/buildroot-external/configs/odroid_c2_defconfig b/buildroot-external/configs/odroid_c2_defconfig index a428789f6..4bd2921c6 100644 --- a/buildroot-external/configs/odroid_c2_defconfig +++ b/buildroot-external/configs/odroid_c2_defconfig @@ -36,6 +36,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_CRDA=y diff --git a/buildroot-external/configs/odroid_c4_defconfig b/buildroot-external/configs/odroid_c4_defconfig index d9cd816a9..da9438e97 100644 --- a/buildroot-external/configs/odroid_c4_defconfig +++ b/buildroot-external/configs/odroid_c4_defconfig @@ -36,6 +36,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_CRDA=y diff --git a/buildroot-external/configs/odroid_n2_defconfig b/buildroot-external/configs/odroid_n2_defconfig index 5d1b43e51..646599344 100644 --- a/buildroot-external/configs/odroid_n2_defconfig +++ b/buildroot-external/configs/odroid_n2_defconfig @@ -36,6 +36,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_CRDA=y diff --git a/buildroot-external/configs/odroid_xu4_defconfig b/buildroot-external/configs/odroid_xu4_defconfig index 4d038c7c0..a7eb04442 100644 --- a/buildroot-external/configs/odroid_xu4_defconfig +++ b/buildroot-external/configs/odroid_xu4_defconfig @@ -36,6 +36,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_LINUX_FIRMWARE=y diff --git a/buildroot-external/configs/ova_defconfig b/buildroot-external/configs/ova_defconfig index 9f593b3b0..cd4fd0673 100644 --- a/buildroot-external/configs/ova_defconfig +++ b/buildroot-external/configs/ova_defconfig @@ -35,6 +35,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_CRDA=y diff --git a/buildroot-external/configs/rpi0_w_defconfig b/buildroot-external/configs/rpi0_w_defconfig index 908208631..1dae58233 100644 --- a/buildroot-external/configs/rpi0_w_defconfig +++ b/buildroot-external/configs/rpi0_w_defconfig @@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_RPI_WIFI_FIRMWARE=y diff --git a/buildroot-external/configs/rpi2_defconfig b/buildroot-external/configs/rpi2_defconfig index 68d73bca6..568f71179 100644 --- a/buildroot-external/configs/rpi2_defconfig +++ b/buildroot-external/configs/rpi2_defconfig @@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_RPI_FIRMWARE=y diff --git a/buildroot-external/configs/rpi3_64_defconfig b/buildroot-external/configs/rpi3_64_defconfig index b2d4f090f..da9378405 100644 --- a/buildroot-external/configs/rpi3_64_defconfig +++ b/buildroot-external/configs/rpi3_64_defconfig @@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_RPI_FIRMWARE=y diff --git a/buildroot-external/configs/rpi3_defconfig b/buildroot-external/configs/rpi3_defconfig index 67bf6426e..0ad2e74c0 100644 --- a/buildroot-external/configs/rpi3_defconfig +++ b/buildroot-external/configs/rpi3_defconfig @@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_RPI_FIRMWARE=y diff --git a/buildroot-external/configs/rpi4_64_defconfig b/buildroot-external/configs/rpi4_64_defconfig index 91bba4378..117b9b8af 100644 --- a/buildroot-external/configs/rpi4_64_defconfig +++ b/buildroot-external/configs/rpi4_64_defconfig @@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_RPI_FIRMWARE=y diff --git a/buildroot-external/configs/rpi4_defconfig b/buildroot-external/configs/rpi4_defconfig index cac392916..add7af347 100644 --- a/buildroot-external/configs/rpi4_defconfig +++ b/buildroot-external/configs/rpi4_defconfig @@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_RPI_FIRMWARE=y diff --git a/buildroot-external/configs/rpi_defconfig b/buildroot-external/configs/rpi_defconfig index 5362abf72..1fdb1c01d 100644 --- a/buildroot-external/configs/rpi_defconfig +++ b/buildroot-external/configs/rpi_defconfig @@ -37,6 +37,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_RPI_FIRMWARE=y diff --git a/buildroot-external/configs/tinker_defconfig b/buildroot-external/configs/tinker_defconfig index 5d9b3c7e9..a64b0c6e8 100644 --- a/buildroot-external/configs/tinker_defconfig +++ b/buildroot-external/configs/tinker_defconfig @@ -38,6 +38,7 @@ BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y BR2_PACKAGE_JQ=y BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y BR2_PACKAGE_SQUASHFS=y BR2_PACKAGE_LINUX_FIRMWARE=y diff --git a/buildroot-external/rootfs-overlay/usr/bin/datactl b/buildroot-external/rootfs-overlay/usr/bin/datactl index adc024685..ba4e0b375 100755 --- a/buildroot-external/rootfs-overlay/usr/bin/datactl +++ b/buildroot-external/rootfs-overlay/usr/bin/datactl @@ -1,31 +1,59 @@ #!/bin/sh # ============================================================================== -# HassOS data partition handling +# Home Assistant OS data partition handling # ============================================================================== set -e -OPTION_FILE=/mnt/overlay/data.opt -DATA_DEVICE_CHILD="$(findfs LABEL="hassos-data")" +# Use current mount point. This avoids "Can't be the same disk!" error +# when using a drive which has been used as a data drive previously. +DATA_DEVICE_CHILD="$(findmnt --noheadings --output=source /mnt/data)" DATA_DEVICE_ROOT="/dev/$(lsblk -no pkname "${DATA_DEVICE_CHILD}")" # Move command if [ "${1}" = "move" ] && [ -e "${2}" ]; then - DEVICE="${2}" + NEW_DEVICE_ROOT="${2}" # Check device - if ! lsblk "${DEVICE}" | grep disk > /dev/null 2>&1; then + if ! lsblk "${NEW_DEVICE_ROOT}" | grep disk > /dev/null 2>&1; then echo "[ERROR] Is not disk!" exit 1 - elif [ "${DEVICE}" = "${DATA_DEVICE_ROOT}" ]; then + elif [ "${NEW_DEVICE_ROOT}" = "${DATA_DEVICE_ROOT}" ]; then echo "[ERROR] Can't be the same disk!" exit 1 fi # Flag device - echo "WARNING: ${DEVICE} will be reset on next restart!" - echo "Press a key to move forward" - read -r + echo "WARNING: All partitions on ${NEW_DEVICE_ROOT} will be deleted!" + printf "Enter \"yes\" to confirm: " + read -r confirm + if [ "${confirm}" != "yes" ]; then + echo "Aborting." + exit 1 + fi + + sgdisk --zap-all "${NEW_DEVICE_ROOT}" + sgdisk \ + -n "0:0:0" \ + -c "0:hassos-data-external" \ + -t "0:0FC63DAF-8483-4772-8E79-3D69D8477DE4" \ + -u "0:a52a4597-fa3a-4851-aefd-2fbe9f849079" \ + "${NEW_DEVICE_ROOT}" + + touch "/mnt/overlay/move-data" + cat << EOF +Disk ${NEW_DEVICE_ROOT} has been prepared to be used as data drive and the data +move has been scheduled for the next reboot. Please reboot the device now and +make sure to leave the disk connected to the system from now on. +EOF + +else + cat << EOF +Usage: datactl move + +Moves data partition to external device provided by (without partition +number). A new partition table and a partition for the complete device will be +created by datactl. +EOF - echo "${DEVICE}" > ${OPTION_FILE} fi diff --git a/buildroot-external/rootfs-overlay/usr/lib/systemd/system/hassos-data.service b/buildroot-external/rootfs-overlay/usr/lib/systemd/system/hassos-data.service index 847ffe9c5..5d7598bbf 100644 --- a/buildroot-external/rootfs-overlay/usr/lib/systemd/system/hassos-data.service +++ b/buildroot-external/rootfs-overlay/usr/lib/systemd/system/hassos-data.service @@ -1,16 +1,17 @@ [Unit] -Description=HassOS data partition +Description=Home Assistant OS data partition migration DefaultDependencies=no RefuseManualStart=true RefuseManualStop=true -Requires=mnt-overlay.mount dev-disk-by\x2dlabel-hassos\x2ddata.device +Requires=mnt-overlay.mount dev-disk-by\x2dlabel-hassos\x2ddata.device dev-disk-by\x2dpartlabel-hassos\x2ddata\x2dexternal.service Wants=hassos-expand.service -After=mnt-overlay.mount dev-disk-by\x2dlabel-hassos\x2ddata.device systemd-fsck@dev-disk-by\x2dlabel-hassos\x2ddata.service +After=mnt-overlay.mount dev-disk-by\x2dlabel-hassos\x2ddata.device systemd-fsck@dev-disk-by\x2dlabel-hassos\x2ddata.service dev-disk-by\x2dpartlabel-hassos\x2ddata\x2dexternal.service Before=hassos-expand.service -ConditionPathExists=/mnt/overlay/data.opt +ConditionPathExists=/mnt/overlay/move-data [Service] Type=oneshot +ExecStartPre=-/usr/bin/rm -f /mnt/overlay/move-data ExecStart=/usr/libexec/hassos-data [Install] diff --git a/buildroot-external/rootfs-overlay/usr/libexec/hassos-data b/buildroot-external/rootfs-overlay/usr/libexec/hassos-data index 874992586..0e1b74023 100755 --- a/buildroot-external/rootfs-overlay/usr/libexec/hassos-data +++ b/buildroot-external/rootfs-overlay/usr/libexec/hassos-data @@ -1,83 +1,24 @@ #!/bin/sh -# shellcheck disable=SC2039 # ============================================================================== -# HassOS data partition handler +# Home Assistant OS data partition migration script # ============================================================================== set -e -OPTION_FILE=/mnt/overlay/data.opt +# Rely on systemd-udev symlinks to find current data partition by fs label +OLD_DEVICE_CHILD="$(readlink -f "/dev/disk/by-label/hassos-data")" -# New data partition exits -if ! [ -e "${OPTION_FILE}" ]; then - echo "[INFO] No data option found" - exit 0 -else - NEW_DEVICE_ROOT="$(cat ${OPTION_FILE})" - rm ${OPTION_FILE} -fi +# Rely on systemd-udev symlinks to find external data partition by partlabel +NEW_DEVICE_CHILD="$(readlink -f "/dev/disk/by-partlabel/hassos-data-external")" -# Get device information -OLD_DEVICE_CHILD="$(findfs LABEL="hassos-data")" -OLD_DEVICE_ROOT="/dev/$(lsblk -no pkname "${OLD_DEVICE_CHILD}")" -OLD_PART_NUM="${OLD_DEVICE_CHILD: -1}" - -# Wait for devices -timeout 90 \ - ash -c \ - "until [ -e \"${NEW_DEVICE_ROOT}\" ]; do sleep 5; done" \ - > /dev/null 2>&1 || true; - -# Check if block device is exists -if [ ! -b "${NEW_DEVICE_ROOT}" ]; then - echo "[ERROR] No block device ${NEW_DEVICE_ROOT}!" - exit 1 -fi -echo "[INFO] Cleanup device ${NEW_DEVICE_ROOT}!" -sgdisk -Z "${NEW_DEVICE_ROOT}" - -# Create new partition -echo "[INFO] Create new hassos-data partition" -sgdisk -o "${NEW_DEVICE_ROOT}" -sgdisk \ - -n "0:0:0" \ - -c "0:hassos-data" \ - -t "0:0FC63DAF-8483-4772-8E79-3D69D8477DE4" \ - -u "0:a52a4597-fa3a-4851-aefd-2fbe9f849079" \ - "${NEW_DEVICE_ROOT}" -sgdisk -v "${NEW_DEVICE_ROOT}" -partx -u "${NEW_DEVICE_ROOT}" - -NEW_DEVICE_CHILD="$(fdisk -l "${NEW_DEVICE_ROOT}" | grep '^/dev' | cut -d' ' -f1 | head -n 1)" - -echo "[INFO] Move hassos-data from ${OLD_DEVICE_CHILD} to ${NEW_DEVICE_CHILD}" -if ! dd if="${OLD_DEVICE_CHILD}" of="${NEW_DEVICE_CHILD}" status=none; then - echo "[ERROR] Data copy fails!" - - # Reset new data partition - sgdisk -o "${NEW_DEVICE_ROOT}" - partx -u "${NEW_DEVICE_ROOT}" +echo "[INFO] Moving data from ${OLD_DEVICE_CHILD} to ${NEW_DEVICE_CHILD}" +if ! e2image -ra -p "${OLD_DEVICE_CHILD}" "${NEW_DEVICE_CHILD}"; then + echo "[ERROR] Copying data partition to external device failed!" exit 1 fi -echo "[INFO] Remove old hassos-data partition ${OLD_PART_NUM} / ${OLD_DEVICE_ROOT}" -if sfdisk -dq "${OLD_DEVICE_ROOT}" | grep -q 'label: gpt'; then - sgdisk -d "${OLD_PART_NUM}" "${OLD_DEVICE_ROOT}" - sgdisk -v "${OLD_DEVICE_ROOT}" +# At this point we have two partition with the same fs label. Make sure +# to rename the internal partition so we won't mount it anymore. +echo "[INFO] Rename old hassos-data partition ${OLD_DEVICE_CHILD}" +e2label "${OLD_DEVICE_CHILD}" hassos-data-old -else - sfdisk --delete "${OLD_DEVICE_ROOT}" "${OLD_PART_NUM}" --force - sfdisk -V "${OLD_DEVICE_ROOT}" -fi - -echo "[INFO] fix filesystem & layout" - -# Fix filesystem -e2fsck -y "${NEW_DEVICE_CHILD}" -resize2fs -f "${NEW_DEVICE_CHILD}" - -# Fix partition layout -partx -d "${OLD_DEVICE_CHILD}" -partx -u "${OLD_DEVICE_ROOT}" -partx -u "${NEW_DEVICE_ROOT}" - -echo "[INFO] Finish hassos data movement" +echo "[INFO] Data move has been completed successfully"