refactor
Some checks failed
ci/woodpecker/push/build Pipeline failed

This commit is contained in:
JMARyA 2025-01-04 21:37:49 +01:00
parent bc69d74ac2
commit 30e2db26ca
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
18 changed files with 257 additions and 337 deletions

View file

@ -3,10 +3,10 @@
boot = "/dev/null" boot = "/dev/null"
root = "/dev/null" root = "/dev/null"
[general]
# Use LUKS encryption on root drive # Use LUKS encryption on root drive
encryption = true encryption = "password"
[general]
# Preset # Preset
mode = "Desktop" mode = "Desktop"

View file

@ -58,12 +58,12 @@ pub struct DriveConfig {
pub boot: String, pub boot: String,
/// Root Drive Path /// Root Drive Path
pub root: String, pub root: String,
/// Enable encryption on root
pub encryption: Option<String>,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct GeneralConfig { pub struct GeneralConfig {
/// Enable encryption on root
pub encryption: bool,
/// Presets /// Presets
pub mode: InstallMode, pub mode: InstallMode,
/// System locale /// System locale

View file

@ -1,8 +1,6 @@
use crate::{ use crate::{install::uncomment_tag, is_root, linux::run_command, print_status};
install::{str_vec, uncomment_tag},
is_root, print_status, run_command,
};
/// Build the `kxkbrc` file for the given `layout` and `variant
pub fn build_kxkbrc(layout: &str, variant: Option<&str>) -> String { pub fn build_kxkbrc(layout: &str, variant: Option<&str>) -> String {
let mut res = String::from("[Layout]\nUse=true\n"); let mut res = String::from("[Layout]\nUse=true\n");
res.push_str(&format!("LayoutList={layout}\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() { 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); 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(); std::fs::create_dir_all("./work").unwrap();
let mount_cmd = str_vec(vec![ let mount_cmd = vec!["mount", "-t", "tmpfs", "-o", "size=10G", "tmpfs", "./work"];
"mount", "-t", "tmpfs", "-o", "size=10G", "tmpfs", "./work",
]);
run_command(&mount_cmd, None, false); run_command(&mount_cmd, None, false);
let mkarchiso_cmd = vec![ let mkarchiso_cmd = vec!["mkarchiso", "-v", "-w", "./work", "-o", "./", "./iso"];
"mkarchiso".to_string(),
"-v".to_string(),
"-w".to_string(),
"./work".to_string(),
"-o".to_string(),
"./".to_string(),
"./iso".to_string(),
];
run_command(&mkarchiso_cmd, None, true); 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); run_command(&umount_cmd, None, false);

View file

@ -1,11 +1,6 @@
use crate::run_command; use crate::linux::arch_chroot;
use super::str_vec;
/// Install the bootloader (`systemd-boot`)
pub fn setup_bootloader() { pub fn setup_bootloader() {
run_command( arch_chroot(&["bootctl", "install"], None, false);
&str_vec(vec!["arch-chroot", "/mnt", "bootctl", "install"]),
None,
false,
);
} }

View file

@ -1,61 +1,51 @@
use crate::{config::DriveConfig, run_command}; use crate::{config::DriveConfig, linux::run_command};
use super::str_vec;
// TODO : Add support for using entire block device // 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) // EFI (BOOT)
run_command( run_command(&["mkfs.vfat", "-F", "32", conf.boot.as_str()], None, false);
&str_vec(vec!["mkfs.vfat", "-F", "32", conf.boot.as_str()]),
None,
false,
);
// ROOT // ROOT
if encrypted { if let Some(pass) = &conf.encryption {
run_command( run_command(
&str_vec(vec!["cryptsetup", "luksFormat", conf.root.as_str()]), &["cryptsetup", "luksFormat", conf.root.as_str()],
None, Some(&format!("YES\n{pass}\n{pass}\n")),
true, true,
); );
} else { } 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 // MOUNT
pub fn mount_drives(conf: &DriveConfig, encrypted: bool) { /// Mount the drives at `/mnt`
if encrypted { pub fn mount_drives(conf: &DriveConfig) {
if let Some(pass) = &conf.encryption {
run_command( run_command(
&str_vec(vec!["cryptsetup", "open", conf.root.as_str(), "root"]), &["cryptsetup", "open", conf.root.as_str(), "root"],
None, Some(&format!("{pass}\n")),
true, true,
); );
run_command( run_command(&["mount", "/dev/mapper/root", "/mnt"], None, false);
&str_vec(vec!["mount", "/dev/mapper/root", "/mnt"]),
None,
false,
);
} else { } else {
run_command( run_command(&["mount", conf.root.as_str(), "/mnt"], None, false);
&str_vec(vec!["mount", conf.root.as_str(), "/mnt"]),
None,
false,
);
} }
run_command( run_command(
&str_vec(vec![ &[
"mount", "mount",
"--mkdir", "--mkdir",
conf.boot.as_str(), conf.boot.as_str(),
"/mnt/boot", "/mnt/boot",
"-o", "-o",
"rw,nosuid,nodev,noatime,fmask=0137,dmask=0027", "rw,nosuid,nodev,noatime,fmask=0137,dmask=0027",
]), ],
None, None,
false, false,
); );

View file

@ -1,15 +1,21 @@
// GENFSTAB // 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() { pub fn genfstab() {
print_status("Generating fstab"); 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(); std::fs::write("/mnt/etc/fstab", stdout).unwrap();
} }
/// Set common config values for the system
pub fn first_boot_values(conf: &GeneralConfig) { pub fn first_boot_values(conf: &GeneralConfig) {
// Locale // Locale
print_status(&format!("Setting locale {}", conf.locale)); print_status(&format!("Setting locale {}", conf.locale));
@ -45,27 +51,9 @@ pub fn first_boot_values(conf: &GeneralConfig) {
// LOCALE // LOCALE
print_status("Setting locale"); print_status("Setting locale");
uncomment_first_value_of(&conf.locale, "/mnt/etc/locale.gen"); uncomment_first_value_of(&conf.locale, "/mnt/etc/locale.gen");
run_command( arch_chroot(&["locale-gen"], None, false);
&str_vec(vec!["arch-chroot", "/mnt", "locale-gen"]),
None,
false,
);
run_command( arch_chroot(&["hwclock", "--systohc"], None, false);
&str_vec(vec!["arch-chroot", "/mnt", "hwclock", "--systohc"]),
None,
false,
);
run_command( systemd_service_enable("NetworkManager.service");
&str_vec(vec![
"arch-chroot",
"/mnt",
"systemctl",
"enable",
"NetworkManager.service",
]),
None,
false,
);
} }

View file

@ -1,16 +1,18 @@
// MKINITCPIO + UKI // MKINITCPIO + UKI
use crate::{config::DriveConfig, print_status, run_command}; use crate::{
config::DriveConfig,
use super::str_vec; linux::{arch_chroot, install_file},
print_status,
};
pub fn setup_mkinitcpio(conf: &DriveConfig) { pub fn setup_mkinitcpio(conf: &DriveConfig) {
print_status("Writing /etc/mkinitcpio.d/linux.preset"); print_status("Writing /etc/mkinitcpio.d/linux.preset");
std::fs::write( install_file(
"/mnt/etc/mkinitcpio.d/linux.preset", "/mnt/etc/mkinitcpio.d/linux.preset",
include_str!("../root/mkinitcpio/linux.preset"), include_str!("../root/mkinitcpio/linux.preset"),
) 0o644,
.unwrap(); );
// Set kernel cmdline // Set kernel cmdline
// TODO : Encryption support // TODO : Encryption support
@ -19,14 +21,11 @@ pub fn setup_mkinitcpio(conf: &DriveConfig) {
// TODO : more configs // TODO : more configs
print_status("Writing /etc/mkinitcpio.conf"); print_status("Writing /etc/mkinitcpio.conf");
std::fs::write( install_file(
"/mnt/etc/mkinitcpio.conf", "/mnt/etc/mkinitcpio.conf",
include_str!("../root/mkinitcpio.conf"), include_str!("../root/mkinitcpio.conf"),
) 0o644,
.unwrap();
run_command(
&str_vec(vec!["arch-chroot", "/mnt", "mkinitcpio", "--allpresets"]),
None,
true,
); );
arch_chroot(&["mkinitcpio", "--allpresets"], None, true);
} }

View file

@ -13,6 +13,7 @@ use kernel::setup_mkinitcpio;
use navos::setup_navos; use navos::setup_navos;
use ollama::setup_ollama; use ollama::setup_ollama;
use security::{setup_secure_boot, setup_tpm_unlock}; use security::{setup_secure_boot, setup_tpm_unlock};
use skel::setup_skel;
use ssh::setup_ssh; use ssh::setup_ssh;
use user::setup_users; use user::setup_users;
use yansi::{Color, Paint}; use yansi::{Color, Paint};
@ -25,6 +26,7 @@ pub mod kernel;
pub mod navos; pub mod navos;
pub mod ollama; pub mod ollama;
pub mod security; pub mod security;
pub mod skel;
pub mod ssh; pub mod ssh;
pub mod user; pub mod user;
pub mod zram; pub mod zram;
@ -35,10 +37,6 @@ use crate::{
print_status, print_status,
}; };
pub fn str_vec(v: Vec<&str>) -> Vec<String> {
v.into_iter().map(|x| x.to_string()).collect()
}
pub fn uncomment_first_value_of(value: &str, file: &str) { pub fn uncomment_first_value_of(value: &str, file: &str) {
// read in the file // read in the file
let content = std::fs::read_to_string(file).unwrap(); 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 // uncomment the '#' symbol if there is one
for line in content.lines() { for line in content.lines() {
if line.contains(value) && !found { if line.contains(value) && !found {
new.push_str(&format!("{}\n", line.replace("#", ""))); new.push_str(&format!("{}\n", line.replace('#', "")));
found = true; found = true;
} else { } else {
new.push_str(&format!("{line}\n")); new.push_str(&format!("{line}\n"));
@ -80,8 +78,8 @@ pub fn uncomment_tag(tag: &str, file: &str) {
pub fn install(conf: InstallConfig) { pub fn install(conf: InstallConfig) {
// Drive Setup // Drive Setup
format_drives(&conf.drive, conf.general.encryption); format_drives(&conf.drive);
mount_drives(&conf.drive, conf.general.encryption); mount_drives(&conf.drive);
// Base Install // Base Install
pacstrap(&conf.pkg); pacstrap(&conf.pkg);
@ -89,9 +87,10 @@ pub fn install(conf: InstallConfig) {
// System Setup // System Setup
first_boot_values(&conf.general); first_boot_values(&conf.general);
setup_skel(&conf.general);
setup_users(&conf.user); setup_users(&conf.user);
setup_ssh(&conf.ssh); setup_ssh(conf.ssh);
setup_bootloader(); setup_bootloader();
@ -135,7 +134,7 @@ pub fn install(conf: InstallConfig) {
setup_mkinitcpio(&conf.drive); setup_mkinitcpio(&conf.drive);
setup_secure_boot(); setup_secure_boot();
if conf.general.encryption { if conf.drive.encryption.is_some() {
setup_tpm_unlock(&conf.drive); setup_tpm_unlock(&conf.drive);
} }

View file

@ -1,6 +1,4 @@
use crate::{print_status, run_command}; use crate::{linux::arch_chroot, print_status};
use super::str_vec;
pub fn setup_navos() { pub fn setup_navos() {
// pacman.conf // pacman.conf
@ -15,31 +13,27 @@ pub fn setup_navos() {
) )
.unwrap(); .unwrap();
run_command( arch_chroot(
&str_vec(vec![ &[
"arch-chroot",
"/mnt",
"pacman-key", "pacman-key",
"--add", "--add",
"/usr/share/pacman/keyrings/navos.gpg", "/usr/share/pacman/keyrings/navos.gpg",
]), ],
None, None,
false, false,
); );
run_command( arch_chroot(
&str_vec(vec![ &[
"arch-chroot",
"/mnt",
"pacman-key", "pacman-key",
"--lsign-key", "--lsign-key",
"778D9D7E5B6AC3762BB5541FEE446EC749C4AE00", "778D9D7E5B6AC3762BB5541FEE446EC749C4AE00",
]), ],
None, None,
false, false,
); );
// remote os-release // remove os-release
print_status("Removing os-release"); print_status("Removing os-release");
std::fs::remove_file("/mnt/etc/os-release").unwrap(); std::fs::remove_file("/mnt/etc/os-release").unwrap();
} }

View file

@ -1,7 +1,6 @@
use crate::{config::OllamaConfig, pkg::install_pkgs, run_command}; use crate::{config::OllamaConfig, linux::systemd_service_enable, pkg::install_pkgs};
use super::str_vec;
/// Setup Ollama AI Service
pub fn setup_ollama(conf: &OllamaConfig) { pub fn setup_ollama(conf: &OllamaConfig) {
if conf.gpu { if conf.gpu {
install_pkgs(&["ollama-cuda"]); install_pkgs(&["ollama-cuda"]);
@ -9,17 +8,7 @@ pub fn setup_ollama(conf: &OllamaConfig) {
install_pkgs(&["ollama"]); install_pkgs(&["ollama"]);
} }
run_command( systemd_service_enable("ollama.service");
&str_vec(vec![
"arch-chroot",
"/mnt",
"systemctl",
"enable",
"ollama.service",
]),
None,
false,
);
for model in conf.models.clone().unwrap_or_default() { for model in conf.models.clone().unwrap_or_default() {
// TODO : Pull models // TODO : Pull models

View file

@ -1,137 +1,70 @@
// TPM Unlock // 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) { pub fn setup_tpm_unlock(conf: &DriveConfig) {
install_pkgs(&["tpm2-tools"]); install_pkgs(&["tpm2-tools"]);
// systemd-cryptenroll --tpm2-device=list // systemd-cryptenroll --tpm2-device=list
// Recovery Key // Recovery Key
run_command( let recovery_key = arch_chroot(
&str_vec(vec![ &["systemd-cryptenroll", "--recovery-key", &conf.root],
"arch-chroot", Some(&format!("{}\n", conf.encryption.as_ref().unwrap())),
"/mnt",
"systemd-cryptenroll",
"--recovery-key",
&conf.root,
]),
None,
false, false,
); )
.0;
install_file("/mnt/root/recovery.key", &recovery_key, 0o400);
run_command( arch_chroot(
&str_vec(vec![ &[
"arch-chroot",
"/mnt",
"systemd-cryptenroll", "systemd-cryptenroll",
"--tpm2-device=auto", "--tpm2-device=auto",
&conf.root, &conf.root,
"--tpm2-pcrs=7", "--tpm2-pcrs=7",
]), ],
None, Some(&format!("{}\n", conf.encryption.as_ref().unwrap())),
false, false,
); );
} }
// SECURE BOOT // SECURE BOOT
/// Setup Secure Boot on the system
pub fn setup_secure_boot() { 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::<Vec<&str>>(); let binding = stdout.lines().collect::<Vec<&str>>();
let status = binding.get(1).unwrap(); let status = binding.get(1).unwrap();
if !status.contains("Setup Mode") { if !status.contains("Setup Mode") || !status.contains("Enabled") {
println!("[!] Secure Boot is not in Setup Mode"); println!(
"{}",
"[!] Secure Boot is not in Setup Mode".paint(Color::Red)
);
std::process::exit(1); 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"]); install_pkgs(&["sbctl", "sbsigntools"]);
run_command( arch_chroot(&["sbctl", "create-keys"], None, false);
&vec![
"arch-chroot".into(),
"/mnt".into(),
"sbctl".into(),
"create-keys".into(),
],
None,
false,
);
run_command( arch_chroot(&["sbctl", "enroll-keys", "--microsoft"], None, false);
&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,
);
run_command( sb_sign("/boot/EFI/Linux/arch-linux.efi");
&str_vec(vec![ sb_sign("/boot/EFI/Linux/arch-linux-fallback.efi");
"arch-chroot", sb_sign("/boot/EFI/systemd/systemd-bootx64.efi");
"/mnt", sb_sign("/boot/EFI/Boot/bootx64.efi");
"sbctl",
"sign",
"-s",
"/boot/EFI/Linux/arch-linux-fallback.efi",
]),
None,
false,
);
run_command( arch_chroot(&["sbctl", "verify"], None, false);
&str_vec(vec![ }
"arch-chroot",
"/mnt", pub fn sb_sign(file: &str) {
"sbctl", arch_chroot(&["sbctl", "sign", "-s", file], None, false);
"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,
);
} }

6
src/install/skel.rs Normal file
View file

@ -0,0 +1,6 @@
use crate::config::GeneralConfig;
pub fn setup_skel(conf: &GeneralConfig) {
// TODO : Implement
unimplemented!()
}

View file

@ -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; use std::io::Write;
pub fn setup_ssh(conf: &Option<SSHConfig>) { /// 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<SSHConfig>) {
if let Some(conf) = conf { if let Some(conf) = conf {
install_pkgs(&["openssh"]); install_pkgs(&["openssh"]);
if let Some(sshd_config) = &conf.sshd_config { if let Some(sshd_config) = &conf.sshd_config {
print_status("Writing /etc/ssh/sshd_config"); print_status("Writing /etc/ssh/sshd_config");
let content = std::fs::read_to_string(sshd_config).unwrap(); 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 { for key in &conf.key {
@ -17,7 +20,7 @@ pub fn setup_ssh(conf: &Option<SSHConfig>) {
std::fs::create_dir_all("/root/.ssh").unwrap(); std::fs::create_dir_all("/root/.ssh").unwrap();
"/root/.ssh/authorized_keys".to_string() "/root/.ssh/authorized_keys".to_string()
} else { } 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") format!("/home/{user}/.ssh/authorized_keys")
}; };
@ -27,8 +30,8 @@ pub fn setup_ssh(conf: &Option<SSHConfig>) {
.open(path) .open(path)
.unwrap(); .unwrap();
print_status(&format!("Adding key to authorized_keys for {}", user)); print_status(&format!("Adding key to authorized_keys for {user}"));
writeln!(authorized_keys, "{}", format!("{}\n", key.key)).unwrap(); writeln!(authorized_keys, "{}\n", key.key).unwrap();
} }
} }
} }

View file

@ -1,19 +1,18 @@
use crate::{config::UserConfig, print_status, run_command}; use crate::{
config::UserConfig,
use super::str_vec; linux::{arch_chroot, install_file},
print_status,
};
/// Setup the users of the system
pub fn setup_users(conf: &[UserConfig]) { pub fn setup_users(conf: &[UserConfig]) {
let mut doas_conf = String::new(); let mut doas_conf = String::new();
for user in conf { for user in conf {
run_command( arch_chroot(&["useradd", "-m", &user.name], None, false);
&str_vec(vec!["arch-chroot", "/mnt", "useradd", "-m", &user.name]),
None,
false,
);
run_command( arch_chroot(
&str_vec(vec!["arch-chroot", "/mnt", "passwd", &user.name]), &["passwd", &user.name],
Some(&format!("{}\n{}\n", user.password, user.password)), Some(&format!("{}\n{}\n", user.password, user.password)),
false, 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);
} }

View file

@ -1,24 +1,19 @@
use crate::{pkg::install_pkgs, print_status, run_command}; use crate::{
linux::{install_file, systemd_service_enable},
use super::str_vec; pkg::install_pkgs,
print_status,
};
/// Setup the ZRAM feature
pub fn setup_zram() { pub fn setup_zram() {
install_pkgs(&["zram-generator"]); install_pkgs(&["zram-generator"]);
print_status("Writing /etc/systemd/zram-generator.conf"); print_status("Writing /etc/systemd/zram-generator.conf");
std::fs::write( install_file(
"/mnt/etc/systemd/zram-generator.conf", "/mnt/etc/systemd/zram-generator.conf",
include_str!("../root/zram-generator.conf"), include_str!("../root/zram-generator.conf"),
) 0o644,
.unwrap();
run_command(
&str_vec(vec![
"arch-chroot",
"/mnt",
"systemctl",
"enable",
"systemd-zram-setup@zram0.service",
]),
None,
false,
); );
systemd_service_enable("systemd-zram-setup@zram0.service");
} }

80
src/linux.rs Normal file
View file

@ -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::<Vec<_>>());
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();
}

View file

@ -1,21 +1,18 @@
use std::io::Write; use std::io::Write;
use config::InstallConfig; use config::InstallConfig;
use nix::unistd::{Uid, getuid};
mod args; mod args;
mod config; mod config;
mod create_iso; mod create_iso;
mod install; mod install;
mod linux;
mod pkg; mod pkg;
use create_iso::create_iso; use create_iso::create_iso;
use install::install; use install::install;
use linux::is_root;
use yansi::{Color, Paint}; use yansi::{Color, Paint};
fn is_root() -> bool {
getuid() == Uid::from_raw(0)
}
fn print_status(msg: &str) { fn print_status(msg: &str) {
println!( 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::<Vec<_>>());
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() { fn main() {
println!( println!(
"{}", "{}",
@ -87,7 +38,7 @@ fn main() {
let kb_variant: Option<&str> = let kb_variant: Option<&str> =
iso_args.get_one("kb_variant").map(|x: &String| x.as_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); std::process::exit(0);
} }
Some(("create-tar", _)) => { Some(("create-tar", _)) => {
@ -163,7 +114,7 @@ fn main() {
} }
// Run the // Run the
install(conf) install(conf);
} }
_ => {} _ => {}
} }

View file

@ -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 DESKTOP_PKG: [&str; 3] = ["plasma", "sddm", "navos/navos"];
pub const SERVER_PKG: [&str; 2] = ["tmux", "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]) { 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.push("--noconfirm");
cmd.extend_from_slice(pkg); cmd.extend_from_slice(pkg);
run_command(&str_vec(cmd), None, true); arch_chroot(&cmd, None, true);
} }
// PACSTRAP // PACSTRAP
/// Initial system pacstrap
pub fn pacstrap(conf: &PackageConfig) { pub fn pacstrap(conf: &PackageConfig) {
let mut cmd: Vec<String> = vec![ let mut cmd: Vec<&str> = vec![
"pacstrap".into(), "pacstrap",
"-K".into(), "-K",
"/mnt".into(), "/mnt",
"base".into(), "base",
"linux".into(), "linux",
"linux-firmware".into(), "linux-firmware",
"linux-headers".into(), "linux-headers",
"git".into(), "git",
"networkmanager".into(), "networkmanager",
"nano".into(), "nano",
"doas".into(), "doas",
]; ];
cmd.extend(conf.pkg.clone()); cmd.extend(
&conf
.pkg
.iter()
.map(std::string::String::as_str)
.collect::<Vec<_>>(),
);
run_command(&cmd, None, true); run_command(&cmd, None, true);
} }