btrfs_cli/filesystem/
resize.rs1use crate::{
2 RunContext, Runnable,
3 util::{open_path, parse_size_with_suffix},
4};
5use anyhow::{Context, Result};
6use btrfs_uapi::filesystem::{ResizeAmount, ResizeArgs, resize};
7use clap::Parser;
8use std::{os::unix::io::AsFd, path::PathBuf};
9
10#[derive(Parser, Debug)]
12pub struct FilesystemResizeCommand {
13 #[clap(long)]
15 pub enqueue: bool,
16
17 #[clap(long)]
19 pub offline: bool,
20
21 pub size: String,
24
25 pub path: PathBuf,
26}
27
28fn parse_resize_amount(s: &str) -> Result<ResizeAmount> {
29 if s == "cancel" {
30 return Ok(ResizeAmount::Cancel);
31 }
32 if s == "max" {
33 return Ok(ResizeAmount::Max);
34 }
35 let (modifier, rest) = if let Some(r) = s.strip_prefix('+') {
36 (1i32, r)
37 } else if let Some(r) = s.strip_prefix('-') {
38 (-1i32, r)
39 } else {
40 (0i32, s)
41 };
42 let bytes = parse_size_with_suffix(rest)?;
43 Ok(match modifier {
44 1 => ResizeAmount::Add(bytes),
45 -1 => ResizeAmount::Sub(bytes),
46 _ => ResizeAmount::Set(bytes),
47 })
48}
49
50fn parse_resize_args(s: &str) -> Result<ResizeArgs> {
51 if let Some(colon) = s.find(':')
52 && let Ok(devid) = s[..colon].parse::<u64>()
53 {
54 let amount = parse_resize_amount(&s[colon + 1..])?;
55 return Ok(ResizeArgs::new(amount).with_devid(devid));
56 }
57 Ok(ResizeArgs::new(parse_resize_amount(s)?))
58}
59
60impl Runnable for FilesystemResizeCommand {
61 fn run(&self, _ctx: &RunContext) -> Result<()> {
62 if self.offline {
63 anyhow::bail!("--offline is not yet implemented");
64 }
65
66 if self.enqueue {
67 anyhow::bail!("--enqueue is not yet implemented");
68 }
69
70 let args = parse_resize_args(&self.size).with_context(|| {
71 format!("invalid resize argument: '{}'", self.size)
72 })?;
73
74 let file = open_path(&self.path)?;
75
76 resize(file.as_fd(), args).with_context(|| {
77 format!("resize failed on '{}'", self.path.display())
78 })?;
79
80 Ok(())
81 }
82}