Compare commits

..

4 commits

Author SHA1 Message Date
cc19087195 Implement deletion of SysV IPC message queues
As usual also the readme and the man page are updated.
2021-07-07 20:48:07 +02:00
4d200bb5f3 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.
2021-07-07 20:31:16 +02:00
a468c5d7bb Move install section into its own file
To keep the readme manageable and clear move help about how to build,
install and run into its own file.
2021-07-07 19:40:14 +02:00
07decf7b36 Add debian package build information in readme
Add prerequisites for building a debian package.
2021-07-07 19:30:18 +02:00
13 changed files with 421 additions and 54 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."

49
INSTALL.md Normal file
View file

@ -0,0 +1,49 @@
# Installation
To build `mqrs` having the rust toolchain installed is mandatory.
## Install Rust
Install the Rust toolchain from [rustup.rs](https://rustup.rs).
## Build `mqrs`
`mqrs` can be built for development:
```sh
cargo b
```
or for releasing:
```sh
cargo b --release
```
## Build the `mqrs` Debian package
For that [`cargo-deb`](https://github.com/mmstick/cargo-deb) is
required, which can be installed with:
```sh
cargo install cargo-deb
```
A Debian package can be built with:
```sh
cargo deb
```
## Install `mqrs`
When a Rust toolchain installed you can also install `mqrs`
directly without cloning it manually:
``` sh
cargo install --git https://git.onders.org/finga/mqrs.git mqrs
```
or from within the project:
```sh
cargo install mqrs
```
## Run `mqrs`
`mqrs` can either be run from the project directory with:
```sh
cargo b
```
or you can copy the produced binary somewhere else or link to them
from `target/{debug,release}/mqrs` depending on which one you built.

View file

@ -1,49 +1,9 @@
# mqrs # mqrs
`mqrs` is a small cli application to handle POSIX message queues. `mqrs` is a small cli application to handle POSIX message queues.
## Installation ## Install `mqrs`
To build `mqrs` a rust toolchain is necessary. For information about how to build, install and run `mqrs` please see
[`INSTALL.md`](INSTALL.md).
### Install Rust
Install the Rust toolchain from [rustup.rs](https://rustup.rs).
### Build `mqrs`
`mqrs` can be built for development:
```sh
cargo b
```
or for releasing:
```sh
cargo b --release
```
### Build the `mqrs` Debian package
```sh
cargo deb
```
### Install `mqrs`
When a Rust toolchain installed you can also install `mqrs`
directly without cloning it manually:
``` sh
cargo install --git https://git.onders.org/finga/mqrs.git mqrs
```
or from within the project:
```sh
cargo install mqrs
```
### Run `mqrs`
`mqrs` can either be run from the project directory with:
```sh
cargo b
```
or you can copy the produced binary somewhere else or link to them
from `target/{debug,release}/mqrs` depending on which
one you built.
## Using `mqrs` ## Using `mqrs`
Depending on which backend you want to use there are different subsets Depending on which backend you want to use there are different subsets
@ -62,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
@ -98,4 +58,16 @@ 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 two commands: `create` and `unlink`.
#### 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.
#### Delete a message queue
Use the `unlink` command to delete a message queue. This can either be
done by providing a `key` or an `id` of the queue:
- `-i`, `--id <id>`: Id of the queue
- `-k`, `--key <key>`: Key of the queue

65
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]
@ -191,7 +192,7 @@ Set a different priority than default, priority >= 0 [default: 0]
Timeout as for example in "5h 23min 42ms" Timeout as for example in "5h 23min 42ms"
.RE .RE
.SS unlink [FLAGS] \fI<QUEUE>\fP .SS unlink [FLAGS] \fI<QUEUE>\fP
Deletes an existing POSIX message queue. Delete an existing POSIX message queue.
.TP 8 .TP 8
.SS ARGS .SS ARGS
.RS .RS
@ -210,7 +211,65 @@ 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 two commands:
.B create\
and
.B unlink\
.
.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
.SS unlink [FLAGS] [OPTIONS]
Delete an existing SysV IPC message queue. It is mandatory to pass
exactly one OPTION.
.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 \-i, \-\-id \fI<id>\fP
Id of the queue
.TP 8
.B \-k, \-\-key \fI<key>\fP
Key of the queue
.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,8 @@ enum PosixCommand {
#[derive(Clap, Debug)] #[derive(Clap, Debug)]
enum SysvCommand { enum SysvCommand {
Create(sysv::Create),
Unlink(sysv::Unlink),
} }
#[derive(Clap, Debug)] #[derive(Clap, Debug)]
@ -65,6 +68,8 @@ 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()?,
SysvCommand::Unlink(u) => u.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)?);
} }

5
src/sysv.rs Normal file
View file

@ -0,0 +1,5 @@
mod create;
mod unlink;
pub use create::Create;
pub use unlink::Unlink;

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(())
}
}

35
src/sysv/unlink.rs Normal file
View file

@ -0,0 +1,35 @@
use anyhow::Result;
use clap::Clap;
use log::info;
/// Delete a message queue
#[derive(Clap, Debug)]
pub struct Unlink {
/// Id of the queue
#[clap(
long,
short,
required_unless_present_any = &["key"],
conflicts_with = "key"
)]
pub id: Option<i32>,
/// Key of the queue
#[clap(long, short, required_unless_present_any = &["id"], conflicts_with = "id")]
pub key: Option<i32>,
}
impl Unlink {
pub fn run(&self) -> Result<()> {
if let Some(id) = self.id {
sysvmq::unlink_id(id)?;
info!("Removed message queue with id: {}", id);
} else if let Some(key) = self.key {
sysvmq::unlink_key(key)?;
info!("Removed message queue key: {}", key);
}
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"

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

@ -0,0 +1,132 @@
use libc::{
msgctl, msgget, 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, num::ParseIntError, ptr};
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 fn unlink_id(id: i32) -> Result<(), SysvMqError> {
let res = unsafe {
msgctl(
id,
ControlCommands::Remove as i32,
ptr::null::<msqid_ds>() as *mut msqid_ds,
)
};
match res {
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
_ => Ok(()),
}
}
pub fn unlink_key(key: i32) -> Result<(), SysvMqError> {
let id = unsafe { msgget(key, 0) };
unlink_id(id)
}
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()
}
}