1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::ffi::OsStr;
4use std::fmt;
5use std::path::Path;
6
7/// Struct containing a disk information.
8///
9/// ```no_run
10/// use sysinfo::Disks;
11///
12/// let disks = Disks::new_with_refreshed_list();
13/// for disk in disks.list() {
14/// println!("{:?}: {:?}", disk.name(), disk.kind());
15/// }
16/// ```
17pub struct Disk {
18 pub(crate) inner: crate::DiskInner,
19}
20
21impl Disk {
22 /// Returns the kind of disk.
23 ///
24 /// ```no_run
25 /// use sysinfo::Disks;
26 ///
27 /// let disks = Disks::new_with_refreshed_list();
28 /// for disk in disks.list() {
29 /// println!("[{:?}] {:?}", disk.name(), disk.kind());
30 /// }
31 /// ```
32 pub fn kind(&self) -> DiskKind {
33 self.inner.kind()
34 }
35
36 /// Returns the disk name.
37 ///
38 /// ```no_run
39 /// use sysinfo::Disks;
40 ///
41 /// let disks = Disks::new_with_refreshed_list();
42 /// for disk in disks.list() {
43 /// println!("{:?}", disk.name());
44 /// }
45 /// ```
46 pub fn name(&self) -> &OsStr {
47 self.inner.name()
48 }
49
50 /// Returns the file system used on this disk (so for example: `EXT4`, `NTFS`, etc...).
51 ///
52 /// ```no_run
53 /// use sysinfo::Disks;
54 ///
55 /// let disks = Disks::new_with_refreshed_list();
56 /// for disk in disks.list() {
57 /// println!("[{:?}] {:?}", disk.name(), disk.file_system());
58 /// }
59 /// ```
60 pub fn file_system(&self) -> &OsStr {
61 self.inner.file_system()
62 }
63
64 /// Returns the mount point of the disk (`/` for example).
65 ///
66 /// ```no_run
67 /// use sysinfo::Disks;
68 ///
69 /// let disks = Disks::new_with_refreshed_list();
70 /// for disk in disks.list() {
71 /// println!("[{:?}] {:?}", disk.name(), disk.mount_point());
72 /// }
73 /// ```
74 pub fn mount_point(&self) -> &Path {
75 self.inner.mount_point()
76 }
77
78 /// Returns the total disk size, in bytes.
79 ///
80 /// ```no_run
81 /// use sysinfo::Disks;
82 ///
83 /// let disks = Disks::new_with_refreshed_list();
84 /// for disk in disks.list() {
85 /// println!("[{:?}] {}B", disk.name(), disk.total_space());
86 /// }
87 /// ```
88 pub fn total_space(&self) -> u64 {
89 self.inner.total_space()
90 }
91
92 /// Returns the available disk size, in bytes.
93 ///
94 /// ```no_run
95 /// use sysinfo::Disks;
96 ///
97 /// let disks = Disks::new_with_refreshed_list();
98 /// for disk in disks.list() {
99 /// println!("[{:?}] {}B", disk.name(), disk.available_space());
100 /// }
101 /// ```
102 pub fn available_space(&self) -> u64 {
103 self.inner.available_space()
104 }
105
106 /// Returns `true` if the disk is removable.
107 ///
108 /// ```no_run
109 /// use sysinfo::Disks;
110 ///
111 /// let disks = Disks::new_with_refreshed_list();
112 /// for disk in disks.list() {
113 /// println!("[{:?}] {}", disk.name(), disk.is_removable());
114 /// }
115 /// ```
116 pub fn is_removable(&self) -> bool {
117 self.inner.is_removable()
118 }
119
120 /// Updates the disk' information.
121 ///
122 /// ```no_run
123 /// use sysinfo::Disks;
124 ///
125 /// let mut disks = Disks::new_with_refreshed_list();
126 /// for disk in disks.list_mut() {
127 /// disk.refresh();
128 /// }
129 /// ```
130 pub fn refresh(&mut self) -> bool {
131 self.inner.refresh()
132 }
133}
134
135/// Disks interface.
136///
137/// ```no_run
138/// use sysinfo::Disks;
139///
140/// let disks = Disks::new_with_refreshed_list();
141/// for disk in disks.list() {
142/// println!("{disk:?}");
143/// }
144/// ```
145///
146/// ⚠️ Note that tmpfs mounts are excluded by default under Linux.
147/// To display tmpfs mount points, the `linux-tmpfs` feature must be enabled.
148///
149/// ⚠️ Note that network devices are excluded by default under Linux.
150/// To display mount points using the CIFS and NFS protocols, the `linux-netdevs`
151/// feature must be enabled. Note, however, that sysinfo may hang under certain
152/// circumstances. For example, if a CIFS or NFS share has been mounted with
153/// the _hard_ option, but the connection has an error, such as the share server has stopped.
154pub struct Disks {
155 inner: crate::DisksInner,
156}
157
158impl Default for Disks {
159 fn default() -> Self {
160 Self::new()
161 }
162}
163
164impl From<Disks> for Vec<Disk> {
165 fn from(disks: Disks) -> Vec<Disk> {
166 disks.inner.into_vec()
167 }
168}
169
170impl From<Vec<Disk>> for Disks {
171 fn from(disks: Vec<Disk>) -> Self {
172 Self {
173 inner: crate::DisksInner::from_vec(disks),
174 }
175 }
176}
177
178impl<'a> IntoIterator for &'a Disks {
179 type Item = &'a Disk;
180 type IntoIter = std::slice::Iter<'a, Disk>;
181
182 fn into_iter(self) -> Self::IntoIter {
183 self.list().iter()
184 }
185}
186
187impl<'a> IntoIterator for &'a mut Disks {
188 type Item = &'a mut Disk;
189 type IntoIter = std::slice::IterMut<'a, Disk>;
190
191 fn into_iter(self) -> Self::IntoIter {
192 self.list_mut().iter_mut()
193 }
194}
195
196impl Disks {
197 /// Creates a new empty [`Disks`][crate::Disks] type.
198 ///
199 /// If you want it to be filled directly, take a look at [`Disks::new_with_refreshed_list`].
200 ///
201 /// ```no_run
202 /// use sysinfo::Disks;
203 ///
204 /// let mut disks = Disks::new();
205 /// disks.refresh_list();
206 /// for disk in disks.list() {
207 /// println!("{disk:?}");
208 /// }
209 /// ```
210 pub fn new() -> Self {
211 Self {
212 inner: crate::DisksInner::new(),
213 }
214 }
215
216 /// Creates a new [`Disks`][crate::Disks] type with the disk list loaded.
217 /// It is a combination of [`Disks::new`] and [`Disks::refresh_list`].
218 ///
219 /// ```no_run
220 /// use sysinfo::Disks;
221 ///
222 /// let mut disks = Disks::new_with_refreshed_list();
223 /// for disk in disks.list() {
224 /// println!("{disk:?}");
225 /// }
226 /// ```
227 pub fn new_with_refreshed_list() -> Self {
228 let mut disks = Self::new();
229 disks.refresh_list();
230 disks
231 }
232
233 /// Returns the disks list.
234 ///
235 /// ```no_run
236 /// use sysinfo::Disks;
237 ///
238 /// let disks = Disks::new_with_refreshed_list();
239 /// for disk in disks.list() {
240 /// println!("{disk:?}");
241 /// }
242 /// ```
243 pub fn list(&self) -> &[Disk] {
244 self.inner.list()
245 }
246
247 /// Returns the disks list.
248 ///
249 /// ```no_run
250 /// use sysinfo::Disks;
251 ///
252 /// let mut disks = Disks::new_with_refreshed_list();
253 /// for disk in disks.list_mut() {
254 /// disk.refresh();
255 /// println!("{disk:?}");
256 /// }
257 /// ```
258 pub fn list_mut(&mut self) -> &mut [Disk] {
259 self.inner.list_mut()
260 }
261
262 /// Refreshes the listed disks' information.
263 ///
264 /// ⚠️ If a disk is added or removed, this method won't take it into account. Use
265 /// [`Disks::refresh_list`] instead.
266 ///
267 /// ⚠️ If you didn't call [`Disks::refresh_list`] beforehand, this method will do nothing as
268 /// the disk list will be empty.
269 ///
270 /// ```no_run
271 /// use sysinfo::Disks;
272 ///
273 /// let mut disks = Disks::new_with_refreshed_list();
274 /// // We wait some time...?
275 /// disks.refresh();
276 /// ```
277 pub fn refresh(&mut self) {
278 for disk in self.list_mut() {
279 disk.refresh();
280 }
281 }
282
283 /// The disk list will be emptied then completely recomputed.
284 ///
285 /// ## Linux
286 ///
287 /// ⚠️ On Linux, the [NFS](https://en.wikipedia.org/wiki/Network_File_System) file
288 /// systems are ignored and the information of a mounted NFS **cannot** be obtained
289 /// via [`Disks::refresh_list`]. This is due to the fact that I/O function
290 /// `statvfs` used by [`Disks::refresh_list`] is blocking and
291 /// [may hang](https://github.com/GuillaumeGomez/sysinfo/pull/876) in some cases,
292 /// requiring to call `systemctl stop` to terminate the NFS service from the remote
293 /// server in some cases.
294 ///
295 /// ```no_run
296 /// use sysinfo::Disks;
297 ///
298 /// let mut disks = Disks::new();
299 /// disks.refresh_list();
300 /// ```
301 pub fn refresh_list(&mut self) {
302 self.inner.refresh_list();
303 }
304}
305
306impl std::ops::Deref for Disks {
307 type Target = [Disk];
308
309 fn deref(&self) -> &Self::Target {
310 self.list()
311 }
312}
313
314impl std::ops::DerefMut for Disks {
315 fn deref_mut(&mut self) -> &mut Self::Target {
316 self.list_mut()
317 }
318}
319
320/// Enum containing the different supported kinds of disks.
321///
322/// This type is returned by [`Disk::kind`](`crate::Disk::kind`).
323///
324/// ```no_run
325/// use sysinfo::Disks;
326///
327/// let disks = Disks::new_with_refreshed_list();
328/// for disk in disks.list() {
329/// println!("{:?}: {:?}", disk.name(), disk.kind());
330/// }
331/// ```
332#[derive(Debug, PartialEq, Eq, Clone, Copy)]
333pub enum DiskKind {
334 /// HDD type.
335 HDD,
336 /// SSD type.
337 SSD,
338 /// Unknown type.
339 Unknown(isize),
340}
341
342impl fmt::Display for DiskKind {
343 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
344 f.write_str(data:match *self {
345 DiskKind::HDD => "HDD",
346 DiskKind::SSD => "SSD",
347 _ => "Unknown",
348 })
349 }
350}
351