Skip to content

Instantly share code, notes, and snippets.

@Kreyren
Created January 26, 2023 23:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kreyren/d83d127d7de1f7a2b5916f4ea9f9a28e to your computer and use it in GitHub Desktop.
Save Kreyren/d83d127d7de1f7a2b5916f4ea9f9a28e to your computer and use it in GitHub Desktop.
#!/bin/sh
# shellcheck shell=sh # Written to comply with IEEE Std 1003.1-2017
#@ Inspired by Milan P. Stanič from https://arvanta.net/alpine/alpine-on-olimex/
#@ Inspired by Milan P. Stanič's script for OlinuXino-A64 boards to do non-UEFI setup -- https://tpaste.us/wxZK
#@ Refactored and rewritten by Jacob Hrbek under Expat License
###! Script to generate a stable alpine image for OLIMEX Teres-1
###!
###! To achieve this we are creating an .img file intended to be flashed on the desired storage device through e.g. `# dd if=./output.img of=/dev/sdX conv=sync status=progress` with the following partitions:
###!
###! ## With UEFI
###! (Allegedly) generally recommended for ARM64 boards, but the exact reasoning is not known, unification?[mps]
###!
###! In this step we are making the following partitionining:
###! Table: msdos
###! Sector 0 to 8191 (16 MB) -- Unformatted used for the bootloader(?)
###! Sector 8192 to 1056767 (2048 MB) -- EXT4 partition used for the u-boot bootloader, needs to be flagged as 'esp' (EFI System Partition) for the grub to install bootaa64.efi on it
###! Sector 1056768 to 17833983 -- EXT4 partition for rootfs of alpine linux
###!
###! Configuration by mps
###!
###! ## Without UEFI (recommended)
###! For those who doesn't like UEFI on their system
###!
###! In this step we are making the following partitioning:
###! Disklabel type: dos
###! Units: sectors of 1 * 512 = 512 bytes
###! Sector 0 to 40959 (20MiB) -- Unformatted used for the bootloader(?)
###! Sector 40960 to 327679 (286720 sectors - 140 MiB) -- fat16 partition used for the u-boot bootloader
###! Sector 327680 to 17104859 (16777216 sectors - 8 GiB) -- EXT4 partition for rootfs of alpine linux
###!
###! Configuration taken from an official olimex image
###!
###! # Creating the .img file with MBR records
###! This can be done through:
###! $ dd if=/dev/zero of=file.img seek=$((512 * 1000)) bs=512 count=1 conv=sync status=progress # Make an img file with the size of 1000 MB with 512 sectors
###! And then formated using e.g. fdisk to be treated as block device
###!
###! 1 GB = 2097152 sectors at block size 512
###!
###! # Additional informations
###! The boot partition should have at least 300 MB to avoid issues with upgrading[https://github.com/OLIMEX/DIY-LAPTOP/issues/52]
###! The Boot partition should be FAT32, because FAT16 has issues[mps]
###!
###! # Experiments on docker
###! alpine:3.17.1
###!
###! Run docker `docker run -v "$PWD/tmpdir":/tmpdir --device=/dev/sdc:/dev/sdc:rwm -it alpine:3.17.1`
###!
###! ```shell
###! # Make directories
###! mkdir -p "/tmpdir/etc/apk/keys" /boot/efi
###! ```
###!
###! ``shell
###! # Get alpine keys
###! wget -qP "/tmpdir/etc/apk/keys" "https://alpinelinux.org/keys/alpine-devel@lists.alpinelinux.org-60ac2099.rsa.pub"
###! ```
###!
###! ```shell
###! # Set up repositories
###! printf "http://dl-cdn.alpinelinux.org/alpine/edge/%s\n" main community testing > "/tmpdir/etc/apk/repositories"
###! ```
###!
###! ```shell
###! # Install required packages
###! apk --allow-untrusted --root /tmpdir --arch aarch64 --initdb add alpine-base alpine-baselayout alpine-conf kmod openrc dbus util-linux blkid chrony u-boot-sunxi sysfsutils ssl_client ca-certificates-bundle alpine-keys ethtool e2fsprogs libudev-zero libudev-zero-helper iwd linux-firmware-none efibootmgr ttf-dejavu agetty terminus-font openresolv tar wget
###! ```
###!
###! ```shell
###! # Download kernel and install it
###! wget https://dev.alpinelinux.org/~mps/sunxi/linux-sunxi-5.17.4-r0.apk
###! apk --allow-untrusted --root "/tmpdir" --arch aarch64 --no-script add ./linux-sunxi-5.17.4-r0.apk
###! ```
###!
###! ```shell
###! # Install bootloader?
###! apk --allow-untrusted --root /tmpdir --arch aarch64 --no-script add grub-efi grub-mkfont
###! ```
###!
###! ```shell
###! # Get the u-boot things on the thing?
###! dd if=/tmpdir/usr/share/u-boot/teres_i/u-boot-sunxi-with-spl.bin of=/dev/sdc bs=8k seek=1
###! ```
###!
###! ```shell
###! No fucking idea what this does
###! for rc in boot/bootmisc boot/hostname boot/modules boot/sysctl boot/urandom boot/networking sysinit/devfs sysinit/hwdrivers sysinit/mdev sysinit/modules shutdown/mount-ro shutdown/killprocs default/dbus default/chronyd default/iwd; do
###! ln -s /etc/init.d/"${rc##*/}" /tmpdir/etc/runlevels/"$rc"
###! done
###! ```
###!
###! Stuck at last step from https://arvanta.net/alpine/alpine-on-olimex/ doing the grub installation:
###!
###! # chroot $TMPDIR grub-install --target=arm64-efi --efi-directory=/boot/efi␏
###! Installing for arm64-efi platform.
###! grub-install: error: disk `hostdisk//dev/dm-0' not found
# Alternavive declaration
# NOTE(Krey): Abstracting for a new version
# make a blank .img file
## dd if=/dev/zero of=./alpine-teres-i.img bs=512 count=$((4 * 2097152)) status=progress
# format partitions on it
## sudo losetup /dev/loop0 ./alpine-teres-i.img
## sudo mkfs.vfat -F 32 -n BOOT /dev/loop0p1
## sudo mkfs.ext4 -L rootfs /dev/loop0p2
# Get the keys and repos
## wget -qP "$TMPDIR/etc/apk/keys" "https://alpinelinux.org/keys/alpine-devel@lists.alpinelinux.org-60ac2099.rsa.pub"
## wget -qP "$TMPDIR/etc/apk/keys" "https://arvanta.net/mps/aports-local/mps@arvanta.net-5a88c744.rsa.pub"
## printf "http://dl-cdn.alpinelinux.org/alpine/latest-stable/%s\n" main community > "$TMPDIR"/etc/apk/repositories
## printf "%s\n" "https://www.arvanta.net/mps/aports-local" >> "$TMPDIR"/etc/apk/repositories
# Install packages
## NOTE(Krey): This is supposed to be using a static apk
## apkVersion="2.12.11-r0"
## wget -qP "$cacheDir/$scriptName/" "https://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/apk-tools-static-2.12.11-r0.apk"
## According to https://linux-sunxi.org/Linux_mainlining_effort#Merged_into_5.14the linux-lts should work (MBUS supported since 5.17)
## apk --allow-untrusted --root "$TMPDIR" --arch aarch64 --initdb add alpine-base alpine-baselayout alpine-conf kmod openrc dbus util-linux blkid chrony u-boot-sunxi sysfsutils ssl_client ca-certificates-bundle alpine-keys ethtool e2fsprogs libudev-zero libudev-zero-helper iwd agetty openresolv tar wget linux-sunxi linux-firmware-rtlwifi iw wpa_supplicant
# Install the u-boot thing?
## dd if="$TMPDIR"/usr/share/u-boot/teres-i/u-boot-sunxi-with-spl.bin of=$DISK bs=8k seek=1
# Setup services
## for rc in boot/bootmisc boot/hostname boot/modules boot/sysctl boot/urandom boot/networking boot/syslog boot/klogd sysinit/devfs sysinit/hwdrivers sysinit/mdev sysinit/modules shutdown/mount-ro shutdown/killprocs default/dbus default/chronyd default/iwd; do ln -s /etc/init.d/"${rc##*/}" "$TMPDIR"/etc/runlevels/"$rc"; done
# WITHOUT UEFI
# mkdir -p "$TMPDIR"/boot/extlinux
# partuuid=`fdisk -l $DISK | grep 'Disk identifier:'| cut -d ' ' -f 3 | cut -d 'x' -f 2`
# ROOTPART="$partuuid-02"
# BOOTPART="$partuuid-01"
# console='console=${console}'
#
# echo "Creating extlinux.conf"
# cat > "$TMPDIR"/boot/extlinux/extlinux.conf</dev/null || die() { ${PRINTF:-"printf"} "FATAL: %s\\n" "$2"; exit 1 ;}
${COMMAND:-command} ${FIXME:-"fixme"} 1>/dev/null || fixme() { ${PRINTF:-"printf"} "FIXME: %s\\n" "$1" ;}
${COMMAND:-command} ${DEBUG:-"debug"} 1>/dev/null || {
[ -z "$SCRIPT_DEBUG" ] || ${PRINTF:-"printf"} "DEBUG: %s\\n" "$2"
}
# Dependencies
${COMMAND:-command} ${CURL:-"curl"} 1>/dev/null || {
case "$LANG" in
en-*|*) die 1 "This script requires curl to verify availability of alpine mirror and download relevant files"
esac
}
# sfdisk
# sed
# grep
# read
# Process arguments
while [ "#$" -gt 0 ]; do case "$1" in
"--apk-key") # set apk-key
apkKey="$2"
shift 1
;;
"--alpine-mirror") # Set the expected alpine mirror
alpineMirror="$2"
shift 1
;;
"--target-dev"|"--target-device"|"--target") # Declare target device
[ -b "$2" ] || {
case "$LANG" in
en-*|*) die 1 "The target device '$2' is not a block device, exitting for safety.."
esac
}
targetDev="$2"
shift 1
;;
# FIXME(Krey): See below we are using a kernel from 3rd party source that needs to be handled
# "--kernel") # Set kernel
# kernel="$2"
# ;;
"-h") # Print short help message
${FIXME:-"fixme"} "Short help message here"
;;
"--help") # Print long help message
${FIXME:-"fixme"} "Long help message here"
;;
*) die 2 "This input is not implemented/recognized: $1"
esac; shift 1; done
# Set default apk-key if it's not set already
apkKey="${apkKey:-"alpine-devel@lists.alpinelinux.org-60ac2099.rsa.pub"}"
# Mirror for alpine linux
## Declare default alpine mirror if none is set
[ -n "$alpineMirror" ] || alpineMirror="http://dl-cdn.alpinelinux.org/alpine"
## Check that the alpine mirror is working
${CURL:-"curl"} "$alpineMirror" || {
case "$?" in
0)
case "$LANG" in
en-*|*) ${DEBUG:-"debug"} 1 "The alpine mirror '$alpineMirror' is working" ;;
esac
;;
97)
case "$LANG" in
en-*|*) ${DIE:-"die"} 1 "Curl returned exit state '97' while checking alpine mirror '$alpineMirror', assuming that the mirror is not reachable"
esac
;;
esac
}
# Kernel
## Set the expected kernel if it's not already set
kernel="${kernel:-"linux-sunxi-5.17.4-r0"}"
kernelUrl="${kernelPackage:-"https://dev.alpinelinux.org/~mps/sunxi/$kernel.apk"}"
## Cache the kernel
[ -f "$cacheDir/$scriptName/$kernel.apk" ] || ${CURL:-"curl"} "$alpineMirror" "$kernelUrl" --output "$cacheDir/$scriptName/$kernel.apk"
# Create the .img file
[ -f "$output" ] || ${DD:-"dd"} \
if="/dev/zero" \
of="$output" \
seek="$((512 * 2099199))" \
bs="512"
# Make the partitions
# NOTE-QA(Krey): This could be sanitized through e.g. `$ [ "$(${FDISK:-"fdisk"} --list "$output" | grep "Disklabel type: dos" | sed -E "s/^(Disklabel\stype:\s)(.*))" = dos ] || printf "%s\n" "o" | ${SFDISK:-sfdisk} "$output"`, but shell is kinda too limited to do that in a maintainable way due to potential changes in fdisk's output
${PRINTF:-"printf"} "%s\n" \
"o" \
"n" \
"p" \
"1" \
"2048" \
"616447" \
"n" \
"2" \
"616448" \
"2713599" \
"w" \
| ${SFDISK:-"sfdisk"} "$output"
### --- ###
echo "eeep2"
exit 255
# NOTE(Krey): Abandoned as shell is too limited on programming capability to make this reliable
# bootloaderEFI="0" # Without UEFI as we don't have an objective reason to use it
# if [ "$bootloaderEFI" = "1" ]; then
#
# elif [ "$bootloaderEFI" = "0" ]; then
# case "$partitioningMethod" in
# "sfdisk")
# # Set the msdos table
# targetDevTable="$(${SFDISK:-"sfdisk"} --list "$targetDev" | ${GREP:-"grep"} "Disklabel" | ${SED:-"sed"} --regexp-extended "s/^(Disklabel\stype\:\s)(.*)$/\2/g")"
# case "$targetDevTable" in
# "dos") # Expected table
# case "$LANG" in
# en-*|*) ${DEBUG:-debug} 1 "Target device '$targetDevice' is already using 'dos' table"
# esac
# ;;
# "gpt") # Unexpected table
# # Print the current partition list for user review
# ${SFDISK:-"sfdisk"} --list "$targetDev"
#
# # Inform user about important decision
# case "$LANG" in
# en-*|*) ${PRINTF:-"printf"} "%s\\n" \
# "The target device '$targetDev' is using wrong table '$targetDevTable', do you wish to overwrite it?" \
# "To proceed type: IRREVERSEBLY DESTROY DATA ON $targetDev"
# esac
#
# # Process the answer
# ${READ:-read} -r makeTableAnswer
# case "$makeTableAnswer" in
# # TRANSLATE(Krey): This needs to be updated with translations
# "IRREVERSEBLY DESTROY DATA ON $targetDev")
# # Make 'dos' partition table on target device
# ${PRINTF:-"printf"} "%s" "o" | ${SFDISK:-"sfdisk"} "$targetDev" || ${DIE:-"die"} 1 "sfdisk failed to make 'dos' partition table on target device '$targetDev'"
#
# # Check the new partition table
# newTargetDevTable="$(${SFDISK:-"sfdisk"} --list "$targetDev" | ${GREP:-"grep"} "Disklabel" | ${SED:-"sed"} --regex-extended "s/^(Disklabel\stype\:\s)(.*)$/\2/g")"
# [ "$newTargetDevTable" = "dos" ] || {
# case "$LANG" in
# en-*|*) ${DIE:-"die"} 1 "The partiion table on target device '$targetDev' has unexpected table '$newTargetDevTable', exitting for safety.."
# esac
# }
#
# ;;
# *)
# case "$LANG" in
# en-*|*) ${DIE:-"die"} 0 "Script terminated.."
# esac
#
# esac
# ;;
# *) ${DIE:-die} 255 "The table on target device '$targetDevice' in unexpected, exitting for safety: $targetDevTable"
# esac
#
# # Ensure that there is a an unformatted space for the bootloader
# check sector 0 to 40959 (20MiB) is an unformatted space ||
#
# ;;
# *)
# case "$LANG" in
# en-*|*) ${DIE:-"die"} 1 "Partitioning method '$partitioningMethod' is not implemented"
# esac
# esac
# else
# die 255 "Unexpected happen while choosing whether we will do EFI in the bootloader"
# fi
### --- ###
echo "eeep"
exit 87
echo "Paritioning disk"
# fat32 512, ext4 8GB
parted -s "$DISK" mktable msdos > /dev/null
parted -s "$DISK" unit s -- mkpart primary ext4 8192 1056767 > /dev/null
parted -s "$DISK" unit s -- mkpart primary ext4 1056768 17833983 > /dev/null
parted -s "$DISK" -- set 1 esp on > /dev/null
echo "Creating dirs and mounting"
mkfs.fat -F 32 -n ESP "$BOOTDEV"
#mkfs.ext4 -qL root "$ROOTDEV"
#mount -t ext4 "$ROOTDEV" "$TMPDIR"
mkfs.f2fs -f -l root "$ROOTDEV"
mount -t f2fs "$ROOTDEV" "$TMPDIR"
mkdir -p "$TMPDIR"/boot
mkdir -p "$TMPDIR"/boot/efi "$TMPDIR"/etc/apk/keys
mount -t vfat "$BOOTDEV" "$TMPDIR"/boot/efi
echo "Setup apk keys and repositories"
wget -qP "$TMPDIR"/etc/apk/keys https://alpinelinux.org/keys/"$APK_KEY"
printf "$MIRROR/edge/%s\n" main community testing > "$TMPDIR"/etc/apk/repositories
echo "installing base packages"
apk --allow-untrusted --root "$TMPDIR" --arch aarch64 --initdb add \
alpine-base alpine-baselayout alpine-conf kmod openrc \
dbus util-linux blkid chrony u-boot-sunxi \
sysfsutils ssl_client ca-certificates-bundle alpine-keys \
ethtool e2fsprogs libudev-zero libudev-zero-helper \
iwd linux-firmware-none efibootmgr ttf-dejavu \
agetty terminus-font openresolv tar wget
apk --allow-untrusted --root "$TMPDIR" --arch aarch64 --no-script add $kernel
apk --allow-untrusted --root "$TMPDIR" --arch aarch64 --no-script add grub-efi grub-mkfont
#dd if="$TMPDIR"/usr/share/u-boot/teres_i/u-boot-sunxi-with-spl.bin of=$DISK bs=8k seek=1
dd if=u-boot-sunxi-with-spl.bin of=$DISK bs=8k seek=1
echo "Setting up services and inittab"
for rc in boot/bootmisc boot/hostname boot/modules boot/sysctl boot/urandom boot/networking \
sysinit/devfs sysinit/hwdrivers sysinit/mdev sysinit/modules \
shutdown/mount-ro shutdown/killprocs \
default/dbus default/chronyd default/iwd; do
ln -s /etc/init.d/"${rc##*/}" "$TMPDIR"/etc/runlevels/"$rc"
done
echo "preparing scripts for setup"
cat > "$TMPDIR"/root/grub-setup.sh< /boot/grub/grub.cfg
exit
EOF
echo 'GRUB_DISABLE_LINUX_PARTUUID=false' >> "$TMPDIR"/etc/default/grub
echo 'GRUB_CMDLINE_LINUX="rootwait console=tty1"' >> "$TMPDIR"/etc/default/grub
echo 'GRUB_TIMEOUT=10' >> "$TMPDIR"/etc/default/grub
echo 'GRUB_FONT="/boot/grub/fonts/dejavu.pf2"' >> "$TMPDIR"/etc/default/grub
chmod 0744 "$TMPDIR"/root/grub-setup.sh
echo "Settting grub boot loader"
mount -t proc none $TMPDIR/proc
mount -o bind /sys $TMPDIR/sys
mount -o bind /dev $TMPDIR/dev
echo "Run this two commands and after that exit"
echo "grub-install --target=arm64-efi --efi-directory=/boot/efi --removable"
echo "grub-mkconfig > /boot/grub/grub.cfg"
chroot $TMPDIR /root/grub-setup.sh
#chroot $TMPDIR /bin/ash -l
umount $TMPDIR/dev
umount $TMPDIR/sys
umount $TMPDIR/proc
sed -i 's/^tty1.*/tty1::respawn:\/sbin\/agetty -L 115200 tty1 linux --login-pause --autologin root --noclear/' $TMPDIR/etc/inittab
echo "Finished, cleaning up"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment