Skip to main content

btrfs_cli/filesystem/
label.rs

1use crate::{Format, Runnable};
2use anyhow::{Context, Result};
3use btrfs_uapi::filesystem::{label_get, label_set};
4use clap::Parser;
5use std::{
6    ffi::CString,
7    fs::File,
8    os::unix::{ffi::OsStrExt, io::AsFd},
9    path::PathBuf,
10};
11
12/// Get or set the label of a btrfs filesystem
13#[derive(Parser, Debug)]
14pub struct FilesystemLabelCommand {
15    /// The device or mount point to operate on
16    pub path: PathBuf,
17
18    /// The new label to set (if omitted, the current label is printed)
19    pub new_label: Option<std::ffi::OsString>,
20}
21
22impl Runnable for FilesystemLabelCommand {
23    fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
24        let file = File::open(&self.path).with_context(|| {
25            format!("failed to open '{}'", self.path.display())
26        })?;
27        match &self.new_label {
28            None => {
29                let label = label_get(file.as_fd()).with_context(|| {
30                    format!("failed to get label for '{}'", self.path.display())
31                })?;
32                println!("{}", label.to_bytes().escape_ascii());
33            }
34            Some(new_label) => {
35                let cstring = CString::new(new_label.as_bytes())
36                    .context("label must not contain null bytes")?;
37                label_set(file.as_fd(), &cstring).with_context(|| {
38                    format!("failed to set label for '{}'", self.path.display())
39                })?;
40            }
41        }
42        Ok(())
43    }
44}