devicemapper/core/
deviceinfo.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5use nix::libc::c_char;
6use semver::Version;
7
8use crate::{
9    core::{
10        device::Device,
11        dm_flags::DmFlags,
12        dm_ioctl as dmi, errors,
13        types::{DmName, DmNameBuf, DmUuid, DmUuidBuf},
14        util::str_from_c_str,
15    },
16    result::{DmError, DmResult},
17};
18
19/// Contains information about the device.
20#[derive(Clone, Debug)]
21pub struct DeviceInfo {
22    version: Version,
23
24    #[allow(dead_code)]
25    data_size: u32,
26
27    #[allow(dead_code)]
28    data_start: u32,
29
30    pub(super) target_count: u32,
31
32    open_count: i32,
33    flags: DmFlags,
34    event_nr: u32,
35    dev: Device,
36    name: Option<DmNameBuf>,
37    uuid: Option<DmUuidBuf>,
38}
39
40impl TryFrom<dmi::Struct_dm_ioctl> for DeviceInfo {
41    type Error = DmError;
42
43    fn try_from(ioctl: dmi::Struct_dm_ioctl) -> DmResult<Self> {
44        let uuid = str_from_c_str(&ioctl.uuid as &[c_char]).ok_or_else(|| {
45            errors::Error::InvalidArgument("Devicemapper UUID is not null terminated".to_string())
46        })?;
47        let uuid = if uuid.is_empty() {
48            None
49        } else {
50            Some(DmUuidBuf::new(uuid.to_string())?)
51        };
52        let name = str_from_c_str(&ioctl.name as &[c_char]).ok_or_else(|| {
53            errors::Error::InvalidArgument("Devicemapper name is not null terminated".to_string())
54        })?;
55        let name = if name.is_empty() {
56            None
57        } else {
58            Some(DmNameBuf::new(name.to_string())?)
59        };
60        Ok(DeviceInfo {
61            version: Version::new(
62                u64::from(ioctl.version[0]),
63                u64::from(ioctl.version[1]),
64                u64::from(ioctl.version[2]),
65            ),
66            data_size: ioctl.data_size,
67            data_start: ioctl.data_start,
68            target_count: ioctl.target_count,
69            open_count: ioctl.open_count,
70            flags: DmFlags::from_bits_truncate(ioctl.flags),
71            event_nr: ioctl.event_nr,
72            // dm_ioctl struct reserves 64 bits for device but kernel "huge"
73            // encoding is only 32 bits.
74            dev: Device::from_kdev_t(ioctl.dev as u32),
75            uuid,
76            name,
77        })
78    }
79}
80
81impl DeviceInfo {
82    /// Parses a DM ioctl structure.
83    ///
84    /// Equivalent to `DeviceInfo::try_from(hdr)`.
85    pub fn new(hdr: dmi::Struct_dm_ioctl) -> DmResult<Self> {
86        DeviceInfo::try_from(hdr)
87    }
88
89    /// The major, minor, and patchlevel versions of devicemapper.
90    pub fn version(&self) -> &Version {
91        &self.version
92    }
93
94    /// The number of times the device is currently open.
95    pub fn open_count(&self) -> i32 {
96        self.open_count
97    }
98
99    /// The last event number for the device.
100    pub fn event_nr(&self) -> u32 {
101        self.event_nr
102    }
103
104    /// The device's major and minor device numbers, as a Device.
105    pub fn device(&self) -> Device {
106        self.dev
107    }
108
109    /// The device's name.
110    pub fn name(&self) -> Option<&DmName> {
111        self.name.as_ref().map(|name| name.as_ref())
112    }
113
114    /// The device's devicemapper uuid.
115    pub fn uuid(&self) -> Option<&DmUuid> {
116        self.uuid.as_ref().map(|uuid| uuid.as_ref())
117    }
118
119    /// The flags returned from the device.
120    pub fn flags(&self) -> DmFlags {
121        self.flags
122    }
123}