mirror of
https://github.com/philmmanjaro/alma.git
synced 2025-07-26 23:19:29 +02:00
Better block device handling (fix #14)
This commit is contained in:
parent
24eee12c58
commit
01969aa524
@ -27,8 +27,7 @@ Dependencies will be handled for you if you install alma from AUR.
|
|||||||
sudo alma create /dev/disk/by-id/usb-Generic_USB_Flash_Disk-0:0
|
sudo alma create /dev/disk/by-id/usb-Generic_USB_Flash_Disk-0:0
|
||||||
```
|
```
|
||||||
|
|
||||||
This will wipe the entire disk and create a bootable installation of Arch Linux. As a precaution,
|
This will wipe the entire disk and create a bootable installation of Arch Linux.
|
||||||
this tool will refuse to work with drive paths which don't start with `/dev/disk/by-id/usb-`.
|
|
||||||
|
|
||||||
After the installation is done you can either boot from it immediately or use `arch-chroot` to
|
After the installation is done you can either boot from it immediately or use `arch-chroot` to
|
||||||
perform further customizations before your first boot.
|
perform further customizations before your first boot.
|
||||||
|
67
src/block.rs
Normal file
67
src/block.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
use super::error::{Error, ErrorKind};
|
||||||
|
use failure::ResultExt;
|
||||||
|
use log::debug;
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BlockDevice {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockDevice {
|
||||||
|
pub fn from_path(path: PathBuf) -> Result<Self, Error> {
|
||||||
|
let real_path = path.canonicalize().context(ErrorKind::DeviceQuery)?;
|
||||||
|
let device_name = real_path
|
||||||
|
.file_name()
|
||||||
|
.and_then(|s| s.to_str())
|
||||||
|
.map(String::from)
|
||||||
|
.ok_or(Error::from(ErrorKind::InvalidDeviceName))?;
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"path: {:?}, real path: {:?}, device name: {:?}",
|
||||||
|
path, real_path, device_name
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Self { name: device_name })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sys_path(&self) -> PathBuf {
|
||||||
|
let mut path = PathBuf::from("/sys/block");
|
||||||
|
path.push(self.name.clone());
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removable(&self) -> Result<bool, Error> {
|
||||||
|
let mut path = self.sys_path();
|
||||||
|
path.push("removable");
|
||||||
|
|
||||||
|
debug!("Reading: {:?}", path);
|
||||||
|
let result = read_to_string(&path).context(ErrorKind::DeviceQuery)?;
|
||||||
|
debug!("{:?} -> {}", path, result);
|
||||||
|
|
||||||
|
Ok(result == "1\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device_path(&self) -> PathBuf {
|
||||||
|
let mut path = PathBuf::from("/dev");
|
||||||
|
path.push(self.name.clone());
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn partition_device_path(&self, index: u8) -> Result<PathBuf, Error> {
|
||||||
|
let name = if self.name.chars().rev().next().unwrap().is_digit(10) {
|
||||||
|
format!("{}p{}", self.name, index)
|
||||||
|
} else {
|
||||||
|
format!("{}{}", self.name, index)
|
||||||
|
};
|
||||||
|
let mut path = PathBuf::from("/dev");
|
||||||
|
path.push(name);
|
||||||
|
|
||||||
|
debug!("Partition {} for {} is in {:?}", index, self.name, path);
|
||||||
|
if !path.exists() {
|
||||||
|
return Err(ErrorKind::NoSuchPartition(index).into());
|
||||||
|
}
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
}
|
15
src/error.rs
15
src/error.rs
@ -8,10 +8,17 @@ pub struct Error {
|
|||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
|
||||||
pub enum ErrorKind {
|
pub enum ErrorKind {
|
||||||
#[fail(
|
#[fail(display = "Error quering information about the block device")]
|
||||||
display = "Provided Path does not point to a USB device. Make sure you specify a file matching /dev/disk/by-id/usb-*"
|
DeviceQuery,
|
||||||
)]
|
|
||||||
NotUSB,
|
#[fail(display = "Invalid device name")]
|
||||||
|
InvalidDeviceName,
|
||||||
|
|
||||||
|
#[fail(display = "The given block device is not removable")]
|
||||||
|
NotRemovableDevice,
|
||||||
|
|
||||||
|
#[fail(display = "Partition {} does not exist", _0)]
|
||||||
|
NoSuchPartition(u8),
|
||||||
|
|
||||||
#[fail(display = "Could not find {}", _0)]
|
#[fail(display = "Could not find {}", _0)]
|
||||||
NoTool(&'static str),
|
NoTool(&'static str),
|
||||||
|
74
src/main.rs
74
src/main.rs
@ -1,6 +1,5 @@
|
|||||||
#[macro_use]
|
|
||||||
extern crate log;
|
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
|
extern crate log;
|
||||||
extern crate nix;
|
extern crate nix;
|
||||||
extern crate simplelog;
|
extern crate simplelog;
|
||||||
extern crate structopt;
|
extern crate structopt;
|
||||||
@ -8,6 +7,7 @@ extern crate tempfile;
|
|||||||
extern crate which;
|
extern crate which;
|
||||||
use nix::sys::signal;
|
use nix::sys::signal;
|
||||||
|
|
||||||
|
mod block;
|
||||||
mod error;
|
mod error;
|
||||||
mod mountstack;
|
mod mountstack;
|
||||||
mod process;
|
mod process;
|
||||||
@ -15,6 +15,7 @@ mod tool;
|
|||||||
|
|
||||||
use error::*;
|
use error::*;
|
||||||
use failure::{Fail, ResultExt};
|
use failure::{Fail, ResultExt};
|
||||||
|
use log::{debug, error, info, warn};
|
||||||
use mountstack::{Filesystem, MountStack};
|
use mountstack::{Filesystem, MountStack};
|
||||||
use process::CommandExt;
|
use process::CommandExt;
|
||||||
use simplelog::*;
|
use simplelog::*;
|
||||||
@ -70,7 +71,7 @@ struct ChrootCommand {
|
|||||||
disk: PathBuf,
|
disk: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create(command: &CreateCommand) -> Result<(), Error> {
|
fn create(command: CreateCommand) -> Result<(), Error> {
|
||||||
let sgdisk = Tool::find("sgdisk")?;
|
let sgdisk = Tool::find("sgdisk")?;
|
||||||
let pacstrap = Tool::find("pacstrap")?;
|
let pacstrap = Tool::find("pacstrap")?;
|
||||||
let arch_chroot = Tool::find("arch-chroot")?;
|
let arch_chroot = Tool::find("arch-chroot")?;
|
||||||
@ -78,22 +79,20 @@ fn create(command: &CreateCommand) -> Result<(), Error> {
|
|||||||
let mkfat = Tool::find("mkfs.fat")?;
|
let mkfat = Tool::find("mkfs.fat")?;
|
||||||
let mkbtrfs = Tool::find("mkfs.btrfs")?;
|
let mkbtrfs = Tool::find("mkfs.btrfs")?;
|
||||||
|
|
||||||
if !(command.disk.starts_with("/dev/disk/by-id")
|
let disk = block::BlockDevice::from_path(command.disk)?;
|
||||||
&& (command
|
|
||||||
.disk
|
if !disk.removable()? {
|
||||||
.file_name()
|
Err(ErrorKind::NotRemovableDevice)?;
|
||||||
.and_then(|s| s.to_str())
|
|
||||||
.filter(|ref f| f.starts_with("usb-"))
|
|
||||||
.is_some()))
|
|
||||||
{
|
|
||||||
Err(ErrorKind::NotUSB)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mount_point = tempdir().context(ErrorKind::TmpDirError)?;
|
let mount_point = tempdir().context(ErrorKind::TmpDirError)?;
|
||||||
let boot_point = mount_point.path().join("boot");
|
let boot_point = mount_point.path().join("boot");
|
||||||
let mut mount_stack = MountStack::new();
|
let mut mount_stack = MountStack::new();
|
||||||
|
let disk_path = disk.device_path();
|
||||||
|
|
||||||
info!("Partitioning the disk");
|
info!("Partitioning the disk");
|
||||||
|
debug!("{:?}", disk_path);
|
||||||
|
|
||||||
sgdisk
|
sgdisk
|
||||||
.execute()
|
.execute()
|
||||||
.args(&[
|
.args(&[
|
||||||
@ -104,27 +103,30 @@ fn create(command: &CreateCommand) -> Result<(), Error> {
|
|||||||
"--largest-new=3",
|
"--largest-new=3",
|
||||||
"--typecode=1:EF02",
|
"--typecode=1:EF02",
|
||||||
"--typecode=2:EF00",
|
"--typecode=2:EF00",
|
||||||
]).arg(&command.disk)
|
]).arg(&disk_path)
|
||||||
.run(ErrorKind::Partitioning)?;
|
.run(ErrorKind::Partitioning)?;
|
||||||
|
|
||||||
thread::sleep(Duration::from_millis(1000));
|
thread::sleep(Duration::from_millis(1000));
|
||||||
|
|
||||||
info!("Formatting filesystems");
|
info!("Formatting filesystems");
|
||||||
|
let boot_partition = disk.partition_device_path(2)?;
|
||||||
mkfat
|
mkfat
|
||||||
.execute()
|
.execute()
|
||||||
.arg("-F32")
|
.arg("-F32")
|
||||||
.arg(format!("{}-part2", command.disk.display()))
|
.arg(&boot_partition)
|
||||||
.run(ErrorKind::Formatting)?;
|
.run(ErrorKind::Formatting)?;
|
||||||
|
|
||||||
|
let root_partition = disk.partition_device_path(3)?;
|
||||||
mkbtrfs
|
mkbtrfs
|
||||||
.execute()
|
.execute()
|
||||||
.arg("-f")
|
.arg("-f")
|
||||||
.arg(format!("{}-part3", command.disk.display()))
|
.arg(&root_partition)
|
||||||
.run(ErrorKind::Formatting)?;
|
.run(ErrorKind::Formatting)?;
|
||||||
|
|
||||||
info!("Mounting filesystems to {}", mount_point.path().display());
|
info!("Mounting filesystems to {}", mount_point.path().display());
|
||||||
mount_stack
|
mount_stack
|
||||||
.mount(
|
.mount(
|
||||||
&PathBuf::from(format!("{}-part3", command.disk.display())),
|
&PathBuf::from(&root_partition),
|
||||||
&mount_point.path(),
|
&mount_point.path(),
|
||||||
Filesystem::Btrfs,
|
Filesystem::Btrfs,
|
||||||
Some("compress=lzo"),
|
Some("compress=lzo"),
|
||||||
@ -133,12 +135,8 @@ fn create(command: &CreateCommand) -> Result<(), Error> {
|
|||||||
fs::create_dir(&boot_point).context(ErrorKind::CreateBoot)?;
|
fs::create_dir(&boot_point).context(ErrorKind::CreateBoot)?;
|
||||||
|
|
||||||
mount_stack
|
mount_stack
|
||||||
.mount(
|
.mount(&boot_partition, &boot_point, Filesystem::Vfat, None)
|
||||||
&PathBuf::from(format!("{}-part2", command.disk.display())),
|
.context(ErrorKind::Mounting)?;
|
||||||
&boot_point,
|
|
||||||
Filesystem::Vfat,
|
|
||||||
None,
|
|
||||||
).context(ErrorKind::Mounting)?;
|
|
||||||
|
|
||||||
info!("Bootstrapping system");
|
info!("Bootstrapping system");
|
||||||
pacstrap
|
pacstrap
|
||||||
@ -191,7 +189,7 @@ fn create(command: &CreateCommand) -> Result<(), Error> {
|
|||||||
.execute()
|
.execute()
|
||||||
.arg(mount_point.path())
|
.arg(mount_point.path())
|
||||||
.args(&["bash", "-c"])
|
.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", command.disk.display()))
|
.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(ErrorKind::Bootloader)?;
|
||||||
|
|
||||||
if command.interactive {
|
if command.interactive {
|
||||||
@ -206,18 +204,12 @@ fn create(command: &CreateCommand) -> Result<(), Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chroot(command: &ChrootCommand) -> Result<(), Error> {
|
fn chroot(command: ChrootCommand) -> Result<(), Error> {
|
||||||
let arch_chroot = Tool::find("arch-chroot")?;
|
let arch_chroot = Tool::find("arch-chroot")?;
|
||||||
|
let disk = block::BlockDevice::from_path(command.disk)?;
|
||||||
|
|
||||||
if !(command.disk.starts_with("/dev/disk/by-id")
|
if !disk.removable()? {
|
||||||
&& (command
|
Err(ErrorKind::NotRemovableDevice)?;
|
||||||
.disk
|
|
||||||
.file_name()
|
|
||||||
.and_then(|s| s.to_str())
|
|
||||||
.filter(|ref f| f.starts_with("usb-"))
|
|
||||||
.is_some()))
|
|
||||||
{
|
|
||||||
Err(ErrorKind::NotUSB)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mount_point = tempdir().context(ErrorKind::TmpDirError)?;
|
let mount_point = tempdir().context(ErrorKind::TmpDirError)?;
|
||||||
@ -225,21 +217,19 @@ fn chroot(command: &ChrootCommand) -> Result<(), Error> {
|
|||||||
let mut mount_stack = MountStack::new();
|
let mut mount_stack = MountStack::new();
|
||||||
|
|
||||||
info!("Mounting filesystems to {}", mount_point.path().display());
|
info!("Mounting filesystems to {}", mount_point.path().display());
|
||||||
|
let root_partition = disk.partition_device_path(3)?;
|
||||||
mount_stack
|
mount_stack
|
||||||
.mount(
|
.mount(
|
||||||
&PathBuf::from(format!("{}-part3", command.disk.display())),
|
&root_partition,
|
||||||
&mount_point.path(),
|
&mount_point.path(),
|
||||||
Filesystem::Btrfs,
|
Filesystem::Btrfs,
|
||||||
Some("compress=lzo"),
|
Some("compress=lzo"),
|
||||||
).context(ErrorKind::Mounting)?;
|
).context(ErrorKind::Mounting)?;
|
||||||
|
|
||||||
|
let boot_partition = disk.partition_device_path(2)?;
|
||||||
mount_stack
|
mount_stack
|
||||||
.mount(
|
.mount(&boot_partition, &boot_point, Filesystem::Vfat, None)
|
||||||
&PathBuf::from(format!("{}-part2", command.disk.display())),
|
.context(ErrorKind::Mounting)?;
|
||||||
&boot_point,
|
|
||||||
Filesystem::Vfat,
|
|
||||||
None,
|
|
||||||
).context(ErrorKind::Mounting)?;
|
|
||||||
|
|
||||||
arch_chroot
|
arch_chroot
|
||||||
.execute()
|
.execute()
|
||||||
@ -273,8 +263,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let result = match app {
|
let result = match app {
|
||||||
App::Create(command) => create(&command),
|
App::Create(command) => create(command),
|
||||||
App::Chroot(command) => chroot(&command),
|
App::Chroot(command) => chroot(command),
|
||||||
};
|
};
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use log::{debug, warn};
|
||||||
use nix;
|
use nix;
|
||||||
use nix::mount::{mount, umount, MsFlags};
|
use nix::mount::{mount, umount, MsFlags};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::error::*;
|
use super::error::*;
|
||||||
use failure::{Fail, ResultExt};
|
use failure::{Fail, ResultExt};
|
||||||
|
use log::error;
|
||||||
use std::process::{Command, ExitStatus};
|
use std::process::{Command, ExitStatus};
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user