├── usr
├── lib
│ └── tik
│ │ ├── config
│ │ ├── modules
│ │ ├── pre
│ │ │ ├── 10-welcome
│ │ │ ├── 15-encrypt
│ │ │ └── 20-mig
│ │ └── post
│ │ │ ├── 20-mig
│ │ │ └── 15-encrypt
│ │ └── lib
│ │ └── tik-functions
└── bin
│ └── tik
├── etc
└── tik
│ └── config
├── LICENSE
└── README.md
/usr/lib/tik/config:
--------------------------------------------------------------------------------
1 | # Directory for users to add custom configuration and modules
2 | # Default: "/etc/tik"
3 | TIK_CUSTOM_DIR="/etc/tik"
4 |
5 | # Directory for OS images to be deployed
6 | # Default: "/usr/lib/tik/img"
7 | TIK_IMG_DIR="/usr/lib/tik/img"
8 |
9 | # To show USB devices in the install device selection dialog, uncomment this variable
10 | # USB devices are filtered out by default
11 | #TIK_ALLOW_USB_INSTALL_DEVICES=1
12 |
13 | # For unattended installations the disk device to deploy the image must be defined
14 | # Default: Undefined
15 | #TIK_INSTALL_DEVICE=""
16 |
17 | # For unattended installations the disk image to deploy must be defined if more than one is present
18 | # Default: Undefined
19 | #TIK_INSTALL_IMAGE=""
20 |
21 | # Display name of the OS to be deployed by tik
22 | # Default: Undefined
23 | #TIK_OS_NAME=""
24 |
25 | # URL for bug reports to go to
26 | # Default: https://aeondesktop.org/reportbug
27 | TIK_BUG_URL="https://aeondesktop.org/reportbug"
28 |
--------------------------------------------------------------------------------
/etc/tik/config:
--------------------------------------------------------------------------------
1 | # Directory for users to add custom configuration and modules
2 | # Default: "/etc/tik"
3 | #TIK_CUSTOM_DIR="/etc/tik"
4 |
5 | # Directory for OS images to be deployed
6 | # Default: "/usr/lib/tik/img"
7 | #TIK_IMG_DIR="/usr/lib/tik/img"
8 |
9 | # To show USB devices in the install device selection dialog, uncomment this variable
10 | # USB devices are filtered out by default
11 | #TIK_ALLOW_USB_INSTALL_DEVICES=1
12 |
13 | # For unattended installations the disk device to deploy the image must be defined if more than one is present
14 | # Default: Undefined
15 | #TIK_INSTALL_DEVICE=""
16 |
17 | # For unattended installations the disk image to deploy must be defined if more than one is present
18 | # Default: Undefined
19 | #TIK_INSTALL_IMAGE=""
20 |
21 | # Display name of the OS to be deployed by tik
22 | # Default: Undefined
23 | #TIK_OS_NAME=""
24 |
25 | # URL for bug reports to go to
26 | # Default: https://aeondesktop.org/reportbug
27 | #TIK_BUG_URL="https://aeondesktop.org/reportbug"
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023-2024 SUSE LLC
4 | Copyright (c) 2023-2024 Richard Brown
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/usr/bin/tik:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # SPDX-License-Identifier: MIT
3 | # SPDX-FileCopyrightText: Copyright 2023-2024 SUSE LLC
4 | # SPDX-FileCopyrightText: Copyright 2023-2024 Richard Brown
5 |
6 | # Define variables
7 | # Style notes
8 | # lowercase variables = internal, not expected to be defined by users
9 | # uppercase variables = user facing, expected to be set by config
10 |
11 | tik_log=~/tik.log
12 | tik_dir=/usr/lib/tik
13 | tik_module="tik"
14 |
15 | # Read libraries
16 | . ${tik_dir}/lib/tik-functions
17 |
18 | # Start logging
19 | exec 2> >(exec tee -i -a "${tik_log}" >&2)
20 | log "[START] $0"
21 |
22 | # Check for debug mode
23 | if [[ $1 == "--debug" ]]; then
24 | debug=1
25 | fi
26 |
27 | # Read configuration files, /usr first, then /etc
28 | . ${tik_dir}/config
29 | . ${TIK_CUSTOM_DIR}/config
30 |
31 | # Check essential paths exist
32 | if [ ! -d "${TIK_IMG_DIR}" ]; then
33 | error "${TIK_IMG_DIR} does not exist"
34 | fi
35 |
36 | cleanup() {
37 | retval=$?
38 | log "[STOP][${retval}] $0"
39 | if [ "${debug}" == "1" ]; then
40 | zenity --timeout 5 --info --no-wrap --text="Test Succeeded:\n\nHave a nice day!"
41 | elif [ "${retval}" == "0" ]; then
42 | zenity --timeout 5 --info --no-wrap --title="Installation Complete!" --text="${TIK_OS_NAME} has been installed.\n\nSystem is rebooting"
43 | prun systemctl reboot --force
44 | else
45 | zenity --error --no-wrap --title="Installation Failed" --text="Please file a bug report at ${TIK_BUG_URL}\n\nPlease include the tik.log file\nIt can be found on the IGNITION partition on this USB Stick\n\nSystem is shutting down"
46 | cp -a ${tik_log} /ignition
47 | prun systemctl poweroff --force
48 | fi
49 | }
50 | trap cleanup EXIT
51 |
52 | load_modules "pre"
53 | load_modules "pre" "custom"
54 |
55 | get_disk
56 | get_img
57 | dump_image "${TIK_INSTALL_IMAGE}" "${TIK_INSTALL_DEVICE}"
58 | reread_partitiontable
59 |
60 | load_modules "post"
61 | load_modules "post" "custom"
62 |
63 | wipe_keyfile
64 | set_boot_target
--------------------------------------------------------------------------------
/usr/lib/tik/modules/pre/10-welcome:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | # SPDX-FileCopyrightText: Copyright 2024 SUSE LLC
3 | # SPDX-FileCopyrightText: Copyright 2024 Richard Brown
4 | # SPDX-FileCopyrightText: Copyright 2024 Raymond Yip
5 |
6 | proceedInstall() {
7 | d --info --ok-label="Install Now" --no-wrap --width=300 --height=300 --icon=distributor-logo-Aeon-symbolic --title="" --text="Welcome to ${TIK_OS_NAME}\n\nPlease press Install Now to continue"
8 | }
9 |
10 | displayACWarningMsg() {
11 | d --warning --no-wrap --title="AC Power Recommended" --text="Runnning on battery power detected\n\nIt is recommended to connect the system to AC power during the install"
12 | }
13 |
14 | checkLaptop() {
15 | chassis=`cat /sys/class/dmi/id/chassis_type`
16 | #Test for respectively Handheld, Notebook, Laptop, and Portable
17 | #if chassis variable matches 8 9 10 or 11 function continues else it proceeds to test AC power and Battery
18 | [[ "$chassis" =~ ^(8|9|10|11)$ ]] || return
19 | #Tested machine is confirmed mobile
20 | givePowerRecommendation=false
21 | #Only check for AC and Battery power connections with upower
22 | updevices=`/usr/bin/upower -e|grep -E 'AC|BAT'`
23 | for pdev in $updevices; do
24 | #Get detailed info for each AC and BAT device in upower
25 | upinfo=`/usr/bin/upower -i $pdev|grep -E 'online|state'`
26 | #Check for discharging state or AC power offline which is equal to no state
27 | if [[ "$upinfo" =~ (discharging|no) ]]; then
28 | #Give power recommendation only once, so set this to true
29 | givePowerRecommendation=true
30 | fi
31 | done
32 | if [ "$givePowerRecommendation" = true ]; then
33 | log "AC Power disconnected and Battery is not charging"
34 | displayACWarningMsg
35 | fi
36 | }
37 |
38 | verify_efi() {
39 | # Verify that the system was booted with EFI, exit with error if not
40 | if [ ! -d /sys/firmware/efi ]; then
41 | # System was not booted with EFI
42 | local error_msg="${TIK_OS_NAME} requires UEFI mode, which is not found on your system.\nPlease check your BIOS settings to see if UEFI can be enabled."
43 | error "${error_msg}"
44 | fi
45 | }
46 |
47 | proceedInstall
48 | verify_efi
49 | checkLaptop
50 |
--------------------------------------------------------------------------------
/usr/lib/tik/modules/pre/15-encrypt:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | # SPDX-FileCopyrightText: Copyright 2024 SUSE LLC
3 | # SPDX-FileCopyrightText: Copyright 2024 Richard Brown
4 |
5 | # Based on the guide documented here: https://en.opensuse.org/index.php?title=Portal:Aeon/Encryption
6 | # verify_tpm checks which encryption mode the system is capable of, and stores it in ${tik_encrypt_mode} for use by post module
7 | # "tik_encrypt_mode = 0" - Default Mode
8 | # "tik_encrypt_mode = 1" - Fallback Mode
9 | # check_secureboot checks if secureboot is disabled for Fallback mode. Does not do anything if Default Mode.
10 | # encrypt_notification does nothing if Default Mode. For Fallback mode it provides a single notification containing the following information
11 | # - That Fallback Mode is enabled because [TPM 2.0 is missing | lacking features]
12 | # - That they will be prompted to enter a passphrase to encrypt their system later
13 | # - If Secureboot is disabled they will be encouraged to exit and enable it
14 | # - For more information go to rewrite https://aeondesktop.org/encrypt
15 |
16 | verify_tpm() {
17 | # Verify that the system has a TPM 2.0
18 | if [ -c /dev/tpmrm0 ]; then
19 | # TPM 2.0 found
20 | tpm_found=1
21 | log "[verify_tpm] TPM 2.0 found, checking for PolicyAuthorizeNV"
22 | # Check for command 0x192 PolicyAuthorizeNV
23 | if prun tpm2_getcap commands | grep -q 'commandIndex: 0x192'; then
24 | # PolicyAuthorizeNV found, set encryption mode to default
25 | tik_encrypt_mode=0
26 | log "[verify_tpm] PolicyAuthorizeNV support found, Default Mode set"
27 | else
28 | # PolicyAuthorizeNV not found, set encryption mode to fallback
29 | tik_encrypt_mode=1
30 | log "[verify_tpm] PolicyAuthorizeNV support not found, Fallback Mode set"
31 | fi
32 | else
33 | # TPM 2.0 not found, set encryption mode to fallback
34 | tpm_found=0
35 | tik_encrypt_mode=1
36 | log "[verify_tpm] TPM 2.0 not found, Fallback Mode set"
37 | fi
38 | }
39 |
40 | check_secureboot() {
41 | # We only care about Secureboot when using Fallback mode
42 | if [ "${tik_encrypt_mode}" == 1 ]; then
43 | if ! mokutil --sb-state | grep -q 'enabled'; then
44 | secureboot_disabled=1
45 | log "[check_secureboot] secureboot disabled, will warn user"
46 | else
47 | log "[check_secureboot] secureboot enabled"
48 | fi
49 | fi
50 | }
51 |
52 | encrypt_notification() {
53 | local preamble="This system does not meet the Recommended Hardware requirements for ${TIK_OS_NAME}"
54 | local postamble="Disk Encryption will use Fallback Mode\nYou will be prompted to create a Passphrase later in the installation\nThis Passphrase will be required to unlock ${TIK_OS_NAME} on every boot\n\nFor more information please visit https://aeondesktop.org/encrypt"
55 | local secureboot_warning="It is Strongly Recommended to enable SecureBoot\n\nWithout SecureBoot this system will be at increased risk of attacks which could compromise the security of your data\nPlease Cancel Installation and enable SecureBoot\n\nFor more information please visit https://aeondesktop.org/encrypt"
56 | local reason
57 | # We're only going to show a notification when using Fallback mode
58 | if [ "${tik_encrypt_mode}" == 1 ]; then
59 | [ "${tpm_found}" == 0 ] && reason="No TPM 2.0 chipset found"
60 | [ "${tpm_found}" == 1 ] && reason="TPM 2.0 chipset found, but older than v1.38"
61 | # Secureboot being disabled makes the notification a Yes/No with the preference being to exit
62 | if [ "${secureboot_disabled}" == 1 ]; then
63 | log "[encrypt_notification] secureboot warning shown"
64 | zenity --width=600 --question --icon=security-low-symbolic --title="Warning" --ok-label="Cancel Installation" --cancel-label="I Understand, Proceed Anyway" --text="${preamble}\n\nReason: SecureBoot Disabled and ${reason}\n\n${secureboot_warning}" && exit 1
65 | log "[encrypt_notification] secureboot warning ignored, installation continuing"
66 | d --width=600 --warning --icon=security-low-symbolic --text="${postamble}"
67 | # Secureboot is enabled, so show a warning
68 | else
69 | d --width=600 --warning --icon=security-medium-symbolic --text="${preamble}\n\nReason: ${reason}\n\n${postamble}"
70 | fi
71 | log "[encrypt_notification] user notified that Fallback mode will be used"
72 | fi
73 | }
74 |
75 | verify_tpm
76 | check_secureboot
77 | encrypt_notification
--------------------------------------------------------------------------------
/usr/lib/tik/modules/post/20-mig:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | # SPDX-FileCopyrightText: Copyright 2024 SUSE LLC
3 | # SPDX-FileCopyrightText: Copyright 2024 Richard Brown
4 |
5 | writemigdesktop() {
6 | prun-opt /usr/bin/tee $1/.config/autostart/aeon-mig-firstboot.desktop << "EOF"
7 | [Desktop Entry]
8 | Name=Aeon Migration FirstBoot Setup
9 | Comment=Sets up Aeon Correctly On FirstBoot after Migration
10 | Exec=/usr/bin/aeon-mig-firstboot
11 | Icon=org.gnome.Terminal
12 | Type=Application
13 | Categories=Utility;System;
14 | Name[en_GB]=startup
15 | EOF
16 | prun-opt /usr/bin/chmod 666 $1/.config/autostart/aeon-mig-firstboot.desktop
17 | }
18 |
19 |
20 | if [ "${migrate}" == 1 ]; then
21 | probe_partitions ${TIK_INSTALL_DEVICE} "crypto_LUKS"
22 | [ -z "${probedpart}" ] || prun /usr/sbin/cryptsetup luksOpen --key-file=${tik_keyfile} ${cryptpart} aeon_root
23 |
24 | probe_partitions $TIK_INSTALL_DEVICE "btrfs" "/usr/lib/os-release"
25 |
26 | [ -n "${probedpart}" ] || error "MIGRATION FAILED: New Installation NOT FOUND"
27 |
28 | prun /usr/bin/mkdir ${mig_dir}/mnt
29 | prun /usr/bin/mount -o compress=zstd:1 ${probedpart} ${mig_dir}/mnt
30 | prun /usr/bin/systemd-repart --pretty 0 --root ${mig_dir}/mnt --dry-run=0 ${probedpart}
31 | prun /usr/bin/mount -o compress=zstd:1,subvol=/@/var ${probedpart} ${mig_dir}/mnt/var
32 | prun /lib/systemd/systemd-growfs ${mig_dir}/mnt/var
33 | etcmountcmd=$(cat ${mig_dir}/mnt/etc/fstab | grep "overlay /etc" | sed 's/\/sysroot\//${mig_dir}\/mnt\//g' | sed 's/\/work-etc.*/\/work-etc ${mig_dir}\/mnt\/etc\//' | sed 's/overlay \/etc overlay/\/usr\/bin\/mount -t overlay overlay -o/')
34 | eval prun "$etcmountcmd"
35 | prun /usr/bin/cat ${mig_dir}/passwd.out | prun tee -a ${mig_dir}/mnt/etc/passwd
36 | prun /usr/bin/cat ${mig_dir}/group.out | prun tee -a ${mig_dir}/mnt/etc/group
37 | prun /usr/bin/cat ${mig_dir}/shadow.out | prun tee -a ${mig_dir}/mnt/etc/shadow
38 | prun /usr/bin/sed -i "/^wheel:/ s/$/$(head -n 1 ${mig_dir}/passwd.out | awk -F'[/:]' '{print $1}')/" ${mig_dir}/mnt/etc/group
39 | prun /usr/bin/cp -a ${mig_dir}/subuid ${mig_dir}/mnt/etc/subuid
40 | prun /usr/bin/cp -a ${mig_dir}/subgid ${mig_dir}/mnt/etc/subgid
41 | # It's not guaranteed that the system will have existing network configs, localtime or AccountsService
42 | prun-opt /usr/bin/cp -a ${mig_dir}/system-connections/* ${mig_dir}/mnt/etc/NetworkManager/system-connections
43 | prun-opt /usr/bin/cp -a ${mig_dir}/localtime ${mig_dir}/mnt/etc/localtime
44 | prun-opt /usr/bin/cp -a ${mig_dir}/users/* ${mig_dir}/mnt/var/lib/AccountsService/users
45 | prun-opt /usr/bin/cp -a ${mig_dir}/icons/* ${mig_dir}/mnt/var/lib/AccountsService/icons
46 | prun-opt /usr/bin/cp -a ${mig_dir}/bluetooth/* ${mig_dir}/mnt/var/lib/bluetooth
47 | prun-opt /usr/bin/cp -a ${mig_dir}/fprint/* ${mig_dir}/mnt/var/lib/fprint
48 | prun-opt /usr/bin/cp -a ${mig_dir}/openvpn/* ${mig_dir}/mnt/etc/openvpn
49 | prun /usr/bin/umount ${mig_dir}/mnt/etc
50 | prun /usr/bin/umount ${mig_dir}/mnt/var
51 | prun /usr/bin/umount ${mig_dir}/mnt
52 | prun /usr/bin/mount -o compress=zstd:1,subvol=/@ ${probedpart} ${mig_dir}/mnt
53 | prun /usr/sbin/btrfs subvolume delete ${mig_dir}/mnt/home
54 | (prun /usr/sbin/btrfs send ${mig_dir}/${snap_dir} | pv -f -F "# %b copied in %t %r" | prun /usr/sbin/btrfs receive ${mig_dir}/mnt) 2>&1 | d --progress --title="Restoring /home" --pulsate --auto-close --no-cancel --width=400
55 | prun /usr/bin/mv ${mig_dir}/mnt/${snap_dir} ${mig_dir}/mnt/home
56 | prun /usr/sbin/btrfs property set -f -ts ${mig_dir}/mnt/home ro false
57 | for subsubvol in $(prun-opt /usr/sbin/btrfs subvolume list -o ${mig_dir}/${snap_dir} --sort=path | rev | cut -f1 -d' ' | rev | sed 's/^@//'); do
58 | subsubvolname=$(basename $subsubvol)
59 | subsubdirname=$(dirname $subsubvol | awk -F "${mig_dir}/${snap_dir}" '{print $2}')
60 | (prun /usr/sbin/btrfs send ${subsubvol} | pv -f -F "# %b copied in %t %r" | prun /usr/sbin/btrfs receive ${mig_dir}/mnt/home/${subsubdirname} ) 2>&1 | d --progress --title="Restoring containers" --pulsate --auto-close --no-cancel --width=400
61 | prun /usr/sbin/btrfs property set -f -ts ${mig_dir}/mnt/home/${subsubdirname}/${subsubvolname} ro false
62 | prun-opt /usr/bin/sed -i 's/driver = "overlay"/driver = "btrfs"/g' ${mig_dir}/mnt/etc/containers/storage.conf
63 | done
64 | for userhome in ${mig_dir}/mnt/home/*/; do
65 | writemigdesktop $userhome
66 | done
67 | prun /usr/bin/umount ${mig_dir}/mnt
68 | prun /usr/bin/rmdir ${mig_dir}/mnt
69 | [ ! -e /dev/mapper/aeon_root ] || prun /usr/sbin/cryptsetup luksClose aeon_root
70 | fi
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tik
2 |
3 | Transactional Installation Kit - A toolkit for deploying Operating System images to UEFI hardware from a USB stick.
4 |
5 | ## General Premise
6 |
7 | A simple, lightweight, extensible tool for deploying a premade OS images to UEFI hardware.
8 |
9 | tik was originally inspired by the "SelfInstaller" functionality offered by [kiwi](https://github.com/OSInside/kiwi) OEM images, but is designed to be wholly independent of the toolchain used to create the OS images.
10 |
11 | It's core functionality is very similar to kiwi's SelfInstaller, with the basic workflow for deploying an image being a very simple process:
12 |
13 | - Identify storage devices on the system
14 | - Offer the user a list of available devices
15 | - Deploy image to that device
16 |
17 | In addition to the above workflow, tik supports the following additional features
18 |
19 | - Unattended automation of the deployment of the image
20 | - Optional extensions to be run before or after the deployment of the image (eg to support functionality like checking the network for an updated image). This functionality is inspired by [jeos-firstboot](https://github.com/openSUSE/jeos-firstboot/)'s module support
21 | - Support for multiple images provided on the same installation media (eg. openSUSE Aeon and openSUSE MicroOS)
22 |
23 | ## tik OS Images
24 |
25 | tik is designed to deploy three types of images.
26 |
27 | - systemd-repart "bundles"
28 | - systemd-repart "self deployment"
29 | - Block images
30 |
31 | In all three cases tik should not care about the contents of the disk image, which potentially could be of any Operating System built using any toolset (eg kiwi, mkosi, etc)
32 |
33 | Features like expanding the partitions to fill the disk are expected to be handled by tools like systemd-repart on the booting of the deployed OS, not by tik (though in theory optional extensions could be written to implement this)
34 |
35 | ### systemd-repart "bundles"
36 |
37 | tik can also deploy images bundled with their own systemd-repart configurations. tik expects the following on disk layout for each systemd-repart "bundle":
38 |
39 | - a Directory with a unique name to describe the OS/Version being deployed. Contained within that directory:
40 | - a `repart.d` Directory containing a complete [repart.d](https://www.freedesktop.org/software/systemd/man/latest/repart.d.html) partition layout for the OS being deployed
41 | - 1 (or more) Directories or Block images to be used by `CopyFiles=` or `CopyBlocks=` parameters in the `repart.d` configuration to populate the contents of the defined partitions
42 |
43 | The `repart.d` configuration is then read and applied to the target storage device, being populated automatically based on the configuration.
44 |
45 | By default these files should be located in `/usr/lib/tik/img` but can be relocated by redefining the `TIK_IMG_DIR` parameter in your tik config.
46 | As `CopyBlocks=` and `CopyFiles=` parameters require absolute filesystem paths, any change to the `TIK_IMG_DIR` parameter will require altering your configuration to match that new location.
47 |
48 | This feature was introduced in tik v1.2
49 |
50 | ### systemd-repart "self-deployment"
51 |
52 | If tik is executed without any images in the defined `TIK_IMG_DIR` it will automatically attempt "self deployment", using the currently booted tik USB stick as its 'image' for writing to the target storage device.
53 | This is primarily for using tik to deploy images from a functioning 'live/portable' USB installation.
54 |
55 | For this to work, tik requires
56 |
57 | - a `repart.d` configuration containing a complete [repart.d](https://www.freedesktop.org/software/systemd/man/latest/repart.d.html) partition layout for the OS being deployed. This must be located in the standard `repart.d` paths, eg `/etc/repart.d/` or `/usr/lib/repart.d`
58 |
59 | The `repart.d` configuration is then read and applied to the target storage device, being populated automatically based on the configuration.
60 | It is expected that the `repart.d` configuration will use `CopyBlocks=auto` to automatically map the contents from the booted tik USB stick to the equivalent new partitions on the target storage device.
61 |
62 | This feature was introduced in tik v1.2
63 |
64 | ### Block images
65 |
66 | tik can deploy a block-based disk images. These expected to be raw.xz files containing
67 |
68 | - the full partition table
69 | - a UEFI ESP/EFI partition
70 | - 1 (or more) OS partitions
71 |
72 | By default these files should be located in `/usr/lib/tik/img` but can be relocated by redefining the `TIK_IMG_DIR` parameter in your tik config
73 |
74 | ## tik Installation Media
75 |
76 | tik is designed to be run on a different style of media than many traditional OS installers
77 |
78 | Traditional tooling like YaST, Agama, Windows Installer, etc are all expected to be read-only Installation media that aren't modifiable by the user at all
79 |
80 | tik Installtion Media are expected to be a variant of openSUSE MicroOS, designed to be run from portable media (eg a USB stick)
81 |
82 | while the "Install OS" of the Installation Media will therefore be read-only when in use, the "Install OS" will be possible of being updated and configured to the users needs, directly on the USB stick after it's imaged
83 |
84 | More importantly, this also means that the Installation Media will have various read-write locations, including /var/lib/tik/images, the location of tiks image files, allowing users to add their own custom variants of such images to be offered when the tik installer boots up
85 |
86 | ## tik + ignition + combustion
87 |
88 | because tik installation media are built separately from the Operating System(s) which tik will offer to deploy, this means that tik installation images can also contain a separate 'ignition/combustion partition' which can have your ignition/combustion configurations stored within
89 |
90 | These will then be automatically used by any OS image which uses ignition or combustion (eg openSUSE MicroOS) on their first boot after tik has deployed an image, assuming the tik Installation USB stick is still connected
91 |
92 | This makes ignition and/or combustion the perfect tools for making any automated customisations to any OS image deployed via tik
93 |
--------------------------------------------------------------------------------
/usr/lib/tik/modules/pre/20-mig:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | # SPDX-FileCopyrightText: Copyright 2024 SUSE LLC
3 | # SPDX-FileCopyrightText: Copyright 2024 Richard Brown
4 |
5 | mig_dir=/var/lib/tik/mig
6 | snap_dir=homebk
7 | if [ ! -d ${mig_dir} ]; then
8 | prun /usr/bin/mkdir -p ${mig_dir}
9 | fi
10 |
11 | if [ ! -z "$(ls -A ${mig_dir})" ]; then
12 | log "existing backup found"
13 | zenity --question --no-wrap --cancel-label="No, Delete Backup" --title="Existing user backup detected" --text="These users can be restored to the new installation\n\nWould you like to use this backup?"
14 | oldbackupyn=$?
15 | log "[oldbackupyn][${oldbackupyn}]"
16 | if [ "${oldbackupyn}" == 0 ]; then
17 | skipbackup=1
18 | migrate=1
19 | log "backup skipped, migration will use existing backup"
20 | else
21 | prun-opt /usr/sbin/btrfs property set -f -ts ${mig_dir}/${snap_dir} ro false
22 | for subsubvol in $(prun-opt /usr/sbin/btrfs subvolume list -o ${mig_dir}/${snap_dir} --sort=path | rev | cut -f1 -d' ' | rev | sed "s/^@//"); do
23 | prun /usr/sbin/btrfs subvolume delete ${subsubvol}
24 | done
25 | prun-opt /usr/sbin/btrfs subvolume delete ${mig_dir}/${snap_dir}
26 | prun-opt /usr/bin/rm ${mig_dir}/*.out
27 | prun-opt /usr/bin/rm ${mig_dir}/system-connections/*
28 | prun-opt /usr/bin/rmdir ${mig_dir}/system-connections
29 | prun-opt /usr/bin/rm ${mig_dir}/users/*
30 | prun-opt /usr/bin/rmdir ${mig_dir}/users
31 | prun-opt /usr/bin/rm ${mig_dir}/icons/*
32 | prun-opt /usr/bin/rmdir ${mig_dir}/icons
33 | prun-opt /usr/bin/rm ${mig_dir}/localtime
34 | prun-opt /usr/bin/rm ${mig_dir}/subgid
35 | prun-opt /usr/bin/rm ${mig_dir}/subuid
36 | prun-opt /usr/bin/rm ${mig_dir}/bluetooth/*
37 | prun-opt /usr/bin/rmdir ${mig_dir}/bluetooth
38 | prun-opt /usr/bin/rm ${mig_dir}/openvpn/*
39 | prun-opt /usr/bin/rmdir ${mig_dir}/openvpn
40 | prun-opt /usr/bin/rm -R ${mig_dir}/fprint/*
41 | prun-opt /usr/bin/rmdir ${mig_dir}/fprint
42 | prun-opt /usr/bin/rmdir ${mig_dir}/mnt
43 | fi
44 | fi
45 |
46 | get_disk
47 |
48 | if [ -z "${skipbackup}" ]; then
49 | # Although Legacy Aeon didn't officially support LUKS encrypted installations,
50 | # some users might have nevertheless enabled encryption anyway.
51 | # Search for existing crypto_LUKS partitions and, if found, prompt the user
52 | # to unlock those so that the migration module can find existing data.
53 | for encrypted_partition in $(lsblk ${TIK_INSTALL_DEVICE} -p -n -r -o ID-LINK,FSTYPE|tr -s ' ' ";"|grep ";crypto_LUKS"|cut -d\; -f1); do
54 | if [ -e /dev/mapper/crypt_${encrypted_partition} ]; then
55 | # Already opened for some reason... do not prompt for the passphrase
56 | # but ensure we will clean up afterwards
57 | crypt_opened="${crypt_opened} crypt_${encrypted_partition}"
58 | else
59 | while [ 1 ]; do
60 | passphrase=$(zenity --password --title="Encrypted partition (${encrypted_partition}) detected" --cancel-label="Skip") || break
61 | if [ -n "${passphrase}" ]; then
62 | echo -n "${passphrase}" | prun /usr/sbin/cryptsetup luksOpen /dev/disk/by-id/${encrypted_partition} crypt_${encrypted_partition}
63 | if [ "${?}" -eq 0 ]; then
64 | crypt_opened="${crypt_opened} crypt_${encrypted_partition}"
65 | # Wait for the mapped device to appear
66 | wait_count=0
67 | while [ ! -e /dev/mapper/crypt_${encrypted_partition} ] && [ ${wait_count} -lt 5 ]; do
68 | sleep 1
69 | wait_count=$((wait_count + 1))
70 | done
71 | break
72 | fi
73 | fi
74 | done
75 | fi
76 | done
77 | unset passphrase
78 |
79 | # Probe selected disk for a btrfs partition containing /usr/lib/os-release
80 | probe_partitions $TIK_INSTALL_DEVICE "btrfs" "/usr/lib/os-release"
81 |
82 | if [ -n "${probedpart}" ]; then
83 | prun /usr/bin/mkdir ${mig_dir}/mnt
84 | prun-opt /usr/bin/mount -o compress=zstd:1,subvol=/@/home ${probedpart} ${mig_dir}/mnt
85 | if [ ${retval} -eq 0 ]; then
86 | prun /usr/sbin/btrfs quota rescan -w ${mig_dir}/mnt | d --progress --title="Detected existing /home subvolume.." --pulsate --auto-close --no-cancel --width=400
87 | home_size=$(prun /usr/sbin/btrfs qgroup show --raw -f ${mig_dir}/mnt | grep @/home$ | awk '{print $2}')
88 | tik_stick_size=$(prun /usr/sbin/btrfs fi usage --raw ${mig_dir} | grep estimated | awk '{print $3}')
89 | if [ ${home_size} -gt ${tik_stick_size} ]; then
90 | # Not enough space to offer migration
91 | migrate=0
92 | fi
93 | if [ ${home_size} -le 16384 ]; then
94 | # /home subvolume is empty
95 | migrate=0
96 | fi
97 | prun /usr/bin/umount ${mig_dir}/mnt
98 | else
99 | log "no @/home subvolume found on ${probedpart}"
100 | migrate=0
101 | fi
102 | prun /usr/bin/rmdir ${mig_dir}/mnt
103 | # partition found, /home subvolume found, no known reason to not migrate, so ask the user
104 | if [ -z "${migrate}" ]; then
105 | if [ "${legacy_aeon}" == 1 ]; then
106 | d --info --width=300 --height=300 --icon=distributor-logo-Aeon-symbolic --no-wrap --title="Message from the Aeon Team" --text="We'd like to thank you for adopting openSUSE Aeon so early in it's development,\nbefore we fully understood what we were building or how we wanted it to look\n\nWe are sorry that you need to reinstall your system\n\nThank you so much for your support.\nWe hope you enjoy the new look openSUSE Aeon"
107 | fi
108 | zenity --question --no-wrap --title="Backup users from the existing install?" --text="These users will be restored to the new installation."
109 | migrateyn=$?
110 | if [ "${migrateyn}" == 0 ]; then
111 | migrate=1
112 | else
113 | migrate=0
114 | fi
115 | fi
116 | fi
117 |
118 | if [ "${migrate}" == 1 ]; then
119 | # We're migrating, lets go!
120 | prun /usr/bin/mkdir ${mig_dir}/mnt
121 | prun /usr/bin/mount -o compress=zstd:1,subvol=/@/home ${probedpart} ${mig_dir}/mnt
122 | # Check for existing snapshot from interrupted backup and delete if it exists boo#1224824
123 | if [ -d ${mig_dir}/mnt/${snap_dir} ]; then
124 | prun /usr/sbin/btrfs subvolume delete ${mig_dir}/mnt/${snap_dir}
125 | fi
126 | prun /usr/sbin/btrfs subvolume snapshot -r ${mig_dir}/mnt ${mig_dir}/mnt/${snap_dir}
127 | (prun /usr/sbin/btrfs send ${mig_dir}/mnt/${snap_dir} | pv -f -F "# %b copied in %t %r" | prun /usr/sbin/btrfs receive ${mig_dir}) 2>&1 | d --progress --title="Backing up /home" --pulsate --auto-close --no-cancel --width=400
128 | prun /usr/sbin/btrfs subvolume delete ${mig_dir}/mnt/${snap_dir}
129 | # Probe for subvolumes nested beneath /home and back them up also
130 | if (prun-opt /usr/sbin/btrfs subvolume list -o ${mig_dir}/mnt | grep -q "ID "); then
131 | prun /usr/sbin/btrfs property set -f -ts ${mig_dir}/${snap_dir} ro false
132 | for subsubvol in $(prun-opt /usr/sbin/btrfs subvolume list -o ${mig_dir}/mnt --sort=path | rev | cut -f1 -d' ' | rev | sed 's/^@\/home//'); do
133 | subsubvolname=$(basename $subsubvol)
134 | subsubdirname=$(dirname $subsubvol)
135 | prun /usr/sbin/btrfs subvolume snapshot -r ${mig_dir}/mnt/${subsubvol} ${mig_dir}/mnt/${subsubvolname}
136 | (prun /usr/sbin/btrfs send ${mig_dir}/mnt/${subsubvolname} | pv -f -F "# %b copied in %t %r" | prun /usr/sbin/btrfs receive ${mig_dir}/${snap_dir}/${subsubdirname}) 2>&1 | d --progress --title="Backing up containers" --pulsate --auto-close --no-cancel --width=400
137 | prun /usr/sbin/btrfs subvolume delete ${mig_dir}/mnt/${subsubvolname}
138 | done
139 | prun /usr/sbin/btrfs property set -f -ts ${mig_dir}/${snap_dir} ro true
140 | fi
141 | prun /usr/bin/umount ${mig_dir}/mnt
142 | prun /usr/bin/mount -o compress=zstd:1 ${probedpart} ${mig_dir}/mnt
143 | prun /usr/bin/mount -o compress=zstd:1,subvol=/@/var ${probedpart} ${mig_dir}/mnt/var
144 | etcmntcmd=$(cat ${mig_dir}/mnt/etc/fstab | grep "overlay /etc" | sed 's/\/sysroot\//${mig_dir}\/mnt\//g' | sed 's/\/work-etc.*/\/work-etc ${mig_dir}\/mnt\/etc\//' | sed 's/overlay \/etc overlay/\/usr\/bin\/mount -t overlay overlay -o/')
145 | eval prun "$etcmntcmd"
146 | prun /usr/bin/awk -F'[/:]' '($3 >= 1000 && $3 != 65534)' ${mig_dir}/mnt/etc/passwd | prun /usr/bin/awk -F':' '{ $7="/bin/bash"; print };' OFS=':' | prun tee ${mig_dir}/passwd.out
147 | prun /usr/bin/awk -F'[/:]' '($3 >= 1000 && $3 != 65534 && $3 != 65533)' ${mig_dir}/mnt/etc/group | prun tee ${mig_dir}/group.out
148 | prun /usr/bin/awk -F'[/:]' '{if ($3 >= 1000 && $3 != 65534) print $1}' ${mig_dir}/mnt/etc/passwd | prun /usr/bin/grep -f - ${mig_dir}/mnt/etc/shadow | prun tee ${mig_dir}/shadow.out
149 | prun /usr/bin/cp -a ${mig_dir}/mnt/etc/subuid ${mig_dir}/subuid
150 | prun /usr/bin/cp -a ${mig_dir}/mnt/etc/subgid ${mig_dir}/subgid
151 | # It's not guaranteed that the system will have existing network configs, custom localtime or AccountsService
152 | prun-opt /usr/bin/cp -a ${mig_dir}/mnt/etc/NetworkManager/system-connections ${mig_dir}/system-connections
153 | prun-opt /usr/bin/cp -a ${mig_dir}/mnt/etc/localtime ${mig_dir}/localtime
154 | prun-opt /usr/bin/cp -a ${mig_dir}/mnt/var/lib/AccountsService/users ${mig_dir}/users
155 | prun-opt /usr/bin/chmod 744 ${mig_dir}/users
156 | prun-opt /usr/bin/cp -a ${mig_dir}/mnt/var/lib/AccountsService/icons ${mig_dir}/icons
157 | prun-opt /usr/bin/cp -a ${mig_dir}/mnt/var/lib/bluetooth ${mig_dir}/bluetooth
158 | prun-opt /usr/bin/cp -a ${mig_dir}/mnt/var/lib/fprint ${mig_dir}/fprint
159 | prun-opt /usr/bin/cp -a ${mig_dir}/mnt/etc/openvpn ${mig_dir}/openvpn
160 | prun-opt /usr/bin/umount ${mig_dir}/mnt/etc
161 | prun /usr/bin/umount ${mig_dir}/mnt/var
162 | prun /usr/bin/umount ${mig_dir}/mnt
163 | prun /usr/bin/rmdir ${mig_dir}/mnt
164 | fi
165 |
166 | # Close eventual mapped LUKS devices
167 | if [ -n "${crypt_opened}" ]; then
168 | for mapped_partition in ${crypt_opened}; do
169 | if [ -e /dev/mapper/crypt_${encrypted_partition} ]; then
170 | # We are going to replace the encrypted partition anyway, so if
171 | # we're unable to gracefully close the device after 5 seconds,
172 | # just give up (hence the prun-opt usage)
173 | wait_count=0
174 | while ! prun-opt /usr/sbin/cryptsetup luksClose /dev/mapper/${mapped_partition} && [ ${wait_count} -lt 5 ]; do
175 | sleep 1
176 | wait_count=$((wait_count + 1))
177 | done
178 | fi
179 | done
180 | fi
181 |
182 | fi
183 |
--------------------------------------------------------------------------------
/usr/lib/tik/modules/post/15-encrypt:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | # SPDX-FileCopyrightText: Copyright 2024 SUSE LLC
3 | # SPDX-FileCopyrightText: Copyright 2024 Richard Brown
4 |
5 | # Module does not actually do any encryption, but is intended to finish installation of an encrypted image, such as one deployed via systemd-repart
6 | # Module expects to find a single ESP partition (find_esp) and a single LUKS2 partition (find_crypt) on $TIK_INSTALL_DEVICE, upon which it will do the following
7 | # - Open the encrypted device, mounting var, etc, boot/efi, tmp, run, sys, dev and proc (open_partition)
8 | # - Against the mounted partition, do the following (configure_encryption)
9 | # - write /etc/kernel/cmdline
10 | # - write /etc/crypttab
11 | # - update any /etc/fstab lines regarding /boot/efi and replace them with the correct ones for the on disk vfat filesystem
12 | # - populate /boot/efi with sdbootutil install & sdbootutil mkinitrd
13 | # - populate /etc/sysconfig/fde-tools (so the measurements can be updated on first boot)
14 | # - Close the partition (close_partition)
15 | # - Generate a recovery key (generate_recoveryKey)
16 | # - Add recovery key to device and identify it as a systemd-recovery key (add_recoveryKey)
17 | # - Display the recovery key to the user (display_recoveryKey)
18 | # - Remove the temporary key-file and replace it either with TPM enrollment or a user-supplied passphrase (add_key)
19 | # It is expected the LUKS2 partition is already encrypted with a key-file in the only populated keyslot.
20 |
21 | encrypt_dir=/var/lib/tik/encrypt
22 | encrypt_pipe=/tmp/encryptpipe
23 | if [ ! -d ${encrypt_dir}/mnt ]; then
24 | prun /usr/bin/mkdir -p ${encrypt_dir}/mnt
25 | fi
26 | if [ ! -p ${encrypt_pipe} ]; then
27 | mkfifo ${encrypt_pipe}
28 | fi
29 |
30 | crypt_progress() {
31 | log "[crypt_progress] Monitoring encryption progress"
32 | (tail -f ${encrypt_pipe}) | d --progress --title="Configuring Encryption" --auto-close --no-cancel --width=400
33 | rm ${encrypt_pipe}
34 | log "[crypt_progress] Encryption progress reached 100%"
35 | }
36 |
37 | find_crypt() {
38 | echo "# Finding encrypted partition" > ${encrypt_pipe}
39 | log "[find_crypt] finding encrypted partition"
40 | probe_partitions ${TIK_INSTALL_DEVICE} "crypto_LUKS"
41 | if [ -z "${probedpart}" ]; then
42 | error "encrypted partition not found"
43 | fi
44 | cryptpart=${probedpart}
45 | log "[find_crypt] found ${cryptpart}"
46 | echo "14" > ${encrypt_pipe}
47 | }
48 |
49 | find_esp() {
50 | echo "# Finding encrypted partition" > ${encrypt_pipe}
51 | log "[find_esp] finding ESP"
52 | probe_partitions ${TIK_INSTALL_DEVICE} "vfat"
53 | if [ -z "${probedpart}" ]; then
54 | error "esp partition not found"
55 | fi
56 | esppart=${probedpart}
57 | log "[find_esp] found ${esppart}"
58 | echo "28" > ${encrypt_pipe}
59 | }
60 |
61 | open_partition() {
62 | echo "# Opening ${cryptpart}" > ${encrypt_pipe}
63 | log "[open_partition] opening ${cryptpart} and mounting for chroot"
64 | prun /usr/sbin/cryptsetup luksOpen --key-file=${tik_keyfile} ${cryptpart} aeon_root
65 | echo "35" > ${encrypt_pipe}
66 | prun /usr/bin/mount -o compress=zstd:1 /dev/mapper/aeon_root ${encrypt_dir}/mnt
67 | for i in proc dev sys tmp 'sys/firmware/efi/efivars' 'sys/fs/cgroup'; do
68 | prun /usr/bin/mount --bind "/$i" "${encrypt_dir}/mnt/$i"
69 | done
70 | prun /usr/bin/mount -o compress=zstd:1,subvol=/@/.snapshots /dev/mapper/aeon_root ${encrypt_dir}/mnt/.snapshots
71 | prun /usr/bin/mount -o compress=zstd:1,subvol=/@/var /dev/mapper/aeon_root ${encrypt_dir}/mnt/var
72 | etcmountcmd=$(cat ${encrypt_dir}/mnt/etc/fstab | grep "overlay /etc" | sed 's/\/sysroot\//${encrypt_dir}\/mnt\//g' | sed 's/\/work-etc.*/\/work-etc ${encrypt_dir}\/mnt\/etc\//' | sed 's/overlay \/etc overlay/\/usr\/bin\/mount -t overlay overlay -o/')
73 | eval prun "$etcmountcmd"
74 | prun /usr/bin/mount ${esppart} ${encrypt_dir}/mnt/boot/efi
75 | prun /usr/bin/mount -t tmpfs tmpfs "${encrypt_dir}/mnt/run"
76 | prun /usr/bin/mount -t securityfs securityfs "${encrypt_dir}/mnt/sys/kernel/security"
77 | echo "42" > ${encrypt_pipe}
78 | }
79 |
80 | configure_encryption() {
81 | # If Default Mode has been detected, configure crypttab for TPM
82 | if [ "${tik_encrypt_mode}" == 0 ]; then
83 | crypttab_opts=',tpm2-device=auto'
84 | fi
85 | echo "# Writing cmdline, crypttab, and fstab" > ${encrypt_pipe}
86 | log "[configure_encryption] configuring cmdline, crypttab, PCR policy, fstab and populating ${esppart}"
87 | espUUID=$(lsblk -n -r -o UUID ${esppart})
88 | prun /usr/bin/gawk -v espUUID=$espUUID -i inplace '$2 == "/boot/efi" { $1 = "UUID="espUUID } { print $0 }' ${encrypt_dir}/mnt/etc/fstab
89 | # root=UUID= cmdline definition is a hard requirement of sdbootutil for updating predictions
90 | rootUUID=$(lsblk -n -r -o UUID /dev/mapper/aeon_root)
91 | prun /usr/bin/sed -i -e "s,\$, root=UUID=${rootUUID}," ${encrypt_dir}/mnt/etc/kernel/cmdline
92 | # /etc/crypttab is a hard requirement of sdbootutil for updating predictions
93 | cryptUUID=$(lsblk -n -r -d -o UUID ${cryptpart})
94 | echo "aeon_root UUID=${cryptUUID} none x-initrd.attach${crypttab_opts}" | prun tee ${encrypt_dir}/mnt/etc/crypttab
95 | echo "# Installing boot loader" > ${encrypt_pipe}
96 | # Populate ESP
97 | prun /usr/bin/chroot ${encrypt_dir}/mnt sdbootutil -vv --esp-path /boot/efi --no-variables install 1>&2
98 | echo "56" > ${encrypt_pipe}
99 | echo "# Creating initrd" > ${encrypt_pipe}
100 | # FIXME: Dracut gets confused by previous installations on occasion with the default config, override the problematic option temporarily
101 | /usr/bin/echo 'hostonly_cmdline="no"' | prun tee ${encrypt_dir}/mnt/etc/dracut.conf.d/99-tik.conf
102 | # mkinitrd done by add-all-kernels
103 | prun /usr/bin/chroot ${encrypt_dir}/mnt sdbootutil -vv --esp-path /boot/efi --no-variables add-all-kernels 1>&2
104 | # FIXME: Dracut gets confused by previous installations on occasion with the default config, remove override now initrd done
105 | prun /usr/bin/rm ${encrypt_dir}/mnt/etc/dracut.conf.d/99-tik.conf
106 | echo "70" > ${encrypt_pipe}
107 | # If Default mode has been detected, configure PCR policy
108 | if [ "${tik_encrypt_mode}" == 0 ]; then
109 | # Explaining the chosen PCR list below
110 | # - 0 - UEFI firmware, will require recovery key after firmware update
111 | # - 4 - Bootloader and drivers, should never recovery key as bootloader should only be updated with new PCR measurements
112 | # - 5 - GPT Partition table, should never require recovery key as partition layout shouldn't change
113 | # - 7 - SecureBoot state, will require recovery key if SecureBoot is enabled/disabled
114 | # - 9 - initrd - should never require recovery key as initrd should only be updated with new PCR measurements
115 | echo "FDE_SEAL_PCR_LIST=0,4,5,7,9" | prun tee ${encrypt_dir}/mnt/etc/sysconfig/fde-tools
116 | # Explaining why the following PCRs were not used
117 | # - 1 - Not only changes with CPU/RAM/hardware changes, but also when UEFI config changes are made, which is too common to lockdown
118 | # - 2 - Includes option ROMs on pluggable hardware, such as external GPUs. Attaching a GPU to your laptop shouldn't hinder booting.
119 | # - 3 - Firmware from pluggable hardware. Attaching hardware to your laptop shouldn't hinder booting
120 | prun /usr/bin/tee ${encrypt_dir}/mnt/etc/systemd/system/firstboot-update-predictions.service << EOF
121 | [Unit]
122 | Description=First Boot Update Predictions
123 | ConditionSecurity=tpm2
124 |
125 | [Service]
126 | Type=oneshot
127 | ExecStart=rm /etc/systemd/system/firstboot-update-predictions.service
128 | ExecStart=rm /etc/systemd/system/default.target.wants/firstboot-update-predictions.service
129 | ExecStart=/usr/bin/sdbootutil update-predictions
130 |
131 | [Install]
132 | WantedBy=default.target
133 | EOF
134 | prun /usr/bin/ln -s ${encrypt_dir}/mnt/etc/systemd/system/firstboot-update-predictions.service ${encrypt_dir}/mnt/etc/systemd/system/default.target.wants/firstboot-update-predictions.service
135 | log "[configure_encryption] Generating Predictions"
136 | echo "# Generating TPM Predictions" > ${encrypt_pipe}
137 | prun /usr/bin/chroot ${encrypt_dir}/mnt sdbootutil -vv update-predictions
138 | echo "73" > ${encrypt_pipe}
139 | log "[configure_encryption] Default Mode - Enrolling ${cryptpart} to TPM 2.0"
140 | echo "# Enrolling to TPM" > ${encrypt_pipe}
141 | prun /usr/bin/chroot ${encrypt_dir}/mnt systemd-cryptenroll --unlock-key-file=${tik_keyfile} --tpm2-device=auto ${cryptpart}
142 | echo "76" > ${encrypt_pipe}
143 | fi
144 | }
145 |
146 | close_partition() {
147 | echo "# Closing ${cryptpart}" > ${encrypt_pipe}
148 | log "[close_partition] unmounting and closing ${cryptpart}"
149 | for i in proc dev run tmp 'boot/efi' etc var '.snapshots' 'sys/kernel/security' 'sys/firmware/efi/efivars' 'sys/fs/cgroup' sys; do
150 | prun /usr/bin/umount "${encrypt_dir}/mnt/$i"
151 | done
152 | prun /usr/bin/umount ${encrypt_dir}/mnt
153 | prun /usr/sbin/cryptsetup luksClose aeon_root
154 | echo "77" > ${encrypt_pipe}
155 | }
156 |
157 | generate_recoveryKey() {
158 | echo "# Generating recovery key" > ${encrypt_pipe}
159 | log "[generate_recoveryKey] generating recovery key"
160 | modhex=('c' 'b' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'n' 'r' 't' 'u' 'v')
161 | mapfile -t raw_key < <(hexdump -v --format '1/1 "%u\n"' -n 32 /dev/random)
162 | [ "${#raw_key[@]}" = 32 ]
163 | key=""
164 | for ((i=0;i<"${#raw_key[@]}";++i)); do
165 | [ "$i" -gt 0 ] && [ "$((i%4))" -eq 0 ] && key="${key}-"
166 | c="${raw_key[i]}"
167 | key="${key}${modhex[$((c>>4))]}${modhex[$((c&15))]}"
168 | done
169 | echo "84" > ${encrypt_pipe}
170 | }
171 |
172 | add_recoveryKey() {
173 | echo "# Adding recovery key to ${cryptpart}" > ${encrypt_pipe}
174 | log "[add_recoveryKey] adding recovery key to ${cryptpart}"
175 | prun /usr/sbin/cryptsetup luksAddKey --key-file=${tik_keyfile} --batch-mode --force-password "${cryptpart}" <<<"${key}"
176 | echo '{"type":"systemd-recovery","keyslots":["2"]}' | prun /usr/sbin/cryptsetup token import "${cryptpart}"
177 | echo "100" > ${encrypt_pipe}
178 | }
179 |
180 | display_recoveryKey() {
181 | local defaultmsg="This ${TIK_OS_NAME} system is encrypted and checks its own integrity on every boot\nIn the event of these integrity checks failing, you will need to use the Recovery Key provided below to enter this system\n\nLikely reasons for integrity checks failing include:\n\n• UEFI System Firmware updated\n• Secure Boot changed from enabled or disabled\n• Boot drive was moved to a different computer\n• Disk partitions were changed\n• Boot loader or initrd were altered unexpectedly\n\nIf you are unaware as to why the system is requesting the recovery key, this systems security may have been compromised\nThe best course of action may be to not unlock the disk until you can determine what changed to require the Recovery Key\n\nThis systems Recovery Key is:\n\n ${key}\n\nPlease save this secret Recovery Key in a secure location\n\n"
182 | local fallbackmsg="In addition to your Passphrase a Recovery Key has been generated:\n\n ${key}\n\nPlease save this secret Recovery Key in a secure location\nIt may be used to regain access to this system if the other Passphrase becomes lost or forgotten\n\n"
183 | local message
184 | [ "${tik_encrypt_mode}" == 0 ] && message=${defaultmsg}
185 | [ "${tik_encrypt_mode}" == 1 ] && message=${fallbackmsg}
186 | log "[display_recoveryKey] displaying recovery key"
187 | zenity --width=500 --height=500 --no-wrap --warning --icon=security-high-symbolic --title="Encryption Recovery Key" --text="${message}You may optionally scan the recovery key off screen:\n$(qrencode ${key} -t UTF8i)\nFor more information please visit https://aeondesktop.org/encrypt"
188 | log "[display_recoveryKey] recovery key dialogue dismissed"
189 | }
190 |
191 | add_key() {
192 | if [ "${tik_encrypt_mode}" == 1 ]; then
193 | d --width=500 --height=300 --no-wrap --warning --icon=security-high-symbolic --title="Set Encryption Passphrase" --text="This ${TIK_OS_NAME} system is encrypted and will require a Passphrase on every boot\n\nYou will be prompted to set the Passphrase on the next screen\n\nFor more information please visit https://aeondesktop.org/encrypt"
194 | log "[add_key] Fallback Mode - Prompting user for passphrase for ${cryptpart}"
195 | # Not using 'd' function to avoid logging the password
196 | while true
197 | do
198 | retval=0
199 | key="$(zenity --password --title='Set Encryption Passphrase')" || retval=$?
200 | case $retval in
201 | 0)
202 | prun /usr/sbin/cryptsetup luksAddKey --key-file=${tik_keyfile} --batch-mode --force-password "${cryptpart}" <<<"${key}"
203 | return 0
204 | ;;
205 | 1|255)
206 | zenity --question --text="Do you really want to quit?" && exit 1
207 | ;;
208 | esac
209 | done
210 | fi
211 | }
212 |
213 | crypt_progress &
214 | find_crypt
215 | find_esp
216 | open_partition
217 | configure_encryption
218 | close_partition
219 | add_key
220 | generate_recoveryKey
221 | add_recoveryKey
222 | display_recoveryKey
--------------------------------------------------------------------------------
/usr/lib/tik/lib/tik-functions:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 | # SPDX-FileCopyrightText: Copyright 2023-2024 SUSE LLC
3 | # SPDX-FileCopyrightText: Copyright 2023-2024 Richard Brown
4 |
5 | log(){
6 | echo "[${tik_module}][$(date +"%Y%m%d-%T")][LOG] $*" 1>&2
7 | }
8 |
9 | warn() {
10 | echo "[${tik_module}][$(date +"%Y%m%d-%T")][WARN] $*" 1>&2
11 | d --warning --text="$*"
12 | }
13 |
14 | error() {
15 | echo "[${tik_module}][$(date +"%Y%m%d-%T")][ERROR] $*" 1>&2
16 | d --error --text "$*"
17 | exit 1
18 | }
19 |
20 | d(){
21 | while true
22 | do
23 | retval=0
24 | result="$(zenity "$@")" || retval=$?
25 | log "[zenity][${retval}][${result}] $@"
26 | case $retval in
27 | 0)
28 | return 0
29 | ;;
30 | 1|255)
31 | zenity --question --text="Do you really want to quit?" && exit 1
32 | ;;
33 | esac
34 | done
35 | }
36 |
37 | # variant of privileged run (prun) function that doesn't require the pkexec call to return 0
38 | prun-opt() {
39 | if [ "${debug}" == "1" ]; then
40 | log "[pkexec-noexec] $@"
41 | else
42 | retval=0
43 | pkexec "$@"
44 | retval=$?
45 | log "[pkexec][${retval}] $@"
46 | fi
47 | }
48 |
49 | # Most commonly used prun function, which requires the called command to work
50 | prun() {
51 | prun-opt "$@"
52 | if [ "${retval}" != "0" ]; then
53 | error "Command $@ FAILED"
54 | fi
55 | }
56 |
57 | get_persistent_device_from_unix_node() {
58 | local unix_device=$1
59 | local schema=$2
60 | local node
61 | local persistent_name
62 | node=$(basename "${unix_device}")
63 | for persistent_name in /dev/disk/"${schema}"/*; do
64 | if [ "$(basename "$(readlink "${persistent_name}")")" = "${node}" ];then
65 | if [[ ${persistent_name} =~ ^/dev/disk/"${schema}"/nvme-eui ]]; then
66 | # Filter out nvme-eui nodes as they are not descriptive to the user
67 | continue
68 | fi
69 | echo "${persistent_name}"
70 | return
71 | fi
72 | done
73 | warn "Could not find ${schema} representation of ${node}. Using original device ${unix_device}"
74 | echo "${unix_device}"
75 | }
76 |
77 | probe_partitions() {
78 | local probe_dir=/var/lib/tik/probe
79 | local filesystem_type=$2
80 | local filematch=$3
81 | local device=$1
82 | local mountops
83 | local part
84 | if [[ "${filesystem_type}" == "btrfs" ]]; then
85 | mountops="-o compress=zstd:1"
86 | fi
87 | prun /usr/bin/mkdir -p ${probe_dir}/mnt
88 | probedpart=""
89 | for part in $(lsblk ${device} -p -n -r -o ID-LINK,FSTYPE|tr -s ' ' ";"|grep ";${filesystem_type}"|cut -d\; -f1); do
90 | if [ -z ${filematch} ]; then
91 | log "[probe_partitions] no file match required"
92 | # Fallback to unix device in order to fix issue with USB devices
93 | probedpart="$(/usr/bin/readlink -f "/dev/disk/by-id/""${part}")"
94 | log "[probe_partitions] Partition ${probedpart} found"
95 | else # Check if ${filematch} exists
96 | # Fallback to unix device in order to fix issue with USB devices
97 | part="$(/usr/bin/readlink -f "/dev/disk/by-id/""${part}")"
98 | prun /usr/bin/mount ${mountops} ${part} "${probe_dir}/mnt"
99 | if [ -f ${probe_dir}/mnt/${filematch} ]; then
100 | log "[probe_partitions] File ${filematch} found"
101 | # Fallback to unix device in order to fix issue with USB devices
102 | probedpart="${part}"
103 | log "[probe_partitions] Partition ${probedpart} found"
104 | if grep -q 'PRETTY_NAME="openSUSE MicroOS"' ${probe_dir}/mnt/${filematch} && [ -f ${probe_dir}/mnt/usr/bin/gnome-shell ]; then
105 | # Found legacy Aeon, activate easter egg
106 | log "Legacy Aeon Install FOUND"
107 | legacy_aeon=1
108 | fi
109 | fi
110 | prun-opt /usr/bin/umount ${probe_dir}/mnt
111 | fi
112 | done
113 | prun /usr/bin/rmdir ${probe_dir}/mnt
114 | }
115 |
116 | get_disk() {
117 | # Volume label for the tik install media must be set to "TIKINSTALL" to filter it out from the device list
118 | tik_volid="TIKINSTALL"
119 | local disk_id="by-id"
120 | local disk_size
121 | local disk_device
122 | local disk_device_by_id
123 | local disk_meta
124 | local disk_list
125 | local device_array
126 | local list_items
127 | local blk_opts="-p -n -r -o NAME,SIZE,TYPE"
128 | local message
129 | local blk_opts_plus_label="${blk_opts},LABEL"
130 | local tik_install_disk_part
131 | local part_meta
132 | local part_count
133 | local part_size
134 | local part_info
135 | local part_fs
136 | local blk_opts_part_info="${blk_opts_plus_label},FSTYPE"
137 | local usb_match_1="usb"
138 | local usb_match_2=":0"
139 |
140 | tik_install_disk_part=$(
141 | eval lsblk "${blk_opts_plus_label}" | \
142 | tr -s ' ' ":" | \
143 | grep ":${tik_volid}" | \
144 | cut -f1 -d:
145 | )
146 |
147 | for disk_meta in $(
148 | eval lsblk "${blk_opts}" | grep -E "disk|raid" | tr ' ' ":"
149 | );do
150 | disk_size=$(echo "${disk_meta}" | cut -f2 -d:)
151 | if [[ "${disk_size}" == "0B" ]]; then
152 | # ignore disks with no size, e.g. empty SD card readers
153 | continue
154 | fi
155 | disk_device="$(echo "${disk_meta}" | cut -f1 -d:)"
156 | # find partitions and info for this disk
157 | part_count=0
158 | part_info=""
159 | for part_meta in $(
160 | eval lsblk "${blk_opts_part_info}" | grep -E "${disk_device}.+part.+" | tr ' ' ":"
161 | );do
162 | part_count=$(expr $part_count + 1)
163 | part_size=$(echo "${part_meta}" | cut -f2 -d:)
164 | part_fs=$(echo "${part_meta}" | cut -f5 -d:)
165 | if [ -n "${part_info}" ]; then
166 | part_info="${part_info},"
167 | fi
168 | if [ -n "${part_fs}" ]; then
169 | part_info="${part_info}${part_fs}(${part_size})"
170 | else
171 | part_info="${part_info}unknown(${part_size})"
172 | fi
173 | done
174 | if [[ ${part_count} -eq 0 ]]; then
175 | part_info="none"
176 | fi
177 | if [[ "${tik_install_disk_part}" == "${disk_device}"* ]]; then
178 | # ignore install source device
179 | continue
180 | fi
181 | if [[ ${disk_device} =~ ^/dev/fd ]];then
182 | # ignore floppy disk devices
183 | continue
184 | fi
185 | if [[ ${disk_device} =~ ^/dev/zram ]];then
186 | # ignore zram devices
187 | continue
188 | fi
189 | disk_device_by_id=$(
190 | get_persistent_device_from_unix_node "${disk_device}" "${disk_id}"
191 | )
192 | if [[ ( "${TIK_ALLOW_USB_INSTALL_DEVICES}" -ne 1 ) && ( "{$disk_device_by_id}" == *"${usb_match_1}"* || "{$disk_device_by_id}" == *"${usb_match_2}"* ) ]]; then
193 | # ignore USB devices if TIK_ALLOW_USB_INSTALL_DEVICES not set in config
194 | continue
195 | fi
196 | if [ -n "${disk_device_by_id}" ];then
197 | disk_device=${disk_device_by_id}
198 | fi
199 | list_items="${list_items} $(basename ${disk_device}) ${disk_size} ${part_count} ${part_info}"
200 | disk_list="${disk_list} $(basename ${disk_device}) ${disk_size}"
201 | done
202 | if [ -n "${TIK_INSTALL_DEVICE}" ];then
203 | # install device overwritten by config.
204 | local device=${TIK_INSTALL_DEVICE}
205 | local device_meta
206 | local device_size
207 | if [ ! -e "${device}" ];then
208 | local no_dev="Given device ${device} does not exist."
209 | error "${no_dev}"
210 | fi
211 | if [ ! -b "${device}" ];then
212 | local no_block_dev="Given device ${device} is not a block special."
213 | error "${no_block_dev}"
214 | fi
215 | device_meta=$(
216 | eval lsblk "${blk_opts}" "${device}" |\
217 | grep -E "disk|raid" | tr ' ' ":"
218 | )
219 | device_size=$(echo "${device_meta}" | cut -f2 -d:)
220 | # this case is not shown in manual selection, threfore we don't need partition info
221 | list_items="$(basename ${device}) ${device_size}"
222 | disk_list="$(basename ${device}) ${device_size}"
223 | message="tik installation device set to to: ${device}"
224 | log "${message}"
225 | fi
226 | if [ -z "${list_items}" ];then
227 | local no_device_text="No device(s) for installation found."
228 | error "${no_device_text}"
229 | fi
230 | if [ -n "${disk_list}" ];then
231 | local count=0
232 | local device_index=0
233 | for entry in ${disk_list};do
234 | if [ $((count % 2)) -eq 0 ];then
235 | device_array[${device_index}]=${entry}
236 | device_index=$((device_index + 1))
237 | fi
238 | count=$((count + 1))
239 | done
240 | if [ "${device_index}" -eq 1 ];then
241 | # one single disk device found, use it
242 | # Add back full path to it
243 | TIK_INSTALL_DEVICE="/dev/disk/${disk_id}/${device_array[0]}"
244 |
245 | # Fallback to unix device in case by-id does not exist
246 | # see get_persistent_device_from_unix_node, it does fallback like this.
247 | if [ ! -e "${TIK_INSTALL_DEVICE}" ]; then
248 | TIK_INSTALL_DEVICE="/dev/${device_array[0]}"
249 | fi
250 | else
251 | # manually select from storage list
252 | d --list --column=Disk --column=Size --column=Partitions --column=Filesystems --width=1050 --height=340 --title="Select A Disk" --text="Select the disk to install the operating system to. Make sure any important documents and files have been backed up.\n" ${list_items}
253 | # Add back full path to it
254 | TIK_INSTALL_DEVICE="/dev/disk/${disk_id}/${result}"
255 |
256 | # Fallback to unix device in case by-id does not exist
257 | # see get_persistent_device_from_unix_node, it does fallback like this.
258 | if [ ! -e "${TIK_INSTALL_DEVICE}" ]; then
259 | TIK_INSTALL_DEVICE="/dev/${result}"
260 | fi
261 | fi
262 | fi
263 | }
264 |
265 | get_img() {
266 | local list_items
267 | local message
268 | local img_meta
269 | local img_item
270 | local img_list
271 | local img_array
272 | local file_type
273 | # Images are assumed to be named to the following standard
274 | # $ProductName.$Version.raw.xz for block devices
275 | # $ProductName.$Version.raw for systemd-repart images
276 | # Any extraneous fields may confuse tik's detection, selection and presentation of the image to the user
277 | for file_type in '*.raw.xz' '*.raw';do
278 | for img_meta in $(cd $TIK_IMG_DIR && (stat --printf="%n\t%s\n" ${file_type} | tr ' ' ":"));do
279 | img_filename="$(echo $img_meta | cut -f1 -d:)"
280 | img_size="$(echo $img_meta | cut -f2 -d:)"
281 | list_items="${list_items} ${img_filename} ${img_size}"
282 | done
283 | done
284 | if [ -n "${TIK_INSTALL_IMAGE}" ];then
285 | # install image overwritten by config.
286 | local img=${TIK_INSTALL_IMAGE}
287 | local img_meta
288 | local img_size
289 | if [ ! -e "${img}" ];then
290 | local no_img="Given image ${img} does not exist."
291 | error "${no_img}"
292 | fi
293 | if [ ! -s "${img}" ];then
294 | local empty_img="Given image ${img} is empty."
295 | error "${empty_img}"
296 | fi
297 | img_meta=$(
298 | eval cd $TIK_IMG_DIR && (stat --printf="%n\t%s\n" $img | tr ' ' ":")
299 | )
300 | img_filename="$(echo $img_meta | cut -f1 -d:)"
301 | img_size="$(echo $img_meta | cut -f2 -d:)"
302 | list_items="${list_items} ${img_filename} ${img_size}"
303 | message="tik installation image set to to: ${img}"
304 | log "${message}"
305 | fi
306 | if [ -z "${list_items}" ];then
307 | TIK_INSTALL_IMAGE='TIK_SELFDEPLOY'
308 | fi
309 | img_list=${list_items}
310 | if [ -n "${img_list}" ];then
311 | local count=0
312 | local img_index=0
313 | for entry in ${img_list};do
314 | if [ $((count % 2)) -eq 0 ];then
315 | img_array[${img_index}]=${entry}
316 | img_index=$((img_index + 1))
317 | fi
318 | count=$((count + 1))
319 | done
320 | if [ "${img_index}" -eq 1 ];then
321 | # one single disk image found, use it
322 | TIK_INSTALL_IMAGE="${img_array[0]}"
323 | else
324 | # manually select from storage list
325 | d --list --column=Image --column=Size --title="Select A Image" --text="Select the operating system image to install.\n" ${list_items}
326 | TIK_INSTALL_IMAGE="$result"
327 | fi
328 | fi
329 | }
330 |
331 | reread_partitiontable() {
332 | # We've just done a lot to $TIK_INSTALL_DEVICE and it's probably a good idea to make sure the partition table is clearly read so tools like dracut dont get confused.
333 | log "[reread_partitiontable] Re-reading partition table"
334 | prun /usr/sbin/blockdev --rereadpt ${TIK_INSTALL_DEVICE}
335 | }
336 |
337 | create_keyfile() {
338 | # Even if there's no partitions using encryption, systemd-repart will need a key-file defined for the --key-file parameter.
339 | tik_keyfile=/tmp/tikkeyfile
340 | log "[create_keyfile] Creating keyfile ${tik_keyfile}"
341 | prun /usr/bin/dd bs=512 count=4 if=/dev/urandom of=${tik_keyfile} iflag=fullblock
342 | prun /usr/bin/chmod 400 ${tik_keyfile}
343 | }
344 |
345 | wipe_keyfile() {
346 | # We made a keyfile and need to clean it up at the end of the installation, possibly wiping it from the newly installed device
347 | log "[wipe_keyfile] Deleting keyfile ${tik_keyfile}"
348 | probe_partitions ${TIK_INSTALL_DEVICE} "crypto_LUKS"
349 | if [ -n "${probedpart}" ]; then
350 | # Assumes Slot 0 is always by the key-file at enrolment
351 | prun /usr/bin/systemd-cryptenroll --unlock-key-file=${tik_keyfile} --wipe-slot=0 ${probedpart}
352 | fi
353 | # We're done with the key-file, so remove it
354 | prun /usr/bin/rm ${tik_keyfile}
355 | }
356 |
357 | dump_image() {
358 | local image_source_files=$1
359 | local image_target=$2
360 |
361 | d --question --no-wrap --title="Begin Installation?" --text="Once the installation begins the changes to the selected disk are irreversible.\n\nProceeding will fully erase the disk.\n\nContinue with installation?"
362 |
363 | case "${image_source_files}" in
364 | *.raw.xz)
365 | dump_image_dd ${image_source_files} ${image_target}
366 | ;;
367 | *.raw)
368 | dump_image_repart_image ${image_source_files} ${image_target}
369 | ;;
370 | TIK_SELFDEPLOY)
371 | dump_image_repart_self ${image_target}
372 | ;;
373 | *)
374 | error "invalid image type provided"
375 | esac
376 | }
377 |
378 | dump_image_dd() {
379 | local image_source_files=$1
380 | local image_target=$2
381 | log "[dump_image_dd] deploying ${TIK_IMG_DIR}/${image_source_files}"
382 | (xzcat ${TIK_IMG_DIR}/${image_source_files} | pv -f -F "# %b copied in %t %r" | prun /usr/bin/dd of=${image_target} bs=64k) 2>&1 | d --progress --title="Installing ${TIK_OS_NAME}" --pulsate --auto-close --no-cancel --width=400
383 | prun /usr/bin/sync | d --progress --title="Syncing" --pulsate --auto-close --no-cancel --width=400
384 | }
385 |
386 | dump_image_repart_image() {
387 | local image_source_files=$1
388 | local image_target=$2
389 | local success=0
390 | local max_attempts=5
391 | local attempt_num=1
392 | create_keyfile
393 | log "[dump_image_repart_image] deploying ${TIK_IMG_DIR}/${image_source_files}"
394 | # systemd-repart doesn't always parse the contents of the image perfectly first time, so retry a few times before declaring it a failure
395 | while [ ${success} = 0 ] && [ ${attempt_num} -lt ${max_attempts} ]; do
396 | prun-opt systemd-repart --no-pager --pretty=0 --empty=force --dry-run=no --key-file=${tik_keyfile} --image=${TIK_IMG_DIR}/${image_source_files} --image-policy=root=unprotected ${image_target} > >(d --progress --title="Installing ${TIK_OS_NAME}" --text="Deploying OS Image" --pulsate --auto-close --no-cancel --width=400)
397 | if [ ${retval} -eq 0 ]; then
398 | success=1
399 | else
400 | # repart couldn't find a root partition
401 | log "[dump_image_repart_image] systemd-repart attempt $attempt_num failed. Trying again..."
402 | sleep 1
403 | # Increment the attempt counter
404 | attempt_num=$(( attempt_num + 1 ))
405 | fi
406 | done
407 | if [ ${success} = 1 ]; then
408 | log "[dump_image_repart_image] systemd-repart succeeded after $attempt_num attempts"
409 | else
410 | error "systemd-repart failed"
411 | fi
412 | }
413 |
414 | dump_image_repart_self() {
415 | local image_target=$1
416 | create_keyfile
417 | log "[dump_image_repart_self] self-deploying"
418 | prun systemd-repart --no-pager --pretty=0 --empty=force --dry-run=no --key-file=${tik_keyfile} ${image_target} > >(d --progress --title="Installing ${TIK_OS_NAME}" --text="Deploying OS Image" --pulsate --auto-close --no-cancel --width=400)
419 | }
420 |
421 | set_boot_target() {
422 | local efipartnum
423 | if [ "${debug}" == "1" ]; then
424 | log "[debug] Not setting EFI boot target"
425 | elif [ -n "${efi_already_set}" ]; then
426 | log "[set_boot_target] boot target already set, not setting again"
427 | else
428 | # Cleanup any existing openSUSE boot entries
429 | prun-opt /usr/sbin/efibootmgr -B -L "openSUSE Boot Manager"
430 | prun /usr/sbin/efibootmgr -O
431 | log "[set_boot_target] searching for ESP partition containing /EFI/systemd/shim.efi on ${TIK_INSTALL_DEVICE}"
432 | probe_partitions ${TIK_INSTALL_DEVICE} "vfat" "/EFI/systemd/shim.efi"
433 | if [ -z "${probedpart}" ]; then
434 | error "esp partition not found"
435 | fi
436 | efipartnum=$(lsblk ${probedpart} -p -n -r -o PARTN)
437 | log "[set_boot_target] found ESP on ${probedpart}, partition number ${efipartnum}"
438 | prun /usr/sbin/efibootmgr -c -L "openSUSE Boot Manager" -d ${TIK_INSTALL_DEVICE} -l "\EFI\systemd\shim.efi" -p ${efipartnum}
439 | # Log to show the resulting eficonfig
440 | log "[set_boot_target] $(prun /usr/sbin/efibootmgr)"
441 | efi_already_set=1
442 | fi
443 | }
444 |
445 | load_modules() {
446 | local module_dir
447 | if [[ $2 = "custom" ]]; then
448 | module_dir=$TIK_CUSTOM_DIR/modules/$1
449 | else
450 | module_dir=$tik_dir/modules/$1
451 | fi
452 | if [ -n "$(ls -A $module_dir)" ]; then
453 | for f in $module_dir/*
454 | do
455 | tik_module="$f"
456 | log "[START] $module_dir/$f"
457 | . $f
458 | log "[STOP] $module_dir/$f"
459 | done
460 | fi
461 | tik_module="tik"
462 | }
463 |
--------------------------------------------------------------------------------