#! /bin/bash # # Copyright 2020, Stormux, # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License as published by the Free # Software Foundation; either version 3, or (at your option) any later # version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this package; see the file COPYING. If not, write to the Free # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # # keep track of mounted status for exit function mounted=1 set -e # Don't want to destroy stuff if this goes majorly wrong. trap cleanup EXIT # make sure the script cleans up after itself before closing. cleanup() { if [[ $mounted -eq 0 ]]; then umount -R /mnt partx -d "${loopdev}" losetup --detach "${loopdev}" fi if [[ -n "${imageFileName}" ]]; then rm "${imageFileName}" fi exit 0 } help() { echo -e "Usage:\n" echo "With no arguments, build with default parameters." for i in "${!command[@]}" ; do echo "-${i/:/ }: ${command[${i}]}" done | sort exit 0 } # Array of command line arguments declare -A command=( [h]="This help screen." [l:]="Language default is en_US." [n:]="Image name, default is stormux-pi<32|64>-.img" [s:]="image size in GB, default is 4." [v:]="Version of the Raspberry Pi for which you are building. (32|64) default is 64." ) # Convert the keys of the associative array to a format usable by getopts args="${!command[*]}" args="${args//[[:space:]]/}" while getopts "${args}" i ; do case "$i" in h) help ;; l) imageLanguage="${OPTARG}.UTF-8" ;; n) imageName="${OPTARG}" ;; s) if [[ "${OPTARG}" =~ ^[[:digit:]]+$ ]]; then imageSize="${OPTARG}G" else echo "Image size must be numeric." exit 1 fi ;; v) if [[ "${OPTARG}" =~ ^32|64$ ]]; then imageVersion="${OPTARG}" else echo "Image version must be 32 for 32 bit (armv7h), or 64 for 64 bit (aarch64 default)." exit 1 fi ;; *) exit 1 ;; esac done # make sure variables are set, or use defaults. export imageVersion="${imageVersion:-64}" export imageSize="${imageSize:-6G}" imageName="${imageName:-stormux-pi4-${imageVersion}-$(date '+%Y-%m-%d').img}" imageName="${imageName/-64-/-aarch64-}" imageName="${imageName/-32-/-armv7h-}" export imageName export imageLanguage="${imageLanguage:-en_US.UTF-8}" # Make sure the image file doesn't exist. if [[ -e "$imageName" ]]; then echo "${imageName} exists, please remove or move it for this script to continue." exit 1 fi # Make sure this script is ran as root. if [ "$(whoami)" != "root" ] ; then echo "Error: This script must be run as root." exit 1 fi # make sure the needed tools are installed if [[ "$(uname -m)" == "x86_64" ]]; then if ! pacman -Q qemu-user-static &> /dev/null ; then echo "Please install qemu-user-static and qemu-user-static-binfmt before continuing." exit 1 fi if ! pacman -Q qemu-user-static-binfmt &> /dev/null ; then echo "Please install qemu-user-static and qemu-user-static-binfmt before continuing." exit 1 fi fi for i in arch-install-scripts dosfstools parted wget ; do if ! pacman -Q $i &> /dev/null ; then echo "Please install $i before continuing." exit 1 fi done # Url for the image to be downloaded. url[32]="http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-armv7-latest.tar.gz" url[64]="http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-aarch64-latest.tar.gz" fallocate -l "$imageSize" "$imageName" loopdev="$(losetup --find --show "${imageName}")" parted --script "${loopdev}" mklabel msdos mkpart primary fat32 0% 200M mkpart primary ext4 200M 100% mkfs.vfat -F32 "${loopdev}p1" mkfs.ext4 -F "${loopdev}p2" mount "${loopdev}p2" /mnt mkdir /mnt/boot mount "${loopdev}p1" /mnt/boot # Things are mounted now, so set mounted to 0 (bash true) mounted=0 imageFileName=$(mktemp) wget "${url[$imageVersion]}" -O "${imageFileName}" if [[ $imageVersion -eq 32 ]]; then # Workaround for bsdtar errors when extracting 32 bit image. set +e fi bsdtar -xpf "${imageFileName}" -C /mnt # Set -e in case it got unset for 32 bit image set -e arch-chroot /mnt << EOF # set up pacman pacman-key --init pacman-key --populate archlinuxarm pacman -Syy # Change kernels for aarch64 if [[ "$imageVersion" == "64" ]]; then pacman -R --noconfirm linux-aarch64 uboot-raspberrypi pacman -S --noconfirm linux-rpi fi # Install packages pacman -Su --needed --noconfirm \ alsa-firmware \ alsa-utils \ base \ base-devel \ bash-completion \ bluez \ bluez-utils \ brltty \ cloud-utils \ cronie \ espeak-ng \ fake-hwclock \ firmware-raspberrypi \ git \ go \ magic-wormhole \ man \ man-pages \ networkmanager \ pipewire \ pipewire-alsa \ pipewire-jack \ pipewire-pulse \ poppler \ python-pyudev \ python-daemonize \ python-evdev \ python-dbus \ python-pyte \ raspberrypi-utils \ realtime-privileges \ rhvoice-voice-bdl \ rng-tools \ rsync \ screen \ sox \ w3m \ wget \ wireless-regdb \ wireplumber \ xdg-user-dirs \ xdg-utils # set the language sed -i "s/#$imageLanguage/$imageLanguage/" /etc/locale.gen echo "LANG=$imageLanguage" > /etc/locale.conf locale-gen # Configure and enable Hardware Random Number Generator echo 'RNGD_OPTS="-o /dev/random -r /dev/hwrng"' > /etc/conf.d/rngd systemctl enable rngd.service # Set the distribution name. echo 'Stormux \r (\l)' > /etc/issue echo >> /etc/issue # Change the alarm user to be stormux usermod -a -g users -G wheel,realtime,audio,video,network,brlapi -m -d /home/stormux -l stormux alarm # Grant sudo privileges to the stormux user for package installation. echo 'stormux ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/wheel # Set the password for the root user echo -e "root\nroot" | passwd "root" # Set the password for the stormux user echo -e "stormux\nstormux" | passwd "stormux" # Change to the stormux user and install some packages sudo -iu stormux # Create desktop, downloads, music, and other directories. xdg-user-dirs-update # Build AUR packages export aurPackages=(fenrir-git \ growpartfs \ log2ram \ yay) export PKGDEST=~/packages for p in "\${aurPackages[@]}" ; do git clone https://aur.archlinux.org/\${p}.git cd ~/\${p} makepkg -A cd ~ rm -rf \${p} done exit # Install built packages for p in /home/stormux/packages/* ; do pacman -U --noconfirm \${p} done rm -rf /home/stormux/packages/ # Enable linger so that hopefully sound will start at login. mkdir -p /var/lib/systemd/linger touch /var/lib/systemd/linger/stormux systemctl --global enable pipewire.service pipewire-pulse.service /usr/share/fenrirscreenreader/tools/configure_pipewire.sh sudo -u stormux /usr/share/fenrirscreenreader/tools/configure_pipewire.sh # Configure sudo for group wheel, remove nopasswd for the stormux user echo '%wheel ALL=(ALL) ALL' > /etc/sudoers.d/wheel # Set the hostname echo stormux > /etc/hostname # Configure services systemctl disable systemd-networkd.service systemd-networkd.socket systemctl enable brltty.path cronie.service fake-hwclock.service fenrirscreenreader.service log2ram.service NetworkManager.service # Cleanup packages pacman -Sc --noconfirm pacman -R --noconfirm go # Update fstab for Raspberry Pi 4. Not needed until linux-aarch64 works. # [[ $imageVersion -eq 4 ]] && sed -i 's/mmcblk0/mmcblk1/g' /etc/fstab EOF # Copy override files into place. cp -rv ../files/boot/* /mnt/boot cp -rv ../files/etc/* /mnt/etc cp -rv ../files/var/* /mnt/var cp -rv ../files/usr/* /mnt/usr find ../files/etc/skel/ -mindepth 1 -exec cp -rv "{}" /mnt/home/stormux/ \; # Exiting calls the cleanup function to unmount. exit 0