1use std::{
2 fs::{self, File},
3 io::{self, Write},
4 thread, time,
5};
6
7pub fn make_filesystem(
18 filesystem_name: &str,
19 device_name: &str,
20) -> io::Result<command_manager::Output> {
21 match run_make_filesystem(filesystem_name, device_name) {
22 Ok(v) => {
23 log::debug!("first time success 'make_filesystem'");
24 return Ok(v);
25 }
26 Err(e) => {
27 log::warn!(
28 "first time failure 'make_filesystem' {}; retrying after 5-second...",
29 e
30 );
31 thread::sleep(time::Duration::from_secs(5));
32 return run_make_filesystem(filesystem_name, device_name);
33 }
34 }
35}
36
37pub fn run_make_filesystem(
38 filesystem_name: &str,
39 device_name: &str,
40) -> io::Result<command_manager::Output> {
41 let device_path = if device_name.starts_with("/dev/") {
42 device_name.to_string()
43 } else {
44 format!("/dev/{}", device_name)
45 };
46
47 log::info!(
48 "making file system with 'mkfs' command on the device path '{}'",
49 device_path
50 );
51
52 let cmd = format!("sudo mkfs -t {} {}", filesystem_name, device_path);
53 let res = command_manager::run(&cmd);
54 if res.is_err() {
55 let e = res.err().unwrap();
58 if !e
59 .to_string()
60 .contains(format!("{} is mounted", device_path).as_str())
61 {
62 return Err(e);
63 }
64
65 log::warn!("ignoring the 'is mounted' error '{}'", e.to_string());
66 Ok(command_manager::Output {
67 stdout: String::new(),
68 stderr: e.to_string(),
69 })
70 } else {
71 res
72 }
73}
74
75pub fn mount_filesystem(
84 filesystem_name: &str,
85 device_name: &str,
86 dir_name: &str,
87) -> io::Result<command_manager::Output> {
88 let device_path = if device_name.starts_with("/dev/") {
89 device_name.to_string()
90 } else {
91 format!("/dev/{}", device_name)
92 };
93
94 log::info!(
95 "mounting the file system with 'mount' command on the device path '{}'",
96 device_path
97 );
98
99 let cmd = format!(
100 "sudo mount {} {} -t {}",
101 device_path, dir_name, filesystem_name
102 );
103 let res = command_manager::run(&cmd);
104 if res.is_err() {
105 let e = res.err().unwrap();
107 if !e
108 .to_string()
109 .contains(format!("{} already mounted", device_path).as_str())
110 {
111 return Err(e);
112 }
113
114 log::warn!("ignoring the 'already mounted' error '{}'", e.to_string());
115 Ok(command_manager::Output {
116 stdout: String::new(),
117 stderr: e.to_string(),
118 })
119 } else {
120 res
121 }
122}
123
124const FSTAB_PATH: &str = "/etc/fstab";
125
126pub fn update_fstab(
136 filesystem_name: &str,
137 device_name: &str,
138 dir_name: &str,
139) -> io::Result<command_manager::Output> {
140 let device_path = if device_name.starts_with("/dev/") {
141 device_name.to_string()
142 } else {
143 format!("/dev/{}", device_name)
144 };
145
146 log::info!(
147 "updating the fstab file on the device path '{}'",
148 device_path
149 );
150
151 let line = format!(
152 "{} {} {} defaults,nofail 0 2",
153 device_path, dir_name, filesystem_name
154 );
155 let mut contents = fs::read_to_string(FSTAB_PATH)?;
156 if contents.contains(&line) {
157 log::warn!("fstab already contains '{}', skipping updating fstab", line);
158 return Ok(command_manager::Output {
159 stdout: contents,
160 stderr: String::new(),
161 });
162 }
163 contents.push('\n');
164 contents.push_str(&line);
165
166 let tmp_path = random_manager::tmp_path(10, None)?;
167 let mut f = File::create(&tmp_path)?;
168 f.write_all(contents.as_bytes())?;
169
170 let cmd = format!("sudo cp {} {}", tmp_path, FSTAB_PATH);
171 command_manager::run(&cmd)?;
172 command_manager::run("sudo mount --all")?;
173
174 Ok(command_manager::Output {
175 stdout: contents,
176 stderr: String::new(),
177 })
178}