eject/platforms/linux/
device.rs

1use 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            // Try again without writing permission
26            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}