Skip to main content

btrfs_cli/inspect/
dump_super.rs

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