Skip to main content

linux_media/
error.rs

1use std::fmt;
2use std::io;
3use std::os::fd::{AsRawFd, RawFd};
4use std::path::PathBuf;
5
6pub type Result<T> = std::result::Result<T, Error>;
7
8#[derive(Debug)]
9pub enum Error {
10    /// Generic io error
11    Io { source: io::Error, path: PathBuf },
12    /// File not found
13    FileNotFound { path: PathBuf, source: io::Error },
14    /// Generic ioctl error
15    /// `code` is constructed from [`std::io::Error::from_raw_os_error`].
16    Ioctl {
17        fd: RawFd,
18        code: io::Error,
19        api: libc::c_ulong,
20    },
21    /// The ioctl is not supported by the file descriptor.
22    NotSupportedIoctl {
23        fd: RawFd,
24        code: libc::c_int,
25        api: libc::c_ulong,
26    },
27    /// The ioctl can’t be handled because the device is busy. This is typically return while device is streaming, and an ioctl tried to change something that would affect the stream, or would require the usage of a hardware resource that was already allocated. The ioctl must not be retried without performing another action to fix the problem first (typically: stop the stream before retrying).
28    DeviceIsBusy {
29        fd: RawFd,
30        code: libc::c_int,
31        api: libc::c_ulong,
32    },
33    /// The request was already queued or the application queued the first buffer directly, but later attempted to use a request.
34    RequestIsAlreadyQueued {
35        fd: RawFd,
36        code: libc::c_int,
37        api: libc::c_ulong,
38    },
39    /// The request did not contain any buffers. All requests are required to have at least one buffer. This can also be returned if some required configuration is missing in the request.
40    RequestNotContainBuffers {
41        fd: RawFd,
42        code: libc::c_int,
43        api: libc::c_ulong,
44    },
45    /// Out of memory when allocating internal data structures for a request.
46    OutOfMemory {
47        fd: RawFd,
48        code: libc::c_int,
49        api: libc::c_ulong,
50    },
51    /// Request has invalid data
52    RequestHasInvalidData {
53        fd: RawFd,
54        code: libc::c_int,
55        api: libc::c_ulong,
56    },
57    /// The hardware is in a bad state. To recover, the application needs to stop streaming to reset the hardware state and then try to restart streaming.
58    HardwareBadState {
59        fd: RawFd,
60        code: libc::c_int,
61        api: libc::c_ulong,
62    },
63    /// parse error as [`crate::MediaInterfaceType`]
64    InterfaceTypeParseError { from: u32 },
65    /// parse error as [`crate::MediaEntityFunctions`]
66    EntityFunctionsParseError { from: u32 },
67    /// parse error as [`crate::MediaEntityFlags`]
68    EntityFlagsParseError { from: u32 },
69    /// parse error as [`crate::MediaPadFlags`]
70    PadFlagsParseError { from: u32 },
71    /// parse error as [`crate::MediaLinkFlags`]
72    LinkFlagsParseError { from: u32 },
73}
74
75impl Error {
76    /// Constructs an Error from an ioctl failure
77    ///
78    /// # Arguments
79    /// - `fd`  : The file descriptor on which the ioctl error occurred.
80    /// - `code`: The return code from the ioctl call.
81    /// - `api` : The kind of operation that resulted in the error.
82    ///
83    /// # References
84    /// <https://www.kernel.org/doc/html/v6.9/userspace-api/media/gen-errors.html>
85    pub fn ioctl_error<F>(fd: F, code: libc::c_int, api: libc::c_ulong) -> Error
86    where
87        F: AsRawFd,
88    {
89        use Error::*;
90        let fd = fd.as_raw_fd();
91        match code {
92            libc::EBUSY => DeviceIsBusy { fd, code, api },
93            libc::ENOTTY => NotSupportedIoctl { fd, code, api },
94            _ => Ioctl {
95                fd,
96                code: io::Error::from_raw_os_error(code),
97                api,
98            },
99        }
100    }
101}
102
103impl fmt::Display for Error {
104    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105        use Error::*;
106        match self {
107            Io { path, .. } => write!(f, "io error: {}", path.display()),
108            FileNotFound { path, .. } => write!(f, "file not found: {}", path.display()),
109            Ioctl { fd, code, api } => {
110                write!(f, "generic ioctl error {}: 0x{:02X}: {}", fd, api, code)
111            }
112            NotSupportedIoctl { fd, code, api } => write!(
113                f,
114                "the ioctl is not supported by the file descriptor {}: 0x{:02X}: {}",
115                fd, api, code
116            ),
117            DeviceIsBusy { fd, code, api } => {
118                write!(f, "the device is busy {}: 0x{:02X}: {}", fd, api, code)
119            }
120            RequestIsAlreadyQueued { fd, code, api } => {
121                write!(
122                    f,
123                    "the request is already queued {}: 0x{:02X}: {}",
124                    fd, api, code
125                )
126            }
127            RequestNotContainBuffers { fd, code, api } => {
128                write!(
129                    f,
130                    "the request did not contain any buffers {}: 0x{:02X}: {}",
131                    fd, api, code
132                )
133            }
134            OutOfMemory { fd, code, api } => {
135                write!(f, "Out of memory when allocating internal data structures for this request. {}: 0x{:02X}: {}", fd, api, code)
136            }
137            RequestHasInvalidData { fd, code, api } => {
138                write!(
139                    f,
140                    "The request has invalid data. {}: 0x{:02X}: {}",
141                    fd, api, code
142                )
143            }
144            HardwareBadState { fd, code, api } => {
145                write!(f, "The hardware is in a bad state. To recover, the application needs to stop streaming to reset the hardware state and then try to restart streaming. {}: 0x{:02X}: {}", fd, api, code)
146            }
147            InterfaceTypeParseError { from, .. } => {
148                write!(f, "interface type parse error: {}", from)
149            }
150            EntityFunctionsParseError { from, .. } => {
151                write!(f, "entity functions parse error: {}", from)
152            }
153            EntityFlagsParseError { from, .. } => {
154                write!(f, "entity flags parse error: {}", from)
155            }
156            PadFlagsParseError { from, .. } => {
157                write!(f, "pad flags parse error: {}", from)
158            }
159            LinkFlagsParseError { from, .. } => {
160                write!(f, "link flags parse error: {}", from)
161            }
162        }
163    }
164}
165
166pub fn trap_io_error(err: io::Error, path: PathBuf) -> Error {
167    use io::ErrorKind::*;
168    match err.kind() {
169        NotFound => Error::FileNotFound { path, source: err },
170        _ => Error::Io { source: err, path },
171    }
172}
173
174#[cfg(test)]
175pub mod test {
176    use super::*;
177
178    // https://www.kernel.org/doc/html/v6.9/userspace-api/media/gen-errors.html
179    #[test]
180    fn enotty_is_not_supported() {
181        use Error::*;
182        let err = NotSupportedIoctl {
183            fd: 0,
184            code: libc::ENOTTY,
185            api: 0,
186        };
187        assert!(matches!(
188            err,
189            NotSupportedIoctl {
190                code: libc::ENOTTY,
191                ..
192            }
193        ));
194    }
195}