From 30e2db26cac463dab8b4e7cb1193d797f82672a5 Mon Sep 17 00:00:00 2001 From: JMARyA Date: Sat, 4 Jan 2025 21:37:49 +0100 Subject: [PATCH] refactor --- installs/testinstall.toml | 4 +- src/config.rs | 4 +- src/create_iso.rs | 24 ++----- src/install/boot.rs | 11 +-- src/install/drives.rs | 48 ++++++------- src/install/first_boot.rs | 36 ++++------ src/install/kernel.rs | 25 ++++--- src/install/mod.rs | 17 +++-- src/install/navos.rs | 22 +++--- src/install/ollama.rs | 17 +---- src/install/security.rs | 137 ++++++++++---------------------------- src/install/skel.rs | 6 ++ src/install/ssh.rs | 15 +++-- src/install/user.rs | 21 +++--- src/install/zram.rs | 27 +++----- src/linux.rs | 80 ++++++++++++++++++++++ src/main.rs | 57 ++-------------- src/pkg.rs | 43 +++++++----- 18 files changed, 257 insertions(+), 337 deletions(-) create mode 100644 src/install/skel.rs create mode 100644 src/linux.rs diff --git a/installs/testinstall.toml b/installs/testinstall.toml index fb996b5..ca5b5dd 100644 --- a/installs/testinstall.toml +++ b/installs/testinstall.toml @@ -3,10 +3,10 @@ boot = "/dev/null" root = "/dev/null" -[general] # Use LUKS encryption on root drive -encryption = true +encryption = "password" +[general] # Preset mode = "Desktop" diff --git a/src/config.rs b/src/config.rs index 335bfcd..d31b3b5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -58,12 +58,12 @@ pub struct DriveConfig { pub boot: String, /// Root Drive Path pub root: String, + /// Enable encryption on root + pub encryption: Option, } #[derive(Debug, Deserialize)] pub struct GeneralConfig { - /// Enable encryption on root - pub encryption: bool, /// Presets pub mode: InstallMode, /// System locale diff --git a/src/create_iso.rs b/src/create_iso.rs index 4e00431..3bdbd4b 100644 --- a/src/create_iso.rs +++ b/src/create_iso.rs @@ -1,8 +1,6 @@ -use crate::{ - install::{str_vec, uncomment_tag}, - is_root, print_status, run_command, -}; +use crate::{install::uncomment_tag, is_root, linux::run_command, print_status}; +/// Build the `kxkbrc` file for the given `layout` and `variant pub fn build_kxkbrc(layout: &str, variant: Option<&str>) -> String { let mut res = String::from("[Layout]\nUse=true\n"); res.push_str(&format!("LayoutList={layout}\n")); @@ -20,7 +18,7 @@ pub fn create_iso(without_gui: bool, kb_layout: &str, kb_variant: Option<&str>) } if !std::fs::exists("./iso").unwrap() { - let cmd = str_vec(vec!["git", "clone", "https://git.hydrar.de/navos/iso"]); + let cmd = vec!["git", "clone", "https://git.hydrar.de/navos/iso"]; run_command(&cmd, None, false); } @@ -41,25 +39,15 @@ pub fn create_iso(without_gui: bool, kb_layout: &str, kb_variant: Option<&str>) std::fs::create_dir_all("./work").unwrap(); - let mount_cmd = str_vec(vec![ - "mount", "-t", "tmpfs", "-o", "size=10G", "tmpfs", "./work", - ]); + let mount_cmd = vec!["mount", "-t", "tmpfs", "-o", "size=10G", "tmpfs", "./work"]; run_command(&mount_cmd, None, false); - let mkarchiso_cmd = vec![ - "mkarchiso".to_string(), - "-v".to_string(), - "-w".to_string(), - "./work".to_string(), - "-o".to_string(), - "./".to_string(), - "./iso".to_string(), - ]; + let mkarchiso_cmd = vec!["mkarchiso", "-v", "-w", "./work", "-o", "./", "./iso"]; run_command(&mkarchiso_cmd, None, true); - let umount_cmd = str_vec(vec!["umount", "-r", "./work"]); + let umount_cmd = vec!["umount", "-r", "./work"]; run_command(&umount_cmd, None, false); diff --git a/src/install/boot.rs b/src/install/boot.rs index b726b66..8c086ad 100644 --- a/src/install/boot.rs +++ b/src/install/boot.rs @@ -1,11 +1,6 @@ -use crate::run_command; - -use super::str_vec; +use crate::linux::arch_chroot; +/// Install the bootloader (`systemd-boot`) pub fn setup_bootloader() { - run_command( - &str_vec(vec!["arch-chroot", "/mnt", "bootctl", "install"]), - None, - false, - ); + arch_chroot(&["bootctl", "install"], None, false); } diff --git a/src/install/drives.rs b/src/install/drives.rs index c9413be..b5c3086 100644 --- a/src/install/drives.rs +++ b/src/install/drives.rs @@ -1,61 +1,51 @@ -use crate::{config::DriveConfig, run_command}; - -use super::str_vec; +use crate::{config::DriveConfig, linux::run_command}; // TODO : Add support for using entire block device -pub fn format_drives(conf: &DriveConfig, encrypted: bool) { +/// Format the drives with the given config +pub fn format_drives(conf: &DriveConfig) { + // TODO : Safety checks !!! + // EFI (BOOT) - run_command( - &str_vec(vec!["mkfs.vfat", "-F", "32", conf.boot.as_str()]), - None, - false, - ); + run_command(&["mkfs.vfat", "-F", "32", conf.boot.as_str()], None, false); // ROOT - if encrypted { + if let Some(pass) = &conf.encryption { run_command( - &str_vec(vec!["cryptsetup", "luksFormat", conf.root.as_str()]), - None, + &["cryptsetup", "luksFormat", conf.root.as_str()], + Some(&format!("YES\n{pass}\n{pass}\n")), true, ); } else { - run_command(&str_vec(vec!["mkfs.ext4", conf.root.as_str()]), None, false); + run_command(&["mkfs.ext4", conf.root.as_str()], None, false); } } // MOUNT -pub fn mount_drives(conf: &DriveConfig, encrypted: bool) { - if encrypted { +/// Mount the drives at `/mnt` +pub fn mount_drives(conf: &DriveConfig) { + if let Some(pass) = &conf.encryption { run_command( - &str_vec(vec!["cryptsetup", "open", conf.root.as_str(), "root"]), - None, + &["cryptsetup", "open", conf.root.as_str(), "root"], + Some(&format!("{pass}\n")), true, ); - run_command( - &str_vec(vec!["mount", "/dev/mapper/root", "/mnt"]), - None, - false, - ); + run_command(&["mount", "/dev/mapper/root", "/mnt"], None, false); } else { - run_command( - &str_vec(vec!["mount", conf.root.as_str(), "/mnt"]), - None, - false, - ); + run_command(&["mount", conf.root.as_str(), "/mnt"], None, false); } run_command( - &str_vec(vec![ + &[ "mount", "--mkdir", conf.boot.as_str(), "/mnt/boot", "-o", "rw,nosuid,nodev,noatime,fmask=0137,dmask=0027", - ]), + ], None, false, ); diff --git a/src/install/first_boot.rs b/src/install/first_boot.rs index 4acc1d3..f2e30e2 100644 --- a/src/install/first_boot.rs +++ b/src/install/first_boot.rs @@ -1,15 +1,21 @@ // GENFSTAB -use crate::{config::GeneralConfig, print_status, run_command}; +use crate::{ + config::GeneralConfig, + linux::{arch_chroot, run_command, systemd_service_enable}, + print_status, +}; -use super::{str_vec, uncomment_first_value_of}; +use super::uncomment_first_value_of; +/// Generate the `/etc/fstab` file pub fn genfstab() { print_status("Generating fstab"); - let (stdout, _) = run_command(&str_vec(vec!["genfstab", "-U", "/mnt"]), None, false); + let (stdout, _) = run_command(&["genfstab", "-U", "/mnt"], None, false); std::fs::write("/mnt/etc/fstab", stdout).unwrap(); } +/// Set common config values for the system pub fn first_boot_values(conf: &GeneralConfig) { // Locale print_status(&format!("Setting locale {}", conf.locale)); @@ -45,27 +51,9 @@ pub fn first_boot_values(conf: &GeneralConfig) { // LOCALE print_status("Setting locale"); uncomment_first_value_of(&conf.locale, "/mnt/etc/locale.gen"); - run_command( - &str_vec(vec!["arch-chroot", "/mnt", "locale-gen"]), - None, - false, - ); + arch_chroot(&["locale-gen"], None, false); - run_command( - &str_vec(vec!["arch-chroot", "/mnt", "hwclock", "--systohc"]), - None, - false, - ); + arch_chroot(&["hwclock", "--systohc"], None, false); - run_command( - &str_vec(vec![ - "arch-chroot", - "/mnt", - "systemctl", - "enable", - "NetworkManager.service", - ]), - None, - false, - ); + systemd_service_enable("NetworkManager.service"); } diff --git a/src/install/kernel.rs b/src/install/kernel.rs index bec10e7..afe37ce 100644 --- a/src/install/kernel.rs +++ b/src/install/kernel.rs @@ -1,16 +1,18 @@ // MKINITCPIO + UKI -use crate::{config::DriveConfig, print_status, run_command}; - -use super::str_vec; +use crate::{ + config::DriveConfig, + linux::{arch_chroot, install_file}, + print_status, +}; pub fn setup_mkinitcpio(conf: &DriveConfig) { print_status("Writing /etc/mkinitcpio.d/linux.preset"); - std::fs::write( + install_file( "/mnt/etc/mkinitcpio.d/linux.preset", include_str!("../root/mkinitcpio/linux.preset"), - ) - .unwrap(); + 0o644, + ); // Set kernel cmdline // TODO : Encryption support @@ -19,14 +21,11 @@ pub fn setup_mkinitcpio(conf: &DriveConfig) { // TODO : more configs print_status("Writing /etc/mkinitcpio.conf"); - std::fs::write( + install_file( "/mnt/etc/mkinitcpio.conf", include_str!("../root/mkinitcpio.conf"), - ) - .unwrap(); - run_command( - &str_vec(vec!["arch-chroot", "/mnt", "mkinitcpio", "--allpresets"]), - None, - true, + 0o644, ); + + arch_chroot(&["mkinitcpio", "--allpresets"], None, true); } diff --git a/src/install/mod.rs b/src/install/mod.rs index 36af1e5..e9f0fc6 100644 --- a/src/install/mod.rs +++ b/src/install/mod.rs @@ -13,6 +13,7 @@ use kernel::setup_mkinitcpio; use navos::setup_navos; use ollama::setup_ollama; use security::{setup_secure_boot, setup_tpm_unlock}; +use skel::setup_skel; use ssh::setup_ssh; use user::setup_users; use yansi::{Color, Paint}; @@ -25,6 +26,7 @@ pub mod kernel; pub mod navos; pub mod ollama; pub mod security; +pub mod skel; pub mod ssh; pub mod user; pub mod zram; @@ -35,10 +37,6 @@ use crate::{ print_status, }; -pub fn str_vec(v: Vec<&str>) -> Vec { - v.into_iter().map(|x| x.to_string()).collect() -} - pub fn uncomment_first_value_of(value: &str, file: &str) { // read in the file let content = std::fs::read_to_string(file).unwrap(); @@ -49,7 +47,7 @@ pub fn uncomment_first_value_of(value: &str, file: &str) { // uncomment the '#' symbol if there is one for line in content.lines() { if line.contains(value) && !found { - new.push_str(&format!("{}\n", line.replace("#", ""))); + new.push_str(&format!("{}\n", line.replace('#', ""))); found = true; } else { new.push_str(&format!("{line}\n")); @@ -80,8 +78,8 @@ pub fn uncomment_tag(tag: &str, file: &str) { pub fn install(conf: InstallConfig) { // Drive Setup - format_drives(&conf.drive, conf.general.encryption); - mount_drives(&conf.drive, conf.general.encryption); + format_drives(&conf.drive); + mount_drives(&conf.drive); // Base Install pacstrap(&conf.pkg); @@ -89,9 +87,10 @@ pub fn install(conf: InstallConfig) { // System Setup first_boot_values(&conf.general); + setup_skel(&conf.general); setup_users(&conf.user); - setup_ssh(&conf.ssh); + setup_ssh(conf.ssh); setup_bootloader(); @@ -135,7 +134,7 @@ pub fn install(conf: InstallConfig) { setup_mkinitcpio(&conf.drive); setup_secure_boot(); - if conf.general.encryption { + if conf.drive.encryption.is_some() { setup_tpm_unlock(&conf.drive); } diff --git a/src/install/navos.rs b/src/install/navos.rs index 2ea0b10..478fc0b 100644 --- a/src/install/navos.rs +++ b/src/install/navos.rs @@ -1,6 +1,4 @@ -use crate::{print_status, run_command}; - -use super::str_vec; +use crate::{linux::arch_chroot, print_status}; pub fn setup_navos() { // pacman.conf @@ -15,31 +13,27 @@ pub fn setup_navos() { ) .unwrap(); - run_command( - &str_vec(vec![ - "arch-chroot", - "/mnt", + arch_chroot( + &[ "pacman-key", "--add", "/usr/share/pacman/keyrings/navos.gpg", - ]), + ], None, false, ); - run_command( - &str_vec(vec![ - "arch-chroot", - "/mnt", + arch_chroot( + &[ "pacman-key", "--lsign-key", "778D9D7E5B6AC3762BB5541FEE446EC749C4AE00", - ]), + ], None, false, ); - // remote os-release + // remove os-release print_status("Removing os-release"); std::fs::remove_file("/mnt/etc/os-release").unwrap(); } diff --git a/src/install/ollama.rs b/src/install/ollama.rs index 75c79bc..1729105 100644 --- a/src/install/ollama.rs +++ b/src/install/ollama.rs @@ -1,7 +1,6 @@ -use crate::{config::OllamaConfig, pkg::install_pkgs, run_command}; - -use super::str_vec; +use crate::{config::OllamaConfig, linux::systemd_service_enable, pkg::install_pkgs}; +/// Setup Ollama AI Service pub fn setup_ollama(conf: &OllamaConfig) { if conf.gpu { install_pkgs(&["ollama-cuda"]); @@ -9,17 +8,7 @@ pub fn setup_ollama(conf: &OllamaConfig) { install_pkgs(&["ollama"]); } - run_command( - &str_vec(vec![ - "arch-chroot", - "/mnt", - "systemctl", - "enable", - "ollama.service", - ]), - None, - false, - ); + systemd_service_enable("ollama.service"); for model in conf.models.clone().unwrap_or_default() { // TODO : Pull models diff --git a/src/install/security.rs b/src/install/security.rs index f6a3386..2f4d140 100644 --- a/src/install/security.rs +++ b/src/install/security.rs @@ -1,137 +1,70 @@ // TPM Unlock -use crate::{config::DriveConfig, pkg::install_pkgs, run_command}; +use yansi::{Color, Paint}; -use super::str_vec; +use crate::{ + config::DriveConfig, + linux::{arch_chroot, install_file, run_command}, + pkg::install_pkgs, +}; +/// Setup TPM Unlock and a recovery key for the root drive pub fn setup_tpm_unlock(conf: &DriveConfig) { install_pkgs(&["tpm2-tools"]); // systemd-cryptenroll --tpm2-device=list // Recovery Key - run_command( - &str_vec(vec![ - "arch-chroot", - "/mnt", - "systemd-cryptenroll", - "--recovery-key", - &conf.root, - ]), - None, + let recovery_key = arch_chroot( + &["systemd-cryptenroll", "--recovery-key", &conf.root], + Some(&format!("{}\n", conf.encryption.as_ref().unwrap())), false, - ); + ) + .0; + install_file("/mnt/root/recovery.key", &recovery_key, 0o400); - run_command( - &str_vec(vec![ - "arch-chroot", - "/mnt", + arch_chroot( + &[ "systemd-cryptenroll", "--tpm2-device=auto", &conf.root, "--tpm2-pcrs=7", - ]), - None, + ], + Some(&format!("{}\n", conf.encryption.as_ref().unwrap())), false, ); } // SECURE BOOT +/// Setup Secure Boot on the system pub fn setup_secure_boot() { - let (stdout, _) = run_command(&str_vec(vec!["sbctl", "status"]), None, false); + let (stdout, _) = run_command(&["sbctl", "status"], None, false); let binding = stdout.lines().collect::>(); let status = binding.get(1).unwrap(); - if !status.contains("Setup Mode") { - println!("[!] Secure Boot is not in Setup Mode"); + if !status.contains("Setup Mode") || !status.contains("Enabled") { + println!( + "{}", + "[!] Secure Boot is not in Setup Mode".paint(Color::Red) + ); std::process::exit(1); - } else { - if !status.contains("Enabled") { - println!("[!] Secure Boot is not in Setup Mode"); - std::process::exit(1); - } } install_pkgs(&["sbctl", "sbsigntools"]); - run_command( - &vec![ - "arch-chroot".into(), - "/mnt".into(), - "sbctl".into(), - "create-keys".into(), - ], - None, - false, - ); + arch_chroot(&["sbctl", "create-keys"], None, false); - run_command( - &str_vec(vec![ - "arch-chroot", - "/mnt", - "sbctl", - "enroll-keys", - "--microsoft", - ]), - None, - false, - ); - run_command( - &str_vec(vec![ - "arch-chroot", - "/mnt", - "sbctl", - "sign", - "-s", - "/boot/EFI/Linux/arch-linux.efi", - ]), - None, - false, - ); + arch_chroot(&["sbctl", "enroll-keys", "--microsoft"], None, false); - run_command( - &str_vec(vec![ - "arch-chroot", - "/mnt", - "sbctl", - "sign", - "-s", - "/boot/EFI/Linux/arch-linux-fallback.efi", - ]), - None, - false, - ); + sb_sign("/boot/EFI/Linux/arch-linux.efi"); + sb_sign("/boot/EFI/Linux/arch-linux-fallback.efi"); + sb_sign("/boot/EFI/systemd/systemd-bootx64.efi"); + sb_sign("/boot/EFI/Boot/bootx64.efi"); - run_command( - &str_vec(vec![ - "arch-chroot", - "/mnt", - "sbctl", - "sign", - "-s", - "/boot/EFI/systemd/systemd-bootx64.efi", - ]), - None, - false, - ); - - run_command( - &str_vec(vec![ - "arch-chroot", - "/mnt", - "sbctl", - "sign", - "-s", - "/boot/EFI/Boot/bootx64.efi", - ]), - None, - false, - ); - - run_command( - &str_vec(vec!["arch-chroot", "/mnt", "sbctl", "verify"]), - None, - false, - ); + arch_chroot(&["sbctl", "verify"], None, false); +} + +pub fn sb_sign(file: &str) { + arch_chroot(&["sbctl", "sign", "-s", file], None, false); } diff --git a/src/install/skel.rs b/src/install/skel.rs new file mode 100644 index 0000000..6cb3214 --- /dev/null +++ b/src/install/skel.rs @@ -0,0 +1,6 @@ +use crate::config::GeneralConfig; + +pub fn setup_skel(conf: &GeneralConfig) { + // TODO : Implement + unimplemented!() +} diff --git a/src/install/ssh.rs b/src/install/ssh.rs index 56dad2a..01f3b89 100644 --- a/src/install/ssh.rs +++ b/src/install/ssh.rs @@ -1,14 +1,17 @@ -use crate::{config::SSHConfig, pkg::install_pkgs, print_status}; +use crate::{config::SSHConfig, linux::install_file, pkg::install_pkgs, print_status}; use std::io::Write; -pub fn setup_ssh(conf: &Option) { +/// Setup SSH on the system +/// +/// This should be done after `setup_users()` to ensure that the users directories exist. +pub fn setup_ssh(conf: Option) { if let Some(conf) = conf { install_pkgs(&["openssh"]); if let Some(sshd_config) = &conf.sshd_config { print_status("Writing /etc/ssh/sshd_config"); let content = std::fs::read_to_string(sshd_config).unwrap(); - std::fs::write("/mnt/etc/ssh/sshd_config", content).unwrap(); + install_file("/mnt/etc/ssh/sshd_config", &content, 0o644); } for key in &conf.key { @@ -17,7 +20,7 @@ pub fn setup_ssh(conf: &Option) { std::fs::create_dir_all("/root/.ssh").unwrap(); "/root/.ssh/authorized_keys".to_string() } else { - std::fs::create_dir_all(&format!("/home/{user}/.ssh")).unwrap(); + std::fs::create_dir_all(format!("/home/{user}/.ssh")).unwrap(); format!("/home/{user}/.ssh/authorized_keys") }; @@ -27,8 +30,8 @@ pub fn setup_ssh(conf: &Option) { .open(path) .unwrap(); - print_status(&format!("Adding key to authorized_keys for {}", user)); - writeln!(authorized_keys, "{}", format!("{}\n", key.key)).unwrap(); + print_status(&format!("Adding key to authorized_keys for {user}")); + writeln!(authorized_keys, "{}\n", key.key).unwrap(); } } } diff --git a/src/install/user.rs b/src/install/user.rs index db87e16..0152dd9 100644 --- a/src/install/user.rs +++ b/src/install/user.rs @@ -1,19 +1,18 @@ -use crate::{config::UserConfig, print_status, run_command}; - -use super::str_vec; +use crate::{ + config::UserConfig, + linux::{arch_chroot, install_file}, + print_status, +}; +/// Setup the users of the system pub fn setup_users(conf: &[UserConfig]) { let mut doas_conf = String::new(); for user in conf { - run_command( - &str_vec(vec!["arch-chroot", "/mnt", "useradd", "-m", &user.name]), - None, - false, - ); + arch_chroot(&["useradd", "-m", &user.name], None, false); - run_command( - &str_vec(vec!["arch-chroot", "/mnt", "passwd", &user.name]), + arch_chroot( + &["passwd", &user.name], Some(&format!("{}\n{}\n", user.password, user.password)), false, ); @@ -24,5 +23,5 @@ pub fn setup_users(conf: &[UserConfig]) { } } - std::fs::write("/mnt/etc/doas.conf", doas_conf).unwrap(); + install_file("/mnt/etc/doas.conf", &doas_conf, 0o644); } diff --git a/src/install/zram.rs b/src/install/zram.rs index 543efaa..cc8b762 100644 --- a/src/install/zram.rs +++ b/src/install/zram.rs @@ -1,24 +1,19 @@ -use crate::{pkg::install_pkgs, print_status, run_command}; - -use super::str_vec; +use crate::{ + linux::{install_file, systemd_service_enable}, + pkg::install_pkgs, + print_status, +}; +/// Setup the ZRAM feature pub fn setup_zram() { install_pkgs(&["zram-generator"]); + print_status("Writing /etc/systemd/zram-generator.conf"); - std::fs::write( + install_file( "/mnt/etc/systemd/zram-generator.conf", include_str!("../root/zram-generator.conf"), - ) - .unwrap(); - run_command( - &str_vec(vec![ - "arch-chroot", - "/mnt", - "systemctl", - "enable", - "systemd-zram-setup@zram0.service", - ]), - None, - false, + 0o644, ); + + systemd_service_enable("systemd-zram-setup@zram0.service"); } diff --git a/src/linux.rs b/src/linux.rs new file mode 100644 index 0000000..d6fd2fc --- /dev/null +++ b/src/linux.rs @@ -0,0 +1,80 @@ +use nix::{unistd::Uid, unistd::getuid}; +use std::{io::Write, os::unix::fs::PermissionsExt}; + +use crate::print_status; + +pub fn is_root() -> bool { + getuid() == Uid::from_raw(0) +} + +pub fn run_command(cmd: &[&str], input: Option<&str>, inherit: bool) -> (String, String) { + print_status(&cmd.join(" ")); + + let mut cmd_setup = std::process::Command::new(cmd[0]); + let mut cmd_setup = cmd_setup.args(cmd.iter().skip(1).collect::>()); + + if inherit { + assert!(input.is_none()); + cmd_setup = cmd_setup + .stdout(std::process::Stdio::inherit()) + .stdin(std::process::Stdio::inherit()); + } else { + cmd_setup = cmd_setup.stdout(std::process::Stdio::piped()); + } + + if input.is_some() { + cmd_setup = cmd_setup.stdin(std::process::Stdio::piped()); + } + + let mut child = cmd_setup.spawn().unwrap(); + + if let Some(input) = input { + let stdin = child.stdin.as_mut().unwrap(); + stdin.write_all(input.as_bytes()).unwrap(); + stdin.flush().unwrap(); + } + + let status = child.wait_with_output().unwrap(); + assert!(status.status.success()); + + let output = String::from_utf8(status.stdout).unwrap(); + let stderr = String::from_utf8(status.stderr).unwrap(); + + if !stderr.trim().is_empty() && !inherit { + eprintln!("{stderr}"); + } + + if !inherit { + println!("{output}"); + } + + (output, stderr) +} + +/// Runs a command in the chroot environment at `/mnt` +pub fn arch_chroot(cmd: &[&str], input: Option<&str>, inherit: bool) -> (String, String) { + let mut chroot_cmd = vec!["arch-chroot", "/mnt"]; + chroot_cmd.extend_from_slice(cmd); + run_command(&chroot_cmd, input, inherit) +} + +/// Enable a systemd `.service` in the chroot environment at `/mnt` +pub fn systemd_service_enable(unit: &str) { + arch_chroot(&["systemctl", "enable", unit], None, false); +} + +/// Installs a file at `path` with `content` and `permissions` +pub fn install_file(path: &str, content: &str, permissions: u32) { + let mut file = std::fs::OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + + file.write_all(content.as_bytes()).unwrap(); + + let permissions = std::fs::Permissions::from_mode(permissions); + print_status(&format!("Wrote file {path} [{permissions:#?}]")); + std::fs::set_permissions(path, permissions).unwrap(); +} diff --git a/src/main.rs b/src/main.rs index fa74d44..4f85aed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,18 @@ use std::io::Write; use config::InstallConfig; -use nix::unistd::{Uid, getuid}; mod args; mod config; mod create_iso; mod install; +mod linux; mod pkg; use create_iso::create_iso; use install::install; +use linux::is_root; use yansi::{Color, Paint}; -fn is_root() -> bool { - getuid() == Uid::from_raw(0) -} - fn print_status(msg: &str) { println!( "{} {}", @@ -24,52 +21,6 @@ fn print_status(msg: &str) { ); } -fn run_command(cmd: &[String], input: Option<&str>, inherit: bool) -> (String, String) { - print_status(&cmd.join(" ")); - - let mut cmd_setup = std::process::Command::new(cmd[0].clone()); - let mut cmd_setup = cmd_setup.args(cmd.into_iter().skip(1).collect::>()); - - if inherit { - assert!(input.is_none()); - cmd_setup = cmd_setup - .stdout(std::process::Stdio::inherit()) - .stdin(std::process::Stdio::inherit()); - } else { - cmd_setup = cmd_setup.stdout(std::process::Stdio::piped()); - } - - if input.is_some() { - cmd_setup = cmd_setup.stdin(std::process::Stdio::piped()); - } - - let mut child = cmd_setup.spawn().unwrap(); - - if let Some(input) = input { - let stdin = child.stdin.as_mut().unwrap(); - stdin.write_all(input.as_bytes()).unwrap(); - stdin.flush().unwrap(); - } - - let status = child.wait_with_output().unwrap(); - assert!(status.status.success()); - - let output = String::from_utf8(status.stdout).unwrap(); - let stderr = String::from_utf8(status.stderr).unwrap(); - - if !stderr.trim().is_empty() { - if !inherit { - eprintln!("{}", stderr); - } - } - - if !inherit { - println!("{}", output); - } - - (output, stderr) -} - fn main() { println!( "{}", @@ -87,7 +38,7 @@ fn main() { let kb_variant: Option<&str> = iso_args.get_one("kb_variant").map(|x: &String| x.as_str()); - create_iso(without_gui, &kb_layout, kb_variant); + create_iso(without_gui, kb_layout, kb_variant); std::process::exit(0); } Some(("create-tar", _)) => { @@ -163,7 +114,7 @@ fn main() { } // Run the - install(conf) + install(conf); } _ => {} } diff --git a/src/pkg.rs b/src/pkg.rs index 24b3721..6ee5e8e 100644 --- a/src/pkg.rs +++ b/src/pkg.rs @@ -1,36 +1,47 @@ -use crate::{config::PackageConfig, install::str_vec, run_command}; +use crate::{ + config::PackageConfig, + linux::{arch_chroot, run_command}, +}; pub const DESKTOP_PKG: [&str; 3] = ["plasma", "sddm", "navos/navos"]; pub const SERVER_PKG: [&str; 2] = ["tmux", "navos/navos"]; +/// Install packages to the chroot environment at `/mnt` pub fn install_pkgs(pkg: &[&str]) { - let mut cmd = vec!["arch-chroot", "/mnt", "pacman", "-Syu"]; + let mut cmd = vec!["pacman", "-Syu"]; cmd.push("--noconfirm"); cmd.extend_from_slice(pkg); - run_command(&str_vec(cmd), None, true); + arch_chroot(&cmd, None, true); } // PACSTRAP +/// Initial system pacstrap pub fn pacstrap(conf: &PackageConfig) { - let mut cmd: Vec = vec![ - "pacstrap".into(), - "-K".into(), - "/mnt".into(), - "base".into(), - "linux".into(), - "linux-firmware".into(), - "linux-headers".into(), - "git".into(), - "networkmanager".into(), - "nano".into(), - "doas".into(), + let mut cmd: Vec<&str> = vec![ + "pacstrap", + "-K", + "/mnt", + "base", + "linux", + "linux-firmware", + "linux-headers", + "git", + "networkmanager", + "nano", + "doas", ]; - cmd.extend(conf.pkg.clone()); + cmd.extend( + &conf + .pkg + .iter() + .map(std::string::String::as_str) + .collect::>(), + ); run_command(&cmd, None, true); }