Files
2025-11-12 18:34:08 +11:00

329 lines
7.6 KiB
Go

package main
import (
"fmt"
"os"
"os/exec"
"strings"
)
// MiasmaInstaller represents the installer for Miasma OS
type MiasmaInstaller struct {
device string
username string
password string
installHardened bool
installPackages []string
}
// NewMiasmaInstaller creates a new MiasmaInstaller instance
func NewMiasmaInstaller() *MiasmaInstaller {
return &MiasmaInstaller{
installHardened: true,
installPackages: []string{},
}
}
func main() {
installer := NewMiasmaInstaller()
// Get system information
fmt.Println("Miasma OS Installer")
fmt.Println("===================")
// Create temporary config file
if err := installer.createTempConfig(); err != nil {
fmt.Printf("Error creating config: %v\n", err)
os.Exit(1)
}
// Make sure we have root privileges
if err := checkRootPrivileges(); err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
// Get user input
if err := installer.getUserInput(); err != nil {
fmt.Printf("Error getting user input: %v\n", err)
os.Exit(1)
}
// Validate disk selection
if err := installer.validateDisk(); err != nil {
fmt.Printf("Error validating disk: %v\n", err)
os.Exit(1)
}
// Run the actual installation
if err := installer.runInstallation(); err != nil {
fmt.Printf("Installation failed: %v\n", err)
os.Exit(1)
}
fmt.Println("Installation completed successfully!")
}
// detectDisks returns a list of available disks
func detectDisks() ([]string, error) {
cmd := exec.Command("lsblk", "-o", "NAME,SIZE,TYPE,MOUNTPOINT", "-n", "-l")
output, err := cmd.Output()
if err != nil {
return nil, err
}
lines := strings.Split(strings.TrimSpace(string(output)), "\n")
var disks []string
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) >= 3 {
name := fields[0]
deviceType := fields[2]
// Only include whole disks (not partitions)
if deviceType == "disk" {
disks = append(disks, "/dev/"+name)
}
}
}
return disks, nil
}
// checkRootPrivileges checks if the installer is running with root privileges
func checkRootPrivileges() error {
cmd := exec.Command("id", "-u")
output, err := cmd.Output()
if err != nil {
return fmt.Errorf("failed to check privileges: %v", err)
}
outputStr := strings.TrimSpace(string(output))
if outputStr != "0" {
return fmt.Errorf("this installer must be run as root")
}
return nil
}
// getUserInput prompts user for installation parameters
func (m *MiasmaInstaller) getUserInput() error {
// Get disk selection
diskList, err := detectDisks()
if err != nil {
return fmt.Errorf("failed to detect disks: %v", err)
}
if len(diskList) == 0 {
return fmt.Errorf("no disks detected")
}
fmt.Println("Available disks:")
for i, disk := range diskList {
fmt.Printf("%d. %s\n", i+1, disk)
}
fmt.Printf("Select disk (1-%d): ", len(diskList))
var diskChoice int
_, err = fmt.Scanf("%d", &diskChoice)
if err != nil || diskChoice < 1 || diskChoice > len(diskList) {
return fmt.Errorf("invalid disk selection")
}
m.device = diskList[diskChoice-1]
// Get username and password
fmt.Print("Enter username: ")
_, err = fmt.Scanf("%s", &m.username)
if err != nil {
return fmt.Errorf("failed to read username: %v", err)
}
fmt.Print("Enter password: ")
_, err = fmt.Scanf("%s", &m.password)
if err != nil {
return fmt.Errorf("failed to read password: %v", err)
}
fmt.Printf("Installing to %s with user %s\n", m.device, m.username)
return nil
}
// validateDisk validates the selected disk
func (m *MiasmaInstaller) validateDisk() error {
if m.device == "" {
return fmt.Errorf("no device selected")
}
// Simple check: device should start with /dev/
if !strings.HasPrefix(m.device, "/dev/") {
return fmt.Errorf("invalid device path: %s", m.device)
}
return nil
}
// createTempConfig creates a temporary alis configuration for Miasma OS
func (m *MiasmaInstaller) createTempConfig() error {
config := fmt.Sprintf(`# Miasma OS Installer Configuration
# Based on alis configuration format
# init
LOG_TRACE="true"
LOG_FILE="false"
# partition
DEVICE="%s"
DEVICE_TRIM="true"
LVM="false"
LUKS_PASSWORD=""
LUKS_PASSWORD_RETYPE=""
FILE_SYSTEM_TYPE="btrfs"
BTRFS_SUBVOLUMES_MOUNTPOINTS=("root,root,/" "home,home,/home" "var,var,/var" "snapshots,snapshots,/.snapshots")
SWAP_SIZE="4096"
PARTITION_MODE="auto"
PARTITION_MOUNT_POINTS=("1=/boot" "2=/")
GPT_AUTOMOUNT="false"
# install
REFLECTOR="true"
REFLECTOR_COUNTRIES=("United States")
PACMAN_MIRROR=""
PACMAN_PARALLEL_DOWNLOADS="true"
KERNELS="linux-hardened"
KERNELS_COMPRESSION="zstd"
KERNELS_PARAMETERS=""
# aur
AUR_PACKAGE="paru-bin"
# display driver
DISPLAY_DRIVER="auto"
KMS="true"
FASTBOOT="true"
FRAMEBUFFER_COMPRESSION="true"
DISPLAY_DRIVER_DDX="false"
VULKAN="true"
DISPLAY_DRIVER_HARDWARE_VIDEO_ACCELERATION="true"
DISPLAY_DRIVER_HARDWARE_VIDEO_ACCELERATION_INTEL="intel-media-driver"
# config
TIMEZONE="UTC"
LOCALES=("en_US.UTF-8 UTF-8")
LOCALE_CONF=("LANG=en_US.UTF-8")
KEYLAYOUT="us"
KEYMODEL=""
KEYVARIANT=""
KEYOPTIONS=""
KEYMAP="us"
FONT=""
FONT_MAP=""
HOSTNAME="miasma"
ROOT_PASSWORD="%s"
ROOT_PASSWORD_RETYPE="%s"
# user
USER_NAME="%s"
USER_PASSWORD="%s"
USER_PASSWORD_RETYPE="%s"
ADDITIONAL_USERS=()
# systemd-homed
SYSTEMD_HOMED="false"
SYSTEMD_HOMED_STORAGE="directory"
SYSTEMD_HOMED_STORAGE_LUKS_TYPE="ext4"
# mkinitcpio
HOOKS="base udev autodetect microcode modconf kms keyboard keymap consolefont block btrfs filesystems fsck"
MODULES=""
UKI="false"
PLYMOUTH="false"
# bootloader
BOOTLOADER="systemd"
SECURE_BOOT="false"
# shell
CUSTOM_SHELL="zsh"
# desktop
DESKTOP_ENVIRONMENT="cosmic"
DISPLAY_MANAGER="auto"
# packages
PACKAGES_MULTILIB="false"
PACKAGES_INSTALL="true"
PACKAGES_PIPEWIRE="true"
# provision
PROVISION="false"
# misc
FWUPD="false"
VAGRANT="false"
# systemd
SYSTEMD_UNITS="+systemd-timesyncd.service +apparmor.service"
# reboot
REBOOT="false"
`,
m.device, m.password, m.password, m.username, m.password, m.password)
return os.WriteFile("alis.conf", []byte(config), 0644)
}
// runInstallation executes the installation process
func (m *MiasmaInstaller) runInstallation() error {
// Create a temporary file to store the username for post-install script
err := os.WriteFile("/tmp/miasma-username", []byte(m.username), 0644)
if err != nil {
return fmt.Errorf("failed to create username file: %v", err)
}
// Copy our custom packages configuration to the alis directory
cmd := exec.Command("cp", "alis-packages.conf", "alis/alis-packages.conf")
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to copy packages config: %v", err)
}
// Copy post-install script to the chroot environment
cmd = exec.Command("cp", "miasma-post-install.sh", "/mnt/miasma-post-install.sh")
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to copy post-install script: %v", err)
}
// Prepare the alis script command
cmd = exec.Command("./alis.sh")
cmd.Dir = "./alis"
// Set environment variables
cmd.Env = append(os.Environ(),
"WARNING_CONFIRM=false",
"ALIS_CONF_FILE=../alis.conf",
)
// Start the installation
fmt.Println("Starting Arch Linux installation with alis...")
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("installation failed: %v\nOutput: %s", err, string(output))
}
fmt.Printf("Installation completed. Applying Miasma OS configurations...\n")
// Run post-installation script
fmt.Println("Running post-installation setup...")
cmd = exec.Command("bash", "/mnt/miasma-post-install.sh")
output, err = cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("post-installation failed: %v\nOutput: %s", err, string(output))
}
fmt.Printf("Post-installation output: %s\n", output)
return nil
}