Implement creation of SysV IPC message queues

This adds the `sysvmq` package which handles SysV IPC message queues.
For consistency the parameter for `permissions` is renamed to `mode`
also for POSIX message queues.
This commit is contained in:
finga 2021-07-07 20:23:04 +02:00
parent a468c5d7bb
commit 4d200bb5f3
11 changed files with 271 additions and 10 deletions

66
Cargo.lock generated
View file

@ -40,6 +40,12 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "cc"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -152,9 +158,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.97" version = "0.2.98"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
[[package]] [[package]]
name = "log" name = "log"
@ -171,6 +177,15 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "memoffset"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "mqrs" name = "mqrs"
version = "0.1.1" version = "0.1.1"
@ -182,6 +197,20 @@ dependencies = [
"humantime", "humantime",
"log", "log",
"posixmq", "posixmq",
"sysvmq",
]
[[package]]
name = "nix"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c3728fec49d363a50a8828a190b379a446cc5cf085c06259bbbeb34447e4ec7"
dependencies = [
"bitflags",
"cc",
"cfg-if",
"libc",
"memoffset",
] ]
[[package]] [[package]]
@ -294,6 +323,15 @@ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "sysvmq"
version = "0.1.0"
dependencies = [
"libc",
"nix",
"thiserror",
]
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.1.2" version = "1.1.2"
@ -312,6 +350,26 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "thiserror"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.44" version = "0.1.44"
@ -325,9 +383,9 @@ dependencies = [
[[package]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.7.1" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"

View file

@ -3,9 +3,12 @@ name = "mqrs"
version = "0.1.1" version = "0.1.1"
authors = ["finga <mqrs@onders.org>"] authors = ["finga <mqrs@onders.org>"]
edition = "2018" edition = "2018"
repository = "https://git.onders.org/finga/mqrs"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
readme = "README.md" readme = "README.md"
description = "A CLI program for interacting with Posix Message Queues." description = "A CLI program for interacting with Posix Message Queues."
keywords = ["message_queue", "mq", "mqueue", "queue"]
categories = ["command-line-utilities"]
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
@ -15,6 +18,10 @@ chrono = "0.4"
humantime = "2.1" humantime = "2.1"
log = "0.4" log = "0.4"
env_logger = "0.8" env_logger = "0.8"
sysvmq = { path = "sysvmq" }
[workspace]
members = ["sysvmq"]
[package.metadata.deb] [package.metadata.deb]
extended-description = "`mqrs` is a small cli application to handle POSIX message queues." extended-description = "`mqrs` is a small cli application to handle POSIX message queues."

View file

@ -22,7 +22,7 @@ The POSIX backend supports six commands: `create`, `info`, `list`,
Use the `create` command to create a new POSIX message queue. Following Use the `create` command to create a new POSIX message queue. Following
optional arguments are supported: optional arguments are supported:
- `-c`, `--capacity`: Maximum number of messages in the queue - `-c`, `--capacity`: Maximum number of messages in the queue
- `-p`, `--permissions`: Permissions (octal) to create the queue with - `-m`, `--mode`: Permissions (octal) to create the queue with
- `-s`, `--msgsize`: Message size in bytes - `-s`, `--msgsize`: Message size in bytes
#### Print information about a message queue #### Print information about a message queue
@ -58,4 +58,10 @@ queue. Following optional arguments are supported:
- `-o,` `--timeout <timeout>`: As for example in "5h 23min 42ms" - `-o,` `--timeout <timeout>`: As for example in "5h 23min 42ms"
### SysV IPC message queues ### SysV IPC message queues
The SysV IPC backend supports no commands yet. The SysV IPC backend supports one command: `create`.
#### Create a message queue
Use the `create` command to create a new SysV IPC message
queue. Following optional arguments are supported:
- `-m`, `--mode`: Permissions (octal) to create the queue
with. Default: 0644.

32
mqrs.1
View file

@ -62,13 +62,14 @@ Produce verbose output
.TP 8 .TP 8
.SS OPTIONS .SS OPTIONS
.RS .RS
.TP 8
.B \-c, \-\-capacity \fI<capacity>\fP .B \-c, \-\-capacity \fI<capacity>\fP
Maximum number of messages in the queue Maximum number of messages in the queue
.TP 8 .TP 8
.B \-s, \-\-msgsize \fI<msgsize>\fP .B \-s, \-\-msgsize \fI<msgsize>\fP
Message size in bytes Message size in bytes
.TP 8 .TP 8
.B \-p, \-\-permissions \fI<permissions>\fP .B \-m, \-\-mode \fI<mode>\fP
Permissions (octal) to create the queue with Permissions (octal) to create the queue with
.RE .RE
.SS help [SUBCOMMAND] .SS help [SUBCOMMAND]
@ -210,7 +211,34 @@ Prints help information
Produce verbose output Produce verbose output
.RE .RE
.SH SYSV IPC MESSAGE QUEUE SUBCOMMANDS .SH SYSV IPC MESSAGE QUEUE SUBCOMMANDS
The SysV IPC backend supports no commands yet. The SysV IPC backend supports one command:
.B create\
.
.SS create [FLAGS] [OPTIONS] \fI<KEY>\fP
Create a new SysV IPC message queue.
.TP 8
.SS ARGS
.RS
.TP 8
.B \fI<KEY>\fP
Key of the new queue
.RE
.TP 8
.SS FLAGS
.RS
.TP 8
.B \-h, \-\-help
Prints help information
.TP 8
.B \-v, \-\-verbose
Produce verbose output
.TP 8
.SS OPTIONS
.RS
.TP 8
.B \-m, \-\-mode \fI<mode>\fP
Permissions (octal) to create the queue with (default: 0644)
.RE
.SH SEE ALSO .SH SEE ALSO
mq_overview(7) mq_overview(7)
.SH BUGS .SH BUGS

View file

@ -2,6 +2,7 @@ use anyhow::Result;
use clap::{crate_authors, crate_version, AppSettings, Clap}; use clap::{crate_authors, crate_version, AppSettings, Clap};
mod posix; mod posix;
mod sysv;
#[derive(Clap, Debug)] #[derive(Clap, Debug)]
enum Backend { enum Backend {
@ -23,6 +24,7 @@ enum PosixCommand {
#[derive(Clap, Debug)] #[derive(Clap, Debug)]
enum SysvCommand { enum SysvCommand {
Create(sysv::Create),
} }
#[derive(Clap, Debug)] #[derive(Clap, Debug)]
@ -65,6 +67,7 @@ fn main() -> Result<()> {
PosixCommand::Recv(r) => r.run()?, PosixCommand::Recv(r) => r.run()?,
}, },
Backend::Sysv(s) => match s { Backend::Sysv(s) => match s {
SysvCommand::Create(c) => c.run()?,
}, },
} }

View file

@ -9,7 +9,7 @@ use std::fs;
pub struct Create { pub struct Create {
/// Permissions (octal) to create the queue with /// Permissions (octal) to create the queue with
#[clap(short, long)] #[clap(short, long)]
permissions: Option<String>, mode: Option<String>,
/// Maximum number of messages in the queue /// Maximum number of messages in the queue
#[clap(short, long)] #[clap(short, long)]
capacity: Option<usize>, capacity: Option<usize>,
@ -39,7 +39,7 @@ impl Create {
pub fn run(&self) -> Result<()> { pub fn run(&self) -> Result<()> {
let mq = &mut posixmq::OpenOptions::readonly(); let mq = &mut posixmq::OpenOptions::readonly();
if let Some(m) = &self.permissions { if let Some(m) = &self.mode {
mq.mode(u32::from_str_radix(&m, 8)?); mq.mode(u32::from_str_radix(&m, 8)?);
} }

3
src/sysv.rs Normal file
View file

@ -0,0 +1,3 @@
mod create;
pub use create::Create;

31
src/sysv/create.rs Normal file
View file

@ -0,0 +1,31 @@
use anyhow::Result;
use clap::Clap;
use log::info;
use sysvmq::SysvMq;
/// Create a SysV message queue
#[derive(Clap, Debug)]
pub struct Create {
/// Permissions (octal) to create the queue with (default: 0644)
#[clap(short, long)]
mode: Option<String>,
/// Key of the new queue
#[clap(value_name = "KEY")]
key: i32,
}
impl Create {
pub fn run(&self) -> Result<()> {
let mut mq = SysvMq::<String>::new();
if let Some(m) = &self.mode {
mq.mode(i32::from_str_radix(&m, 8)?);
}
mq.create(self.key)?;
info!("SysV message queue created, key: {}, id: {}", mq.key, mq.id);
Ok(())
}
}

2
sysvmq/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
Cargo.lock

12
sysvmq/Cargo.toml Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "sysvmq"
version = "0.1.0"
edition = "2018"
authors = ["finga <mqrs@onders.org>"]
repository = "https://git.onders.org/finga/mqrs"
license = "GPL-3.0-or-later"
[dependencies]
libc = "0.2.98"
thiserror = "1.0.26"
nix = "0.21.0"

111
sysvmq/src/lib.rs Normal file
View file

@ -0,0 +1,111 @@
use libc::{
msgget, 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, num::ParseIntError};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum SysvMqError {
#[error("SysV message queue: {0}")]
ErrnoError(&'static str),
#[error("No message queue found with key {0}")]
KeyNotFound(i32),
#[error("IO Error: {0}")]
IoError(#[from] std::io::Error),
#[error("Parse Error: {0}")]
ParserError(#[from] ParseIntError),
}
/// 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 struct SysvMq<T> {
pub id: i32,
pub key: i32,
message_mask: i32,
mode: i32,
types: PhantomData<T>,
}
impl<T> SysvMq<T> {
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, SysvMqError> {
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<T> Default for SysvMq<T> {
fn default() -> Self {
Self::new()
}
}