| 1 | // Take a look at the license at the top of the repository in the LICENSE file. | 
| 2 |  | 
|---|
| 3 | use std::ffi::OsStr; | 
|---|
| 4 | use std::fmt; | 
|---|
| 5 | use 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 | /// ``` | 
|---|
| 17 | pub struct Disk { | 
|---|
| 18 | pub(crate) inner: crate::DiskInner, | 
|---|
| 19 | } | 
|---|
| 20 |  | 
|---|
| 21 | impl 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. | 
|---|
| 154 | pub struct Disks { | 
|---|
| 155 | inner: crate::DisksInner, | 
|---|
| 156 | } | 
|---|
| 157 |  | 
|---|
| 158 | impl Default for Disks { | 
|---|
| 159 | fn default() -> Self { | 
|---|
| 160 | Self::new() | 
|---|
| 161 | } | 
|---|
| 162 | } | 
|---|
| 163 |  | 
|---|
| 164 | impl From<Disks> for Vec<Disk> { | 
|---|
| 165 | fn from(disks: Disks) -> Vec<Disk> { | 
|---|
| 166 | disks.inner.into_vec() | 
|---|
| 167 | } | 
|---|
| 168 | } | 
|---|
| 169 |  | 
|---|
| 170 | impl 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 |  | 
|---|
| 178 | impl<'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 |  | 
|---|
| 187 | impl<'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 |  | 
|---|
| 196 | impl 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 |  | 
|---|
| 306 | impl std::ops::Deref for Disks { | 
|---|
| 307 | type Target = [Disk]; | 
|---|
| 308 |  | 
|---|
| 309 | fn deref(&self) -> &Self::Target { | 
|---|
| 310 | self.list() | 
|---|
| 311 | } | 
|---|
| 312 | } | 
|---|
| 313 |  | 
|---|
| 314 | impl 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)] | 
|---|
| 333 | pub enum DiskKind { | 
|---|
| 334 | /// HDD type. | 
|---|
| 335 | HDD, | 
|---|
| 336 | /// SSD type. | 
|---|
| 337 | SSD, | 
|---|
| 338 | /// Unknown type. | 
|---|
| 339 | Unknown(isize), | 
|---|
| 340 | } | 
|---|
| 341 |  | 
|---|
| 342 | impl 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 |  | 
|---|