Files
samios/packaging/scripts/samios-installer.sh
T
2026-08-11 23:48:31 -07:00

507 lines
15 KiB
Bash
Executable File

#!/bin/bash
# SamiOS Automated Installer
# Partitions disk, formats, pacstraps base system, installs bootloader, creates user
# Usage: samios install [options]
set -e
# ── Canonical version source ────────────────────────────────────────────
# Walk up to find ./VERSION, fall back to /etc/samios-version, fall back
# to a placeholder. This guarantees the installer and the CLI it emits
# agree on the version string without any duplicate hardcoding.
_VERSION_FILE=""
_d="$(cd "$(dirname "$0")" && pwd)"
while [ "$_d" != "/" ]; do
if [ -f "$_d/VERSION" ]; then
_VERSION_FILE="$_d/VERSION"
break
fi
_d="$(dirname "$_d")"
done
if [ -z "$_VERSION_FILE" ] && [ -r /etc/samios-version ]; then
VERSION="$(head -n1 /etc/samios-version)"
elif [ -n "$_VERSION_FILE" ]; then
VERSION="$(head -n1 "$_VERSION_FILE")"
# Remember the file so install_samios_cli can mirror it onto the new
# system at /etc/samios-version.
_EMIT_VERSION_FILE="$_VERSION_FILE"
else
VERSION="0.0.0-unknown"
fi
unset _d _VERSION_FILE
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
NC='\033[0m'
log() { echo -e "${BLUE}[SamiOS]${NC} $*"; }
ok() { echo -e "${GREEN}${NC} $*"; }
warn() { echo -e "${YELLOW}${NC} $*"; }
err() { echo -e "${RED}${NC} $*" >&2; }
# ============================================================
# Pre-flight checks
# ============================================================
check_root() {
if [ "$(id -u)" -ne 0 ]; then
err "This script must be run as root"
exit 1
fi
}
check_uefi() {
if [ -d /sys/firmware/efi/efivars ]; then
UEFI=true
ok "UEFI mode detected"
else
UEFI=false
ok "BIOS mode detected"
fi
}
detect_disks() {
log "Detecting available disks..."
mapfile -t DISKS < <(lsblk -d -n -p -o NAME | grep -v "loop\|sr\|fd")
echo ""
echo "Available disks:"
for i in "${!DISKS[@]}"; do
SIZE=$(lsblk -d -n -o SIZE "${DISKS[$i]}" 2>/dev/null)
MODEL=$(lsblk -d -n -o MODEL "${DISKS[$i]}" 2>/dev/null)
echo " [$i] ${DISKS[$i]} - ${SIZE} ${MODEL}"
done
echo ""
}
select_disk() {
if [ -n "$TARGET_DISK" ]; then
return
fi
read -p "Select target disk [0-$(( ${#DISKS[@]} - 1 ))]: " DISK_IDX
TARGET_DISK="${DISKS[$DISK_IDX]}"
echo ""
warn "WARNING: This will ERASE ALL DATA on ${TARGET_DISK}"
read -p "Type 'YES' to confirm: " CONFIRM
if [ "$CONFIRM" != "YES" ]; then
err "Installation cancelled"
exit 1
fi
}
# ============================================================
# Partitioning
# ============================================================
partition_disk() {
log "Partitioning ${TARGET_DISK}..."
# Wipe all partition tables
sgdisk --zap-all "$TARGET_DISK"
if [ "$UEFI" = true ]; then
# UEFI: GPT with EFI System Partition + root
sgdisk -n 1:0:+1G -t 1:ef00 -c 1:"EFI System" "$TARGET_DISK"
sgdisk -n 2:0:0 -t 2:8300 -c 2:"SamiOS Root" "$TARGET_DISK"
partprobe "$TARGET_DISK"
sleep 2
# Determine partition names
if [[ "$TARGET_DISK" == *"nvme"* ]] || [[ "$TARGET_DISK" == *"mmcblk"* ]]; then
EFI_PART="${TARGET_DISK}p1"
ROOT_PART="${TARGET_DISK}p2"
else
EFI_PART="${TARGET_DISK}1"
ROOT_PART="${TARGET_DISK}2"
fi
# Format
mkfs.fat -F32 "$EFI_PART"
mkfs.ext4 -F -L samios "$ROOT_PART"
ok "UEFI partitions created"
else
# BIOS: MBR with single root + boot
sgdisk -n 1:0:0 -t 1:8300 -c 1:"SamiOS" "$TARGET_DISK"
partprobe "$TARGET_DISK"
sleep 2
if [[ "$TARGET_DISK" == *"nvme"* ]] || [[ "$TARGET_DISK" == *"mmcblk"* ]]; then
ROOT_PART="${TARGET_DISK}p1"
else
ROOT_PART="${TARGET_DISK}1"
fi
mkfs.ext4 -F -L samios "$ROOT_PART"
ok "BIOS partition created"
fi
}
# ============================================================
# Mount and pacstrap
# ============================================================
mount_and_install() {
log "Mounting filesystems..."
MOUNT_POINT="/mnt"
mount "$ROOT_PART" "$MOUNT_POINT"
if [ "$UEFI" = true ]; then
mkdir -p "$MOUNT_POINT/boot/efi"
mount "$EFI_PART" "$MOUNT_POINT/boot/efi"
fi
log "Installing base system (this takes a few minutes)..."
# Install base system
pacstrap "$MOUNT_POINT" base base-devel linux linux-firmware
# Generate fstab
genfstab -U "$MOUNT_POINT" > "$MOUNT_POINT/etc/fstab"
ok "Base system installed"
}
# ============================================================
# System configuration
# ============================================================
configure_system() {
log "Configuring system..."
MOUNT_POINT="/mnt"
# Hostname
echo "samios" > "$MOUNT_POINT/etc/hostname"
# Hosts
cat > "$MOUNT_POINT/etc/hosts" << 'HOSTS'
127.0.0.1 localhost
::1 localhost
127.0.1.1 samios.localdomain samios
HOSTS
# Timezone
arch-chroot "$MOUNT_POINT" ln -sf /usr/share/zoneinfo/America/New_York /etc/localtime
arch-chroot "$MOUNT_POINT" hwclock --systohc
# Locale
sed -i 's/^#en_US.UTF-8/en_US.UTF-8/' "$MOUNT_POINT/etc/locale.gen"
arch-chroot "$MOUNT_POINT" locale-gen
echo "LANG=en_US.UTF-8" > "$MOUNT_POINT/etc/locale.conf"
# Keymap
echo "KEYMAP=us" > "$MOUNT_POINT/etc/vconsole.conf"
# Install essential packages
arch-chroot "$MOUNT_POINT" pacman -S --noconfirm \
networkmanager \
sudo \
grub \
efibootmgr \
os-prober \
nano \
vim \
less \
man-db \
man-pages \
git \
curl \
wget \
bash-completion \
reflector \
openssh
# Enable NetworkManager
arch-chroot "$MOUNT_POINT" systemctl enable NetworkManager
# Enable SSH (optional)
arch-chroot "$MOUNT_POINT" systemctl enable sshd
ok "System configured"
}
# ============================================================
# Bootloader
# ============================================================
install_bootloader() {
log "Installing bootloader..."
MOUNT_POINT="/mnt"
if [ "$UEFI" = true ]; then
arch-chroot "$MOUNT_POINT" grub-install --target=x86_64-efi \
--efi-directory=/boot/efi --bootloader-id=SamiOS
else
arch-chroot "$MOUNT_POINT" grub-install --target=i386-pc "$TARGET_DISK"
fi
# Configure GRUB
arch-chroot "$MOUNT_POINT" grub-mkconfig -o /boot/grub/grub.cfg
ok "Bootloader installed"
}
# ============================================================
# User creation
# ============================================================
create_user() {
log "Creating user account..."
MOUNT_POINT="/mnt"
INTERACTIVE_USER="${INSTALL_USER:-sami}"
if [ -z "$INSTALL_PASSWORD" ]; then
read -s -p "Enter password for ${INTERACTIVE_USER}: " USER_PASS
echo ""
read -s -p "Confirm password: " USER_PASS_CONFIRM
echo ""
if [ "$USER_PASS" != "$USER_PASS_CONFIRM" ]; then
err "Passwords do not match"
exit 1
fi
else
USER_PASS="$INSTALL_PASSWORD"
fi
# Create user
arch-chroot "$MOUNT_POINT" useradd -m -G wheel,storage,power,network -s /bin/bash "$INTERACTIVE_USER"
# Set password
echo "$INTERACTIVE_USER:$USER_PASS" | arch-chroot "$MOUNT_POINT" chpasswd
# Enable sudo for wheel group
sed -i 's/^# %wheel ALL=(ALL:ALL) ALL/%wheel ALL=(ALL:ALL) ALL/' "$MOUNT_POINT/etc/sudoers"
# Set root password
echo "root:$USER_PASS" | arch-chroot "$MOUNT_POINT" chpasswd
ok "User ${INTERACTIVE_USER} created"
}
# ============================================================
# SamiOS CLI tool
# ============================================================
# shellcheck disable=SC2120 # MOUNT_POINT arrives as a global from earlier steps
install_samios_cli() {
log "Installing SamiOS CLI tool..."
# Tolerate being called with no args; default to /mnt as every other
# step in the installer does. shellcheck SC2120 sees no args because
# MOUNT_POINT is a global from earlier steps.
local MOUNT_POINT="${1:-${MOUNT_POINT:-/mnt}}"
cat > "$MOUNT_POINT/usr/local/bin/samios" << 'SAMIOS_CLI'
#!/bin/bash
# SamiOS CLI - installed by samios-installer.sh
# No embedded VERSION literal: walks up to /etc/samios-version at runtime.
set -e
_lookup_version() {
local d
d="$(cd "$(dirname "$0")" && pwd)"
while [ "$d" != "/" ]; do
if [ -f "$d/VERSION" ]; then
head -n1 "$d/VERSION"
return 0
fi
d="$(dirname "$d")"
done
if [ -r /etc/samios-version ]; then
head -n1 /etc/samios-version
return 0
fi
echo "0.0.0-unknown"
}
VERSION="$(_lookup_version)"
unset -f _lookup_version
cmd_help() {
cat << EOF
SamiOS CLI v${VERSION}
Commands:
version Show version
status Show system status
update Update system packages
install <pkg> Install a package
remove <pkg> Remove a package
services List running services
fonts Check fonts and policy
help Show this help
EOF
}
cmd_version() {
echo "SamiOS v${VERSION}"
echo "Kernel: $(uname -r)"
echo "Architecture: $(uname -m)"
}
cmd_status() {
echo "=== SamiOS System Status ==="
echo "Version: ${VERSION}"
echo "Hostname: $(hostname)"
echo "Kernel: $(uname -r)"
echo "Uptime: $(uptime -p)"
echo
echo "=== Disk Usage ==="
df -h / | tail -n 1
echo
echo "=== Memory ==="
free -h | grep "Mem:"
echo
echo "=== Network ==="
ip -br addr show | grep -v "lo" 2>/dev/null
}
cmd_update() { sudo pacman -Syu --noconfirm; }
cmd_install() { [ -z "$1" ] && echo "Usage: samios install <package>" && exit 1; sudo pacman -S --noconfirm "$1"; }
cmd_remove() { [ -z "$1" ] && echo "Usage: samios remove <package>" && exit 1; sudo pacman -R --noconfirm "$1"; }
cmd_services() { systemctl list-units --type=service --state=running; }
cmd_fonts() {
echo "=== Installed Fonts ==="
fc-list | wc -l
echo "fonts installed"
echo
echo "=== Font Policy ==="
echo "Excluded: fonts with '7777' in name (personal branding)"
if fc-list | grep -iq "7777"; then
echo "WARNING: Found 7777 fonts:"
fc-list | grep -i "7777"
else
echo "OK: No forbidden fonts"
fi
}
case "${1:-}" in
version) cmd_version ;;
status) cmd_status ;;
update) cmd_update ;;
install) shift; cmd_install "$@" ;;
remove) shift; cmd_remove "$@" ;;
services) cmd_services ;;
fonts) cmd_fonts ;;
help|--help|-h|"") cmd_help ;;
*) echo "Unknown: $1"; exit 1 ;;
esac
SAMIOS_CLI
chmod +x "$MOUNT_POINT/usr/local/bin/samios"
# Mirror the canonical VERSION file so the installed CLI's walk-up
# lookup resolves /etc/samios-version as a stable, non-relative anchor.
# The heredoc above writes a CLI with NO embedded VERSION literal —
# it walks up at runtime and reads from this file. This is the
# single-source-of-truth invariant: the literal exists ONLY in
# /etc/samios-version on disk, never inside any script.
if [ -n "$_EMIT_VERSION_FILE" ] && [ -f "$_EMIT_VERSION_FILE" ]; then
cp "$_EMIT_VERSION_FILE" "$MOUNT_POINT/etc/samios-version"
else
printf '%s\n' "$VERSION" > "$MOUNT_POINT/etc/samios-version"
fi
chmod 644 "$MOUNT_POINT/etc/samios-version"
# MOTD
cat > "$MOUNT_POINT/etc/motd" << 'MOTD'
___ ___ ___ ___ ___
/\ \ /\__\ /\ \ /\__\ /\ \
/::\ \ /::| | /::\ \ /:/ / /::\ \
/:/\:\ \ /:|:| | /:/\:\ \ /:/ / /:/\:\ \
/:\ \:\ \ /:/|:| |__ /::\~\:\ \ /:/ / ___ /::\~\:\ \
/:/\:\ \:\__\/:/ |:| /\__\ /:/\:\ \:\__\ /:/__/ /\__\ /:/\:\ \:\__\
\/__\:\/:/ /\/ |:|/:/ / \/_|::\/:/ / \:\ \ /:/ / \:\~\:\ \/__/
\::/ / |:/:/ / |:|::/ / \:\ /:/ / \:\ \:\__\
/:/ / |::/ / |:|\/__/ \:\/:/ / \:\ \/__/
/:/ / /:/ / |:| | \::/ / \:\__\
\/__/ \/__/ \|__| \/__/ \/__/
Welcome to SamiOS! Type 'samios help' to get started.
MOTD
# Bashrc welcome
cat > "$MOUNT_POINT/etc/bash.bashrc" << 'BASHRC'
# SamiOS system-wide bashrc
export PS1='\[\033[01;34m\]sami\[\033[01;34m\]@samios\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
alias ls='ls --color=auto'
alias ll='ls -la'
alias la='ls -A'
alias l='ls -CF'
alias update='sudo pacman -Syu'
alias install='sudo pacman -S'
alias remove='sudo pacman -R'
# SamiOS CLI in PATH
export PATH="/usr/local/bin:$PATH"
BASHRC
ok "SamiOS CLI and configs installed"
}
# ============================================================
# Cleanup and finish
# ============================================================
finish_install() {
log "Finalizing installation..."
MOUNT_POINT="/mnt"
# Unmount
umount -R "$MOUNT_POINT"
echo ""
echo "============================================"
echo " SamiOS Installation Complete! "
echo "============================================"
echo ""
echo " Disk: $TARGET_DISK"
echo " User: ${INSTALL_USER:-sami}"
echo " Bootloader: $([ "$UEFI" = true ] && echo "GRUB (UEFI)" || echo "GRUB (BIOS)")"
echo ""
echo " Next steps:"
echo " 1. Reboot: systemctl reboot"
echo " 2. Log in as ${INSTALL_USER:-sami}"
echo " 3. Run: samios status"
echo " 4. Install desktop: samios install plasma"
echo ""
}
# ============================================================
# Main
# ============================================================
main() {
echo ""
echo "============================================"
echo " SamiOS Installer v${VERSION} "
echo "============================================"
echo ""
check_root
check_uefi
detect_disks
select_disk
partition_disk
mount_and_install
configure_system
install_bootloader
create_user
install_samios_cli
finish_install
}
# Parse args
while [ $# -gt 0 ]; do
case "$1" in
--disk) TARGET_DISK="$2"; shift 2 ;;
--user) INSTALL_USER="$2"; shift 2 ;;
--password) INSTALL_PASSWORD="$2"; shift 2 ;;
--help|-h) echo "Usage: samios install [--disk /dev/sdX] [--user username] [--password pass]"; exit 0 ;;
*) shift ;;
esac
done
main