Skip to main content

btrfs_cli/subvolume/
set_default.rs

1use crate::{Format, Runnable};
2use anyhow::{Context, Result, anyhow};
3use btrfs_uapi::subvolume::{
4    FS_TREE_OBJECTID, subvolume_default_set, subvolume_info,
5};
6use clap::Parser;
7use std::{fs::File, os::unix::io::AsFd, path::PathBuf};
8
9/// Set the default subvolume of a filesystem.
10///
11/// Accepts either a subvolume path (btrfs subvolume set-default /mnt/fs/subvol)
12/// or a numeric ID with a filesystem path (btrfs subvolume set-default 256 /mnt/fs).
13#[derive(Parser, Debug)]
14pub struct SubvolumeSetDefaultCommand {
15    /// Subvolume path OR numeric subvolume ID
16    #[clap(required = true)]
17    subvol_or_id: String,
18
19    /// Filesystem mount point (required when first arg is a numeric ID)
20    path: Option<PathBuf>,
21}
22
23impl Runnable for SubvolumeSetDefaultCommand {
24    fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
25        match self.subvol_or_id.parse::<u64>() {
26            Ok(id) => {
27                let mount = self.path.as_ref().ok_or_else(|| {
28                    anyhow!("a filesystem path is required when specifying a subvolume ID")
29                })?;
30
31                let file = File::open(mount).with_context(|| {
32                    format!("failed to open '{}'", mount.display())
33                })?;
34
35                let id_to_use = if id == 0 { FS_TREE_OBJECTID } else { id };
36
37                subvolume_default_set(file.as_fd(), id_to_use).with_context(
38                    || {
39                        format!(
40                            "failed to set default subvolume to ID {} on '{}'",
41                            id_to_use,
42                            mount.display()
43                        )
44                    },
45                )?;
46
47                println!("Set default subvolume to ID {id_to_use}");
48            }
49            Err(_) => {
50                let subvol_path = PathBuf::from(&self.subvol_or_id);
51
52                let file = File::open(&subvol_path).with_context(|| {
53                    format!("failed to open '{}'", subvol_path.display())
54                })?;
55
56                let info = subvolume_info(file.as_fd()).with_context(|| {
57                    format!(
58                        "failed to get subvolume info for '{}'",
59                        subvol_path.display()
60                    )
61                })?;
62
63                subvolume_default_set(file.as_fd(), info.id).with_context(
64                    || {
65                        format!(
66                            "failed to set default subvolume to '{}' (ID {})",
67                            subvol_path.display(),
68                            info.id
69                        )
70                    },
71                )?;
72
73                println!(
74                    "Set default subvolume to '{}' (ID {})",
75                    subvol_path.display(),
76                    info.id
77                );
78            }
79        }
80
81        Ok(())
82    }
83}