eject/platforms/linux/
device.rs1use super::{cdrom, scsi};
2use crate::{
3 device::DriveStatus,
4 error::{ErrorKind, Result},
5};
6use nix::{
7 fcntl::{open, OFlag},
8 libc::EINVAL,
9 sys::stat::Mode,
10 unistd::close,
11};
12use std::{os::unix::prelude::RawFd, path::Path};
13
14pub struct DeviceHandle(pub RawFd);
15
16impl DeviceHandle {
17 pub fn open(path: impl AsRef<Path>) -> Result<Self> {
18 let mut result: Result<RawFd> = open(
19 path.as_ref(),
20 OFlag::O_RDWR | OFlag::O_NONBLOCK,
21 Mode::empty(),
22 )
23 .map_err(Into::into);
24 if result.as_ref().err().map(|e| e.kind) == Some(ErrorKind::AccessDenied) {
25 result = open(
27 path.as_ref(),
28 OFlag::O_RDONLY | OFlag::O_NONBLOCK,
29 Mode::empty(),
30 )
31 .map_err(Into::into);
32 }
33 if let Err(err) = &mut result {
34 if err.code == EINVAL {
35 err.kind = ErrorKind::InvalidPath;
36 }
37 }
38 result.map(Self)
39 }
40
41 pub fn eject(&self) -> Result<()> {
42 if cdrom::set_ejection_lock(self.0, false)
43 .and_then(|_| cdrom::eject(self.0))
44 .is_ok()
45 {
46 return Ok(());
47 }
48 scsi::set_ejection_lock(self.0, false)?;
49 scsi::eject(self.0)
50 }
51
52 pub fn retract(&self) -> Result<()> {
53 if cdrom::retract(self.0).is_ok() {
54 return Ok(());
55 }
56 scsi::retract(self.0)
57 }
58
59 pub fn set_ejection_lock(&self, locked: bool) -> Result<()> {
60 if cdrom::set_ejection_lock(self.0, locked).is_ok() {
61 return Ok(());
62 }
63 scsi::set_ejection_lock(self.0, locked)
64 }
65
66 pub fn status(&self) -> Result<DriveStatus> {
67 cdrom::status(self.0, 0)
68 }
69}
70
71impl Drop for DeviceHandle {
72 fn drop(&mut self) {
73 let _ = close(self.0);
74 }
75}