use libc::{ msgctl, msgget, msginfo, msqid_ds, IPC_CREAT, IPC_EXCL, IPC_INFO, IPC_NOWAIT, IPC_PRIVATE, IPC_RMID, IPC_SET, IPC_STAT, MSG_COPY, MSG_EXCEPT, MSG_INFO, MSG_NOERROR, MSG_STAT, }; use nix::errno::{errno, Errno}; use std::{marker::PhantomData, mem::MaybeUninit, ptr}; use thiserror::Error; #[derive(Debug, Error)] pub enum SysvMqError { #[error("SysV message queue: {0}")] ErrnoError(&'static str), } /// IPC bit flags #[repr(i32)] pub enum Flags { /// Create key if key does not exist. CreateKey = IPC_CREAT, /// Fail if key exists. Exclusive = IPC_EXCL, /// Return error on wait. NoWait = IPC_NOWAIT, /// No error if message is too big. NoError = MSG_NOERROR, /// Receive any message except of specified type. Except = MSG_EXCEPT, /// Copy (not remove) all queue messages. Copy = MSG_COPY, /// Private key (Special key value). Private = IPC_PRIVATE, } /// Commands for `msgctl()` #[repr(i32)] pub enum ControlCommands { /// Remove identifier (Control command for `msgctl`, `semctl`, and `shmctl`). Remove = IPC_RMID, /// Set `ipc_perm` options (Control command for `msgctl`, `semctl`, and `shmctl`). SetPerm = IPC_SET, /// Get `ipc_perm` options (Control command for `msgctl`, `semctl`, and `shmctl`). GetPerm = IPC_STAT, /// See ipcs (Control command for `msgctl`, `semctl`, and `shmctl`). IpcInfo = IPC_INFO, /// IPCS control command. Stat = MSG_STAT, /// IPCS control command. MsgInfo = MSG_INFO, } pub fn unlink_id(id: i32) -> Result<(), SysvMqError> { let res = unsafe { msgctl( id, ControlCommands::Remove as i32, ptr::null::() as *mut msqid_ds, ) }; match res { -1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())), _ => Ok(()), } } pub fn id_from_key(key: i32) -> Result { let id = unsafe { msgget(key, 0) }; match id { -1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())), id => Ok(id), } } pub fn ipc_info(id: i32) -> Result<(), SysvMqError> { let mut msginfo = MaybeUninit::::uninit(); unsafe { msgctl( id, ControlCommands::IpcInfo as i32, msginfo.as_mut_ptr() as *mut msqid_ds, ); } let msginfo = unsafe { msginfo.assume_init() }; println!("info: {:?}", msginfo); Ok(()) } pub fn stat_info(id: i32) -> Result<(), SysvMqError> { let mut msginfo = MaybeUninit::::uninit(); unsafe { msgctl(id, ControlCommands::Stat as i32, msginfo.as_mut_ptr()); } let msginfo = unsafe { msginfo.assume_init() }; println!("info: {:?}", msginfo); Ok(()) } pub fn msg_info(id: i32) -> Result<(), SysvMqError> { let mut msginfo = MaybeUninit::::uninit(); unsafe { msgctl( id, ControlCommands::MsgInfo as i32, msginfo.as_mut_ptr() as *mut msqid_ds, ); } let msginfo = unsafe { msginfo.assume_init() }; println!("info: {:?}", msginfo); Ok(()) } pub struct SysvMq { pub id: i32, pub key: i32, message_mask: i32, mode: i32, types: PhantomData, } impl SysvMq { pub fn create(&mut self, key: i32) -> Result<&Self, SysvMqError> { self.key = key; self.id = unsafe { msgget(self.key, Flags::CreateKey as i32 | self.mode) }; match self.id { -1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())), _ => Ok(self), } } pub fn open(mut self, key: i32) -> Result { self.key = key; self.id = unsafe { msgget(self.key, self.mode) }; match self.id { -1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())), _ => Ok(self), } } pub fn mode(&mut self, mode: i32) -> &Self { self.mode = mode; self } pub fn nonblocking(&mut self) -> &Self { self.message_mask |= Flags::NoWait as i32; self } pub fn new() -> Self { SysvMq { id: -1, key: 0, message_mask: 0, mode: 0o644, types: PhantomData, } } } impl Default for SysvMq { fn default() -> Self { Self::new() } }