Steam now offered in x86_64 installer. Fix up the rhvoice dictionary copy. A few minor cleanups. Rename pi images to more clearly show they support both Raspberry Pi 4 and 5.

This commit is contained in:
Storm Dragon
2026-06-23 19:40:06 -04:00
parent 426069f36a
commit 5ec1d7727d
6 changed files with 287 additions and 60 deletions
+16 -15
View File
@@ -3,17 +3,17 @@
Stormux provides an Arch-based Raspberry Pi image that already includes Fenrir, Orca, and other screen-reader friendly defaults. This repository hosts the scripts maintained by the Stormux community (originally crafted by Storm) so anyone can rebuild the image, customize the overlay, and share accessible Pi spins. Stormux provides an Arch-based Raspberry Pi image that already includes Fenrir, Orca, and other screen-reader friendly defaults. This repository hosts the scripts maintained by the Stormux community (originally crafted by Storm) so anyone can rebuild the image, customize the overlay, and share accessible Pi spins.
## Purpose & Scope ## Purpose & Scope
This repo captures the complete build pipeline for the Stormux Raspberry Pi images: downloading Arch Linux ARM, layering the accessible defaults, compiling Fenrir and helper tools, and producing a ready-to-flash `.img`. Running the script yourself lets you reproduce the same system the project ships for the Pi 4/400, tweak it, and publish new spins without reverse-engineering the original release. This repo captures the complete build pipeline for the Stormux Raspberry Pi images: bootstrapping Arch Linux ARM, layering the accessible defaults, installing Fenrir and helper tools, and producing a compressed ready-to-flash image. Running the script yourself lets you reproduce the same system the project ships for Raspberry Pi 4/5-class systems, tweak it, and publish new spins without reverse-engineering the original release.
## What You Need ## What You Need
- A 64-bit Arch Linux host (bare metal or VM) with at least 20GB free disk space. - A 64-bit Arch Linux host (bare metal or VM) with at least 20GB free disk space.
- Root access on that host. The builder partitions loopback devices and must run as root. - Root access on that host. The builder partitions loopback devices and must run as root.
- Required packages: `arch-install-scripts`, `dosfstools`, `parted`, `wget`, `qemu-user-static`, `qemu-user-static-binfmt`, plus standard developer tools that Arch already ships. - Required packages: `arch-install-scripts`, `dosfstools`, `parted`, `qemu-user-static`, `qemu-user-static-binfmt`, plus standard developer tools that Arch already ships.
- A Raspberry Pi 4/400 or similar board (a Pi 3 works with the `-v 32` option) and a microSD card (8GB or larger recommended). - A Raspberry Pi 4, Raspberry Pi 400, Raspberry Pi 5, or compatible board, plus a microSD card (8 GB or larger recommended).
Install dependencies on the build host with: Install dependencies on the build host with:
```bash ```bash
sudo pacman -S arch-install-scripts dosfstools parted wget qemu-user-static qemu-user-static-binfmt sudo pacman -S arch-install-scripts dosfstools parted qemu-user-static qemu-user-static-binfmt
``` ```
## Getting the Source ## Getting the Source
@@ -31,14 +31,14 @@ The script is designed for an x86_64 Arch host so it can emulate ARM binaries wi
1. Become root (`sudo -i`) so the script can create loop devices and mount them. 1. Become root (`sudo -i`) so the script can create loop devices and mount them.
2. From `/path/to/stormux`, run: 2. From `/path/to/stormux`, run:
```bash ```bash
sudo ./pi4/build/build-stormux.sh -v 64 -l en_US -s 6 sudo ./pi4/build/build-stormux.sh -l en_US -s 6
``` ```
- `-v 64` builds the aarch64 image (use `-v 32` for the Pi 3/armv7h). - The builder creates an aarch64 image for Raspberry Pi 4/5-class systems.
- `-l en_US` selects the locale (use `es_ES`, `fr_FR`, etc.). - `-l en_US` selects the locale (use `es_ES`, `fr_FR`, etc.).
- `-s 6` sets the image size in gigabytes. - `-s 6` sets the image size in gigabytes.
- Add `-n my-stormux.img` to override the default filename. - Add `-n my-stormux.img` to override the default filename.
3. Grab coffee. The script downloads the latest Arch Linux ARM tarball, provisions packages (Fenrir, Orca, NetworkManager, PipeWire, etc.), copies the overlay from `pi4/files/`, and cleans up. 3. Grab coffee. The script bootstraps Arch Linux ARM, provisions packages (Fenrir, Orca, NetworkManager, PipeWire, etc.), copies the overlay from `pi4/files/`, installs the latest `sas`, cleans up, compresses the image, and writes a SHA-1 checksum.
4. When the `build-stormux.sh` command returns, you should have an `.img` file in your working directory (for example `stormux-pi4-aarch64-YYYY-MM-DD.img`). 4. When the `build-stormux.sh` command returns, you should have an `.img.xz` file and matching `.sha1sum` in your working directory (for example `stormux-rpi4-5-aarch64-YYYY-MM-DD.img.xz`).
If the build is interrupted, run `sudo umount -R /mnt && sudo losetup -D` to be sure nothing is still mounted. If the build is interrupted, run `sudo umount -R /mnt && sudo losetup -D` to be sure nothing is still mounted.
@@ -61,20 +61,22 @@ Rebuild after pulling so your custom image inherits any upstream fixes (new pack
## Flashing and Booting ## Flashing and Booting
1. Verify the image: 1. Verify the image:
```bash ```bash
ls -lh stormux-pi4-*.img ls -lh stormux-rpi4-5-*.img.xz stormux-rpi4-5-*.img.xz.sha1sum
sha1sum -c stormux-rpi4-5-*.img.xz.sha1sum
``` ```
2. Write it to an SD card (replace `/dev/sdX` with your card, not a partition): 2. Write it to an SD card (replace `/dev/sdX` with your card, not a partition):
```bash ```bash
sudo dd if=stormux-pi4-aarch64-*.img of=/dev/sdX bs=4M status=progress conv=fsync xzcat stormux-rpi4-5-aarch64-*.img.xz | sudo dd of=/dev/sdX bs=4M status=progress conv=fsync
``` ```
3. Insert the card into your Pi 4/400 and power it on. You should hear Fenrir start speaking once the user session loads. 3. Insert the card into your Raspberry Pi and power it on. You should hear Fenrir start speaking once the user session loads.
4. Log in using the default credentials (username `stormux`, password `stormux`). Root uses `root`/`root` until you change it. 4. Log in using the default credentials (username `stormux`, password `stormux`). Root uses `root`/`root` until you change it.
5. Run `sudo configure-stormux` (or follow the automatic prompt) to finish the guided setup: configure networking via `nmtui`, update the clock, optionally resize the SD card with `growpartfs`, and toggle Fenrirs layout. 5. Run `sudo configure-stormux` (or follow the automatic prompt) to finish the guided setup: configure networking via `nmtui`, update the clock, optionally resize the SD card with `growpartfs`, and toggle Fenrirs layout.
## Testing Without Hardware ## Testing Without Hardware
You can boot the image in a container to verify services before flashing: You can boot the image in a container to verify services before flashing:
```bash ```bash
sudo systemd-nspawn -i stormux-pi4-aarch64-*.img --boot xz -dk stormux-rpi4-5-aarch64-*.img.xz
sudo systemd-nspawn -i stormux-rpi4-5-aarch64-*.img --boot
``` ```
Use `machinectl` to connect to the console and ensure critical services start. For unit files you edit, run `systemd-analyze verify path/to/unit` inside the container or the Pi. Use `machinectl` to connect to the console and ensure critical services start. For unit files you edit, run `systemd-analyze verify path/to/unit` inside the container or the Pi.
@@ -86,9 +88,8 @@ Use `machinectl` to connect to the console and ensure critical services start. F
## Sharing Your Image ## Sharing Your Image
When you are happy with your customizations: When you are happy with your customizations:
1. Rebuild so you have a clean `.img` file named clearly (for example, `stormux-pi4-a11y-v1.img`). 1. Rebuild so you have a clean `.img.xz` file named clearly.
2. Compress it (`xz -T0 -z stormux-pi4-a11y-v1.img`). 2. Publish the compressed image, its `.sha1sum`, the exact commit you built from, and any extra scripts you used. The README and `AGENTS.md` in this repo explain the layout so others can reproduce your work.
3. Publish the image along with the exact commit you built from and any extra scripts you used. The README and `AGENTS.md` in this repo explain the layout so others can reproduce your work.
## Huge Thanks to Storm ## Huge Thanks to Storm
Storm did the heavy lifting—curating packages, wiring up Fenrir/Orca defaults, scripting the first-boot assistant, and sharing the whole build process so the community can remix it. This repo exists because accessibility was treated as a first-class feature from day one, and the documentation lets anyone extend that work. If the image improves your Pi experience, consider contributing improvements or telling Storm thanks. Storm did the heavy lifting—curating packages, wiring up Fenrir/Orca defaults, scripting the first-boot assistant, and sharing the whole build process so the community can remix it. This repo exists because accessibility was treated as a first-class feature from day one, and the documentation lets anyone extend that work. If the image improves your Pi experience, consider contributing improvements or telling Storm thanks.
+14 -2
View File
@@ -100,6 +100,16 @@ finish_build() {
exit 0 exit 0
} }
copy_rhvoice_english_fixes() {
local sourceDir="../files/etc/RHVoice/dicts/English"
local targetDir="/mnt/etc/RHVoice/dicts/English"
if [[ -d "$sourceDir" ]]; then
mkdir -p "$targetDir"
cp -a "$sourceDir/." "$targetDir/"
fi
}
# shellcheck disable=SC2329 # install_sas is emitted into the chroot heredoc with declare -f # shellcheck disable=SC2329 # install_sas is emitted into the chroot heredoc with declare -f
install_sas() { install_sas() {
local sasRepo="https://git.stormux.org/storm/sas" local sasRepo="https://git.stormux.org/storm/sas"
@@ -137,7 +147,7 @@ help() {
declare -A command=( declare -A command=(
[h]="This help screen." [h]="This help screen."
[l:]="Language default is en_US." [l:]="Language default is en_US."
[n:]="Image name, default is stormux-pi4-aarch64-<yyyy-mm-dd>.img" [n:]="Image name, default is stormux-rpi4-5-aarch64-<yyyy-mm-dd>.img"
[s:]="image size in GB, default is 6." [s:]="image size in GB, default is 6."
) )
@@ -169,7 +179,7 @@ done
# make sure variables are set, or use defaults. # make sure variables are set, or use defaults.
export imageSize="${imageSize:-6G}" export imageSize="${imageSize:-6G}"
imageName="${imageName:-stormux-pi4-aarch64-$(date '+%Y-%m-%d').img}" imageName="${imageName:-stormux-rpi4-5-aarch64-$(date '+%Y-%m-%d').img}"
export imageName export imageName
export imageLanguage="${imageLanguage:-en_US.UTF-8}" export imageLanguage="${imageLanguage:-en_US.UTF-8}"
@@ -481,6 +491,8 @@ sed -i '/^DisableSandbox/d' /etc/pacman.conf
EOF EOF
copy_rhvoice_english_fixes
# Copy skel files to stormux user home (after user rename in chroot) # Copy skel files to stormux user home (after user rename in chroot)
find ../files/etc/skel/ -mindepth 1 -exec cp -rv "{}" /mnt/home/stormux/ \; find ../files/etc/skel/ -mindepth 1 -exec cp -rv "{}" /mnt/home/stormux/ \;
+201
View File
@@ -0,0 +1,201 @@
# Stormux x86_64 ISO Build
This directory contains the archiso profile for building a Stormux x86_64 live/install ISO image.
## Overview
The x86_64 build uses archiso (Arch Linux ISO build system) and is configured for accessibility with the Fenrir screen reader. The `airootfs/` tree is maintained as the x86_64 live-system overlay; shared behavior may mirror the Pi image, but files are not copied from `pi4/files/` during the build.
## Directory Structure
```
x86_64/
├── build.sh # Main build script
├── profiledef.sh # Archiso profile definition
├── pacman.conf # Pacman config with Stormux repository
├── packages.x86_64 # Package list for installation
├── grub/ # UEFI boot configuration
│ ├── grub.cfg
│ └── loopback.cfg
├── syslinux/ # BIOS boot configuration
│ ├── archiso_head.cfg
│ ├── archiso_pxe.cfg
│ ├── archiso_pxe-linux.cfg
│ ├── archiso_sys.cfg
│ ├── archiso_sys-linux.cfg
│ ├── archiso_tail.cfg
│ ├── splash.png
│ └── syslinux.cfg
└── airootfs/ # Live system overlay files
├── etc/ # Live-system configuration
├── root/ # x86_64-specific scripts
├── usr/ # Live-system utilities and installer
└── var/ # Live-system variable data
```
## Overlay Maintenance
Edit files directly under `airootfs/` using the final filesystem path they should have in the live ISO. For example, live-system scripts belong under `airootfs/usr/local/bin/`, and systemd units belong under `airootfs/etc/systemd/system/`.
Some files intentionally match the Pi overlay, such as shell defaults, Fenrir support scripts, and shared Stormux helper behavior. Keep both trees in sync when a change is meant to affect both image families.
Pi hardware files remain Pi-only and should not be added to the x86_64 profile unless there is a specific PC use for them:
- `boot/cmdline.txt` - Pi boot command line
- `boot/config.txt` - Pi hardware configuration
- `etc/modprobe.d/brcmfmac.conf` - Pi wireless driver config
## Prerequisites
Building requires an Arch Linux host system with:
- `archiso` package installed
- Root privileges
- Internet connection for package downloads and build-time helper installs
## Building the ISO
```bash
cd x86_64
sudo ./build.sh
```
### Build Options
- `-o <dir>` - Output directory (default: `./out`)
- `-w <dir>` - Work directory (default: `./work`)
- `-h` - Show help
### Build Process
1. Uses the maintained `airootfs/` overlay as-is
2. Adds Stormux repository GPG key to the build host's keyring
- Uses the included `stormux_repo.pub` file
- Key fingerprint: 52ADA49000F1FF0456F8AEEFB4CDE1CD56EF8E82
3. Runs `mkarchiso` to build the ISO
- Packages from Stormux repo can be installed during build
- The latest `sas` helper is installed into the live environment during image creation
4. Renames the ISO to `stormux-x86_64-YYYY-MM-DD.iso` when possible and writes a matching `.sha1sum`
The Stormux repository key is also embedded in the ISO at `/usr/share/stormux/stormux_repo.pub` and automatically imported on first boot via the `stormux-repo-init.service`, ensuring the live environment can install additional packages from the Stormux repository.
## Key Features
### Accessibility
- **Fenrir screen reader** starts automatically (not speakup)
- **Pipewire audio** properly initialized before Fenrir starts
- **Speech-dispatcher** integration for speech synthesis
- GRUB plays an audible tune on boot for accessibility
- Boot menu defaults to accessible entry
- Service startup order ensures audio is ready before screen reader
- First-login live-environment setup calibrates volume, checks networking and time, then offers to run the installer
### Package Management
- Stormux repository configured with priority over Arch repos
- Custom packages from Stormux repo: fenrir, w3m-git, yay, etc.
### Default Configuration
- Default user: `stormux` / Password: `stormux`
- Root password: `root`
- NetworkManager for network configuration
- Braille terminal support (brltty)
- Multiple speech synthesizers (espeak-ng, rhvoice)
## Audio and Speech Initialization
The live environment uses a carefully orchestrated startup sequence to ensure Fenrir has working audio:
1. **stormux-audio-setup.service** - Runs after sound hardware is detected
- Enables systemd user linger for the stormux user
- Starts pipewire user services
- Unmutes audio and sets volume to 70%
2. **stormux-speech.service** - Runs after audio setup
- Waits 2 seconds for pipewire to fully initialize
- Starts fenrirscreenreader.service
3. **fenrirscreenreader.service** - Screen reader with dependencies
- Configured to wait for pipewire, speech-dispatcher, and sound.target
- Uses speech-dispatcher for TTS output
This ensures Fenrir never starts without working audio, preventing system freezes or silent boot.
## Live Setup and Installer Flow
On first login to tty1, the live environment runs a short setup script. It calibrates speech volume, checks for network access, updates the live environment clock, copies the detected timezone into the installer defaults, and then asks whether to run `install-stormux`.
The installer gives one last chance to accept or change the timezone before installation. The live setup changes are for the temporary live environment only; the installed system is configured by `install-stormux`.
## Differences from Pi4 Build
1. **No ARM-specific packages** - Uses x86_64 standard Linux kernel
2. **Fenrir instead of speakup** - More feature-rich screen reader
3. **UEFI and BIOS support** - Boots on both modern and legacy systems
4. **ISO format** - Live/install medium instead of disk image
5. **No Pi hardware configs** - Standard x86_64 PC configuration
6. **Different audio startup** - Pipewire user services instead of system-wide
## Testing
After building, test the ISO with:
- QEMU/KVM virtual machine
- VirtualBox
- Physical hardware (USB/CD)
For VM testing with audio:
```bash
./qemu-boot.sh
```
After installing to the test disk, boot the installed system with:
```bash
./qemu-boot.sh -i
```
## Customization
### Adding Packages
Edit `packages.x86_64` and add package names (one per line).
### Modifying Boot Configuration
- BIOS: Edit `syslinux/archiso_sys-linux.cfg`
- UEFI: Edit `grub/grub.cfg`
### Adding Overlay Files
Place files in `airootfs/` following the target filesystem structure.
The x86_64 build uses this overlay directly.
## Troubleshooting
### Build fails with GPG errors
The build script should automatically add the Stormux repository key. If it fails:
1. Check that `x86_64/stormux_repo.pub` exists
2. Manually add the key to your build host:
```bash
sudo pacman-key --add x86_64/stormux_repo.pub
sudo pacman-key --lsign-key 52ADA49000F1FF0456F8AEEFB4CDE1CD56EF8E82
```
### Missing packages
Ensure the Stormux repository is accessible:
```bash
curl -I https://packages.stormux.org/x86_64/
```
### Disk space issues
The build requires significant space:
- Work directory: ~3-4 GB
- Output ISO: ~1-2 GB
Ensure adequate free space in work and output directories.
@@ -24,6 +24,7 @@ timezone=""
enableSsh="no" # "yes" or "no" enableSsh="no" # "yes" or "no"
installLinuxGameManager="no" # "yes" or "no" installLinuxGameManager="no" # "yes" or "no"
installAudiogameManager="no" # "yes" or "no" installAudiogameManager="no" # "yes" or "no"
installSteam="no" # "yes" or "no"
autoLoginUser="" # User to auto-login for desktop environments autoLoginUser="" # User to auto-login for desktop environments
minHomePartitionMiB=1024 minHomePartitionMiB=1024
errorCount=0 errorCount=0
@@ -54,6 +55,7 @@ log_info() {
echo "$*" | tee -a "$logFile" echo "$*" | tee -a "$logFile"
} }
# shellcheck disable=SC2329 # Invoked by the ERR trap after pre-install prompts finish.
handle_unexpected_failure() { handle_unexpected_failure() {
local exitCode="$1" local exitCode="$1"
@@ -1157,6 +1159,17 @@ gather_system_info() {
installAudiogameManager="no" installAudiogameManager="no"
log_info "Audiogame Manager will not be installed" log_info "Audiogame Manager will not be installed"
fi fi
echo ""
echo "Install Steam? [y/N]:"
read -r steamChoice
if [[ "$steamChoice" =~ ^[Yy]$ ]]; then
installSteam="yes"
log_info "Steam will be installed"
else
installSteam="no"
log_info "Steam will not be installed"
fi
fi fi
# SSH configuration # SSH configuration
@@ -1209,6 +1222,11 @@ gather_system_info() {
echo " Desktop: $desktopEnvironment" echo " Desktop: $desktopEnvironment"
fi fi
echo " SSH enabled: $enableSsh" echo " SSH enabled: $enableSsh"
if [[ "$hasDesktop" == true ]]; then
echo " linux-game-manager: $installLinuxGameManager"
echo " audiogame-manager: $installAudiogameManager"
echo " Steam: $installSteam"
fi
echo " Timezone: $timezone" echo " Timezone: $timezone"
echo "" echo ""
echo "Press Enter to continue with installation..." echo "Press Enter to continue with installation..."
@@ -1253,6 +1271,34 @@ refresh_package_sources() {
return 0 return 0
} }
enable_multilib_repo() {
local pacmanConf="$1"
if [[ ! -f "$pacmanConf" ]]; then
log_error "Pacman config not found: $pacmanConf"
return 1
fi
log_info "Enabling multilib repository in $pacmanConf"
sed -i \
-e 's/^#\[multilib\]$/[multilib]/' \
-e '/^\[multilib\]$/,/^\[/ s/^#Include = \/etc\/pacman.d\/mirrorlist$/Include = \/etc\/pacman.d\/mirrorlist/' \
"$pacmanConf"
}
copy_rhvoice_english_fixes() {
local sourceDir="/etc/RHVoice/dicts/English"
local targetDir="$mountPoint/etc/RHVoice/dicts/English"
if [[ -d "$sourceDir" ]]; then
log_info "Installing RHVoice English dictionary fixes"
mkdir -p "$targetDir"
cp -a "$sourceDir/." "$targetDir/"
else
log_warning "RHVoice English dictionary fixes not found at $sourceDir"
fi
}
install_base_system() { install_base_system() {
log_info "=== Installing Base System ===" log_info "=== Installing Base System ==="
@@ -1294,6 +1340,11 @@ install_base_system() {
shopt -u nullglob shopt -u nullglob
fi fi
if [[ "$installSteam" == "yes" ]]; then
enable_multilib_repo /etc/pacman.conf
enable_multilib_repo "$mountPoint/etc/pacman.conf"
fi
# Define package groups # Define package groups
local basePackages=( local basePackages=(
base base-devel linux linux-firmware base base-devel linux linux-firmware
@@ -1335,6 +1386,9 @@ install_base_system() {
case "$desktopEnvironment" in case "$desktopEnvironment" in
*) *)
allPackages+=(xlibre-xserver xlibre-input-libinput nodm-dgw brave-bin) allPackages+=(xlibre-xserver xlibre-input-libinput nodm-dgw brave-bin)
if [[ "$installSteam" == "yes" ]]; then
allPackages+=(steam)
fi
;;& ;;&
i3) i3)
allPackages+=(i3-wm orca python-psutil lxterminal pluma) allPackages+=(i3-wm orca python-psutil lxterminal pluma)
@@ -1367,6 +1421,8 @@ install_base_system() {
return 1 return 1
fi fi
copy_rhvoice_english_fixes
# Generate or preserve fstab # Generate or preserve fstab
if [[ "$useExistingMount" == true ]]; then if [[ "$useExistingMount" == true ]]; then
if [[ -s "$mountPoint/etc/fstab" ]]; then if [[ -s "$mountPoint/etc/fstab" ]]; then
-33
View File
@@ -1,33 +0,0 @@
#!/usr/bin/env bash
# Fix live ISO services for x86_64
set -e
cd "$(dirname "$0")"
echo "=== Fixing Live ISO Services for x86_64 ==="
echo
# 1. Remove Pi-specific first boot script
if [ -f airootfs/etc/profile.d/stormux_first_boot.sh ]; then
echo "Removing Pi-specific first boot script..."
sudo rm airootfs/etc/profile.d/stormux_first_boot.sh
fi
# 2. Mask systemd-firstboot (blocks boot with interactive prompts)
echo "Masking systemd-firstboot.service..."
sudo ln -sf /dev/null airootfs/etc/systemd/system/systemd-firstboot.service
# 3. Install Fenrir audio configurations
echo "Installing Fenrir audio configurations..."
sudo ./setup-fenrir-audio-configs.sh
# 4. Check/verify enabled services
echo
echo "=== Enabled Services ==="
ls -la airootfs/etc/systemd/system/multi-user.target.wants/ | grep -E "fenrir|speech|audio" || echo "No speech/audio services in multi-user.target.wants"
ls -la airootfs/etc/systemd/system/sound.target.wants/ | grep -E "audio|sound" || echo "No services in sound.target.wants"
echo
echo "=== Configuration Complete ==="
echo "Next step: sudo ./build.sh -v"
-10
View File
@@ -1,10 +0,0 @@
#!/usr/bin/env bash
# Mask systemd-firstboot for live ISO (it blocks boot)
cd airootfs/etc/systemd/system
# Create mask symlink
ln -sf /dev/null systemd-firstboot.service
echo "Masked systemd-firstboot.service"
ls -la systemd-firstboot.service