Skip to main content

btrfs_cli/subvolume/
show.rs

1use crate::{
2    Format, Runnable,
3    util::{ParsedUuid, format_time, open_path},
4};
5use anyhow::{Context, Result};
6use btrfs_uapi::{
7    send_receive::subvolume_search_by_uuid,
8    subvolume::{subvolume_info, subvolume_info_by_id},
9};
10use clap::Parser;
11use std::{os::unix::io::AsFd, path::PathBuf};
12
13/// Show detailed information about a subvolume
14///
15/// Displays UUIDs, generation numbers, creation time, flags, and send/receive
16/// transaction IDs for the subvolume that contains the given path.
17///
18/// The subvolume can be specified by path (default), or by root id or UUID
19/// that are looked up relative to the given path.
20#[derive(Parser, Debug)]
21pub struct SubvolumeShowCommand {
22    /// Look up subvolume by its root ID instead of path
23    #[clap(short = 'r', long = "rootid")]
24    pub rootid: Option<u64>,
25
26    /// Look up subvolume by its UUID instead of path
27    #[clap(short = 'u', long = "uuid", conflicts_with = "rootid")]
28    pub uuid: Option<ParsedUuid>,
29
30    /// Path to a subvolume or any file within it
31    pub path: PathBuf,
32}
33
34impl Runnable for SubvolumeShowCommand {
35    fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
36        let file = open_path(&self.path)?;
37
38        let info = if let Some(rootid) = self.rootid {
39            subvolume_info_by_id(file.as_fd(), rootid).with_context(|| {
40                format!("failed to get subvolume info for rootid {rootid}")
41            })?
42        } else if let Some(ref uuid) = self.uuid {
43            let inner = &**uuid;
44            let rootid = subvolume_search_by_uuid(file.as_fd(), inner)
45                .with_context(|| {
46                    format!("failed to find subvolume with UUID {inner}")
47                })?;
48            subvolume_info_by_id(file.as_fd(), rootid).with_context(|| {
49                format!("failed to get subvolume info for UUID {inner}")
50            })?
51        } else {
52            subvolume_info(file.as_fd()).with_context(|| {
53                format!(
54                    "failed to get subvolume info for '{}'",
55                    self.path.display()
56                )
57            })?
58        };
59
60        println!("{}", self.path.display());
61        println!("\tName: \t\t\t{}", info.name);
62        println!("\tUUID: \t\t\t{}", format_uuid(&info.uuid));
63        println!("\tParent UUID: \t\t{}", format_uuid(&info.parent_uuid));
64        println!("\tReceived UUID: \t\t{}", format_uuid(&info.received_uuid));
65        println!("\tCreation time: \t\t{}", format_time(info.otime));
66        println!("\tSubvolume ID: \t\t{}", info.id);
67        println!("\tGeneration: \t\t{}", info.generation);
68        println!("\tGen at creation: \t{}", info.otransid);
69        println!("\tParent ID: \t\t{}", info.parent_id);
70        println!("\tTop level ID: \t\t{}", info.parent_id);
71        println!("\tFlags: \t\t\t{}", info.flags);
72        println!("\tSend transid: \t\t{}", info.stransid);
73        println!("\tSend time: \t\t{}", format_time(info.stime));
74        println!("\tReceive transid: \t{}", info.rtransid);
75        println!("\tReceive time: \t\t{}", format_time(info.rtime));
76
77        Ok(())
78    }
79}
80
81fn format_uuid(uuid: &uuid::Uuid) -> String {
82    if uuid.is_nil() {
83        "-".to_string()
84    } else {
85        uuid.hyphenated().to_string()
86    }
87}