dbus_udisks2/
block.rs

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    /// This will be true if this block contains an encrypted volume.
44    pub fn is_encrypted(&self) -> bool {
45        self.encrypted.is_some()
46    }
47
48    /// If this block contains an encrypted volume, find the block associated with it.
49    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    // Partitions are listed by their dbus paths.
353    pub partitions: Vec<String>,
354}
355
356#[derive(Clone, Debug, Default)]
357pub struct Partition {
358    // Defines the file system by a type UUID.
359    pub type_: String,
360    // An optional label that may be applied to a disk.
361    pub name: String,
362    // Points to the dbus path that this partition exists within.
363    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}