]> git.sesse.net Git - bcachefs-tools-debian/blob - rust-src/src/cmd_list.rs
cb35291648fc362d46ab150ec3cf4a0163da86a3
[bcachefs-tools-debian] / rust-src / src / cmd_list.rs
1 use atty::Stream;
2 use log::{error};
3 use bch_bindgen::bcachefs;
4 use bch_bindgen::opt_set;
5 use bch_bindgen::fs::Fs;
6 use bch_bindgen::bkey::BkeySC;
7 use bch_bindgen::btree::BtreeTrans;
8 use bch_bindgen::btree::BtreeIter;
9 use bch_bindgen::btree::BtreeNodeIter;
10 use bch_bindgen::btree::BtreeIterFlags;
11 use clap::{Parser};
12
13 fn list_keys(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
14     let trans = BtreeTrans::new(fs);
15     let mut iter = BtreeIter::new(&trans, opt.btree, opt.start,
16         BtreeIterFlags::ALL_SNAPSHOTS|
17         BtreeIterFlags::PREFETCH);
18
19     while let Some(k) = iter.peek_and_restart()? {
20         if k.k.p > opt.end {
21             break;
22         }
23
24         println!("{}", k.to_text(fs));
25         iter.advance();
26     }
27
28     Ok(())
29 }
30
31 fn list_btree_formats(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
32     let trans = BtreeTrans::new(fs);
33     let mut iter = BtreeNodeIter::new(&trans, opt.btree, opt.start,
34         0, opt.level,
35         BtreeIterFlags::PREFETCH);
36
37     while let Some(b) = iter.peek_and_restart()? {
38         if b.key.k.p > opt.end {
39             break;
40         }
41
42         println!("{}", b.to_text(fs));
43         iter.advance();
44     }
45
46     Ok(())
47 }
48
49 fn list_btree_nodes(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
50     let trans = BtreeTrans::new(fs);
51     let mut iter = BtreeNodeIter::new(&trans, opt.btree, opt.start,
52         0, opt.level,
53         BtreeIterFlags::PREFETCH);
54
55     while let Some(b) = iter.peek_and_restart()? {
56         if b.key.k.p > opt.end {
57             break;
58         }
59
60         println!("{}", BkeySC::from(&b.key).to_text(fs));
61         iter.advance();
62     }
63
64     Ok(())
65 }
66
67 fn list_nodes_ondisk(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
68     let trans = BtreeTrans::new(fs);
69     let mut iter = BtreeNodeIter::new(&trans, opt.btree, opt.start,
70         0, opt.level,
71         BtreeIterFlags::PREFETCH);
72
73     while let Some(b) = iter.peek_and_restart()? {
74         if b.key.k.p > opt.end {
75             break;
76         }
77
78         println!("{}", b.ondisk_to_text(fs));
79         iter.advance();
80     }
81
82     Ok(())
83 }
84
85 #[derive(Clone, clap::ValueEnum, Debug)]
86 enum Mode {
87     Keys,
88     Formats,
89     Nodes,
90     NodesOndisk,
91 }
92
93 /// List filesystem metadata in textual form
94 #[derive(Parser, Debug)]
95 pub struct Cli {
96     /// Btree to list from
97     #[arg(short, long, default_value_t=bcachefs::btree_id::BTREE_ID_extents)]
98     btree:      bcachefs::btree_id,
99
100     /// Btree depth to descend to (0 == leaves)
101     #[arg(short, long, default_value_t=0)]
102     level:      u32,
103
104     /// Start position to list from
105     #[arg(short, long, default_value="POS_MIN")]
106     start:      bcachefs::bpos,
107
108     /// End position
109     #[arg(short, long, default_value="SPOS_MAX")]
110     end:        bcachefs::bpos,
111
112     #[arg(short, long, default_value="keys")]
113     mode:       Mode,
114
115     /// Check (fsck) the filesystem first
116     #[arg(short, long, default_value_t=false)]
117     fsck:       bool,
118
119     /// Force color on/off. Default: autodetect tty
120     #[arg(short, long, action = clap::ArgAction::Set, default_value_t=atty::is(Stream::Stdout))]
121     colorize:   bool,
122
123     /// Verbose mode
124     #[arg(short, long)]
125     verbose:    bool,
126
127     #[arg(required(true))]
128     devices:    Vec<std::path::PathBuf>,
129 }
130
131 fn cmd_list_inner(opt: Cli) -> anyhow::Result<()> {
132     let mut fs_opts: bcachefs::bch_opts = Default::default();
133
134     opt_set!(fs_opts, nochanges,        1);
135     opt_set!(fs_opts, read_only,        1);
136     opt_set!(fs_opts, norecovery,       1);
137     opt_set!(fs_opts, degraded,         1);
138     opt_set!(fs_opts, errors,           bcachefs::bch_error_actions::BCH_ON_ERROR_continue as u8);
139
140     if opt.fsck {
141         opt_set!(fs_opts, fix_errors,   bcachefs::fsck_err_opts::FSCK_FIX_yes as u8);
142         opt_set!(fs_opts, norecovery,   0);
143     }
144
145     if opt.verbose {
146         opt_set!(fs_opts, verbose,      1);
147     }
148
149     let fs = Fs::open(&opt.devices, fs_opts)?;
150
151     match opt.mode {
152         Mode::Keys          => list_keys(&fs, opt),
153         Mode::Formats       => list_btree_formats(&fs, opt),
154         Mode::Nodes         => list_btree_nodes(&fs, opt),
155         Mode::NodesOndisk   => list_nodes_ondisk(&fs, opt),
156     }
157 }
158
159 pub fn cmd_list(argv: Vec<String>) -> i32 {
160     let opt = Cli::parse_from(argv);
161     colored::control::set_override(opt.colorize);
162     if let Err(e) = cmd_list_inner(opt) {
163         error!("Fatal error: {}", e);
164         1
165     } else {
166         0
167     }
168 }