diff --git a/src/completion_queue.rs b/src/completion_queue.rs index 867fb1a..4017aa1 100644 --- a/src/completion_queue.rs +++ b/src/completion_queue.rs @@ -10,7 +10,7 @@ use super::{IoUring, CQE, CQEs, CQEsBlocking, resultify}; /// /// Each element is a [`CQE`](crate::cqe::CQE). /// -/// Completion does not imply success. Completed events may be [timeouts](crate::cqe::CQE::is_iou_timeout). +/// Completion does not imply success; the event may have errored. pub struct CompletionQueue<'ring> { pub(crate) ring: NonNull, _marker: PhantomData<&'ring mut IoUring>, diff --git a/src/lib.rs b/src/lib.rs index c9638d5..e4b887a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,9 +30,7 @@ //! //! A timeout is submitted as an additional IO event which completes after the specified time. //! Therefore when you create a timeout, all that happens is that a completion event will appear -//! after that specified time. This also means that when processing completion events, you need to -//! be prepared for the possibility that the completion represents a timeout and not a normal IO -//! event (`CQE` has a method to check for this). +//! after that specified time. /// Types related to completion queue events. pub mod cqe; diff --git a/src/registrar/mod.rs b/src/registrar/mod.rs index 1c31fbb..9340667 100644 --- a/src/registrar/mod.rs +++ b/src/registrar/mod.rs @@ -259,6 +259,62 @@ impl fmt::Debug for Registrar<'_> { unsafe impl<'ring> Send for Registrar<'ring> { } unsafe impl<'ring> Sync for Registrar<'ring> { } +/// An opaque struct representing a process's credentials. +/// +/// You can obtain a process's `Personality` using the registrar's +/// [`register_personality`](crate::registrar::Registrar::register_personality) method +/// and then use it to issue `SQEs` with that process's credentials. This may be useful if +/// you are sharing a ring between users. +/// ```no_run +/// use std::io; +/// use std::fs::File; +/// use std::ffi::CString; +/// use std::os::unix::fs::PermissionsExt; +/// use nix::libc; +/// use nix::unistd::{geteuid, seteuid, Uid}; +/// use iou::sqe::{Mode, OFlag}; +/// +/// fn main() -> io::Result<()> { +/// if (!geteuid().is_root()) { panic!("example requires root"); } +/// +/// let mut ring = iou::IoUring::new(1)?; +/// let path = "personality-tmp.txt"; +/// let c_path = CString::new(path).unwrap(); +/// +/// // create a file only accessible by the owner +/// { +/// let f = File::create(path)?; +/// let mut perms = f.metadata()?.permissions(); +/// perms.set_mode(0o600); +/// std::fs::set_permissions(path, perms)?; +/// } +/// +/// let pers = ring.registrar().register_personality()?; +/// +/// // other users can't access that file normally... +/// seteuid(Uid::from_raw(2000)).unwrap(); +/// unsafe { +/// let mut sqe = ring.prepare_sqe().unwrap(); +/// sqe.prep_openat(libc::AT_FDCWD, &c_path, OFlag::O_RDONLY, Mode::empty()); +/// } +/// ring.submit_sqes()?; +/// assert!(ring.wait_for_cqe()?.result().is_err()); +/// +/// // ... but they can use the process's Personality to perform IO +/// // as if they were that process. +/// unsafe { +/// let mut sqe = ring.prepare_sqe().unwrap(); +/// sqe.prep_openat(libc::AT_FDCWD, &c_path, OFlag::O_RDONLY, Mode::empty()); +/// sqe.set_personality(pers); +/// } +/// ring.submit_sqes()?; +/// assert!(ring.wait_for_cqe()?.result().is_ok()); +/// +/// seteuid(Uid::from_raw(0)).unwrap(); +/// let _ = std::fs::remove_file(&path); +/// Ok(()) +/// } +/// ``` #[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Clone, Copy)] pub struct Personality { pub(crate) id: u16, diff --git a/src/sqe.rs b/src/sqe.rs index 7b6f70a..acad2c8 100644 --- a/src/sqe.rs +++ b/src/sqe.rs @@ -106,7 +106,7 @@ impl<'a> SQE<'a> { /// Prepare a read on a file descriptor. /// /// Both the file descriptor and the buffer can be pre-registered. See the - /// [`registrar][crate::registrar] module for more information. + /// [`registrar`][crate::registrar] module for more information. #[inline] pub unsafe fn prep_read( &mut self, @@ -154,7 +154,7 @@ impl<'a> SQE<'a> { /// Prepare a write on a file descriptor. /// /// Both the file descriptor and the buffer can be pre-registered. See the - /// [`registrar][crate::registrar] module for more information. + /// [`registrar`][crate::registrar] module for more information. #[inline] pub unsafe fn prep_write( &mut self,