Compare commits
3 Commits
9a0a6fef00
...
eb36d6d976
| Author | SHA1 | Date | |
|---|---|---|---|
| eb36d6d976 | |||
| 040eecca09 | |||
| 973b2573c8 |
@@ -24,18 +24,52 @@ mounted=1
|
|||||||
set -e # Don't want to destroy stuff if this goes majorly wrong.
|
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.
|
trap cleanup EXIT # make sure the script cleans up after itself before closing.
|
||||||
|
|
||||||
|
# shellcheck disable=SC2329 # verify_image is invoked from cleanup, which is invoked via trap EXIT
|
||||||
|
verify_image() {
|
||||||
|
echo "Checking completed image filesystems..."
|
||||||
|
fsck.vfat -n "${loopdev}p1"
|
||||||
|
e2fsck -fn "${loopdev}p2"
|
||||||
|
}
|
||||||
|
|
||||||
# shellcheck disable=SC2329 # cleanup is invoked via trap EXIT
|
# shellcheck disable=SC2329 # compress_image is invoked from finish_build
|
||||||
cleanup() {
|
compress_image() {
|
||||||
status=$? # capture original exit status so failures propagate
|
local compressedImage="${imageName}.xz"
|
||||||
|
|
||||||
|
if [[ ! -s "${imageName}" ]]; then
|
||||||
|
echo "Image file ${imageName} was not created or is empty."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Compressing ${imageName} to ${compressedImage}..."
|
||||||
|
xz -T0 -9 "${imageName}"
|
||||||
|
echo "Creating SHA-1 checksum for ${compressedImage}..."
|
||||||
|
sha1sum "${compressedImage}" > "${compressedImage}.sha1sum"
|
||||||
|
echo "Image build complete: ${compressedImage}"
|
||||||
|
echo "Checksum: ${compressedImage}.sha1sum"
|
||||||
|
}
|
||||||
|
|
||||||
|
# shellcheck disable=SC2329 # cleanup_image is invoked from cleanup and finish_build
|
||||||
|
cleanup_image() {
|
||||||
|
local verifyFilesystems="${1:-false}"
|
||||||
|
local cleanupStatus=0
|
||||||
|
|
||||||
if [[ $mounted -eq 0 ]]; then
|
if [[ $mounted -eq 0 ]]; then
|
||||||
umount -R /mnt || true
|
if ! umount -R /mnt; then
|
||||||
|
cleanupStatus=1
|
||||||
|
elif [[ "$verifyFilesystems" == true ]]; then
|
||||||
|
if ! verify_image; then
|
||||||
|
cleanupStatus=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "${loopdev:-}" ]]; then
|
if [[ -n "${loopdev:-}" ]]; then
|
||||||
partx -d "${loopdev}" || true
|
if ! partx -d "${loopdev}"; then
|
||||||
losetup --detach "${loopdev}" || true
|
cleanupStatus=1
|
||||||
|
fi
|
||||||
|
if ! losetup --detach "${loopdev}"; then
|
||||||
|
cleanupStatus=1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Clean up temporary pacman config directory
|
# Clean up temporary pacman config directory
|
||||||
@@ -43,9 +77,41 @@ cleanup() {
|
|||||||
rm -rf "${tmpDir}"
|
rm -rf "${tmpDir}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
return "$cleanupStatus"
|
||||||
|
}
|
||||||
|
|
||||||
|
# shellcheck disable=SC2329 # cleanup is invoked via trap EXIT
|
||||||
|
cleanup() {
|
||||||
|
local status=$? # capture original exit status so failures propagate
|
||||||
|
local cleanupStatus=0
|
||||||
|
|
||||||
|
if ! cleanup_image false; then
|
||||||
|
cleanupStatus=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $status -eq 0 && $cleanupStatus -ne 0 ]]; then
|
||||||
|
echo "Image build commands completed, but cleanup or filesystem verification failed."
|
||||||
|
status=1
|
||||||
|
fi
|
||||||
|
|
||||||
exit "$status"
|
exit "$status"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finish_build() {
|
||||||
|
trap - EXIT
|
||||||
|
|
||||||
|
if ! cleanup_image true; then
|
||||||
|
echo "Image build commands completed, but cleanup or filesystem verification failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! compress_image; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
help() {
|
help() {
|
||||||
echo -e "Usage:\n"
|
echo -e "Usage:\n"
|
||||||
echo "With no arguments, build with default parameters."
|
echo "With no arguments, build with default parameters."
|
||||||
@@ -100,6 +166,12 @@ if [[ -e "$imageName" ]]; then
|
|||||||
echo "${imageName} exists, please remove or move it for this script to continue."
|
echo "${imageName} exists, please remove or move it for this script to continue."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
for outputFile in "${imageName}.xz" "${imageName}.xz.sha1sum"; do
|
||||||
|
if [[ -e "$outputFile" ]]; then
|
||||||
|
echo "${outputFile} exists, please remove or move it for this script to continue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# Make sure this script is ran as root.
|
# Make sure this script is ran as root.
|
||||||
if [ "$(whoami)" != "root" ] ; then
|
if [ "$(whoami)" != "root" ] ; then
|
||||||
@@ -124,6 +196,12 @@ for i in arch-install-scripts dosfstools parted ; do
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
for i in e2fsck fsck.vfat sha1sum xz ; do
|
||||||
|
if ! command -v "$i" &> /dev/null ; then
|
||||||
|
echo "Please install ${i} before continuing."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
fallocate -l "$imageSize" "$imageName"
|
fallocate -l "$imageSize" "$imageName"
|
||||||
@@ -257,12 +335,17 @@ packages=(
|
|||||||
fake-hwclock
|
fake-hwclock
|
||||||
fenrir
|
fenrir
|
||||||
firmware-raspberrypi
|
firmware-raspberrypi
|
||||||
linux-firmware
|
|
||||||
git
|
git
|
||||||
gstreamer
|
gstreamer
|
||||||
gst-plugins-base
|
gst-plugins-base
|
||||||
gst-plugins-good
|
gst-plugins-good
|
||||||
ii
|
ii
|
||||||
|
# Keep Pi onboard firmware plus common USB/network chipset firmware without
|
||||||
|
# pulling in unrelated desktop/server GPU firmware.
|
||||||
|
linux-firmware-atheros
|
||||||
|
linux-firmware-broadcom
|
||||||
|
linux-firmware-mediatek
|
||||||
|
linux-firmware-realtek
|
||||||
magic-wormhole
|
magic-wormhole
|
||||||
man
|
man
|
||||||
man-pages
|
man-pages
|
||||||
@@ -387,5 +470,5 @@ find ../files/etc/skel/ -mindepth 1 -exec cp -rv "{}" /mnt/home/stormux/ \;
|
|||||||
# Copy boot files again to ensure custom config overrides any package changes
|
# Copy boot files again to ensure custom config overrides any package changes
|
||||||
cp -rv ../files/boot/* /mnt/boot
|
cp -rv ../files/boot/* /mnt/boot
|
||||||
|
|
||||||
# Exiting calls the cleanup function to unmount.
|
# Clean up, verify, compress, and create the checksum.
|
||||||
exit 0
|
finish_build
|
||||||
|
|||||||
@@ -933,12 +933,55 @@ get_bios_install_disk() {
|
|||||||
# System information gathering
|
# System information gathering
|
||||||
#
|
#
|
||||||
|
|
||||||
|
is_valid_hostname() {
|
||||||
|
local candidate="$1"
|
||||||
|
local label
|
||||||
|
local -a labels
|
||||||
|
|
||||||
|
if [[ -z "$candidate" ]] || [[ ${#candidate} -gt 253 ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$candidate" == .* ]] || [[ "$candidate" == *. ]] || [[ "$candidate" == *..* ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$candidate" == *[!A-Za-z0-9.-]* ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS=. read -r -a labels <<< "$candidate"
|
||||||
|
for label in "${labels[@]}"; do
|
||||||
|
if [[ -z "$label" ]] || [[ ${#label} -gt 63 ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! "$label" =~ ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
gather_system_info() {
|
gather_system_info() {
|
||||||
log_info "=== System Configuration ==="
|
log_info "=== System Configuration ==="
|
||||||
|
|
||||||
# Hostname
|
# Hostname
|
||||||
echo "Enter hostname for the new system:"
|
echo "Hostnames may contain letters, numbers, and hyphens, with optional dots between name parts."
|
||||||
read -r hostname
|
echo "They cannot contain spaces or underscores, and each part must start and end with a letter or number."
|
||||||
|
echo "Examples: stormux, stormux-laptop, stormux-desktop"
|
||||||
|
while true; do
|
||||||
|
echo "Enter hostname for the new system:"
|
||||||
|
read -r hostname
|
||||||
|
|
||||||
|
if is_valid_hostname "$hostname"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "ERROR: Invalid hostname."
|
||||||
|
echo "Use letters, numbers, and hyphens only; do not use spaces. Example: stormux-laptop"
|
||||||
|
done
|
||||||
log_info "Hostname set to: $hostname"
|
log_info "Hostname set to: $hostname"
|
||||||
|
|
||||||
# Root password
|
# Root password
|
||||||
@@ -1173,6 +1216,40 @@ gather_system_info() {
|
|||||||
# Base system installation
|
# Base system installation
|
||||||
#
|
#
|
||||||
|
|
||||||
|
refresh_package_sources() {
|
||||||
|
local mirrorlist="/etc/pacman.d/mirrorlist"
|
||||||
|
local mirrorlistBackup="${mirrorlist}.stormux-backup"
|
||||||
|
local targetSyncDir="$mountPoint/var/lib/pacman/sync"
|
||||||
|
|
||||||
|
log_info "Refreshing package mirrors and databases"
|
||||||
|
|
||||||
|
if command -v reflector >/dev/null 2>&1; then
|
||||||
|
log_info "Selecting recently synced fast Arch mirrors"
|
||||||
|
cp -a "$mirrorlist" "$mirrorlistBackup"
|
||||||
|
|
||||||
|
if reflector --protocol https --latest 20 --sort rate --number 10 --save "$mirrorlist"; then
|
||||||
|
log_info "Mirrorlist refreshed"
|
||||||
|
else
|
||||||
|
log_warning "Mirror refresh failed; keeping the existing mirrorlist"
|
||||||
|
cp -a "$mirrorlistBackup" "$mirrorlist"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_warning "reflector is not installed; using the existing mirrorlist"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Forcing package database refresh"
|
||||||
|
if ! pacman -Syy --noconfirm; then
|
||||||
|
log_error "Package database refresh failed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Clearing target package sync cache for pacstrap"
|
||||||
|
mkdir -p "$targetSyncDir"
|
||||||
|
rm -f "$targetSyncDir"/*.db "$targetSyncDir"/*.db.sig "$targetSyncDir"/*.files "$targetSyncDir"/*.files.sig
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
install_base_system() {
|
install_base_system() {
|
||||||
log_info "=== Installing Base System ==="
|
log_info "=== Installing Base System ==="
|
||||||
|
|
||||||
@@ -1278,6 +1355,11 @@ install_base_system() {
|
|||||||
log_info "Installing packages: ${allPackages[*]}"
|
log_info "Installing packages: ${allPackages[*]}"
|
||||||
log_info "Installing packages (this may take several minutes)"
|
log_info "Installing packages (this may take several minutes)"
|
||||||
|
|
||||||
|
if ! refresh_package_sources; then
|
||||||
|
log_error "Could not refresh package sources"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Run pacstrap
|
# Run pacstrap
|
||||||
if ! pacstrap "$mountPoint" "${allPackages[@]}"; then
|
if ! pacstrap "$mountPoint" "${allPackages[@]}"; then
|
||||||
log_error "pacstrap failed"
|
log_error "pacstrap failed"
|
||||||
|
|||||||
Reference in New Issue
Block a user