Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9496559875 | ||
|
|
ddab0d827f | ||
|
|
aacdf8eb4a | ||
|
|
a6c65ca973 | ||
|
|
19fd4b1ed4 | ||
|
|
185d098bdd |
57
docs/superpowers/specs/2026-04-02-xlibre-updater-design.md
Normal file
57
docs/superpowers/specs/2026-04-02-xlibre-updater-design.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# XLibre Updater Design
|
||||
|
||||
## Goal
|
||||
Add a repository-managed workflow for updating and building the Stormux XLibre package set in the correct dependency order, while keeping `xlibre-video-dummy-with-vt` manually maintained and reviewed against upstream `xlibre-video-dummy`.
|
||||
|
||||
## Scope
|
||||
This design covers:
|
||||
- correcting the package build order in `scripts/upgrade-xlibre.sh`
|
||||
- reviewing and updating `scripts/xlibre-video-dummy-with-vt/PKGBUILD`
|
||||
- regenerating `.SRCINFO` after PKGBUILD changes
|
||||
|
||||
This design does not automate AUR publication or rewrite the downstream package from upstream sources.
|
||||
|
||||
## Current State
|
||||
The updater script currently builds packages in an order that does not match the XLibre dependency chain. `xlibre-video-dummy-with-vt` is also version-skewed relative to the current AUR `xlibre-video-dummy` package and needs a manual rebase of relevant packaging changes.
|
||||
|
||||
## Dependency Order
|
||||
The package build order will be:
|
||||
|
||||
1. `xlibre-xserver-common`
|
||||
2. `xlibre-xserver-devel`
|
||||
3. `xlibre-input-libinput`
|
||||
4. `xlibre-xserver`
|
||||
5. `xlibre-video-fbdev`
|
||||
6. `xlibre-video-dummy-with-vt`
|
||||
|
||||
This order reflects current AUR dependencies: `xlibre-xserver` requires `xlibre-xserver-common` and `xlibre-input-libinput`, while the input and video driver packages require `xlibre-xserver-devel` to build.
|
||||
|
||||
## Downstream Package Policy
|
||||
`xlibre-video-dummy-with-vt` remains a separate, manually maintained package because it has a different maintainer and should not be auto-derived from the upstream AUR package.
|
||||
|
||||
The maintenance rule is:
|
||||
- treat AUR `xlibre-video-dummy` as the packaging baseline
|
||||
- manually port relevant upstream PKGBUILD changes into `xlibre-video-dummy-with-vt`
|
||||
- keep only the intentional downstream delta needed for VT behavior
|
||||
|
||||
## Implementation Shape
|
||||
`scripts/upgrade-xlibre.sh` will continue cloning packages from AUR and building them locally, but with the corrected order.
|
||||
|
||||
`scripts/xlibre-video-dummy-with-vt/PKGBUILD` will be updated to match the current upstream package structure where appropriate:
|
||||
- current version and release
|
||||
- current `depends` and `makedepends`
|
||||
- current build flags and source layout
|
||||
- regenerated checksums
|
||||
|
||||
The VT-specific patch remains the only behavioral divergence.
|
||||
|
||||
## Error Handling
|
||||
The script should fail fast on clone or build errors and stop rather than continuing with a broken package chain. Because package order is intentional, partial success should be considered incomplete.
|
||||
|
||||
## Verification
|
||||
Verification will be task-focused:
|
||||
- confirm the updater script contains the corrected package order
|
||||
- compare the downstream PKGBUILD against current upstream `xlibre-video-dummy`
|
||||
- regenerate and verify `.SRCINFO`
|
||||
- run `shellcheck` on the updater script
|
||||
- run `makepkg --printsrcinfo` in the downstream package directory
|
||||
194
scripts/updatepkg.sh
Executable file
194
scripts/updatepkg.sh
Executable file
@@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
shopt -s nullglob
|
||||
|
||||
# ---- Configurable Variables ----
|
||||
repoDir="/var/www/packages.stormux.org"
|
||||
keyId="52ADA49000F1FF0456F8AEEFB4CDE1CD56EF8E82"
|
||||
repoName="stormux"
|
||||
dbName="${repoName}.db.tar.gz"
|
||||
filesName="${repoName}.files.tar.gz"
|
||||
rebuildDb="${REBUILD_DB:-false}"
|
||||
|
||||
require_cmd() {
|
||||
local cmd="$1"
|
||||
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
echo "❌ Required command not found: $cmd"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ---- Safety Checks ----
|
||||
if [[ ! -d "$repoDir" ]]; then
|
||||
echo "❌ Repo dir does not exist: $repoDir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
require_cmd "gpg"
|
||||
require_cmd "repo-add"
|
||||
require_cmd "repo-remove"
|
||||
|
||||
# ---- Create Architecture Directories ----
|
||||
mkdir -p "$repoDir/x86_64" "$repoDir/aarch64"
|
||||
|
||||
# ---- Process Each Architecture ----
|
||||
process_arch() {
|
||||
local arch="$1"
|
||||
local archDir="$repoDir/$arch"
|
||||
local pkgFiles=()
|
||||
local selectedPkgFiles=()
|
||||
local repoAddArgs=()
|
||||
local -A currentPkgNames=()
|
||||
local -A newestPkgByName=()
|
||||
local repoPkgNames=()
|
||||
local dbFile="$dbName"
|
||||
local filesFile="$filesName"
|
||||
local dbSig="${dbFile}.sig"
|
||||
local filesSig="${filesFile}.sig"
|
||||
local dbLink="${repoName}.db"
|
||||
local filesLink="${repoName}.files"
|
||||
|
||||
echo "🏗️ Processing $arch packages..."
|
||||
|
||||
# Enter arch directory (packages should already be sorted by update.sh)
|
||||
cd "$archDir" || return 1
|
||||
|
||||
# Select only the newest archive for each package name. repo-add cannot
|
||||
# safely consume multiple versions of the same package in a single run.
|
||||
pkgFiles=( *.pkg.tar.zst *.pkg.tar.xz )
|
||||
for pkg in "${pkgFiles[@]}"; do
|
||||
local pkgName pkgVersion existingPkg existingVersion
|
||||
pkgName="$(bsdtar -xOqf "$pkg" .PKGINFO | sed -n 's/^pkgname = //p' | head -n1)"
|
||||
pkgVersion="$(bsdtar -xOqf "$pkg" .PKGINFO | sed -n 's/^pkgver = //p' | head -n1)-$(bsdtar -xOqf "$pkg" .PKGINFO | sed -n 's/^pkgrel = //p' | head -n1)"
|
||||
|
||||
if [[ -z "$pkgName" || -z "$pkgVersion" ]]; then
|
||||
echo "❌ Unable to determine package metadata for $pkg"
|
||||
cd "$repoDir" || exit 1
|
||||
return 1
|
||||
fi
|
||||
|
||||
existingPkg="${currentPkgNames[$pkgName]:-}"
|
||||
if [[ -z "$existingPkg" ]]; then
|
||||
currentPkgNames["$pkgName"]="$pkg"
|
||||
else
|
||||
existingVersion="$(bsdtar -xOqf "$existingPkg" .PKGINFO | sed -n 's/^pkgver = //p' | head -n1)-$(bsdtar -xOqf "$existingPkg" .PKGINFO | sed -n 's/^pkgrel = //p' | head -n1)"
|
||||
if (( $(vercmp "$pkgVersion" "$existingVersion") > 0 )); then
|
||||
currentPkgNames["$pkgName"]="$pkg"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
for pkgName in "${!currentPkgNames[@]}"; do
|
||||
newestPkgByName["$pkgName"]="${currentPkgNames[$pkgName]}"
|
||||
selectedPkgFiles+=( "${currentPkgNames[$pkgName]}" )
|
||||
done
|
||||
|
||||
pkgFiles=( "${selectedPkgFiles[@]}" )
|
||||
|
||||
# Sign all unsigned selected packages
|
||||
echo "🔏 Signing $arch packages..."
|
||||
for pkg in "${pkgFiles[@]}"; do
|
||||
if [[ ! -f "$pkg.sig" ]]; then
|
||||
echo " 📝 Signing $pkg"
|
||||
gpg --default-key "$keyId" --detach-sign "$pkg"
|
||||
else
|
||||
echo " ✅ $pkg already signed"
|
||||
fi
|
||||
done
|
||||
|
||||
# Track which package names should remain in the repo after this run.
|
||||
for pkg in "${pkgFiles[@]}"; do
|
||||
local pkgName
|
||||
pkgName="$(bsdtar -xOqf "$pkg" .PKGINFO | sed -n 's/^pkgname = //p' | head -n1)"
|
||||
if [[ -n "$pkgName" ]]; then
|
||||
currentPkgNames["$pkgName"]=1
|
||||
else
|
||||
echo "❌ Unable to determine package name for $pkg"
|
||||
cd "$repoDir" || exit 1
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Rebuild database for this architecture
|
||||
if [[ "$rebuildDb" == "true" ]]; then
|
||||
echo "🗃️ Rebuilding $arch repo database..."
|
||||
rm -f "$dbFile" "$dbSig" "$filesFile" "$filesSig" "$dbLink" "$filesLink"
|
||||
elif [[ -f "$dbFile" ]]; then
|
||||
echo "🗃️ Updating $arch repo database..."
|
||||
else
|
||||
echo "🆕 Creating new $arch repo database..."
|
||||
fi
|
||||
|
||||
# Remove packages that still exist in the repo database but are no longer
|
||||
# present in the current directory. repo-remove with --remove also deletes
|
||||
# the matching package archive and detached signature from disk.
|
||||
if [[ -f "$dbFile" ]]; then
|
||||
mapfile -t repoPkgNames < <(
|
||||
bsdtar -tf "$dbFile" |
|
||||
awk -F/ 'NF == 2 && $2 == "desc" {print $1}' |
|
||||
while read -r entry; do
|
||||
bsdtar -xOf "$dbFile" "${entry}/desc" |
|
||||
awk 'found {print; exit} /^%NAME%$/ {found=1}'
|
||||
done |
|
||||
sort -u
|
||||
)
|
||||
|
||||
for pkgName in "${repoPkgNames[@]}"; do
|
||||
if [[ -z "${currentPkgNames[$pkgName]:-}" ]]; then
|
||||
echo "🧹 Removing stale repo package $pkgName"
|
||||
repo-remove --sign --key "$keyId" --remove "$dbFile" "$pkgName"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Only run repo-add if there are packages
|
||||
if ((${#pkgFiles[@]} > 0)); then
|
||||
repoAddArgs=(--sign --key "$keyId" --remove)
|
||||
if [[ "$rebuildDb" != "true" && -f "$dbFile" ]]; then
|
||||
repoAddArgs+=(--verify)
|
||||
fi
|
||||
|
||||
repo-add "${repoAddArgs[@]}" "$dbFile" "${pkgFiles[@]}"
|
||||
|
||||
if [[ ! -f "$dbFile" ]]; then
|
||||
echo "❌ repo-add did not create $dbFile"
|
||||
cd "$repoDir" || exit 1
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -e "$dbLink" ]]; then
|
||||
ln -s "$dbFile" "$dbLink"
|
||||
fi
|
||||
|
||||
if [[ -f "$filesFile" && ! -e "$filesLink" ]]; then
|
||||
ln -s "$filesFile" "$filesLink"
|
||||
fi
|
||||
|
||||
echo "✅ $arch repo updated successfully"
|
||||
else
|
||||
echo "ℹ️ No $arch packages found"
|
||||
fi
|
||||
|
||||
# Remove orphaned package archives and detached signatures that are not part
|
||||
# of the current package set. This keeps the on-disk repo contents aligned
|
||||
# with the package database after rebuilds and package removals.
|
||||
for pkg in *.pkg.tar.zst *.pkg.tar.xz; do
|
||||
local pkgName
|
||||
pkgName="$(bsdtar -xOqf "$pkg" .PKGINFO | sed -n 's/^pkgname = //p' | head -n1)"
|
||||
if [[ -z "${newestPkgByName[$pkgName]:-}" || "${newestPkgByName[$pkgName]}" != "$pkg" ]]; then
|
||||
echo "🧹 Removing orphaned package file $pkg"
|
||||
rm -f "$pkg" "$pkg.sig"
|
||||
fi
|
||||
done
|
||||
|
||||
cd "$repoDir" || exit
|
||||
}
|
||||
|
||||
# ---- Process Both Architectures ----
|
||||
process_arch "x86_64"
|
||||
process_arch "aarch64"
|
||||
|
||||
# ---- Done ----
|
||||
echo "✅ All repositories updated and signed successfully."
|
||||
28
scripts/upgrade-xlibre.sh
Executable file
28
scripts/upgrade-xlibre.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
startDir="$(pwd)"
|
||||
buildDir="${startDir}/xlibre-build"
|
||||
|
||||
packageList=(
|
||||
xlibre-input-libinput
|
||||
xlibre-xserver
|
||||
xlibre-video-amdgpu
|
||||
xlibre-video-ati
|
||||
xlibre-video-fbdev
|
||||
xlibre-video-intel
|
||||
xlibre-video-nouveau
|
||||
xlibre-video-vesa
|
||||
xlibre-video-dummy-with-vt
|
||||
)
|
||||
|
||||
mkdir -p "${buildDir}"
|
||||
|
||||
for i in "${packageList[@]}" ; do
|
||||
yay -Ga "$i"
|
||||
pushd "$i"
|
||||
makepkg -Acrsf
|
||||
cp -v ./*.pkg.tar.* "${buildDir}/"
|
||||
popd
|
||||
done
|
||||
23
scripts/xlibre-video-dummy-with-vt/.SRCINFO
Normal file
23
scripts/xlibre-video-dummy-with-vt/.SRCINFO
Normal file
@@ -0,0 +1,23 @@
|
||||
pkgbase = xlibre-video-dummy-with-vt
|
||||
pkgdesc = XLibre dummy video driver with an allocated vt
|
||||
pkgver = 25.0.0
|
||||
pkgrel = 5
|
||||
url = https://github.com/X11Libre/xf86-video-dummy
|
||||
arch = x86_64
|
||||
arch = aarch64
|
||||
groups = xlibre-drivers
|
||||
license = MIT
|
||||
license = X11
|
||||
makedepends = xlibre-xserver-devel>=25.0
|
||||
makedepends = xorgproto
|
||||
depends = xlibre-xserver>=25.0
|
||||
depends = glibc
|
||||
provides = xf86-video-dummy
|
||||
provides = x11win-video-dummy
|
||||
conflicts = xf86-video-dummy
|
||||
source = https://github.com/X11Libre/xf86-video-dummy/archive/refs/tags/xlibre-xf86-video-dummy-25.0.0.tar.gz
|
||||
source = dummy_driver.patch
|
||||
sha256sums = b56e610705cd3d4d86422a11c6b0d93357e4d4749a05178a85fd250301d357b9
|
||||
sha256sums = 68cdcf21e9b54a7fdb8e968292e1ef9ad154ddb1361b141a0a635c2a13c92bfa
|
||||
|
||||
pkgname = xlibre-video-dummy-with-vt
|
||||
5
scripts/xlibre-video-dummy-with-vt/.gitignore
vendored
Normal file
5
scripts/xlibre-video-dummy-with-vt/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
*
|
||||
!PKGBUILD
|
||||
!.SRCINFO
|
||||
!.gitignore
|
||||
!.nvchecker.toml
|
||||
5
scripts/xlibre-video-dummy-with-vt/.nvchecker.toml
Normal file
5
scripts/xlibre-video-dummy-with-vt/.nvchecker.toml
Normal file
@@ -0,0 +1,5 @@
|
||||
[xlibre-video-dummy]
|
||||
source = "git"
|
||||
git = "https://github.com/x11libre/xf86-video-dummy.git"
|
||||
include_regex = "xlibre-xf86-video-dummy-.*"
|
||||
prefix = "xlibre-xf86-video-dummy-"
|
||||
59
scripts/xlibre-video-dummy-with-vt/PKGBUILD
Normal file
59
scripts/xlibre-video-dummy-with-vt/PKGBUILD
Normal file
@@ -0,0 +1,59 @@
|
||||
# Maintainer: Storm Dragon <storm_dragon@linux-a11y.org>
|
||||
|
||||
pkgname=xlibre-video-dummy-with-vt
|
||||
pkgver=25.0.0
|
||||
pkgrel=5
|
||||
pkgdesc="XLibre dummy video driver with an allocated vt"
|
||||
arch=(x86_64 aarch64)
|
||||
_pkgname=xf86-video-dummy
|
||||
url="https://github.com/X11Libre/${_pkgname}"
|
||||
license=('MIT' 'X11')
|
||||
depends=("xlibre-xserver>=${pkgver%.*}" 'glibc')
|
||||
makedepends=("xlibre-xserver-devel>=${pkgver%.*}" 'xorgproto')
|
||||
conflicts=("${_pkgname}")
|
||||
provides=("${_pkgname}" 'x11win-video-dummy')
|
||||
source=("${url}/archive/refs/tags/xlibre-${_pkgname}-${pkgver}.tar.gz"
|
||||
"dummy_driver.patch")
|
||||
groups=('xlibre-drivers')
|
||||
sha256sums=('b56e610705cd3d4d86422a11c6b0d93357e4d4749a05178a85fd250301d357b9'
|
||||
'68cdcf21e9b54a7fdb8e968292e1ef9ad154ddb1361b141a0a635c2a13c92bfa')
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${_pkgname}-xlibre-${_pkgname}-${pkgver}/src"
|
||||
patch -i "${srcdir}/dummy_driver.patch"
|
||||
}
|
||||
|
||||
build() {
|
||||
case "$CARCH" in
|
||||
"x86_64")
|
||||
CFLAGS=" -march=x86-64"
|
||||
;;
|
||||
"aarch64")
|
||||
CFLAGS=" -march=armv8-a"
|
||||
;;
|
||||
*)
|
||||
CFLAGS=" -march=native"
|
||||
;;
|
||||
esac
|
||||
CFLAGS+=" -mtune=generic -O2 -pipe -fexceptions -Wp,-D_FORTIFY_SOURCE=3 -Wformat -Werror=format-security"
|
||||
CFLAGS+=" -fstack-clash-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"
|
||||
LDFLAGS=" -Wl,-O1 -Wl,--sort-common -Wl,--as-needed -Wl,-z,lazy -Wl,-z,relro -Wl,-z,pack-relative-relocs"
|
||||
if [[ $CARCH != 'aarch64' ]]; then
|
||||
CFLAGS+=" -fcf-protection"
|
||||
fi
|
||||
CXXFLAGS="${CFLAGS} -Wp,-D_GLIBCXX_ASSERTIONS"
|
||||
export CFLAGS="${CFLAGS}"
|
||||
export CXXFLAGS="${CXXFLAGS}"
|
||||
export LDFLAGS="${LDFLAGS}"
|
||||
|
||||
cd "${srcdir}/${_pkgname}-xlibre-${_pkgname}-${pkgver}"
|
||||
./autogen.sh
|
||||
./configure --prefix=/usr
|
||||
make
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${_pkgname}-xlibre-${_pkgname}-${pkgver}"
|
||||
make DESTDIR="${pkgdir}" install
|
||||
install -Dm644 COPYING "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
|
||||
}
|
||||
17
scripts/xlibre-video-dummy-with-vt/dummy_driver.patch
Normal file
17
scripts/xlibre-video-dummy-with-vt/dummy_driver.patch
Normal file
@@ -0,0 +1,17 @@
|
||||
--- a/src/dummy_driver.c
|
||||
+++ b/src/dummy_driver.c
|
||||
@@ -1016,10 +1016,10 @@ dummyDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer ptr)
|
||||
CARD32 *flag;
|
||||
|
||||
switch (op) {
|
||||
- case GET_REQUIRED_HW_INTERFACES:
|
||||
- flag = (CARD32*)ptr;
|
||||
- (*flag) = HW_SKIP_CONSOLE;
|
||||
- return TRUE;
|
||||
+ case GET_REQUIRED_HW_INTERFACES:
|
||||
+ flag = (CARD32*)ptr;
|
||||
+ /* Allow the driver to allocate a VT instead of skipping the console. */
|
||||
+ return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
@@ -11,7 +11,8 @@ mountPoint="/mnt"
|
||||
bootMode="" # Will be "uefi" or "bios"
|
||||
targetDisk=""
|
||||
homeDisk=""
|
||||
partitionLayout="" # "single", "separate_home", "separate_disk"
|
||||
partitionLayout="" # "single", "separate_home", "separate_disk", "manual_mnt"
|
||||
useExistingMount=false # true when using manually mounted filesystems at /mnt
|
||||
hostname=""
|
||||
rootPassword=""
|
||||
declare -a userNames=()
|
||||
@@ -43,7 +44,7 @@ log_warning() {
|
||||
}
|
||||
|
||||
log_info() {
|
||||
echo "INFO: $*" | tee -a "$logFile"
|
||||
echo "$*" | tee -a "$logFile"
|
||||
}
|
||||
|
||||
#
|
||||
@@ -92,7 +93,7 @@ check_internet() {
|
||||
|
||||
check_required_tools() {
|
||||
log_info "Checking for required tools..."
|
||||
local tools=(parted mkfs.vfat mkfs.ext4 pacstrap arch-chroot genfstab lsblk)
|
||||
local tools=(parted mkfs.vfat mkfs.ext4 pacstrap arch-chroot genfstab lsblk blkid findmnt mountpoint)
|
||||
local missing=()
|
||||
|
||||
for tool in "${tools[@]}"; do
|
||||
@@ -164,6 +165,39 @@ select_disk() {
|
||||
done
|
||||
}
|
||||
|
||||
select_install_target() {
|
||||
echo "Select installation target:"
|
||||
|
||||
mapfile -t disks < <(list_available_disks | awk '{print $1}')
|
||||
|
||||
if [[ ${#disks[@]} -gt 0 ]]; then
|
||||
# Display disk information
|
||||
log "Available disks:"
|
||||
lsblk -dno NAME,SIZE,TYPE,MODEL | grep -E "^($(IFS='|'; echo "${disks[*]}")).*disk" || true
|
||||
else
|
||||
log_warning "No suitable installation disks detected"
|
||||
fi
|
||||
|
||||
local manualOption="Use existing /mnt (already mounted root/home/boot)"
|
||||
PS3="Enter target number: "
|
||||
select targetChoice in "${disks[@]}" "$manualOption" "Cancel"; do
|
||||
if [[ "$targetChoice" == "Cancel" ]]; then
|
||||
log_info "Target selection cancelled by user"
|
||||
return 1
|
||||
elif [[ "$targetChoice" == "$manualOption" ]]; then
|
||||
useExistingMount=true
|
||||
partitionLayout="manual_mnt"
|
||||
log_info "Selected existing mount mode at $mountPoint"
|
||||
return 0
|
||||
elif [[ -n "$targetChoice" ]]; then
|
||||
targetDisk="/dev/$targetChoice"
|
||||
useExistingMount=false
|
||||
log_info "Selected disk: $targetDisk"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
confirm_disk_destruction() {
|
||||
local disk="$1"
|
||||
log ""
|
||||
@@ -571,6 +605,152 @@ mount_filesystems() {
|
||||
log_info "Filesystems mounted successfully"
|
||||
}
|
||||
|
||||
validate_existing_mountpoint() {
|
||||
log_info "=== Validating Existing Mountpoint ==="
|
||||
|
||||
if [[ ! -d "$mountPoint" ]]; then
|
||||
log_error "Mountpoint does not exist: $mountPoint"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! mountpoint -q "$mountPoint"; then
|
||||
log_error "$mountPoint is not mounted"
|
||||
log_error "Mount root to $mountPoint before running this installer mode"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local rootSource
|
||||
rootSource=$(findmnt -n -o SOURCE --target "$mountPoint" 2>/dev/null || true)
|
||||
if [[ -z "$rootSource" ]]; then
|
||||
log_error "Could not determine mounted root source for $mountPoint"
|
||||
return 1
|
||||
fi
|
||||
if [[ "$rootSource" != /dev/* ]]; then
|
||||
log_error "Unsupported root source for manual install mode: $rootSource"
|
||||
log_error "Root at $mountPoint must be backed by a /dev/* block device"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$mountPoint/home" ]]; then
|
||||
log_error "Required directory is missing: $mountPoint/home"
|
||||
log_error "Create or mount /home at $mountPoint/home before continuing"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$bootMode" == "uefi" ]]; then
|
||||
if [[ ! -d "$mountPoint/boot" ]]; then
|
||||
log_error "Required directory is missing for UEFI: $mountPoint/boot"
|
||||
log_error "Mount the EFI system partition at $mountPoint/boot before continuing"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! mountpoint -q "$mountPoint/boot"; then
|
||||
log_error "$mountPoint/boot is not mounted"
|
||||
log_error "For UEFI installs, mount EFI at $mountPoint/boot before continuing"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local efiFsType
|
||||
efiFsType=$(findmnt -n -o FSTYPE --target "$mountPoint/boot" 2>/dev/null || true)
|
||||
if [[ "$efiFsType" != "vfat" && "$efiFsType" != "fat" && "$efiFsType" != "msdos" ]]; then
|
||||
log_error "Unexpected EFI filesystem type at $mountPoint/boot: ${efiFsType:-unknown}"
|
||||
log_error "UEFI boot partition must be FAT (vfat)"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! mountpoint -q "$mountPoint/home"; then
|
||||
log_warning "$mountPoint/home is not a separate mountpoint"
|
||||
log_warning "Continuing with /home as a directory inside root"
|
||||
fi
|
||||
|
||||
local writeTestFile="$mountPoint/.stormux-write-test-$$"
|
||||
if ! touch "$writeTestFile" 2>/dev/null; then
|
||||
log_error "$mountPoint is not writable"
|
||||
return 1
|
||||
fi
|
||||
rm -f "$writeTestFile"
|
||||
|
||||
log ""
|
||||
log "Manual mount summary (current mounts):"
|
||||
log " $(findmnt -n -o SOURCE,FSTYPE,TARGET --target "$mountPoint" 2>/dev/null || echo "$mountPoint not mounted")"
|
||||
|
||||
if mountpoint -q "$mountPoint/home"; then
|
||||
log " $(findmnt -n -o SOURCE,FSTYPE,TARGET --target "$mountPoint/home" 2>/dev/null || echo "$mountPoint/home not mounted")"
|
||||
else
|
||||
log " $mountPoint/home is a directory inside root (not a separate mount)"
|
||||
fi
|
||||
|
||||
if [[ "$bootMode" == "uefi" ]]; then
|
||||
log " $(findmnt -n -o SOURCE,FSTYPE,TARGET --target "$mountPoint/boot" 2>/dev/null || echo "$mountPoint/boot not mounted")"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Type 'YES' (in capital letters) to continue using existing mounts at $mountPoint:"
|
||||
read -r manualMountConfirmation
|
||||
if [[ "$manualMountConfirmation" != "YES" ]]; then
|
||||
log_info "Existing mount mode not confirmed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Existing mountpoint validation passed"
|
||||
return 0
|
||||
}
|
||||
|
||||
get_root_partition_device() {
|
||||
if [[ "$useExistingMount" == true ]]; then
|
||||
findmnt -n -o SOURCE --target "$mountPoint" 2>/dev/null || true
|
||||
else
|
||||
if [[ "$bootMode" == "uefi" ]]; then
|
||||
get_partition_device "$targetDisk" 2
|
||||
else
|
||||
get_partition_device "$targetDisk" 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
get_bios_install_disk() {
|
||||
if [[ "$useExistingMount" == false ]]; then
|
||||
echo "$targetDisk"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local rootPart
|
||||
rootPart=$(get_root_partition_device)
|
||||
if [[ -z "$rootPart" ]]; then
|
||||
log_error "Could not determine root source from mounted $mountPoint"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$rootPart" != /dev/* ]]; then
|
||||
log_error "Unsupported root source for BIOS bootloader installation: $rootPart"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local rootType
|
||||
rootType=$(lsblk -no TYPE "$rootPart" 2>/dev/null | head -n 1 || true)
|
||||
|
||||
case "$rootType" in
|
||||
part)
|
||||
local parentDisk
|
||||
parentDisk=$(lsblk -no PKNAME "$rootPart" 2>/dev/null | head -n 1 || true)
|
||||
if [[ -z "$parentDisk" ]]; then
|
||||
log_error "Could not determine parent disk for root partition: $rootPart"
|
||||
return 1
|
||||
fi
|
||||
echo "/dev/$parentDisk"
|
||||
;;
|
||||
disk)
|
||||
echo "$rootPart"
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported root device type for BIOS bootloader installation: $rootType"
|
||||
log_error "Automatic disk detection only supports direct partition or disk root devices"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
#
|
||||
# System information gathering
|
||||
#
|
||||
@@ -1425,9 +1605,18 @@ EOF
|
||||
|
||||
# Get root partition UUID
|
||||
local rootPart
|
||||
rootPart=$(get_partition_device "$targetDisk" 2)
|
||||
rootPart=$(get_root_partition_device)
|
||||
if [[ -z "$rootPart" ]]; then
|
||||
log_error "Could not determine root partition device"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local rootUUID
|
||||
rootUUID=$(blkid -s UUID -o value "$rootPart")
|
||||
if [[ -z "$rootUUID" ]]; then
|
||||
log_error "Could not determine root partition UUID for $rootPart"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Create boot entry
|
||||
cat > "$mountPoint/boot/loader/entries/arch.conf" <<EOF
|
||||
@@ -1444,8 +1633,11 @@ EOF
|
||||
log_info "Installing GRUB for BIOS"
|
||||
log_info "Installing GRUB"
|
||||
|
||||
local grubTargetDisk
|
||||
grubTargetDisk=$(get_bios_install_disk) || return 1
|
||||
|
||||
# Install GRUB to disk
|
||||
arch-chroot "$mountPoint" grub-install --target=i386-pc "$targetDisk"
|
||||
arch-chroot "$mountPoint" grub-install --target=i386-pc "$grubTargetDisk"
|
||||
|
||||
# Generate GRUB config
|
||||
arch-chroot "$mountPoint" grub-mkconfig -o /boot/grub/grub.cfg
|
||||
@@ -1603,33 +1795,40 @@ fi
|
||||
|
||||
# Disk selection
|
||||
log_info "=== Disk Selection ==="
|
||||
if ! select_disk targetDisk "Select target disk for Stormux installation:"; then
|
||||
log_error "Target disk selection cancelled"
|
||||
if ! select_install_target; then
|
||||
log_error "Target selection cancelled"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! confirm_disk_destruction "$targetDisk"; then
|
||||
log_error "Disk destruction not confirmed"
|
||||
echo "Installation cancelled."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Partition layout selection
|
||||
if ! select_partition_layout; then
|
||||
log_error "Partition layout selection cancelled"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If separate disk layout, select home disk
|
||||
if [[ "$partitionLayout" == "separate_disk" ]]; then
|
||||
if ! select_disk homeDisk "Select disk for /home partition:"; then
|
||||
log_error "Home disk selection cancelled"
|
||||
if [[ "$useExistingMount" == false ]]; then
|
||||
if ! confirm_disk_destruction "$targetDisk"; then
|
||||
log_error "Disk destruction not confirmed"
|
||||
echo "Installation cancelled."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! confirm_disk_destruction "$homeDisk"; then
|
||||
log_error "Home disk destruction not confirmed"
|
||||
echo "Installation cancelled."
|
||||
# Partition layout selection
|
||||
if ! select_partition_layout; then
|
||||
log_error "Partition layout selection cancelled"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If separate disk layout, select home disk
|
||||
if [[ "$partitionLayout" == "separate_disk" ]]; then
|
||||
if ! select_disk homeDisk "Select disk for /home partition:"; then
|
||||
log_error "Home disk selection cancelled"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! confirm_disk_destruction "$homeDisk"; then
|
||||
log_error "Home disk destruction not confirmed"
|
||||
echo "Installation cancelled."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if ! validate_existing_mountpoint; then
|
||||
log_error "Existing mountpoint validation failed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -1640,25 +1839,29 @@ if ! gather_system_info; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Partition disks
|
||||
if ! partition_disks; then
|
||||
log_error "Disk partitioning failed"
|
||||
echo "ERROR: Disk partitioning failed"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$useExistingMount" == false ]]; then
|
||||
# Partition disks
|
||||
if ! partition_disks; then
|
||||
log_error "Disk partitioning failed"
|
||||
echo "ERROR: Disk partitioning failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create filesystems
|
||||
if ! create_filesystems; then
|
||||
log_error "Filesystem creation failed"
|
||||
echo "ERROR: Filesystem creation failed"
|
||||
exit 1
|
||||
fi
|
||||
# Create filesystems
|
||||
if ! create_filesystems; then
|
||||
log_error "Filesystem creation failed"
|
||||
echo "ERROR: Filesystem creation failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Mount filesystems
|
||||
if ! mount_filesystems; then
|
||||
log_error "Filesystem mounting failed"
|
||||
echo "ERROR: Filesystem mounting failed"
|
||||
exit 1
|
||||
# Mount filesystems
|
||||
if ! mount_filesystems; then
|
||||
log_error "Filesystem mounting failed"
|
||||
echo "ERROR: Filesystem mounting failed"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log_info "Skipping partitioning, filesystem creation, and mounting (using existing $mountPoint)"
|
||||
fi
|
||||
|
||||
# Install base system
|
||||
|
||||
Reference in New Issue
Block a user