forked from lix-project/lix-installer
Verify the apfs volume doesn't already exist before trying to create it (#217)
* Verify the apfs volume doesn't already exist before trying to create it * Use plist instead of raw parsing * Remove an unwrap
This commit is contained in:
parent
6b3a84002e
commit
fd149eef47
5 changed files with 44 additions and 5 deletions
|
@ -5,6 +5,7 @@ use tracing::{span, Span};
|
||||||
|
|
||||||
use crate::action::{ActionError, StatefulAction};
|
use crate::action::{ActionError, StatefulAction};
|
||||||
use crate::execute_command;
|
use crate::execute_command;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::action::{Action, ActionDescription};
|
use crate::action::{Action, ActionDescription};
|
||||||
|
|
||||||
|
@ -22,6 +23,22 @@ impl CreateApfsVolume {
|
||||||
name: String,
|
name: String,
|
||||||
case_sensitive: bool,
|
case_sensitive: bool,
|
||||||
) -> Result<StatefulAction<Self>, ActionError> {
|
) -> Result<StatefulAction<Self>, ActionError> {
|
||||||
|
let output =
|
||||||
|
execute_command(Command::new("/usr/sbin/diskutil").args(["apfs", "list", "-plist"]))
|
||||||
|
.await
|
||||||
|
.map_err(ActionError::Command)?;
|
||||||
|
|
||||||
|
let parsed: DiskUtilApfsListOutput = plist::from_bytes(&output.stdout)?;
|
||||||
|
for container in parsed.containers {
|
||||||
|
for volume in container.volumes {
|
||||||
|
if volume.name == name {
|
||||||
|
return Err(ActionError::Custom(Box::new(
|
||||||
|
CreateApfsVolumeError::ExistingVolume(name),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
disk: disk.as_ref().to_path_buf(),
|
disk: disk.as_ref().to_path_buf(),
|
||||||
name,
|
name,
|
||||||
|
@ -120,7 +137,25 @@ impl Action for CreateApfsVolume {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum CreateVolumeError {
|
pub enum CreateApfsVolumeError {
|
||||||
#[error("Failed to execute command")]
|
#[error("Existing volume called `{0}` found in `diskutil apfs list`, delete it with `diskutil apfs deleteVolume \"{0}\"`")]
|
||||||
Command(#[source] std::io::Error),
|
ExistingVolume(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
struct DiskUtilApfsListOutput {
|
||||||
|
containers: Vec<DiskUtilApfsContainer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
struct DiskUtilApfsContainer {
|
||||||
|
volumes: Vec<DiskUtilApfsListVolume>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
struct DiskUtilApfsListVolume {
|
||||||
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ impl Action for EnableOwnership {
|
||||||
.await
|
.await
|
||||||
.map_err(ActionError::Command)?
|
.map_err(ActionError::Command)?
|
||||||
.stdout;
|
.stdout;
|
||||||
let the_plist: DiskUtilOutput = plist::from_reader(Cursor::new(buf)).unwrap();
|
let the_plist: DiskUtilOutput = plist::from_reader(Cursor::new(buf))?;
|
||||||
|
|
||||||
the_plist.global_permissions_enabled
|
the_plist.global_permissions_enabled
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub(crate) mod kickstart_launchctl_service;
|
||||||
pub(crate) mod unmount_apfs_volume;
|
pub(crate) mod unmount_apfs_volume;
|
||||||
|
|
||||||
pub use bootstrap_apfs_volume::{BootstrapApfsVolume, BootstrapVolumeError};
|
pub use bootstrap_apfs_volume::{BootstrapApfsVolume, BootstrapVolumeError};
|
||||||
pub use create_apfs_volume::{CreateApfsVolume, CreateVolumeError};
|
pub use create_apfs_volume::{CreateApfsVolume, CreateApfsVolumeError};
|
||||||
pub use create_nix_volume::{CreateNixVolume, NIX_VOLUME_MOUNTD_DEST};
|
pub use create_nix_volume::{CreateNixVolume, NIX_VOLUME_MOUNTD_DEST};
|
||||||
pub use create_synthetic_objects::{CreateSyntheticObjects, CreateSyntheticObjectsError};
|
pub use create_synthetic_objects::{CreateSyntheticObjects, CreateSyntheticObjectsError};
|
||||||
pub use enable_ownership::{EnableOwnership, EnableOwnershipError};
|
pub use enable_ownership::{EnableOwnership, EnableOwnershipError};
|
||||||
|
|
|
@ -327,6 +327,9 @@ pub enum ActionError {
|
||||||
#[from]
|
#[from]
|
||||||
std::string::FromUtf8Error,
|
std::string::FromUtf8Error,
|
||||||
),
|
),
|
||||||
|
/// A MacOS (Darwin) plist related error
|
||||||
|
#[error(transparent)]
|
||||||
|
Plist(#[from] plist::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasExpectedErrors for ActionError {
|
impl HasExpectedErrors for ActionError {
|
||||||
|
|
|
@ -114,6 +114,7 @@ pub struct CommonSettings {
|
||||||
feature = "cli",
|
feature = "cli",
|
||||||
clap(long, env = "NIX_INSTALLER_NIX_BUILD_USER_ID_BASE", global = true)
|
clap(long, env = "NIX_INSTALLER_NIX_BUILD_USER_ID_BASE", global = true)
|
||||||
)]
|
)]
|
||||||
|
// Service users on Mac should be between 200-400
|
||||||
#[cfg_attr(all(target_os = "macos", feature = "cli"), clap(default_value_t = 300))]
|
#[cfg_attr(all(target_os = "macos", feature = "cli"), clap(default_value_t = 300))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
all(target_os = "linux", feature = "cli"),
|
all(target_os = "linux", feature = "cli"),
|
||||||
|
|
Loading…
Reference in a new issue