Skip to content

Usb installer #1909

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/usb-installer/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build
62 changes: 62 additions & 0 deletions packages/usb-installer/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/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 Done!
4 changes: 4 additions & 0 deletions packages/usb-installer/builder.Dockerfile
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
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
42 changes: 42 additions & 0 deletions packages/usb-installer/overlay/opt/custom-tty
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/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
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
10 changes: 10 additions & 0 deletions packages/usb-installer/run.sh
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 -it --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
57 changes: 57 additions & 0 deletions packages/usb-installer/usb-installer.Dockerfile
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 and bootloader
RUN apt-get install --yes --no-install-recommends linux-image-amd64 systemd-sysv systemd-boot xz-utils

# 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 os/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 getty@tty1.service