Add plist use to the CreateFstabEntry action (#221)

This commit is contained in:
Ana Hobden 2023-02-01 10:40:56 -08:00 committed by GitHub
parent fd149eef47
commit 8042ac5131
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 18 additions and 41 deletions

3
Cargo.lock generated
View file

@ -1868,6 +1868,9 @@ name = "uuid"
version = "1.2.2" version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "valuable" name = "valuable"

View file

@ -52,7 +52,7 @@ dyn-clone = { version = "1.0.9", default-features = false }
rand = { version = "0.8.5", default-features = false, features = [ "std", "std_rng" ] } rand = { version = "0.8.5", default-features = false, features = [ "std", "std_rng" ] }
semver = { version = "1.0.14", default-features = false, features = ["serde", "std"] } semver = { version = "1.0.14", default-features = false, features = ["serde", "std"] }
term = { version = "0.7.0", default-features = false } term = { version = "0.7.0", default-features = false }
uuid = "1.2.2" uuid = { version = "1.2.2", features = ["serde"] }
[dev-dependencies] [dev-dependencies]
eyre = { version = "0.6.8", default-features = false, features = [ "track-caller" ] } eyre = { version = "0.6.8", default-features = false, features = [ "track-caller" ] }

View file

@ -6,9 +6,9 @@ use crate::{
execute_command, execute_command,
}; };
use rand::Rng; use rand::Rng;
use serde::Deserialize;
use std::{ use std::{
io::SeekFrom, io::SeekFrom,
os::unix::prelude::PermissionsExt,
path::{Path, PathBuf}, path::{Path, PathBuf},
str::FromStr, str::FromStr,
}; };
@ -82,13 +82,7 @@ impl Action for CreateFstabEntry {
async fn execute(&mut self) -> Result<(), ActionError> { async fn execute(&mut self) -> Result<(), ActionError> {
let Self { apfs_volume_label } = self; let Self { apfs_volume_label } = self;
let fstab_path = Path::new(FSTAB_PATH); let fstab_path = Path::new(FSTAB_PATH);
let uuid = get_uuid_for_label(&apfs_volume_label) let uuid = get_uuid_for_label(&apfs_volume_label).await?;
.await?
.ok_or_else(|| {
ActionError::Custom(Box::new(CreateFstabEntryError::NoVolume(
apfs_volume_label.clone(),
)))
})?;
let fstab_entry = fstab_entry(&uuid, apfs_volume_label); let fstab_entry = fstab_entry(&uuid, apfs_volume_label);
let mut fstab = tokio::fs::OpenOptions::new() let mut fstab = tokio::fs::OpenOptions::new()
@ -133,13 +127,7 @@ impl Action for CreateFstabEntry {
async fn revert(&mut self) -> Result<(), ActionError> { async fn revert(&mut self) -> Result<(), ActionError> {
let Self { apfs_volume_label } = self; let Self { apfs_volume_label } = self;
let fstab_path = Path::new(FSTAB_PATH); let fstab_path = Path::new(FSTAB_PATH);
let uuid = get_uuid_for_label(&apfs_volume_label) let uuid = get_uuid_for_label(&apfs_volume_label).await?;
.await?
.ok_or_else(|| {
ActionError::Custom(Box::new(CreateFstabEntryError::NoVolume(
apfs_volume_label.clone(),
)))
})?;
let fstab_entry = fstab_entry(&uuid, apfs_volume_label); let fstab_entry = fstab_entry(&uuid, apfs_volume_label);
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
@ -177,11 +165,12 @@ impl Action for CreateFstabEntry {
} }
} }
async fn get_uuid_for_label(apfs_volume_label: &str) -> Result<Option<Uuid>, ActionError> { async fn get_uuid_for_label(apfs_volume_label: &str) -> Result<Uuid, ActionError> {
let output = execute_command( let output = execute_command(
Command::new("/usr/sbin/diskutil") Command::new("/usr/sbin/diskutil")
.process_group(0) .process_group(0)
.arg("info") .arg("info")
.arg("-plist")
.arg(apfs_volume_label) .arg(apfs_volume_label)
.stdin(std::process::Stdio::null()) .stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::piped()), .stdout(std::process::Stdio::piped()),
@ -189,27 +178,9 @@ async fn get_uuid_for_label(apfs_volume_label: &str) -> Result<Option<Uuid>, Act
.await .await
.map_err(|e| ActionError::Command(e))?; .map_err(|e| ActionError::Command(e))?;
let stdout = String::from_utf8(output.stdout)?; let parsed: DiskUtilApfsInfoOutput = plist::from_bytes(&output.stdout)?;
let mut found = None; Ok(parsed.volume_uuid)
for line in stdout.lines() {
let prefix = "Volume UUID:";
let trimmed = line.trim();
if let Some(index) = trimmed.find(prefix) {
let maybe_uuid = trimmed[(index + prefix.len())..].trim();
let uuid = Uuid::parse_str(maybe_uuid).map_err(|err| {
ActionError::Custom(Box::new(CreateFstabEntryError::Uuid(
maybe_uuid.to_string(),
err,
)))
})?;
found = Some(uuid);
break;
}
}
Ok(found)
} }
fn fstab_prelude_comment(apfs_volume_label: &str) -> String { fn fstab_prelude_comment(apfs_volume_label: &str) -> String {
@ -228,10 +199,13 @@ fn fstab_entry(uuid: &Uuid, apfs_volume_label: &str) -> String {
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum CreateFstabEntryError { pub enum CreateFstabEntryError {
#[error("UUID error: {0}")]
Uuid(String, #[source] uuid::Error),
#[error("No volume labelled `{0}` present, cannot get UUID to add to /etc/fstab")]
NoVolume(String),
#[error("An `/etc/fstab` entry for the volume labelled `{0}` already exists. If a Nix Store already exists it may need to be deleted with `diskutil apfs deleteVolume \"{0}\") and should be removed from `/etc/fstab`")] #[error("An `/etc/fstab` entry for the volume labelled `{0}` already exists. If a Nix Store already exists it may need to be deleted with `diskutil apfs deleteVolume \"{0}\") and should be removed from `/etc/fstab`")]
EntryExists(String), EntryExists(String),
} }
#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "PascalCase")]
struct DiskUtilApfsInfoOutput {
#[serde(rename = "VolumeUUID")]
volume_uuid: Uuid,
}