ioctl: add conversions of errors to Errno
This is convenient for the cases where we want to convert the errors
back to their original code, including those we decided should be
specially handled by the caller.
diff --git a/lib/src/ioctl.rs b/lib/src/ioctl.rs
index 52088fd..7cbc30e 100644
--- a/lib/src/ioctl.rs
+++ b/lib/src/ioctl.rs
@@ -31,6 +31,7 @@
pub use g_fmt::*;
pub use g_selection::*;
pub use mmap::*;
+use nix::errno::Errno;
pub use qbuf::*;
pub use querybuf::*;
pub use querycap::*;
@@ -113,3 +114,17 @@
QueueType::VideoCaptureMplane | QueueType::VideoOutputMplane
)
}
+
+/// Extension trait for allowing easy conversion of ioctl errors into their originating error code.
+pub trait IntoErrno {
+ fn into_errno(self) -> i32;
+}
+
+impl<T> IntoErrno for T
+where
+ T: Into<Errno>,
+{
+ fn into_errno(self) -> i32 {
+ self.into() as i32
+ }
+}
diff --git a/lib/src/ioctl/decoder_cmd.rs b/lib/src/ioctl/decoder_cmd.rs
index ec551d6..6fff403 100644
--- a/lib/src/ioctl/decoder_cmd.rs
+++ b/lib/src/ioctl/decoder_cmd.rs
@@ -1,6 +1,5 @@
use crate::bindings;
use nix::errno::Errno;
-use nix::Error;
use std::{mem, os::unix::io::AsRawFd};
use thiserror::Error;
@@ -28,10 +27,20 @@
#[error("command not supported by device")]
UnsupportedCommand(DecoderCommand),
#[error("ioctl error: {0}")]
- IoctlError(Error),
+ IoctlError(Errno),
}
-fn map_nix_error(error: nix::Error, command: DecoderCommand) -> DecoderCmdError {
+impl From<DecoderCmdError> for Errno {
+ fn from(err: DecoderCmdError) -> Self {
+ match err {
+ DecoderCmdError::DrainInProgress => Errno::EBUSY,
+ DecoderCmdError::UnsupportedCommand(_) => Errno::EINVAL,
+ DecoderCmdError::IoctlError(e) => e,
+ }
+ }
+}
+
+fn map_nix_error(error: Errno, command: DecoderCommand) -> DecoderCmdError {
match error {
Errno::EBUSY => DecoderCmdError::DrainInProgress,
Errno::EINVAL => DecoderCmdError::UnsupportedCommand(command),
diff --git a/lib/src/ioctl/dqbuf.rs b/lib/src/ioctl/dqbuf.rs
index b0ef3f6..fbe1bb4 100644
--- a/lib/src/ioctl/dqbuf.rs
+++ b/lib/src/ioctl/dqbuf.rs
@@ -2,7 +2,7 @@
use crate::bindings;
use crate::QueueType;
-use nix::{self, errno::Errno, Error};
+use nix::{self, errno::Errno};
use std::mem;
use std::os::unix::io::AsRawFd;
use std::{fmt::Debug, pin::Pin};
@@ -216,11 +216,11 @@
#[error("no buffer ready for dequeue")]
NotReady,
#[error("ioctl error: {0}")]
- IoctlError(Error),
+ IoctlError(Errno),
}
-impl From<Error> for DqBufError {
- fn from(error: Error) -> Self {
+impl From<Errno> for DqBufError {
+ fn from(error: Errno) -> Self {
match error {
Errno::EAGAIN => Self::NotReady,
Errno::EPIPE => Self::Eos,
@@ -229,6 +229,16 @@
}
}
+impl From<DqBufError> for Errno {
+ fn from(err: DqBufError) -> Self {
+ match err {
+ DqBufError::Eos => Errno::EPIPE,
+ DqBufError::NotReady => Errno::EAGAIN,
+ DqBufError::IoctlError(e) => e,
+ }
+ }
+}
+
pub type DqBufResult<T> = Result<T, DqBufError>;
/// Safe wrapper around the `VIDIOC_DQBUF` ioctl.
diff --git a/lib/src/ioctl/encoder_cmd.rs b/lib/src/ioctl/encoder_cmd.rs
index 2b3769c..56dc567 100644
--- a/lib/src/ioctl/encoder_cmd.rs
+++ b/lib/src/ioctl/encoder_cmd.rs
@@ -1,6 +1,5 @@
use crate::bindings;
use nix::errno::Errno;
-use nix::Error;
use std::{mem, os::unix::io::AsRawFd};
use thiserror::Error;
@@ -26,10 +25,20 @@
#[error("command not supported by device")]
UnsupportedCommand(EncoderCommand),
#[error("ioctl error: {0}")]
- IoctlError(Error),
+ IoctlError(Errno),
}
-fn map_nix_error(error: nix::Error, command: EncoderCommand) -> EncoderCmdError {
+impl From<EncoderCmdError> for Errno {
+ fn from(err: EncoderCmdError) -> Self {
+ match err {
+ EncoderCmdError::DrainInProgress => Errno::EBUSY,
+ EncoderCmdError::UnsupportedCommand(_) => Errno::EINVAL,
+ EncoderCmdError::IoctlError(e) => e,
+ }
+ }
+}
+
+fn map_nix_error(error: Errno, command: EncoderCommand) -> EncoderCmdError {
match error {
Errno::EBUSY => EncoderCmdError::DrainInProgress,
Errno::EINVAL => EncoderCmdError::UnsupportedCommand(command),
diff --git a/lib/src/ioctl/enum_fmt.rs b/lib/src/ioctl/enum_fmt.rs
index 44cbdf9..e7e058d 100644
--- a/lib/src/ioctl/enum_fmt.rs
+++ b/lib/src/ioctl/enum_fmt.rs
@@ -82,6 +82,14 @@
IoctlError(#[from] nix::Error),
}
+impl From<EnumFmtError> for Errno {
+ fn from(err: EnumFmtError) -> Self {
+ match err {
+ EnumFmtError::IoctlError(e) => e,
+ }
+ }
+}
+
/// Safe wrapper around the `VIDIOC_ENUM_FMT` ioctl.
pub fn enum_fmt<T: EnumFmt, F: AsRawFd>(
fd: &F,
diff --git a/lib/src/ioctl/expbuf.rs b/lib/src/ioctl/expbuf.rs
index dc1c1fa..7dae7df 100644
--- a/lib/src/ioctl/expbuf.rs
+++ b/lib/src/ioctl/expbuf.rs
@@ -1,5 +1,6 @@
//! Safe wrapper for the `VIDIOC_EXPBUF` ioctl.
use bitflags::bitflags;
+use nix::errno::Errno;
use nix::fcntl::OFlag;
use std::mem;
use std::os::unix::io::{AsRawFd, FromRawFd};
@@ -26,7 +27,15 @@
#[derive(Debug, Error)]
pub enum ExpbufError {
#[error("ioctl error: {0}")]
- IoctlError(#[from] nix::Error),
+ IoctlError(#[from] Errno),
+}
+
+impl From<ExpbufError> for Errno {
+ fn from(err: ExpbufError) -> Self {
+ match err {
+ ExpbufError::IoctlError(e) => e,
+ }
+ }
}
/// Safe wrapper around the `VIDIOC_EXPBUF` ioctl.
diff --git a/lib/src/ioctl/g_fmt.rs b/lib/src/ioctl/g_fmt.rs
index 9d21cd8..97cc464 100644
--- a/lib/src/ioctl/g_fmt.rs
+++ b/lib/src/ioctl/g_fmt.rs
@@ -124,6 +124,16 @@
IoctlError(nix::Error),
}
+impl From<GFmtError> for Errno {
+ fn from(err: GFmtError) -> Self {
+ match err {
+ GFmtError::FromV4L2FormatConversionError(_) => Errno::EINVAL,
+ GFmtError::InvalidBufferType => Errno::EINVAL,
+ GFmtError::IoctlError(e) => e,
+ }
+ }
+}
+
/// Safe wrapper around the `VIDIOC_G_FMT` ioctl.
pub fn g_fmt<E: Into<FormatConversionError>, T: Fmt<E>, F: AsRawFd>(
fd: &F,
@@ -155,6 +165,18 @@
IoctlError(nix::Error),
}
+impl From<SFmtError> for Errno {
+ fn from(err: SFmtError) -> Self {
+ match err {
+ SFmtError::FromV4L2FormatConversionError(_) => Errno::EINVAL,
+ SFmtError::ToV4L2FormatConversionError(_) => Errno::EINVAL,
+ SFmtError::InvalidBufferType => Errno::EINVAL,
+ SFmtError::DeviceBusy => Errno::EBUSY,
+ SFmtError::IoctlError(e) => e,
+ }
+ }
+}
+
/// Safe wrapper around the `VIDIOC_S_FMT` ioctl.
pub fn s_fmt<E: Into<FormatConversionError>, T: Fmt<E>, F: AsRawFd>(
fd: &mut F,
@@ -185,6 +207,17 @@
IoctlError(nix::Error),
}
+impl From<TryFmtError> for Errno {
+ fn from(err: TryFmtError) -> Self {
+ match err {
+ TryFmtError::FromV4L2FormatConversionError(_) => Errno::EINVAL,
+ TryFmtError::ToV4L2FormatConversionError(_) => Errno::EINVAL,
+ TryFmtError::InvalidBufferType => Errno::EINVAL,
+ TryFmtError::IoctlError(e) => e,
+ }
+ }
+}
+
/// Safe wrapper around the `VIDIOC_TRY_FMT` ioctl.
pub fn try_fmt<E: Into<FormatConversionError>, T: Fmt<E>, F: AsRawFd>(
fd: &F,
diff --git a/lib/src/ioctl/g_selection.rs b/lib/src/ioctl/g_selection.rs
index 19c48b2..2a83d3c 100644
--- a/lib/src/ioctl/g_selection.rs
+++ b/lib/src/ioctl/g_selection.rs
@@ -50,7 +50,16 @@
#[error("invalid type or target requested")]
Invalid,
#[error("ioctl error: {0}")]
- IoctlError(nix::Error),
+ IoctlError(Errno),
+}
+
+impl From<GSelectionError> for Errno {
+ fn from(err: GSelectionError) -> Self {
+ match err {
+ GSelectionError::Invalid => Errno::EINVAL,
+ GSelectionError::IoctlError(e) => e,
+ }
+ }
}
pub fn g_selection<F: AsRawFd, R: From<v4l2_rect>>(
@@ -83,6 +92,17 @@
IoctlError(nix::Error),
}
+impl From<SSelectionError> for Errno {
+ fn from(err: SSelectionError) -> Self {
+ match err {
+ SSelectionError::Invalid => Errno::EINVAL,
+ SSelectionError::InvalidRange => Errno::ERANGE,
+ SSelectionError::Busy => Errno::EBUSY,
+ SSelectionError::IoctlError(e) => e,
+ }
+ }
+}
+
pub fn s_selection<F: AsRawFd, RI: Into<v4l2_rect>, RO: From<v4l2_rect>>(
fd: &F,
selection: SelectionType,
diff --git a/lib/src/ioctl/mmap.rs b/lib/src/ioctl/mmap.rs
index 69accee..f6dd9ae 100644
--- a/lib/src/ioctl/mmap.rs
+++ b/lib/src/ioctl/mmap.rs
@@ -7,6 +7,7 @@
use log::error;
use nix::{
+ errno::Errno,
libc::{c_void, off_t, size_t},
sys::mman,
};
@@ -74,7 +75,15 @@
#[derive(Debug, Error)]
pub enum MmapError {
#[error("ioctl error: {0}")]
- IoctlError(#[from] nix::Error),
+ IoctlError(#[from] Errno),
+}
+
+impl From<MmapError> for Errno {
+ fn from(err: MmapError) -> Self {
+ match err {
+ MmapError::IoctlError(e) => e,
+ }
+ }
}
// TODO should be unsafe because the mapping can be used after a buffer is queued?
diff --git a/lib/src/ioctl/qbuf.rs b/lib/src/ioctl/qbuf.rs
index 2fe7a14..9de195d 100644
--- a/lib/src/ioctl/qbuf.rs
+++ b/lib/src/ioctl/qbuf.rs
@@ -4,10 +4,8 @@
use crate::{bindings, QueueType};
use bitflags::bitflags;
-use nix::{
- sys::time::{TimeVal, TimeValLike},
- Error,
-};
+use nix::errno::Errno;
+use nix::sys::time::{TimeVal, TimeValLike};
use std::fmt::Debug;
use std::mem;
use std::os::unix::io::AsRawFd;
@@ -35,12 +33,22 @@
#[error("data offset specified while using the single-planar API")]
DataOffsetNotSupported,
#[error("ioctl error: {0}")]
- IoctlError(Error),
+ IoctlError(Errno),
}
-impl From<Error> for QBufError {
- fn from(error: Error) -> Self {
- Self::IoctlError(error)
+impl From<Errno> for QBufError {
+ fn from(errno: Errno) -> Self {
+ Self::IoctlError(errno)
+ }
+}
+
+impl From<QBufError> for Errno {
+ fn from(err: QBufError) -> Self {
+ match err {
+ QBufError::NumPlanesMismatch(_, _) => Errno::EINVAL,
+ QBufError::DataOffsetNotSupported => Errno::EINVAL,
+ QBufError::IoctlError(e) => e,
+ }
}
}
diff --git a/lib/src/ioctl/querybuf.rs b/lib/src/ioctl/querybuf.rs
index 29ea03a..2f16157 100644
--- a/lib/src/ioctl/querybuf.rs
+++ b/lib/src/ioctl/querybuf.rs
@@ -1,6 +1,7 @@
use super::{is_multi_planar, BufferFlags, PlaneData};
use crate::bindings;
use crate::QueueType;
+use nix::errno::Errno;
use thiserror::Error;
use std::mem;
@@ -71,7 +72,15 @@
#[derive(Debug, Error)]
pub enum QueryBufError {
#[error("ioctl error: {0}")]
- IoctlError(#[from] nix::Error),
+ IoctlError(#[from] Errno),
+}
+
+impl From<QueryBufError> for Errno {
+ fn from(err: QueryBufError) -> Self {
+ match err {
+ QueryBufError::IoctlError(e) => e,
+ }
+ }
}
/// Safe wrapper around the `VIDIOC_QUERYBUF` ioctl.
diff --git a/lib/src/ioctl/querycap.rs b/lib/src/ioctl/querycap.rs
index b4cf15a..f7b0dfd 100644
--- a/lib/src/ioctl/querycap.rs
+++ b/lib/src/ioctl/querycap.rs
@@ -2,7 +2,7 @@
use super::string_from_cstr;
use crate::bindings;
use bitflags::bitflags;
-use nix::Error;
+use nix::errno::Errno;
use std::fmt;
use std::mem;
use std::os::unix::io::AsRawFd;
@@ -111,7 +111,15 @@
#[derive(Debug, Error)]
pub enum QueryCapError {
#[error("ioctl error: {0}")]
- IoctlError(Error),
+ IoctlError(Errno),
+}
+
+impl From<QueryCapError> for Errno {
+ fn from(err: QueryCapError) -> Self {
+ match err {
+ QueryCapError::IoctlError(e) => e,
+ }
+ }
}
/// Safe wrapper around the `VIDIOC_QUERYCAP` ioctl.
diff --git a/lib/src/ioctl/queryctrl.rs b/lib/src/ioctl/queryctrl.rs
index 57262fb..bfc87c0 100644
--- a/lib/src/ioctl/queryctrl.rs
+++ b/lib/src/ioctl/queryctrl.rs
@@ -3,7 +3,7 @@
use std::os::unix::io::AsRawFd;
use bitflags::bitflags;
-use nix::Error;
+use nix::errno::Errno;
use thiserror::Error;
use crate::bindings;
@@ -57,7 +57,15 @@
#[derive(Debug, Error)]
pub enum QueryCtrlError {
#[error("ioctl error: {0}")]
- IoctlError(Error),
+ IoctlError(Errno),
+}
+
+impl From<QueryCtrlError> for Errno {
+ fn from(err: QueryCtrlError) -> Self {
+ match err {
+ QueryCtrlError::IoctlError(e) => e,
+ }
+ }
}
/// Safe wrapper around the `VIDIOC_QUERYCTRL` ioctl.
diff --git a/lib/src/ioctl/reqbufs.rs b/lib/src/ioctl/reqbufs.rs
index 941abed..8264b78 100644
--- a/lib/src/ioctl/reqbufs.rs
+++ b/lib/src/ioctl/reqbufs.rs
@@ -80,6 +80,15 @@
IoctlError(nix::Error),
}
+impl From<ReqbufsError> for Errno {
+ fn from(err: ReqbufsError) -> Self {
+ match err {
+ ReqbufsError::InvalidBufferType(_, _) => Errno::EINVAL,
+ ReqbufsError::IoctlError(e) => e,
+ }
+ }
+}
+
/// Safe wrapper around the `VIDIOC_REQBUFS` ioctl.
pub fn reqbufs<T: ReqBufs, F: AsRawFd>(
fd: &F,
diff --git a/lib/src/ioctl/streamon.rs b/lib/src/ioctl/streamon.rs
index 6fa425a..26413bd 100644
--- a/lib/src/ioctl/streamon.rs
+++ b/lib/src/ioctl/streamon.rs
@@ -1,7 +1,6 @@
//! Safe wrapper for the `VIDIOC_STREAM(ON|OFF)` ioctls.
use crate::QueueType;
use nix::errno::Errno;
-use nix::Error;
use std::os::unix::io::AsRawFd;
use thiserror::Error;
@@ -20,7 +19,18 @@
#[error("invalid pipeline link configuration")]
InvalidPipelineConfig,
#[error("ioctl error: {0}")]
- IoctlError(Error),
+ IoctlError(Errno),
+}
+
+impl From<StreamOnError> for Errno {
+ fn from(err: StreamOnError) -> Self {
+ match err {
+ StreamOnError::InvalidQueue(_) => Errno::EINVAL,
+ StreamOnError::InvalidPadConfig => Errno::EPIPE,
+ StreamOnError::InvalidPipelineConfig => Errno::ENOLINK,
+ StreamOnError::IoctlError(e) => e,
+ }
+ }
}
/// Safe wrapper around the `VIDIOC_STREAMON` ioctl.
@@ -39,7 +49,16 @@
#[error("queue type not supported")]
InvalidQueue,
#[error("ioctl error: {0}")]
- IoctlError(Error),
+ IoctlError(Errno),
+}
+
+impl From<StreamOffError> for Errno {
+ fn from(err: StreamOffError) -> Self {
+ match err {
+ StreamOffError::InvalidQueue => Errno::EINVAL,
+ StreamOffError::IoctlError(e) => e,
+ }
+ }
}
/// Safe wrapper around the `VIDIOC_STREAMOFF` ioctl.
diff --git a/lib/src/ioctl/subscribe_event.rs b/lib/src/ioctl/subscribe_event.rs
index 5aaf0d4..d9bb3da 100644
--- a/lib/src/ioctl/subscribe_event.rs
+++ b/lib/src/ioctl/subscribe_event.rs
@@ -104,7 +104,15 @@
#[derive(Debug, Error)]
pub enum SubscribeEventError {
#[error("ioctl error: {0}")]
- IoctlError(#[from] nix::Error),
+ IoctlError(#[from] Errno),
+}
+
+impl From<SubscribeEventError> for Errno {
+ fn from(err: SubscribeEventError) -> Self {
+ match err {
+ SubscribeEventError::IoctlError(e) => e,
+ }
+ }
}
pub fn subscribe_event(
@@ -146,11 +154,11 @@
#[error("error while converting event")]
EventConversionError(#[from] EventConversionError),
#[error("ioctl error: {0}")]
- IoctlError(nix::Error),
+ IoctlError(Errno),
}
-impl From<nix::Error> for DqEventError {
- fn from(error: nix::Error) -> Self {
+impl From<Errno> for DqEventError {
+ fn from(error: Errno) -> Self {
match error {
Errno::ENOENT => Self::NotReady,
error => Self::IoctlError(error),
@@ -158,6 +166,16 @@
}
}
+impl From<DqEventError> for Errno {
+ fn from(err: DqEventError) -> Self {
+ match err {
+ DqEventError::NotReady => Errno::ENOENT,
+ DqEventError::EventConversionError(_) => Errno::EINVAL,
+ DqEventError::IoctlError(e) => e,
+ }
+ }
+}
+
pub fn dqevent(fd: &impl AsRawFd) -> Result<Event, DqEventError> {
// Safe because this struct is expected to be initialized to 0.
let mut event: bindings::v4l2_event = unsafe { mem::zeroed() };