Skip to main content

btrfs_cli/subvolume/
flags.rs

1use crate::{Format, Runnable};
2use anyhow::{Context, Result};
3use btrfs_uapi::subvolume::{
4    SubvolumeFlags, subvolume_flags_get, subvolume_flags_set,
5};
6use clap::Parser;
7use std::{fs::File, os::unix::io::AsFd, path::PathBuf};
8
9/// Wrapper around SubvolumeFlags that implements FromStr for clap parsing.
10#[derive(Debug, Clone, Copy)]
11pub struct ParsedSubvolumeFlags(SubvolumeFlags);
12
13impl std::str::FromStr for ParsedSubvolumeFlags {
14    type Err = String;
15
16    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
17        match s {
18            "readonly" => Ok(Self(SubvolumeFlags::RDONLY)),
19            "-" | "" | "none" => Ok(Self(SubvolumeFlags::empty())),
20            _ => Err(format!("unknown flag '{s}'; expected 'readonly' or '-'")),
21        }
22    }
23}
24
25/// Show the flags of a subvolume
26#[derive(Parser, Debug)]
27pub struct SubvolumeGetFlagsCommand {
28    /// Path to a subvolume
29    pub path: PathBuf,
30}
31
32impl Runnable for SubvolumeGetFlagsCommand {
33    fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
34        let file = File::open(&self.path).with_context(|| {
35            format!("failed to open '{}'", self.path.display())
36        })?;
37
38        let flags = subvolume_flags_get(file.as_fd()).with_context(|| {
39            format!("failed to get flags for '{}'", self.path.display())
40        })?;
41
42        println!("{}", flags);
43
44        Ok(())
45    }
46}
47
48/// Set the flags of a subvolume
49#[derive(Parser, Debug)]
50pub struct SubvolumeSetFlagsCommand {
51    /// Flags to set ("readonly" or "-" to clear)
52    pub flags: ParsedSubvolumeFlags,
53
54    /// Path to a subvolume
55    pub path: PathBuf,
56}
57
58impl Runnable for SubvolumeSetFlagsCommand {
59    fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
60        let file = File::open(&self.path).with_context(|| {
61            format!("failed to open '{}'", self.path.display())
62        })?;
63
64        subvolume_flags_set(file.as_fd(), self.flags.0).with_context(|| {
65            format!("failed to set flags on '{}'", self.path.display())
66        })?;
67
68        println!("Set flags to {} on '{}'", self.flags.0, self.path.display());
69
70        Ok(())
71    }
72}