Skip to main content

btrfs_cli/inspect/
dump_super.rs

1use super::print_super;
2use crate::{Format, Runnable};
3use anyhow::{Context, Result, bail};
4use btrfs_disk::superblock::{self, SUPER_MIRROR_MAX};
5use clap::Parser;
6use std::{fs::File, path::PathBuf};
7
8/// Dump the btrfs superblock from a device or image file.
9///
10/// Reads and displays the superblock stored on a btrfs block device or
11/// filesystem image. By default only the primary superblock (mirror 0,
12/// at offset 64 KiB) is printed. Use -a to print all mirrors, or -s to
13/// select a specific one.
14#[derive(Parser, Debug)]
15pub struct DumpSuperCommand {
16    /// Path to a btrfs block device or image file
17    path: PathBuf,
18
19    /// Print full information including sys_chunk_array and backup roots
20    #[clap(short = 'f', long)]
21    full: bool,
22
23    /// Print all superblock mirrors (0, 1, 2)
24    #[clap(short = 'a', long)]
25    all: bool,
26
27    /// Print only this superblock mirror (0, 1, or 2)
28    #[clap(short = 's', long = "super", value_parser = clap::value_parser!(u32).range(..SUPER_MIRROR_MAX as i64))]
29    mirror: Option<u32>,
30
31    /// Attempt to print superblocks with bad magic
32    #[clap(short = 'F', long)]
33    force: bool,
34}
35
36impl Runnable for DumpSuperCommand {
37    fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
38        let mut file = File::open(&self.path).with_context(|| {
39            format!("failed to open '{}'", self.path.display())
40        })?;
41
42        let mirrors: Vec<u32> = if self.all {
43            (0..SUPER_MIRROR_MAX).collect()
44        } else if let Some(m) = self.mirror {
45            vec![m]
46        } else {
47            vec![0]
48        };
49
50        for (i, &mirror) in mirrors.iter().enumerate() {
51            if i > 0 {
52                println!();
53            }
54
55            let offset = superblock::super_mirror_offset(mirror);
56            println!(
57                "superblock: bytenr={offset}, device={}",
58                self.path.display()
59            );
60
61            let sb = match superblock::read_superblock(&mut file, mirror) {
62                Ok(sb) => sb,
63                Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
64                    println!(
65                        "superblock mirror {mirror} beyond end of device, skipping"
66                    );
67                    continue;
68                }
69                Err(e) => {
70                    return Err(e).with_context(|| {
71                        format!(
72                            "failed to read superblock mirror {mirror} from '{}'",
73                            self.path.display()
74                        )
75                    });
76                }
77            };
78
79            if !sb.magic_is_valid() && !self.force {
80                if self.all {
81                    println!(
82                        "superblock mirror {mirror} has bad magic, skipping (use -F to force)"
83                    );
84                    continue;
85                }
86                bail!(
87                    "bad magic on superblock mirror {mirror} of '{}' (use -F to force)",
88                    self.path.display()
89                );
90            }
91
92            println!(
93                "---------------------------------------------------------"
94            );
95            print_super::print_superblock(&sb, self.full);
96        }
97
98        Ok(())
99    }
100}