diff --git a/hive-c0re/src/bin/hivectl.rs b/hive-c0re/src/bin/hivectl.rs index 4ba1a7f0..cedf83e2 100644 --- a/hive-c0re/src/bin/hivectl.rs +++ b/hive-c0re/src/bin/hivectl.rs @@ -740,19 +740,7 @@ async fn main() -> Result<()> { } => stop(&socket, scope.to_scope(), graceful, no_wait).await, Cmd::Start { scope, no_wait } => start(&socket, scope.to_scope(), no_wait).await, Cmd::Restart { scope, graceful } => restart(&socket, scope.to_scope(), graceful).await, - Cmd::Subvol { cmd } => match cmd { - SubvolCmd::Upgrade { name, yes } => subvol_upgrade(&socket, &name, yes).await, - SubvolCmd::Snapshot { cmd } => match cmd { - SnapshotCmd::Create { name, label } => subvol_snapshot_create(&name, label).await, - SnapshotCmd::Delete { name, label } => subvol_snapshot_delete(&name, &label).await, - SnapshotCmd::Send { - name, - label, - parent, - dest, - } => subvol_snapshot_send(&name, &label, parent.as_deref(), &dest).await, - }, - }, + Cmd::Subvol { cmd } => dispatch_subvol(&socket, cmd).await, Cmd::Choom { name, resume_session, @@ -1714,6 +1702,29 @@ fn single_agent_scope(name: &str) -> hive_host_sock::LifecycleScope { /// migration via hive-priv, then restart it. The restart is attempted /// regardless of the migration outcome so a failed migration never leaves /// the agent down; the migration error (if any) is surfaced afterwards. +/// Route a `hivectl subvol …` subcommand. Split out of `main`'s top-level +/// match so the CLI router stays within the clippy line budget and the +/// subvolume-op subcommands are dispatched in one place. +async fn dispatch_subvol(socket: &Path, cmd: SubvolCmd) -> Result<()> { + match cmd { + SubvolCmd::Upgrade { name, yes } => subvol_upgrade(socket, &name, yes).await, + SubvolCmd::Snapshot { cmd } => match cmd { + SnapshotCmd::Create { name, label } => { + subvol_snapshot_create(socket, &name, label).await + } + SnapshotCmd::Delete { name, label } => { + subvol_snapshot_delete(socket, &name, &label).await + } + SnapshotCmd::Send { + name, + label, + parent, + dest, + } => subvol_snapshot_send(socket, &name, &label, parent.as_deref(), &dest).await, + }, + } +} + async fn subvol_upgrade(socket: &Path, name: &str, yes: bool) -> Result<()> { if !agent_exists(name)? { bail!("no agent named {name:?} (no state dir under the agents root)"); @@ -1749,7 +1760,14 @@ async fn subvol_upgrade(socket: &Path, name: &str, yes: bool) -> Result<()> { .with_context(|| format!("waiting for {name} to stop before the migration"))?; println!("migrating {name} state dir to a btrfs subvolume…"); - let upgrade = hive_c0re::priv_client::upgrade_agent_subvolume(name).await; + let upgrade = daemon_request( + socket, + hive_host_sock::HostRequest::UpgradeSubvolume { + name: name.to_owned(), + }, + "upgrade", + ) + .await; // Always attempt the restart, even if the migration failed — don't leave // the agent down. Capture the result rather than `?`-ing it so a @@ -1806,7 +1824,7 @@ async fn subvol_upgrade(socket: &Path, name: &str, yes: bool) -> Result<()> { /// — mara: "we are making up the rules here, lets go strict"). hive-priv /// enforces the same rules server-side, so this check is /// belt-and-suspenders (fail fast client-side with a clear message). -async fn subvol_snapshot_create(name: &str, label: String) -> Result<()> { +async fn subvol_snapshot_create(socket: &Path, name: &str, label: String) -> Result<()> { if !agent_exists(name)? { bail!("no agent named {name:?} (no state dir under the agents root)"); } @@ -1821,19 +1839,31 @@ async fn subvol_snapshot_create(name: &str, label: String) -> Result<()> { "snapshot label {label:?} must be [A-Za-z0-9_-] only (no \".\" — hive-priv rejects it)" ); } - let path = hive_c0re::priv_client::snapshot_agent_subvolume(name, &label) - .await - .with_context(|| format!("snapshot {name} state subvolume (label {label:?})"))?; - println!("{path}"); - Ok(()) + // The daemon returns the snapshot's host path as a message line, which + // `daemon_request` prints — same bare-path output as before. + daemon_request( + socket, + hive_host_sock::HostRequest::SnapshotSubvolume { + name: name.to_owned(), + label, + }, + "snapshot", + ) + .await } /// `subvol snapshot delete