mirror of
https://github.com/philmmanjaro/alma.git
synced 2025-07-25 14:39:29 +02:00
190 lines
4.8 KiB
Rust
190 lines
4.8 KiB
Rust
#[macro_use]
|
|
extern crate log;
|
|
extern crate failure;
|
|
extern crate simplelog;
|
|
extern crate structopt;
|
|
extern crate which;
|
|
|
|
mod error;
|
|
mod tool;
|
|
|
|
use error::*;
|
|
use failure::{Fail, ResultExt};
|
|
use simplelog::*;
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
use std::process::{exit, Command};
|
|
use std::thread;
|
|
use std::time::Duration;
|
|
use structopt::StructOpt;
|
|
use tool::Tool;
|
|
|
|
static MKINITCPIO: &'static str = "MODULES=()
|
|
BINARIES=()
|
|
FILES=()
|
|
HOOKS=(base udev block filesystems keyboard fsck)";
|
|
|
|
#[derive(Fail, Debug)]
|
|
#[fail(display = "Process failed")]
|
|
pub struct ProcessFailed;
|
|
|
|
trait CommandExt {
|
|
fn run(&mut self, context: ErrorKind) -> Result<(), Error>;
|
|
}
|
|
|
|
impl CommandExt for Command {
|
|
fn run(&mut self, context: ErrorKind) -> Result<(), Error> {
|
|
let exit_status = self.spawn().context(context)?.wait().context(context)?;
|
|
|
|
if !exit_status.success() {
|
|
return Err(ProcessFailed {}.context(context).into());
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(StructOpt)]
|
|
#[structopt(name = "alma", about = "Arch Linux Mobile Applicance")]
|
|
enum App {
|
|
#[structopt(name = "create", about = "Create a new Arch Linux USB")]
|
|
Create {
|
|
#[structopt(parse(from_os_str))]
|
|
disk: PathBuf,
|
|
},
|
|
}
|
|
|
|
fn create(disk: PathBuf) -> Result<(), Error> {
|
|
let sgdisk = Tool::find("sgdisk")?;
|
|
let sync = Tool::find("sync")?;
|
|
let partprobe = Tool::find("partprobe")?;
|
|
let pacstrap = Tool::find("pacstrap")?;
|
|
let arch_chroot = Tool::find("arch-chroot")?;
|
|
let mount = Tool::find("mount")?;
|
|
let umount = Tool::find("umount")?;
|
|
let mkfat = Tool::find("mkfs.fat")?;
|
|
let mkbtrfs = Tool::find("mkfs.btrfs")?;
|
|
|
|
if !(disk.starts_with("/dev/disk/by-id")
|
|
&& (disk
|
|
.file_name()
|
|
.and_then(|s| s.to_str())
|
|
.filter(|ref f| f.starts_with("usb-"))
|
|
.is_some()))
|
|
{
|
|
return Err(ErrorKind::NotUSB.into());
|
|
}
|
|
|
|
info!("Partitioning the disk");
|
|
sgdisk
|
|
.execute()
|
|
.args(&[
|
|
"-Z",
|
|
"-o",
|
|
"--new=1::+10M",
|
|
"--new=2::+500M",
|
|
"--largest-new=3",
|
|
"--typecode=1:EF02",
|
|
"--typecode=2:EF00",
|
|
]).arg(&disk)
|
|
.run(ErrorKind::Creation)?;
|
|
partprobe.execute().run(ErrorKind::Creation)?;
|
|
|
|
thread::sleep(Duration::from_millis(1000));
|
|
|
|
info!("Formatting filesystems");
|
|
mkfat
|
|
.execute()
|
|
.arg("-F32")
|
|
.arg(format!("{}-part2", disk.display()))
|
|
.run(ErrorKind::Creation)?;
|
|
mkbtrfs
|
|
.execute()
|
|
.arg("-f")
|
|
.arg(format!("{}-part3", disk.display()))
|
|
.run(ErrorKind::Creation)?;
|
|
|
|
info!("Mounting filesystems to /mnt/dok");
|
|
mount
|
|
.execute()
|
|
.arg(format!("{}-part3", disk.display()))
|
|
.arg("/mnt/dok")
|
|
.run(ErrorKind::Creation)?;
|
|
|
|
fs::create_dir("/mnt/dok/boot").context(ErrorKind::Creation)?;
|
|
|
|
mount
|
|
.execute()
|
|
.arg(format!("{}-part2", disk.display()))
|
|
.arg("/mnt/dok/boot")
|
|
.run(ErrorKind::Creation)?;
|
|
|
|
info!("Bootstrapping system");
|
|
pacstrap
|
|
.execute()
|
|
.args(&[
|
|
"-c",
|
|
"/mnt/dok",
|
|
"base",
|
|
"grub",
|
|
"efibootmgr",
|
|
"intel-ucode",
|
|
"networkmanager",
|
|
"btrfs-progs",
|
|
]).run(ErrorKind::Creation)?;
|
|
|
|
arch_chroot
|
|
.execute()
|
|
.args(&["/mnt/dok", "systemctl", "enable", "NetworkManager"])
|
|
.run(ErrorKind::Creation)?;
|
|
|
|
info!("Generating initramfs");
|
|
fs::write("/mnt/dok/etc/mkinitcpio.conf", MKINITCPIO).context(ErrorKind::Creation)?;
|
|
arch_chroot
|
|
.execute()
|
|
.args(&["/mnt/dok", "mkinitcpio", "-p", "linux"])
|
|
.run(ErrorKind::Creation)?;
|
|
|
|
info!("Installing the Bootloader");
|
|
arch_chroot
|
|
.execute()
|
|
.args(&["/mnt/dok", "bash", "-c"])
|
|
.arg(format!("grub-install --target=i386-pc --boot-directory /boot {} && grub-install --target=x86_64-efi --efi-directory /boot --boot-directory /boot --removable && grub-mkconfig -o /boot/grub/grub.cfg", disk.display()))
|
|
.run(ErrorKind::Creation)?;
|
|
|
|
info!("Unmounting filesystems");
|
|
umount
|
|
.execute()
|
|
.args(&["/mnt/dok/boot", "/mnt/dok"])
|
|
.run(ErrorKind::Creation)?;
|
|
|
|
sync.execute().run(ErrorKind::Creation)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn main() {
|
|
let app = App::from_args();
|
|
|
|
CombinedLogger::init(vec![
|
|
TermLogger::new(LevelFilter::Debug, Config::default()).unwrap(),
|
|
]).unwrap();
|
|
|
|
let result = match app {
|
|
App::Create { disk } => create(disk),
|
|
};
|
|
|
|
match result {
|
|
Ok(()) => {
|
|
exit(0);
|
|
}
|
|
Err(error) => {
|
|
error!("{}", error);
|
|
if let Some(cause) = error.cause() {
|
|
error!(" {}", cause);
|
|
}
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|