Migrate ALMA to anyhow (#54)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use crate::error::ErrorKind;
|
||||
use anyhow::anyhow;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub struct AurHelper {
|
||||
@@ -7,9 +7,9 @@ pub struct AurHelper {
|
||||
}
|
||||
|
||||
impl FromStr for AurHelper {
|
||||
type Err = ErrorKind;
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
fn from_str(s: &str) -> anyhow::Result<Self> {
|
||||
match s {
|
||||
"yay" => Ok(AurHelper {
|
||||
name: String::from("yay"),
|
||||
@@ -32,7 +32,7 @@ impl FromStr for AurHelper {
|
||||
String::from("--noconfirm"),
|
||||
],
|
||||
}),
|
||||
_ => Err(ErrorKind::AurHelper {}),
|
||||
_ => Err(anyhow!("Error parsing AUR helper string: {}", s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
133
src/error.rs
133
src/error.rs
@@ -1,133 +0,0 @@
|
||||
use failure::{Backtrace, Context, Fail};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
inner: Context<ErrorKind>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
|
||||
pub enum ErrorKind {
|
||||
#[fail(display = "Error quering information about the block device")]
|
||||
DeviceQuery,
|
||||
|
||||
#[fail(display = "Invalid device name")]
|
||||
InvalidDeviceName,
|
||||
|
||||
#[fail(display = "The given block device is neither removable nor a loop device")]
|
||||
DangerousDevice,
|
||||
|
||||
#[fail(display = "Partition {} does not exist", _0)]
|
||||
NoSuchPartition(u8),
|
||||
|
||||
#[fail(display = "Could not find {}", _0)]
|
||||
NoTool(&'static str),
|
||||
|
||||
#[fail(display = "Error creating a temporary directory")]
|
||||
TmpDirError,
|
||||
|
||||
#[fail(display = "Partitioning error")]
|
||||
Partitioning,
|
||||
|
||||
#[fail(display = "Error formatting filesystems")]
|
||||
Formatting,
|
||||
|
||||
#[fail(display = "Error mounting filesystems")]
|
||||
Mounting,
|
||||
|
||||
#[fail(display = "Error creating the boot directory")]
|
||||
CreateBoot,
|
||||
|
||||
#[fail(display = "Pacstrap error")]
|
||||
Pacstrap,
|
||||
|
||||
#[fail(display = "fstab error")]
|
||||
Fstab,
|
||||
|
||||
#[fail(display = "Post installation configuration error")]
|
||||
PostInstallation,
|
||||
|
||||
#[fail(display = "Initramfs error")]
|
||||
Initramfs,
|
||||
|
||||
#[fail(display = "Bootloader error")]
|
||||
Bootloader,
|
||||
|
||||
#[fail(display = "Error caused by the interactive mode")]
|
||||
Interactive,
|
||||
|
||||
#[fail(display = "Failed umounting filesystems")]
|
||||
UmountFailure,
|
||||
|
||||
#[fail(display = "Error setting up an encrypted device")]
|
||||
LuksSetup,
|
||||
|
||||
#[fail(display = "Error opening the encrypted device")]
|
||||
LuksOpen,
|
||||
|
||||
#[fail(display = "Error closing the encrypted device")]
|
||||
LuksClose,
|
||||
|
||||
#[fail(display = "Error detecting whether the root partition is an encrypted device")]
|
||||
LuksDetection,
|
||||
|
||||
#[fail(display = "Error setting the locale")]
|
||||
Locale,
|
||||
|
||||
#[fail(display = "Failed launching Qemu")]
|
||||
Qemu,
|
||||
|
||||
#[fail(display = "Error loading preset \"{}\"", _0)]
|
||||
Preset(String),
|
||||
|
||||
#[fail(display = "Missing environment variables \"{:?}\"", _0)]
|
||||
MissingEnvironmentVariables(Vec<String>),
|
||||
|
||||
#[fail(display = "Error executing preset script")]
|
||||
PresetScript,
|
||||
|
||||
#[fail(display = "Error parsing AUR helper string")]
|
||||
AurHelper,
|
||||
|
||||
#[fail(display = "Error creating the image")]
|
||||
Image,
|
||||
|
||||
#[fail(display = "Error setting up a loop device: {}", _0)]
|
||||
Losetup(String),
|
||||
|
||||
#[fail(display = "Error querying storage devices")]
|
||||
StorageDevicesQuery,
|
||||
|
||||
#[fail(display = "There are no removable devices")]
|
||||
NoRemovableDevices,
|
||||
}
|
||||
|
||||
impl Fail for Error {
|
||||
fn cause(&self) -> Option<&dyn Fail> {
|
||||
self.inner.cause()
|
||||
}
|
||||
|
||||
fn backtrace(&self) -> Option<&Backtrace> {
|
||||
self.inner.backtrace()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
Display::fmt(&self.inner, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorKind> for Error {
|
||||
fn from(kind: ErrorKind) -> Error {
|
||||
Error {
|
||||
inner: Context::new(kind),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Context<ErrorKind>> for Error {
|
||||
fn from(inner: Context<ErrorKind>) -> Error {
|
||||
Error { inner }
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ impl Initcpio {
|
||||
Self { encrypted }
|
||||
}
|
||||
|
||||
pub fn to_config(&self) -> String {
|
||||
pub fn to_config(&self) -> anyhow::Result<String> {
|
||||
let mut output = String::from(
|
||||
"MODULES=()
|
||||
BINARIES=()
|
||||
@@ -18,11 +18,11 @@ HOOKS=(base udev keyboard consolefont block ",
|
||||
);
|
||||
|
||||
if self.encrypted {
|
||||
output.write_str("encrypt ").unwrap();
|
||||
output.write_str("encrypt ")?;
|
||||
}
|
||||
|
||||
output.write_str("filesystems keyboard fsck)\n").unwrap();
|
||||
output.write_str("filesystems keyboard fsck)\n")?;
|
||||
|
||||
output
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
||||
135
src/main.rs
135
src/main.rs
@@ -1,20 +1,17 @@
|
||||
mod args;
|
||||
mod aur;
|
||||
mod constants;
|
||||
mod error;
|
||||
mod initcpio;
|
||||
mod presets;
|
||||
mod process;
|
||||
mod storage;
|
||||
mod tool;
|
||||
|
||||
use anyhow::{anyhow, Context};
|
||||
use args::Command;
|
||||
use byte_unit::Byte;
|
||||
use console::style;
|
||||
use dialoguer::{theme::ColorfulTheme, Select};
|
||||
use error::Error;
|
||||
use error::ErrorKind;
|
||||
use failure::{Fail, ResultExt};
|
||||
use log::{debug, error, info, log_enabled, Level, LevelFilter};
|
||||
use process::CommandExt;
|
||||
use std::collections::HashSet;
|
||||
@@ -22,7 +19,7 @@ use std::fs;
|
||||
use std::io::Write;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{exit, Command as ProcessCommand};
|
||||
use std::process::Command as ProcessCommand;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use storage::EncryptedDevice;
|
||||
@@ -31,7 +28,7 @@ use structopt::StructOpt;
|
||||
use tempfile::tempdir;
|
||||
use tool::Tool;
|
||||
|
||||
fn main() {
|
||||
fn main() -> anyhow::Result<()> {
|
||||
// Get struct of args using structopt
|
||||
let app = args::App::from_args();
|
||||
|
||||
@@ -46,26 +43,13 @@ fn main() {
|
||||
builder.init();
|
||||
|
||||
// Match command from arguments and run relevant code
|
||||
let result = match app.cmd {
|
||||
match app.cmd {
|
||||
Command::Create(command) => create(command),
|
||||
Command::Chroot(command) => tool::chroot(command),
|
||||
Command::Qemu(command) => tool::qemu(command),
|
||||
};
|
||||
}?;
|
||||
|
||||
// Check if command return an Error
|
||||
// Print all causes to stderr if so
|
||||
match result {
|
||||
Ok(()) => {
|
||||
exit(0);
|
||||
}
|
||||
Err(error) => {
|
||||
error!("{}", error);
|
||||
for cause in (&error as &dyn Fail).iter_causes() {
|
||||
error!("Caused by: {}", cause);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove swap entry from fstab and any commented lines
|
||||
@@ -82,7 +66,7 @@ fn fix_fstab(fstab: &str) -> String {
|
||||
}
|
||||
|
||||
/// Creates a file at the path provided, and mounts it to a loop device
|
||||
fn create_image(path: &Path, size: Byte, overwrite: bool) -> Result<LoopDevice, Error> {
|
||||
fn create_image(path: &Path, size: Byte, overwrite: bool) -> anyhow::Result<LoopDevice> {
|
||||
{
|
||||
let mut options = fs::OpenOptions::new();
|
||||
|
||||
@@ -92,21 +76,21 @@ fn create_image(path: &Path, size: Byte, overwrite: bool) -> Result<LoopDevice,
|
||||
} else {
|
||||
options.create_new(true);
|
||||
}
|
||||
let file = options.open(path).context(ErrorKind::Image)?;
|
||||
let file = options.open(path).context("Error creating the image")?;
|
||||
|
||||
file.set_len(size.get_bytes() as u64)
|
||||
.context(ErrorKind::Image)?;
|
||||
.context("Error creating the image")?;
|
||||
}
|
||||
|
||||
LoopDevice::create(path)
|
||||
}
|
||||
|
||||
/// Requests selection of block device (no device was given in the arguments)
|
||||
fn select_block_device(allow_non_removable: bool) -> Result<PathBuf, Error> {
|
||||
fn select_block_device(allow_non_removable: bool) -> anyhow::Result<PathBuf> {
|
||||
let devices = storage::get_storage_devices(allow_non_removable)?;
|
||||
|
||||
if devices.is_empty() {
|
||||
return Err(ErrorKind::NoRemovableDevices.into());
|
||||
return Err(anyhow!("There are no removable devices"));
|
||||
}
|
||||
|
||||
if allow_non_removable {
|
||||
@@ -122,15 +106,14 @@ fn select_block_device(allow_non_removable: bool) -> Result<PathBuf, Error> {
|
||||
.with_prompt("Select a removable device")
|
||||
.default(0)
|
||||
.items(&devices)
|
||||
.interact()
|
||||
.unwrap();
|
||||
.interact()?;
|
||||
|
||||
Ok(PathBuf::from("/dev").join(&devices[selection].name))
|
||||
}
|
||||
|
||||
/// Creates the installation
|
||||
#[allow(clippy::cognitive_complexity)] // TODO: Split steps into functions and remove this
|
||||
fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
fn create(command: args::CreateCommand) -> anyhow::Result<()> {
|
||||
let presets = presets::PresetsCollection::load(&command.presets)?;
|
||||
|
||||
let sgdisk = Tool::find("sgdisk")?;
|
||||
@@ -173,7 +156,7 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
command.allow_non_removable,
|
||||
)?;
|
||||
|
||||
let mount_point = tempdir().context(ErrorKind::TmpDirError)?;
|
||||
let mount_point = tempdir().context("Error creating a temporary directory")?;
|
||||
let disk_path = storage_device.path();
|
||||
|
||||
info!("Partitioning the block device");
|
||||
@@ -191,7 +174,8 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
"--typecode=2:EF02",
|
||||
])
|
||||
.arg(&disk_path)
|
||||
.run(ErrorKind::Partitioning)?;
|
||||
.run()
|
||||
.context("Partitioning error")?;
|
||||
|
||||
thread::sleep(Duration::from_millis(1000));
|
||||
|
||||
@@ -252,23 +236,26 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
.arg(mount_point.path())
|
||||
.args(packages)
|
||||
.args(&command.extra_packages)
|
||||
.run(ErrorKind::Pacstrap)?;
|
||||
.run()
|
||||
.context("Pacstrap error")?;
|
||||
|
||||
let fstab = fix_fstab(
|
||||
&genfstab
|
||||
.execute()
|
||||
.arg("-U")
|
||||
.arg(mount_point.path())
|
||||
.run_text_output(ErrorKind::Fstab)?,
|
||||
.run_text_output()
|
||||
.context("fstab error")?,
|
||||
);
|
||||
debug!("fstab:\n{}", fstab);
|
||||
fs::write(mount_point.path().join("etc/fstab"), fstab).context(ErrorKind::Fstab)?;
|
||||
fs::write(mount_point.path().join("etc/fstab"), fstab).context("fstab error")?;
|
||||
if presets.aur_packages.len() > 0 {
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&["useradd", "-m", "aur"])
|
||||
.run(ErrorKind::PostInstallation)?;
|
||||
.run()
|
||||
.context("Failed to create temporary user to install AUR packages")?;
|
||||
|
||||
arch_chroot
|
||||
.execute()
|
||||
@@ -279,7 +266,8 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
"s/# %wheel ALL=(ALL) NOPASSWD: ALL/aur ALL=(ALL) NOPASSWD: ALL/g",
|
||||
])
|
||||
.arg("/etc/sudoers")
|
||||
.run(ErrorKind::PostInstallation)?;
|
||||
.run()
|
||||
.context("Failed to modify sudoers file for AUR packages")?;
|
||||
|
||||
arch_chroot
|
||||
.execute()
|
||||
@@ -292,7 +280,8 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
&command.aur_helper.name
|
||||
))
|
||||
.arg(format!("/home/aur/{}", &command.aur_helper.name))
|
||||
.run(ErrorKind::PostInstallation)?;
|
||||
.run()
|
||||
.context("Failed to clone AUR helper package")?;
|
||||
|
||||
arch_chroot
|
||||
.execute()
|
||||
@@ -305,7 +294,8 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
&command.aur_helper.name
|
||||
),
|
||||
])
|
||||
.run(ErrorKind::PostInstallation)?;
|
||||
.run()
|
||||
.context("Failed to build AUR helper")?;
|
||||
|
||||
arch_chroot
|
||||
.execute()
|
||||
@@ -314,14 +304,16 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
.args(&command.aur_helper.install_command)
|
||||
.args(presets.aur_packages)
|
||||
.args(&command.aur_packages)
|
||||
.run(ErrorKind::PostInstallation)?;
|
||||
.run()
|
||||
.context("Failed to install AUR packages")?;
|
||||
|
||||
// Clean up aur user:
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&["userdel", "-r", "aur"])
|
||||
.run(ErrorKind::PostInstallation)?;
|
||||
.run()
|
||||
.context("Failed to delete temporary aur user")?;
|
||||
|
||||
arch_chroot
|
||||
.execute()
|
||||
@@ -332,7 +324,8 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
"s/aur ALL=(ALL) NOPASSWD: ALL/# %wheel ALL=(ALL) NOPASSWD: ALL/g",
|
||||
])
|
||||
.arg("/etc/sudoers")
|
||||
.run(ErrorKind::PostInstallation)?;
|
||||
.run()
|
||||
.context("Failed to undo sudoers changes")?;
|
||||
}
|
||||
if !presets.scripts.is_empty() {
|
||||
info!("Running custom scripts");
|
||||
@@ -347,23 +340,23 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
mount_point
|
||||
.path()
|
||||
.join(PathBuf::from("shared_dirs/"))
|
||||
.join(dir.file_name().unwrap()),
|
||||
.join(dir.file_name().expect("Dir had no filename")),
|
||||
)
|
||||
.context(ErrorKind::PresetScript)?;
|
||||
.context("Failed mounting shared directories in preset")?;
|
||||
|
||||
// Bind mount shared directories
|
||||
let target = mount_point
|
||||
.path()
|
||||
.join(PathBuf::from("shared_dirs/"))
|
||||
.join(dir.file_name().unwrap());
|
||||
.join(dir.file_name().expect("Dir had no filename"));
|
||||
bind_mount_stack
|
||||
.bind_mount(dir.clone(), target, None)
|
||||
.context(ErrorKind::Mounting)?;
|
||||
.context("Failed mounting shared directories in preset")?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut script_file =
|
||||
tempfile::NamedTempFile::new_in(mount_point.path()).context(ErrorKind::PresetScript)?;
|
||||
let mut script_file = tempfile::NamedTempFile::new_in(mount_point.path())
|
||||
.context("Failed creating temporary preset script")?;
|
||||
script_file
|
||||
.write_all(script.script_text.as_bytes())
|
||||
.and_then(|_| script_file.as_file_mut().metadata())
|
||||
@@ -372,14 +365,21 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
permissions.set_mode(0o755);
|
||||
fs::set_permissions(script_file.path(), permissions)
|
||||
})
|
||||
.context(ErrorKind::PresetScript)?;
|
||||
.context("Failed creating temporary preset script")?;
|
||||
|
||||
let script_path = script_file.into_temp_path();
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.arg(Path::new("/").join(script_path.file_name().unwrap()))
|
||||
.run(ErrorKind::PostInstallation)?;
|
||||
.arg(
|
||||
Path::new("/").join(
|
||||
script_path
|
||||
.file_name()
|
||||
.expect("Script path had no file name"),
|
||||
),
|
||||
)
|
||||
.run()
|
||||
.context("Failed running preset script")?;
|
||||
}
|
||||
|
||||
info!("Performing post installation tasks");
|
||||
@@ -388,14 +388,15 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&["systemctl", "enable", "NetworkManager"])
|
||||
.run(ErrorKind::PostInstallation)?;
|
||||
.run()
|
||||
.context("Failed to enable NetworkManager")?;
|
||||
|
||||
info!("Configuring journald");
|
||||
fs::write(
|
||||
mount_point.path().join("etc/systemd/journald.conf"),
|
||||
constants::JOURNALD_CONF,
|
||||
)
|
||||
.context(ErrorKind::PostInstallation)?;
|
||||
.context("Failed to write to journald.conf")?;
|
||||
|
||||
info!("Setting locale");
|
||||
fs::OpenOptions::new()
|
||||
@@ -403,53 +404,56 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
.write(true)
|
||||
.open(mount_point.path().join("etc/locale.gen"))
|
||||
.and_then(|mut locale_gen| locale_gen.write_all(b"en_US.UTF-8 UTF-8\n"))
|
||||
.context(ErrorKind::Locale)?;
|
||||
.context("Failed to create locale.gen")?;
|
||||
fs::write(
|
||||
mount_point.path().join("etc/locale.conf"),
|
||||
"LANG=en_US.UTF-8",
|
||||
)
|
||||
.context(ErrorKind::Locale)?;
|
||||
.context("Failed to write to locale.conf")?;
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.arg("locale-gen")
|
||||
.run(ErrorKind::Locale)?;
|
||||
.run()
|
||||
.context("locale-gen failed")?;
|
||||
|
||||
info!("Generating initramfs");
|
||||
fs::write(
|
||||
mount_point.path().join("etc/mkinitcpio.conf"),
|
||||
initcpio::Initcpio::new(encrypted_root.is_some()).to_config(),
|
||||
initcpio::Initcpio::new(encrypted_root.is_some()).to_config()?,
|
||||
)
|
||||
.context(ErrorKind::Initramfs)?;
|
||||
.context("Failed to write to mkinitcpio.conf")?;
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&["mkinitcpio", "-p", "linux"])
|
||||
.run(ErrorKind::Initramfs)?;
|
||||
.run()
|
||||
.context("Failed to run mkinitcpio - do you have the base and linux packages installed?")?;
|
||||
|
||||
if encrypted_root.is_some() {
|
||||
debug!("Setting up GRUB for an encrypted root partition");
|
||||
|
||||
let uuid = blkid
|
||||
.unwrap()
|
||||
.expect("No tool for blkid")
|
||||
.execute()
|
||||
.arg(root_partition_base.path())
|
||||
.args(&["-o", "value", "-s", "UUID"])
|
||||
.run_text_output(ErrorKind::Partitioning)?;
|
||||
.run_text_output()
|
||||
.context("Failed to run blkid")?;
|
||||
let trimmed = uuid.trim();
|
||||
debug!("Root partition UUID: {}", trimmed);
|
||||
|
||||
let mut grub_file = fs::OpenOptions::new()
|
||||
.append(true)
|
||||
.open(mount_point.path().join("etc/default/grub"))
|
||||
.context(ErrorKind::Bootloader)?;
|
||||
.context("Failed to create /etc/default/grub")?;
|
||||
|
||||
write!(
|
||||
&mut grub_file,
|
||||
"GRUB_CMDLINE_LINUX=\"cryptdevice=UUID={}:luks_root\"",
|
||||
trimmed
|
||||
)
|
||||
.context(ErrorKind::Bootloader)?;
|
||||
.context("Failed to write to /etc/default/grub")?;
|
||||
}
|
||||
|
||||
info!("Installing the Bootloader");
|
||||
@@ -458,7 +462,7 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
.arg(mount_point.path())
|
||||
.args(&["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_path.display()))
|
||||
.run(ErrorKind::Bootloader)?;
|
||||
.run().context("Failed to install grub")?;
|
||||
|
||||
debug!(
|
||||
"GRUB configuration: {}",
|
||||
@@ -471,7 +475,8 @@ fn create(command: args::CreateCommand) -> Result<(), Error> {
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.run(ErrorKind::Interactive)?;
|
||||
.run()
|
||||
.context("Failed to enter interactive chroot")?;
|
||||
}
|
||||
|
||||
info!("Unmounting filesystems");
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use failure::ResultExt;
|
||||
use anyhow::{anyhow, Context};
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
@@ -34,11 +33,9 @@ fn visit_dirs(dir: &Path, filevec: &mut Vec<PathBuf>) -> Result<(), io::Error> {
|
||||
}
|
||||
|
||||
impl Preset {
|
||||
fn load(path: &Path) -> Result<Self, Error> {
|
||||
let data = fs::read_to_string(path)
|
||||
.with_context(|_| ErrorKind::Preset(format!("{}", path.display())))?;
|
||||
Ok(toml::from_str(&data)
|
||||
.with_context(|_| ErrorKind::Preset(format!("{}", path.display())))?)
|
||||
fn load(path: &Path) -> anyhow::Result<Self> {
|
||||
let data = fs::read_to_string(path).with_context(|| format!("{}", path.display()))?;
|
||||
Ok(toml::from_str(&data).with_context(|| format!("{}", path.display()))?)
|
||||
}
|
||||
|
||||
fn process(
|
||||
@@ -48,7 +45,7 @@ impl Preset {
|
||||
environment_variables: &mut HashSet<String>,
|
||||
path: &PathBuf,
|
||||
aur_packages: &mut HashSet<String>,
|
||||
) -> Result<(), ErrorKind> {
|
||||
) -> anyhow::Result<()> {
|
||||
if let Some(preset_packages) = &self.packages {
|
||||
packages.extend(preset_packages.clone());
|
||||
}
|
||||
@@ -73,18 +70,18 @@ impl Preset {
|
||||
x.iter()
|
||||
.cloned()
|
||||
.map(|y| {
|
||||
let full_path = path.parent().unwrap().join(&y);
|
||||
let full_path = path.parent().expect("Path has no parent").join(&y);
|
||||
if full_path.is_dir() {
|
||||
Ok(full_path)
|
||||
} else {
|
||||
Err(ErrorKind::Preset(format!(
|
||||
Err(anyhow!(
|
||||
"Preset: {} - shared directory: {} is not directory",
|
||||
path.display(),
|
||||
y.display()
|
||||
)))
|
||||
))
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>, ErrorKind>>()
|
||||
.collect::<anyhow::Result<Vec<_>>>()
|
||||
})
|
||||
.map_or(Ok(None), |r| r.map(Some))?,
|
||||
});
|
||||
@@ -105,7 +102,7 @@ pub struct PresetsCollection {
|
||||
}
|
||||
|
||||
impl PresetsCollection {
|
||||
pub fn load(list: &[PathBuf]) -> Result<Self, Error> {
|
||||
pub fn load(list: &[PathBuf]) -> anyhow::Result<Self> {
|
||||
let mut packages = HashSet::new();
|
||||
let mut aur_packages = HashSet::new();
|
||||
let mut scripts: Vec<Script> = Vec::new();
|
||||
@@ -117,7 +114,7 @@ impl PresetsCollection {
|
||||
// Recursively load directories of preset files
|
||||
let mut dir_paths: Vec<PathBuf> = Vec::new();
|
||||
visit_dirs(&preset, &mut dir_paths)
|
||||
.with_context(|_| ErrorKind::Preset(format!("{}", preset.display())))?;
|
||||
.with_context(|| format!("{}", preset.display()))?;
|
||||
|
||||
// Order not guaranteed so we sort
|
||||
// In the future may want to support numerical sort i.e. 15_... < 100_...
|
||||
@@ -148,7 +145,10 @@ impl PresetsCollection {
|
||||
.collect();
|
||||
|
||||
if !missing_envrionments.is_empty() {
|
||||
return Err(ErrorKind::MissingEnvironmentVariables(missing_envrionments).into());
|
||||
return Err(anyhow!(
|
||||
"Missing environment variables {:?}",
|
||||
missing_envrionments
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
|
||||
@@ -1,51 +1,35 @@
|
||||
use super::error::{Error, ErrorKind};
|
||||
use failure::{Fail, ResultExt};
|
||||
use anyhow::anyhow;
|
||||
use log::error;
|
||||
use std::process::{Command, ExitStatus};
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
|
||||
#[derive(Debug, Fail)]
|
||||
enum ProcessError {
|
||||
#[fail(display = "{}", _0)]
|
||||
BadExitCode(ExitStatus),
|
||||
|
||||
#[fail(display = "Process output isn't valid UTF-8")]
|
||||
InvalidUtf8,
|
||||
}
|
||||
|
||||
pub trait CommandExt {
|
||||
fn run(&mut self, context: ErrorKind) -> Result<(), Error>;
|
||||
fn run_text_output(&mut self, context: ErrorKind) -> Result<String, Error>;
|
||||
fn run(&mut self) -> anyhow::Result<()>;
|
||||
fn run_text_output(&mut self) -> anyhow::Result<String>;
|
||||
}
|
||||
|
||||
impl CommandExt for Command {
|
||||
fn run(&mut self, context: ErrorKind) -> Result<(), Error> {
|
||||
let exit_status = self
|
||||
.spawn()
|
||||
.with_context(|_| context.clone())?
|
||||
.wait()
|
||||
.with_context(|_| context.clone())?;
|
||||
fn run(&mut self) -> anyhow::Result<()> {
|
||||
let exit_status = self.spawn()?.wait()?;
|
||||
|
||||
if !exit_status.success() {
|
||||
Err(ProcessError::BadExitCode(exit_status)).with_context(|_| context.clone())?;
|
||||
Err(anyhow!("Bad exit code: {}", exit_status))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_text_output(&mut self, context: ErrorKind) -> Result<String, Error> {
|
||||
let output = self.output().with_context(|_| context.clone())?;
|
||||
fn run_text_output(&mut self) -> anyhow::Result<String> {
|
||||
let output = self.output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
let error = str::from_utf8(&output.stderr).unwrap_or("[INVALID UTF8]");
|
||||
error!("{}", error);
|
||||
Err(ProcessError::BadExitCode(output.status)).with_context(|_| context.clone())?;
|
||||
Err(anyhow!("Bad exit code: {}", output.status))?;
|
||||
}
|
||||
|
||||
Ok(String::from(
|
||||
str::from_utf8(&output.stdout)
|
||||
.map_err(|_| ProcessError::InvalidUtf8)
|
||||
.with_context(|_| context.clone())?,
|
||||
))
|
||||
Ok(String::from(str::from_utf8(&output.stdout).map_err(
|
||||
|_| anyhow!("Process output is not valid UTF-8"),
|
||||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use super::markers::BlockDevice;
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use crate::process::CommandExt;
|
||||
use crate::tool::Tool;
|
||||
use failure::ResultExt;
|
||||
use anyhow::Context;
|
||||
use log::{debug, warn};
|
||||
use std::fs;
|
||||
use std::io::Read;
|
||||
@@ -21,14 +20,15 @@ pub struct EncryptedDevice<'t, 'o> {
|
||||
}
|
||||
|
||||
impl<'t, 'o> EncryptedDevice<'t, 'o> {
|
||||
pub fn prepare(cryptsetup: &Tool, device: &dyn BlockDevice) -> Result<(), Error> {
|
||||
pub fn prepare(cryptsetup: &Tool, device: &dyn BlockDevice) -> anyhow::Result<()> {
|
||||
debug!("Preparing encrypted device in {}", device.path().display());
|
||||
cryptsetup
|
||||
.execute()
|
||||
.arg("luksFormat")
|
||||
.arg("-q")
|
||||
.arg(device.path())
|
||||
.run(ErrorKind::LuksSetup)?;
|
||||
.run()
|
||||
.context("Error setting up an encrypted device")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -37,7 +37,7 @@ impl<'t, 'o> EncryptedDevice<'t, 'o> {
|
||||
cryptsetup: &'t Tool,
|
||||
device: &'o dyn BlockDevice,
|
||||
name: String,
|
||||
) -> Result<EncryptedDevice<'t, 'o>, Error> {
|
||||
) -> anyhow::Result<EncryptedDevice<'t, 'o>> {
|
||||
debug!(
|
||||
"Opening encrypted device {} as {}",
|
||||
device.path().display(),
|
||||
@@ -48,7 +48,8 @@ impl<'t, 'o> EncryptedDevice<'t, 'o> {
|
||||
.arg("open")
|
||||
.arg(device.path())
|
||||
.arg(&name)
|
||||
.run(ErrorKind::LuksOpen)?;
|
||||
.run()
|
||||
.context("Error opening the encrypted device")?;
|
||||
|
||||
let path = PathBuf::from("/dev/mapper").join(&name);
|
||||
Ok(Self {
|
||||
@@ -59,13 +60,14 @@ impl<'t, 'o> EncryptedDevice<'t, 'o> {
|
||||
})
|
||||
}
|
||||
|
||||
fn _close(&mut self) -> Result<(), Error> {
|
||||
fn _close(&mut self) -> anyhow::Result<()> {
|
||||
debug!("Closing encrypted device {}", self.name);
|
||||
self.cryptsetup
|
||||
.execute()
|
||||
.arg("close")
|
||||
.arg(&self.name)
|
||||
.run(ErrorKind::LuksClose)?;
|
||||
.run()
|
||||
.context("Error closing the encrypted device")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -85,16 +87,16 @@ impl<'t, 'o> BlockDevice for EncryptedDevice<'t, 'o> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_encrypted_device(device: &dyn BlockDevice) -> Result<bool, Error> {
|
||||
pub fn is_encrypted_device(device: &dyn BlockDevice) -> anyhow::Result<bool> {
|
||||
let mut f = fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.write(false)
|
||||
.open(device.path())
|
||||
.context(ErrorKind::LuksDetection)?;
|
||||
.context("Error detecting whether the root partition is an encrypted device")?;
|
||||
|
||||
let mut buffer = [0; 6];
|
||||
f.read_exact(&mut buffer)
|
||||
.context(ErrorKind::LuksDetection)?;
|
||||
.context("Error detecting whether the root partition is an encrypted device")?;
|
||||
|
||||
Ok(buffer == LUKS_MAGIC_1 || buffer == LUKS_MAGIC_2)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use super::markers::BlockDevice;
|
||||
use crate::{
|
||||
error::{Error, ErrorKind},
|
||||
process::CommandExt,
|
||||
tool::Tool,
|
||||
};
|
||||
use crate::{process::CommandExt, tool::Tool};
|
||||
use anyhow::Context;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum FilesystemType {
|
||||
@@ -31,14 +28,14 @@ impl<'a> Filesystem<'a> {
|
||||
block: &'a dyn BlockDevice,
|
||||
fs_type: FilesystemType,
|
||||
mkfs: &Tool,
|
||||
) -> Result<Self, Error> {
|
||||
) -> anyhow::Result<Self> {
|
||||
let mut command = mkfs.execute();
|
||||
match fs_type {
|
||||
FilesystemType::Ext4 => command.arg("-F").arg(block.path()),
|
||||
FilesystemType::Vfat => command.arg("-F32").arg(block.path()),
|
||||
};
|
||||
|
||||
command.run(ErrorKind::Formatting)?;
|
||||
command.run().context("Error formatting filesystem")?;
|
||||
|
||||
Ok(Self { fs_type, block })
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use crate::tool::Tool;
|
||||
use failure::ResultExt;
|
||||
use anyhow::{anyhow, Context};
|
||||
use log::info;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
@@ -11,20 +10,24 @@ pub struct LoopDevice {
|
||||
}
|
||||
|
||||
impl LoopDevice {
|
||||
pub fn create(file: &Path) -> Result<Self, Error> {
|
||||
pub fn create(file: &Path) -> anyhow::Result<Self> {
|
||||
let losetup = Tool::find("losetup")?;
|
||||
let output = losetup
|
||||
.execute()
|
||||
.args(&["--find", "-P", "--show"])
|
||||
.arg(file)
|
||||
.output()
|
||||
.context(ErrorKind::Image)?;
|
||||
.context("Error creating the image")?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(ErrorKind::Losetup(String::from_utf8(output.stderr).unwrap()).into());
|
||||
return Err(anyhow!(String::from_utf8(output.stderr)?));
|
||||
}
|
||||
|
||||
let path = PathBuf::from(String::from_utf8(output.stdout).unwrap().trim());
|
||||
let path = PathBuf::from(
|
||||
String::from_utf8(output.stdout)
|
||||
.context("Output not valid UTF-8")?
|
||||
.trim(),
|
||||
);
|
||||
info!("Mounted {} to {}", file.display(), path.display());
|
||||
|
||||
Ok(LoopDevice { path, losetup })
|
||||
@@ -43,7 +46,7 @@ impl Drop for LoopDevice {
|
||||
.arg("-d")
|
||||
.arg(&self.path)
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.expect("Failed to spawn command to detach loop device")
|
||||
.wait()
|
||||
.ok();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use super::Filesystem;
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use failure::Fail;
|
||||
use anyhow::anyhow;
|
||||
use log::{debug, warn};
|
||||
use nix::mount::{mount, umount, MsFlags};
|
||||
use std::marker::PhantomData;
|
||||
@@ -56,21 +55,25 @@ impl<'a> MountStack<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _umount(&mut self) -> Result<(), Error> {
|
||||
fn _umount(&mut self) -> anyhow::Result<()> {
|
||||
let mut result = Ok(());
|
||||
|
||||
while let Some(target) = self.targets.pop() {
|
||||
debug!("Unmounting {}", target.display());
|
||||
if let Err(e) = umount(&target) {
|
||||
warn!("Unable to umount {}: {}", target.display(), e);
|
||||
result = Err(Error::from(e.context(ErrorKind::UmountFailure)));
|
||||
result = Err(anyhow!(
|
||||
"Failed unmounting filesystem: {}, {}",
|
||||
target.display(),
|
||||
e
|
||||
));
|
||||
};
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn umount(mut self) -> Result<(), Error> {
|
||||
pub fn umount(mut self) -> anyhow::Result<()> {
|
||||
self._umount()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use anyhow::Context;
|
||||
use byte_unit::Byte;
|
||||
use failure::ResultExt;
|
||||
use std::{fmt, fs};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -27,16 +26,16 @@ fn trimmed(source: String) -> String {
|
||||
String::from(source.trim_end())
|
||||
}
|
||||
|
||||
pub fn get_storage_devices(allow_non_removable: bool) -> Result<Vec<Device>, Error> {
|
||||
pub fn get_storage_devices(allow_non_removable: bool) -> anyhow::Result<Vec<Device>> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
for entry in fs::read_dir("/sys/block").context(ErrorKind::StorageDevicesQuery)? {
|
||||
let entry = entry.context(ErrorKind::StorageDevicesQuery)?;
|
||||
for entry in fs::read_dir("/sys/block").context("Error querying storage devices")? {
|
||||
let entry = entry.context("Error querying storage devices")?;
|
||||
|
||||
let removable = allow_non_removable
|
||||
|| fs::read_to_string(entry.path().join("removable"))
|
||||
.map(|v| v == "1\n")
|
||||
.context(ErrorKind::StorageDevicesQuery)?;
|
||||
.context("Error querying storage devices")?;
|
||||
|
||||
if !removable {
|
||||
continue;
|
||||
@@ -44,7 +43,7 @@ pub fn get_storage_devices(allow_non_removable: bool) -> Result<Vec<Device>, Err
|
||||
|
||||
let model = fs::read_to_string(entry.path().join("device/model"))
|
||||
.map(trimmed)
|
||||
.context(ErrorKind::StorageDevicesQuery)?;
|
||||
.context("Error querying storage devices")?;
|
||||
|
||||
if model == "CD-ROM" {
|
||||
continue;
|
||||
@@ -54,19 +53,19 @@ pub fn get_storage_devices(allow_non_removable: bool) -> Result<Vec<Device>, Err
|
||||
name: entry
|
||||
.path()
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.expect("Could not get file name for dir entry /sys/block")
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
model,
|
||||
vendor: fs::read_to_string(entry.path().join("device/vendor"))
|
||||
.map(trimmed)
|
||||
.context(ErrorKind::StorageDevicesQuery)?,
|
||||
.context("Error querying storage devices")?,
|
||||
size: Byte::from_bytes(
|
||||
fs::read_to_string(entry.path().join("size"))
|
||||
.context(ErrorKind::StorageDevicesQuery)?
|
||||
.context("Error querying storage devices")?
|
||||
.trim()
|
||||
.parse::<u128>()
|
||||
.unwrap()
|
||||
.context("Could not parse block size to unsigned integer (u128)")?
|
||||
* 512,
|
||||
),
|
||||
})
|
||||
@@ -81,7 +80,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn sanity() {
|
||||
let devices = get_storage_devices(false).unwrap();
|
||||
let devices = get_storage_devices(false).expect("No devices");
|
||||
println!("{:?}", devices);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::markers::{BlockDevice, Origin};
|
||||
use super::partition::Partition;
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use failure::ResultExt;
|
||||
use anyhow::{anyhow, Context};
|
||||
use log::debug;
|
||||
use std::fs::read_to_string;
|
||||
use std::marker::PhantomData;
|
||||
@@ -15,14 +14,16 @@ pub struct StorageDevice<'a> {
|
||||
}
|
||||
|
||||
impl<'a> StorageDevice<'a> {
|
||||
pub fn from_path(path: &'a Path, allow_non_removable: bool) -> Result<Self, Error> {
|
||||
pub fn from_path(path: &'a Path, allow_non_removable: bool) -> anyhow::Result<Self> {
|
||||
debug!("path: {:?}", path);
|
||||
let path = path.canonicalize().context(ErrorKind::DeviceQuery)?;
|
||||
let path = path
|
||||
.canonicalize()
|
||||
.context("Error querying information about the block device")?;
|
||||
let device_name = path
|
||||
.file_name()
|
||||
.and_then(|s| s.to_str())
|
||||
.map(String::from)
|
||||
.ok_or_else(|| Error::from(ErrorKind::InvalidDeviceName))?;
|
||||
.ok_or_else(|| anyhow!("Invalid device name: {}", path.display()))?;
|
||||
|
||||
debug!("real path: {:?}, device name: {:?}", path, device_name);
|
||||
|
||||
@@ -35,7 +36,10 @@ impl<'a> StorageDevice<'a> {
|
||||
// If we only allow removable/loop devices, and the device is neither removable or a loop
|
||||
// device then throw a DangerousDevice error
|
||||
if !(allow_non_removable || _self.is_removable_device()? || _self.is_loop_device()) {
|
||||
return Err(ErrorKind::DangerousDevice.into());
|
||||
return Err(anyhow!(
|
||||
"The given block device is neither removable nor a loop device: {}",
|
||||
_self.name
|
||||
));
|
||||
}
|
||||
|
||||
Ok(_self)
|
||||
@@ -47,12 +51,13 @@ impl<'a> StorageDevice<'a> {
|
||||
path
|
||||
}
|
||||
|
||||
fn is_removable_device(&self) -> Result<bool, Error> {
|
||||
fn is_removable_device(&self) -> anyhow::Result<bool> {
|
||||
let mut path = self.sys_path();
|
||||
path.push("removable");
|
||||
|
||||
debug!("Reading: {:?}", path);
|
||||
let result = read_to_string(&path).context(ErrorKind::DeviceQuery)?;
|
||||
let result =
|
||||
read_to_string(&path).context("Error querying information about the block device")?;
|
||||
debug!("{:?} -> {}", path, result);
|
||||
|
||||
Ok(result == "1\n")
|
||||
@@ -64,8 +69,15 @@ impl<'a> StorageDevice<'a> {
|
||||
path.exists()
|
||||
}
|
||||
|
||||
pub fn get_partition(&self, index: u8) -> Result<Partition, Error> {
|
||||
let name = if self.name.chars().rev().next().unwrap().is_digit(10) {
|
||||
pub fn get_partition(&self, index: u8) -> anyhow::Result<Partition> {
|
||||
let name = if self
|
||||
.name
|
||||
.chars()
|
||||
.rev()
|
||||
.next()
|
||||
.expect("Storage device name is empty")
|
||||
.is_digit(10)
|
||||
{
|
||||
format!("{}p{}", self.name, index)
|
||||
} else {
|
||||
format!("{}{}", self.name, index)
|
||||
@@ -75,7 +87,7 @@ impl<'a> StorageDevice<'a> {
|
||||
|
||||
debug!("Partition {} for {} is in {:?}", index, self.name, path);
|
||||
if !path.exists() {
|
||||
return Err(ErrorKind::NoSuchPartition(index).into());
|
||||
return Err(anyhow!("Partition {} does not exist", index));
|
||||
}
|
||||
Ok(Partition::new::<Self>(path))
|
||||
}
|
||||
|
||||
@@ -2,19 +2,18 @@ use super::mount;
|
||||
use super::Tool;
|
||||
use crate::args;
|
||||
use crate::constants::{BOOT_PARTITION_INDEX, ROOT_PARTITION_INDEX};
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use crate::process::CommandExt;
|
||||
use crate::storage;
|
||||
use crate::storage::{is_encrypted_device, EncryptedDevice};
|
||||
use crate::storage::{BlockDevice, Filesystem, FilesystemType, LoopDevice};
|
||||
use anyhow::Context;
|
||||
use log::info;
|
||||
|
||||
use failure::ResultExt;
|
||||
use tempfile::tempdir;
|
||||
|
||||
/// Use arch-chroot to chroot to the given device
|
||||
/// Also handles encrypted root partitions (detected by checking for the LUKS magic header)
|
||||
pub fn chroot(command: args::ChrootCommand) -> Result<(), Error> {
|
||||
pub fn chroot(command: args::ChrootCommand) -> anyhow::Result<()> {
|
||||
let arch_chroot = Tool::find("arch-chroot")?;
|
||||
let cryptsetup;
|
||||
|
||||
@@ -26,12 +25,12 @@ pub fn chroot(command: args::ChrootCommand) -> Result<(), Error> {
|
||||
Err(_) => {
|
||||
loop_device = Some(LoopDevice::create(&command.block_device)?);
|
||||
storage::StorageDevice::from_path(
|
||||
loop_device.as_ref().unwrap().path(),
|
||||
loop_device.as_ref().expect("loop device not found").path(),
|
||||
command.allow_non_removable,
|
||||
)?
|
||||
}
|
||||
};
|
||||
let mount_point = tempdir().context(ErrorKind::TmpDirError)?;
|
||||
let mount_point = tempdir().context("Error creating a temporary directory")?;
|
||||
|
||||
let boot_partition = storage_device.get_partition(BOOT_PARTITION_INDEX)?;
|
||||
let boot_filesystem = Filesystem::from_partition(&boot_partition, FilesystemType::Vfat);
|
||||
@@ -40,7 +39,7 @@ pub fn chroot(command: args::ChrootCommand) -> Result<(), Error> {
|
||||
let encrypted_root = if is_encrypted_device(&root_partition_base)? {
|
||||
cryptsetup = Some(Tool::find("cryptsetup")?);
|
||||
Some(EncryptedDevice::open(
|
||||
cryptsetup.as_ref().unwrap(),
|
||||
cryptsetup.as_ref().expect("cryptsetup not found"),
|
||||
&root_partition_base,
|
||||
"alma_root".into(),
|
||||
)?)
|
||||
@@ -61,7 +60,13 @@ pub fn chroot(command: args::ChrootCommand) -> Result<(), Error> {
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&command.command)
|
||||
.run(ErrorKind::Interactive)?;
|
||||
.run()
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Error running command in chroot: {}",
|
||||
command.command.join(" "),
|
||||
)
|
||||
})?;
|
||||
|
||||
info!("Unmounting filesystems");
|
||||
mount_stack.umount()?;
|
||||
|
||||
@@ -6,8 +6,7 @@ pub use chroot::chroot;
|
||||
pub use mount::mount;
|
||||
pub use qemu::qemu;
|
||||
|
||||
use crate::error::*;
|
||||
use failure::ResultExt;
|
||||
use anyhow::anyhow;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use which::which;
|
||||
@@ -18,10 +17,17 @@ pub struct Tool {
|
||||
}
|
||||
|
||||
impl Tool {
|
||||
pub fn find(name: &'static str) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
exec: which(name).context(ErrorKind::NoTool(name))?,
|
||||
})
|
||||
pub fn find(name: &'static str) -> anyhow::Result<Self> {
|
||||
// Note this conversion is only necessary until which releases their new version using
|
||||
// thiserror instead of failure - then we can just use .with_context() on the thiserror
|
||||
// Error
|
||||
// Commit pending release:
|
||||
// BLOCKED: https://github.com/harryfei/which-rs/commit/e6e839c4f6cdf8d3e33ec7eafdd50d34472740ea
|
||||
let which = match which(name) {
|
||||
Ok(x) => Ok(x),
|
||||
Err(_) => Err(anyhow!("Could not find tool: {}", name)),
|
||||
}?;
|
||||
Ok(Self { exec: which })
|
||||
}
|
||||
|
||||
pub fn execute(&self) -> Command {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use crate::storage::{Filesystem, MountStack};
|
||||
use failure::ResultExt;
|
||||
use anyhow::Context;
|
||||
use log::{debug, info};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
@@ -12,7 +11,7 @@ pub fn mount<'a>(
|
||||
mount_path: &Path,
|
||||
boot_filesystem: &'a Filesystem,
|
||||
root_filesystem: &'a Filesystem,
|
||||
) -> Result<MountStack<'a>, Error> {
|
||||
) -> anyhow::Result<MountStack<'a>> {
|
||||
let mut mount_stack = MountStack::new();
|
||||
debug!(
|
||||
"Root partition: {}",
|
||||
@@ -22,16 +21,16 @@ pub fn mount<'a>(
|
||||
info!("Mounting filesystems to {}", mount_path.display());
|
||||
mount_stack
|
||||
.mount(&root_filesystem, mount_path.into(), None)
|
||||
.context(ErrorKind::Mounting)?;
|
||||
.with_context(|| format!("Error mounting filesystem to {}", mount_path.display()))?;
|
||||
|
||||
let boot_point = mount_path.join("boot");
|
||||
if !boot_point.exists() {
|
||||
fs::create_dir(&boot_point).context(ErrorKind::CreateBoot)?;
|
||||
fs::create_dir(&boot_point).context("Error creating the boot directory")?;
|
||||
}
|
||||
|
||||
mount_stack
|
||||
.mount(&boot_filesystem, boot_point, None)
|
||||
.context(ErrorKind::Mounting)?;
|
||||
.context("Error mounting the boot point")?;
|
||||
|
||||
Ok(mount_stack)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
use super::Tool;
|
||||
use crate::args;
|
||||
use crate::error;
|
||||
use anyhow::Context;
|
||||
use log::debug;
|
||||
|
||||
use failure::ResultExt;
|
||||
use std::os::unix::process::CommandExt as UnixCommandExt;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Loads given block device in qemu
|
||||
/// Uses kvm if it is enabled
|
||||
pub fn qemu(command: args::QemuCommand) -> Result<(), error::Error> {
|
||||
pub fn qemu(command: args::QemuCommand) -> anyhow::Result<()> {
|
||||
let qemu = Tool::find("qemu-system-x86_64")?;
|
||||
|
||||
let mut run = qemu.execute();
|
||||
@@ -39,5 +38,5 @@ pub fn qemu(command: args::QemuCommand) -> Result<(), error::Error> {
|
||||
|
||||
let err = run.exec();
|
||||
|
||||
Err(err).context(error::ErrorKind::Qemu)?
|
||||
Err(err).context("Failed launching Qemu")?
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user