1use crate::utils::*;
2use crate::DbusObjects;
3use dbus::arg::RefArg;
4use std::path::PathBuf;
5
6#[derive(Clone, Debug, Default)]
7pub struct Block {
8 pub crypto_backing_device: String,
9 pub device_number: u64,
10 pub device: PathBuf,
11 pub drive: String,
12 pub encrypted: Option<Encrypted>,
13 pub hint_auto: bool,
14 pub hint_icon_name: Option<String>,
15 pub hint_ignore: bool,
16 pub hint_name: Option<String>,
17 pub hint_partitionable: bool,
18 pub hint_symbolic_icon_name: Option<String>,
19 pub hint_system: bool,
20 pub id_label: Option<String>,
21 pub id_type: Option<String>,
22 pub id_usage: Option<String>,
23 pub id_uuid: Option<String>,
24 pub id_version: Option<String>,
25 pub id: String,
26 pub loopback: bool,
27 pub mdraid: PathBuf,
28 pub mdraid_member: PathBuf,
29 pub mount_points: Vec<PathBuf>,
30 pub partition: Option<Partition>,
31 pub path: String,
32 pub preferred_device: PathBuf,
33 pub read_only: bool,
34 pub size: u64,
35 pub swapspace: Option<bool>,
36 pub symlinks: Vec<PathBuf>,
37 pub table: Option<PartitionTable>,
38 pub userspace_mount_options: Vec<String>,
39 pub configuration: Option<BlockConfiguration>,
40}
41
42impl Block {
43 pub fn is_encrypted(&self) -> bool {
45 self.encrypted.is_some()
46 }
47
48 pub fn get_encrypted_block<'a>(&self, within: &'a [Block]) -> Option<&'a Block> {
50 if self.encrypted.is_some() {
51 within.iter().find(|b| b.crypto_backing_device == self.path)
52 } else {
53 None
54 }
55 }
56}
57
58impl ParseFrom for Block {
59 fn parse_from(path: &str, objects: &DbusObjects) -> Option<Block> {
60 if objects.get("org.freedesktop.UDisks2.Loop").is_some() {
61 return None;
62 }
63
64 let mut block = Block::default();
65 block.path = path.to_owned();
66
67 match objects.get("org.freedesktop.UDisks2.Block") {
68 Some(object) => {
69 for (key, ref value) in object {
70 match key.as_str() {
71 "CryptoBackingDevice" => {
72 block.crypto_backing_device = get_string(value).unwrap()
73 }
74 "Device" => block.device = PathBuf::from(get_byte_array(value).unwrap()),
75 "DeviceNumber" => block.device_number = get_u64(value),
76 "Drive" => block.drive = get_string(value).unwrap(),
77 "HintAuto" => block.hint_auto = get_bool(value),
78 "HintIconName" => block.hint_icon_name = get_string(value),
79 "HintIgnore" => block.hint_ignore = get_bool(value),
80 "HintName" => block.hint_name = get_string(value),
81 "HintPartitionable" => block.hint_partitionable = get_bool(value),
82 "HintSymbolicIconName" => block.hint_symbolic_icon_name = get_string(value),
83 "HintSystem" => block.hint_system = get_bool(value),
84 "Id" => block.id = get_string(value).unwrap_or_default(),
85 "IdLabel" => block.id_label = get_string(value),
86 "IdType" => block.id_type = get_string(value),
87 "IdUsage" => block.id_usage = get_string(value),
88 "IdUUID" => block.id_uuid = get_string(value),
89 "IdVersion" => block.id_version = get_string(value),
90 "MDRaid" => {
91 block.mdraid = get_string(value).map(PathBuf::from).unwrap_or_default()
92 }
93 "MDRaidMember" => {
94 block.mdraid_member =
95 get_string(value).map(PathBuf::from).unwrap_or_default()
96 }
97 "PreferredDevice" => {
98 block.preferred_device = PathBuf::from(get_byte_array(value).unwrap())
99 }
100 "ReadOnly" => block.read_only = get_bool(value),
101 "Size" => block.size = get_u64(value),
102 "Symlinks" => {
103 block.symlinks = get_array_of_byte_arrays(value)
104 .map(|paths| {
105 paths.into_iter().map(PathBuf::from).collect::<Vec<_>>()
106 })
107 .unwrap_or_default()
108 }
109 "UserspaceMountOptions" => {
110 block.userspace_mount_options =
111 get_string_array(value).unwrap_or_default()
112 }
113 "Configuration" => {
114 let mut configuration = BlockConfiguration::default();
115 for value in value.as_iter().unwrap() {
116 if let Some(mut iterator) = value.as_iter() {
117 if let Some(mut iterator) =
118 iterator.next().and_then(|i| i.as_iter())
119 {
120 if let (Some(key), Some(mut array)) = (
121 iterator.next(),
122 iterator.next().and_then(|i| i.as_iter()),
123 ) {
124 if let Some(key) = key.as_str() {
125 if key == "fstab" {
126 while let (Some(key), Some(value)) =
127 (array.next(), array.next())
128 {
129 if let Some(key) = key.as_str() {
130 match key {
131 "fsname" => {
132 configuration.fstab.fsname =
133 vva(value)
134 .unwrap_or_default()
135 }
136 "dir" => {
137 configuration.fstab.dir =
138 vva(value)
139 .unwrap_or_default()
140 }
141 "type" => {
142 configuration.fstab.type_ =
143 vva(value)
144 .unwrap_or_default()
145 }
146 "opts" => {
147 configuration.fstab.opts =
148 vva(value)
149 .unwrap_or_default()
150 }
151 "freq" => {
152 configuration.fstab.freq = value
153 .as_u64()
154 .unwrap_or_default()
155 as i32
156 }
157 "passno" => {
158 configuration.fstab.passno =
159 value
160 .as_u64()
161 .unwrap_or_default()
162 as i32
163 }
164 _ => {
165 eprintln!("unhandled block config fstab key: {:?}, {:?}", key, value);
166 }
167 }
168 }
169 }
170 } else if key == "crypttab" {
171 while let (Some(key), Some(value)) =
172 (array.next(), array.next())
173 {
174 if let Some(key) = key.as_str() {
175 match key {
176 "name" => {
177 configuration.crypttab.name =
178 vva(value)
179 .unwrap_or_default()
180 }
181 "device" => {
182 configuration.crypttab.device =
183 vva(value)
184 .unwrap_or_default()
185 }
186 "passphrase-path" => {
187 configuration
188 .crypttab
189 .passphrase_path =
190 vva(value)
191 .unwrap_or_default()
192 }
193 "options" => {
194 configuration.crypttab.options =
195 vva(value)
196 .unwrap_or_default()
197 }
198 _ => {
199 eprintln!("unhandled block config crypttab key: {:?}, {:?}", key, value);
200 }
201 }
202 }
203 }
204 } else {
205 eprintln!("unknown block config key: {}", key);
206 }
207 }
208 }
209 }
210 }
211 }
212
213 block.configuration = Some(configuration);
214 }
215 _ => {
216 #[cfg(debug_assertions)]
217 eprintln!("unhandled org.freedesktop.UDisks2.Block.{}", key);
218 eprintln!("value: {:#?}", value);
219 }
220 }
221 }
222 }
223 None => return None,
224 }
225
226 for (key, object) in objects {
227 match key.as_str() {
228 "org.freedesktop.UDisks2.Block" => (),
229 "org.freedesktop.UDisks2.Swapspace" => {
230 block.swapspace = Some(object.get("Active").map_or(false, get_bool));
231 }
232 "org.freedesktop.UDisks2.PartitionTable" => {
233 let mut table = PartitionTable::default();
234 for (key, ref value) in object {
235 match key.as_str() {
236 "Type" => table.type_ = get_string(value).unwrap_or_default(),
237 "Partitions" => {
238 table.partitions = get_string_array(value).unwrap_or_default();
239 table.partitions.sort_unstable();
240 }
241 _ => {
242 #[cfg(debug_assertions)]
243 eprintln!(
244 "unhandled org.freedesktop.UDisks2.PartitionTable.{}",
245 key
246 );
247 }
248 }
249 }
250
251 block.table = Some(table);
252 }
253 "org.freedesktop.UDisks2.Partition" => {
254 let mut partition = Partition::default();
255 for (key, value) in object {
256 match key.as_str() {
257 "Type" => partition.type_ = get_string(value).unwrap_or_default(),
258 "Name" => partition.name = get_string(value).unwrap_or_default(),
259 "UUID" => partition.uuid = get_string(value).unwrap_or_default(),
260 "Table" => {
261 partition.table =
262 get_string(value).expect("partition is not part of a table")
263 }
264 "Flags" => partition.flags = get_u64(value),
265 "Offset" => partition.offset = get_u64(value),
266 "Size" => partition.size = get_u64(value),
267 "Number" => partition.number = get_u64(value) as u32,
268 "IsContained" => partition.is_contained = get_bool(value),
269 "IsContainer" => partition.is_container = get_bool(value),
270 _ => {
271 #[cfg(debug_assertions)]
272 eprintln!("unhandled org.freedesktop.UDisks2.Partition.{}", key);
273 }
274 }
275 }
276
277 block.partition = Some(partition);
278 }
279 "org.freedesktop.UDisks2.Filesystem" => {
280 block.mount_points = object
281 .get("MountPoints")
282 .and_then(get_array_of_byte_arrays)
283 .map(|paths| paths.into_iter().map(PathBuf::from).collect::<Vec<_>>())
284 .unwrap_or_default()
285 }
286 "org.freedesktop.UDisks2.Encrypted" => {
287 let mut encrypted = Encrypted::default();
288 for (key, ref value) in object {
289 match key.as_str() {
290 "HintEncryptionType" => {
291 encrypted.hint_encryption_type =
292 get_string(value).unwrap_or_default()
293 }
294 "MetadataSize" => encrypted.metadata_size = get_u64(value),
295 "CleartextDevice" => {
296 encrypted.cleartext_device = get_string(value).unwrap_or_default()
297 }
298 _ => {
299 #[cfg(debug_assertions)]
300 eprintln!("unhandled org.freedesktop.UDisks2.Encrypted.{}", key);
301 }
302 }
303 }
304
305 block.encrypted = Some(encrypted);
306 }
307 _ => {
308 #[cfg(debug_assertions)]
309 eprintln!("unhandled org.freedesktop.UDisks2.{}", key);
310 }
311 }
312 }
313
314 Some(block)
315 }
316}
317
318#[derive(Clone, Debug, Default)]
319pub struct BlockConfiguration {
320 pub fstab: BlockConfigurationFstab,
321 pub crypttab: BlockConfigurationCrypttab,
322}
323
324#[derive(Clone, Debug, Default)]
325pub struct BlockConfigurationFstab {
326 pub fsname: String,
327 pub dir: String,
328 pub type_: String,
329 pub opts: String,
330 pub freq: i32,
331 pub passno: i32,
332}
333
334#[derive(Clone, Debug, Default)]
335pub struct BlockConfigurationCrypttab {
336 pub name: String,
337 pub device: String,
338 pub passphrase_path: String,
339 pub options: String,
340}
341
342#[derive(Clone, Debug, Default)]
343pub struct Encrypted {
344 pub hint_encryption_type: String,
345 pub metadata_size: u64,
346 pub cleartext_device: String,
347}
348
349#[derive(Clone, Debug, Default)]
350pub struct PartitionTable {
351 pub type_: String,
352 pub partitions: Vec<String>,
354}
355
356#[derive(Clone, Debug, Default)]
357pub struct Partition {
358 pub type_: String,
360 pub name: String,
362 pub table: String,
364 pub flags: u64,
365 pub number: u32,
366 pub offset: u64,
367 pub size: u64,
368 pub uuid: String,
369 pub is_container: bool,
370 pub is_contained: bool,
371}