-
Notifications
You must be signed in to change notification settings - Fork 573
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This makes it significantly easier for custom hardware users to install umbrelOS. It also auto-reflashes internal storage for Umbrel Home users on boot, providing full factory reset functionality. A new USB installer image will be produced in CI for every release.
- Loading branch information
1 parent
6e2dfcc
commit 135f62e
Showing
9 changed files
with
212 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
#!/usr/bin/env bash | ||
|
||
echo "Creating disk image..." | ||
rootfs_tar_size="$(du --block-size 1M /data/build/rootfs.tar | awk '{print $1}')" | ||
rootfs_buffer="512" | ||
disk_size_mb="$((rootfs_tar_size + rootfs_buffer))" | ||
disk_size_sector=$(expr $disk_size_mb \* 1024 \* 1024 / 512) | ||
disk_image="/data/build/umbrelos-amd64-usb-installer.img" | ||
dd if=/dev/zero of="${disk_image}" bs="${disk_size_sector}" count=512 | ||
|
||
echo Creating disk partitions... | ||
gpt_efi="ef00" | ||
gpt_root_amd64="8304" | ||
sgdisk \ | ||
--new 1:2048:+200M \ | ||
--typecode 1:"${gpt_efi}" \ | ||
--change-name 1:ESP \ | ||
--new 2:0:0 \ | ||
--typecode 2:"${gpt_root_amd64}" \ | ||
--change-name 1:ROOTFS \ | ||
"${disk_image}" | ||
|
||
disk_layout=$(fdisk -l "${disk_image}") | ||
echo "${disk_layout}" | ||
|
||
echo Attaching partitions to loopback devices... | ||
efi_start=$(echo "${disk_layout}" -l "${disk_image}" | grep EFI | awk '{print $2}') | ||
efi_size=$(echo "${disk_layout}" -l "${disk_image}" | grep EFI | awk '{print $4}') | ||
root_start=$(echo "${disk_layout}" -l "${disk_image}" | grep root | awk '{print $2}') | ||
root_size=$(echo "${disk_layout}" -l "${disk_image}" | grep root | awk '{print $4}') | ||
efi_device=$(losetup --offset $((512*efi_start)) --sizelimit $((512*efi_size)) --show --find "${disk_image}") | ||
root_device=$(losetup --offset $((512*root_start)) --sizelimit $((512*root_size)) --show --find "${disk_image}") | ||
|
||
echo Formatting partitions... | ||
mkfs.vfat -n "ESP" "${efi_device}" | ||
mkfs.ext4 -L "ROOTFS" "${root_device}" | ||
|
||
echo Mounting partitions... | ||
efi_mount_point="/mnt/efi" | ||
root_mount_point="/mnt/root" | ||
mkdir -p "${efi_mount_point}" | ||
mkdir -p "${root_mount_point}" | ||
mount "${efi_device}" "${efi_mount_point}" | ||
mount -t ext4 "${root_device}" "${root_mount_point}" | ||
|
||
echo Extracting rootfs... | ||
tar -xf /data/build/rootfs.tar --directory "${root_mount_point}" | ||
|
||
echo Copying boot directory over to ESP partition... | ||
cp -r "${root_mount_point}/boot/." "${efi_mount_point}" | ||
tree "${efi_mount_point}" | ||
echo | ||
|
||
echo Unmounting partitions... | ||
umount "${root_mount_point}" | ||
umount "${efi_mount_point}" | ||
|
||
echo Detaching loopback devices... | ||
losetup --detach "${efi_device}" | ||
losetup --detach "${root_device}" | ||
|
||
echo "Compressing image..." | ||
xz --keep --threads 0 --force "${disk_image}" | ||
|
||
echo Done! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
FROM debian:bookworm | ||
|
||
RUN apt-get -y update | ||
RUN apt-get -y install fdisk gdisk qemu-utils dosfstools tree xz-utils |
14 changes: 14 additions & 0 deletions
14
packages/os/usb-installer/overlay/etc/systemd/system/custom-tty.service
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[Unit] | ||
Description=Custom TTY | ||
After=multi-user.target | ||
|
||
[Service] | ||
ExecStart=/opt/custom-tty | ||
StandardInput=tty | ||
StandardOutput=tty | ||
StandardError=tty | ||
TTYPath=/dev/tty1 | ||
Restart=on-failure | ||
|
||
[Install] | ||
WantedBy=multi-user.target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
#!/usr/bin/env bash | ||
|
||
sleep 1 | ||
|
||
clear | ||
|
||
cat << 'EOF' | ||
,;###GGGGGGGGGGl#Sp | ||
,##GGGlW""^' '`""%GGGG#S, | ||
,#GGG" "lGG#o | ||
#GGl^ '$GG# | ||
,#GGb \GGG, | ||
lGG" "GGG | ||
#GGGlGGGl##p,,p##lGGl##p,,p###ll##GGGG | ||
!GGGlW"""*GGGGGGG#""""WlGGGGG#W""*WGGGGS | ||
"" "^ '" "" | ||
umbrelOS USB Installer | ||
EOF | ||
echo | ||
|
||
# If device is an Umbrel Home auto flash and shutdown non-interactively since we don't have video output. | ||
if dmidecode -t system | grep --silent 'Umbrel Home' | ||
then | ||
echo "Umbrel Home detected." | ||
echo "Automatically flashing internal storage..." | ||
xz --decompress --stdout /umbrelos-amd64.img.xz | dd of=/dev/nvme0n1 bs=4M status=progress | ||
echo "umbrelOS has been installed, shutting down." | ||
poweroff | ||
exit 1 | ||
fi | ||
|
||
# For all other devices, run the interactive installer. | ||
echo "Installing umbrelOS will wipe your entire storage device." | ||
echo | ||
readarray -t devices < <(lsblk --nodeps --output NAME,VENDOR,MODEL,SIZE | sed '1d') | ||
PS3="Select a storage device by number to install umbrelOS on: " | ||
select device in "${devices[@]}" | ||
do | ||
if [[ -n "$device" ]] | ||
then | ||
echo "installing umbrelOS on: $device" | ||
device_path="/dev/$(echo $device | awk '{print $1}')" | ||
xz --decompress --stdout /umbrelos-amd64.img.xz | dd of=$device_path bs=4M status=progress | ||
sync | ||
echo | ||
echo "umbrelOS has been installed!" | ||
printf "Press any key to shutdown, remember to remove the USB drive before turning the device back on." | ||
read -n 1 -s | ||
poweroff | ||
break | ||
else | ||
echo "Invalid choice, please try again." | ||
fi | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#!/usr/bin/env bash | ||
set -euo pipefail | ||
|
||
mkdir -p build | ||
docker build -f usb-installer.Dockerfile --platform linux/amd64 -t usb-installer ../ | ||
docker export -o build/rootfs.tar $(docker run -d usb-installer /bin/true) | ||
docker build -f builder.Dockerfile -t usb-installer:builder . | ||
docker run --entrypoint /data/build.sh -v $PWD:/data --privileged usb-installer:builder | ||
|
||
# qemu-system-x86_64 -net nic -net user -machine accel=tcg -m 2048 -hda build/umbrelos-amd64-usb-installer.img -bios OVMF.fd |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
FROM debian:bookworm-slim | ||
|
||
RUN echo "root:root" | chpasswd | ||
|
||
RUN apt-get -y update | ||
|
||
# Install Linux kernel, systemd, bootloader and script deps | ||
RUN apt-get install --yes --no-install-recommends linux-image-amd64 systemd-sysv systemd-boot xz-utils dmidecode | ||
|
||
# We can't install the bootloader via `bootctl install` from Docker because it complains | ||
# about an invalid ESP partition. We can't easily fix it with loopback mounts from a Docker | ||
# build environment. Instead we just manually install the bootloader to /boot and | ||
# migrate /boot to an ESP partition in a post processing step outside of Docker. | ||
RUN mkdir -p "/boot/EFI/systemd/" | ||
RUN mkdir -p "/boot/EFI/BOOT/" | ||
RUN cp "/usr/lib/systemd/boot/efi/systemd-bootx64.efi" "/boot/EFI/systemd/systemd-bootx64.efi" | ||
RUN cp "/usr/lib/systemd/boot/efi/systemd-bootx64.efi" "/boot/EFI/BOOT/bootx64.efi" | ||
|
||
# Generate boot config | ||
RUN mkdir -p "/boot/loader/entries" | ||
|
||
RUN echo " \n\ | ||
title Debian \n\ | ||
linux $(ls /boot/vmlinuz-* | sed 's/\/boot//') \n\ | ||
initrd $(ls /boot/initrd.img* | sed 's/\/boot//') \n\ | ||
options root=LABEL=ROOTFS rw quiet loglevel=1" | tee "/boot/loader/entries/debian.conf" | ||
|
||
RUN echo " \n\ | ||
default debian \n\ | ||
timeout 0 \n\ | ||
console-mode max \n\ | ||
editor no" | tee "/boot/loader/loader.conf" | ||
|
||
# Verify boot status | ||
RUN bootctl --esp-path=/boot status | ||
|
||
# Reduce size | ||
# We have to do this extremely aggreseively because we're close to GitHub's 2GB release asset limit | ||
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* /tmp/* /usr/share/man /usr/share/doc /usr/share/info /var/log/* | ||
RUN find / -name '*.a' -delete && \ | ||
find / -name '*.so*' -exec strip --strip-debug {} \; | ||
RUN rm -rf /usr/lib/modules/6.1.0-20-amd64/kernel/drivers/gpu | ||
RUN rm -rf /usr/lib/modules/6.1.0-20-amd64/kernel/drivers/net | ||
RUN rm -rf /usr/lib/modules/6.1.0-20-amd64/kernel/drivers/infiniband | ||
RUN rm -rf /usr/lib/modules/6.1.0-20-amd64/kernel/net | ||
RUN rm -rf /usr/lib/modules/6.1.0-20-amd64/kernel/sound | ||
|
||
# Copy in umbrelOS image | ||
COPY build/umbrelos-amd64.img.xz / | ||
|
||
# Copy in filesystem overlay | ||
COPY usb-installer/overlay / | ||
|
||
# Configure TTY services | ||
RUN systemctl enable custom-tty.service | ||
RUN systemctl mask console-getty.service | ||
RUN systemctl mask [email protected] |