From f72608375936814d898360fc7c392e385bc19d40 Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 8 Jul 2021 14:13:59 +0200 Subject: [PATCH 1/6] Remove unneccessary `pub` declarations --- src/posix/info.rs | 2 +- src/posix/recv.rs | 12 ++++++------ src/posix/send.rs | 12 ++++++------ src/sysv/unlink.rs | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/posix/info.rs b/src/posix/info.rs index 0fd1e76..abf9641 100644 --- a/src/posix/info.rs +++ b/src/posix/info.rs @@ -7,7 +7,7 @@ use posixmq::PosixMq; pub struct Info { /// Name of the queue #[clap(value_name = "QUEUE")] - pub queue: String, + queue: String, } impl Info { diff --git a/src/posix/recv.rs b/src/posix/recv.rs index 0b8563a..6d83cef 100644 --- a/src/posix/recv.rs +++ b/src/posix/recv.rs @@ -11,22 +11,22 @@ use std::str; pub struct Recv { /// Do not block #[clap(short, long)] - pub non_blocking: bool, + non_blocking: bool, /// Print messages as they are received #[clap(short, long)] - pub follow: bool, + follow: bool, /// Print a timestamp before each message #[clap(short, long)] - pub timestamp: bool, + timestamp: bool, /// Timeout, example "5h 23min 42ms" #[clap(short = 'o', long, conflicts_with = "deadline")] - pub timeout: Option, + timeout: Option, /// Deadline until messages are received (format: "%Y-%m-%d %H:%M:%S") #[clap(short, long, conflicts_with = "timeout")] - pub deadline: Option, + deadline: Option, /// Name of the queue #[clap(value_name = "QUEUE")] - pub queue: String, + queue: String, } fn print_message(priority: u32, length: usize, timestamp: bool, msg: &str) { diff --git a/src/posix/send.rs b/src/posix/send.rs index 917679b..d6feefc 100644 --- a/src/posix/send.rs +++ b/src/posix/send.rs @@ -9,22 +9,22 @@ use log::info; pub struct Send { /// Set a different priority, priority >= 0 #[clap(short, long, default_value = "0")] - pub priority: u32, + priority: u32, /// Do not block #[clap(short, long)] - pub non_blocking: bool, + non_blocking: bool, /// Timeout, example "5h 23min 42ms" #[clap(short = 'o', long, conflicts_with = "deadline")] - pub timeout: Option, + timeout: Option, /// Deadline until messages are sent (format: "%Y-%m-%d %H:%M:%S") #[clap(short, long, conflicts_with = "timeout")] - pub deadline: Option, + deadline: Option, /// Name of the queue #[clap(value_name = "QUEUE")] - pub queue: String, + queue: String, /// Message to be sent to the queue #[clap(value_name = "MESSAGE")] - pub msg: String, + msg: String, } impl Send { diff --git a/src/sysv/unlink.rs b/src/sysv/unlink.rs index 277edb6..ede5b67 100644 --- a/src/sysv/unlink.rs +++ b/src/sysv/unlink.rs @@ -12,10 +12,10 @@ pub struct Unlink { required_unless_present_any = &["key"], conflicts_with = "key" )] - pub id: Option, + id: Option, /// Key of the queue #[clap(long, short, required_unless_present_any = &["id"], conflicts_with = "id")] - pub key: Option, + key: Option, } impl Unlink { From 8d127d840ef29ea718562de16c55c99776be6cde Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 8 Jul 2021 14:14:25 +0200 Subject: [PATCH 2/6] Minor fixes in readme and clap help --- README.md | 7 ++++--- src/posix/list.rs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e7251f7..12bbbff 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # mqrs -`mqrs` is a small cli application to handle POSIX message queues. +`mqrs` is a small cli application to handle different kinds of message +queues. ## Install `mqrs` For information about how to build, install and run `mqrs` please see @@ -8,8 +9,8 @@ For information about how to build, install and run `mqrs` please see ## Using `mqrs` Depending on which backend you want to use there are different subsets of subcommands. Following backends are supported: -- `posix`: Uses POSIX message queues -- `sysv`: Uses SysV IPC message queues +- `posix`: Use POSIX message queues +- `sysv`: Use SysV IPC message queues If a command is clearly distinguishable from all the others, it does not have to be completed further. diff --git a/src/posix/list.rs b/src/posix/list.rs index 54c031a..f9c02b6 100644 --- a/src/posix/list.rs +++ b/src/posix/list.rs @@ -4,7 +4,7 @@ use clap::Clap; use log::warn; use std::{fs, os::unix::fs::PermissionsExt}; -/// Print information about an existing message queue +/// Print a list of existing message queues #[derive(Clap, Debug)] pub struct List { /// Show all parameters From f4796e7da65ad00053c9b4baacd2fbd40526030c Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 8 Jul 2021 14:20:53 +0200 Subject: [PATCH 3/6] Refactor `sysvmq::unlink_*` and check for error Use `sysvmq::id_from_key(key)` to receive the id of a queue identified with `key`. Here an error check is added as well. Adapt `Sysv::Unlink::run()` to comply with that change. --- src/sysv/unlink.rs | 6 ++++-- sysvmq/src/lib.rs | 7 +++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/sysv/unlink.rs b/src/sysv/unlink.rs index ede5b67..981289b 100644 --- a/src/sysv/unlink.rs +++ b/src/sysv/unlink.rs @@ -25,9 +25,11 @@ impl Unlink { info!("Removed message queue with id: {}", id); } else if let Some(key) = self.key { - sysvmq::unlink_key(key)?; + let id = sysvmq::id_from_key(key)?; - info!("Removed message queue key: {}", key); + sysvmq::unlink_id(id)?; + + info!("Removed message queue key: {} (id: {})", key, id); } Ok(()) diff --git a/sysvmq/src/lib.rs b/sysvmq/src/lib.rs index bb2c21d..b9de136 100644 --- a/sysvmq/src/lib.rs +++ b/sysvmq/src/lib.rs @@ -69,10 +69,13 @@ pub fn unlink_id(id: i32) -> Result<(), SysvMqError> { } } -pub fn unlink_key(key: i32) -> Result<(), SysvMqError> { +pub fn id_from_key(key: i32) -> Result { let id = unsafe { msgget(key, 0) }; - unlink_id(id) + match id { + -1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())), + id => Ok(id), + } } pub struct SysvMq { From 4c82d41f8e198a0a9aac83527e2734f384238044 Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 8 Jul 2021 14:46:10 +0200 Subject: [PATCH 4/6] Implement printing a list of SysV IPC mqs What could be improved is when printing the information to use a better human readable format. As usual the readme and the man page are both updated. --- README.md | 4 ++++ mqrs.1 | 12 ++++++++++++ src/main.rs | 2 ++ src/sysv.rs | 2 ++ src/sysv/list.rs | 26 ++++++++++++++++++++++++++ 5 files changed, 46 insertions(+) create mode 100644 src/sysv/list.rs diff --git a/README.md b/README.md index 12bbbff..5f68f7c 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,10 @@ queue. Following optional arguments are supported: - `-m`, `--mode`: Permissions (octal) to create the queue with. Default: 0644. +#### List all message queues +Use the `list` command to print a list of all message queues. No +further arguments are supported. + #### 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: diff --git a/mqrs.1 b/mqrs.1 index eb7b912..af46d24 100644 --- a/mqrs.1 +++ b/mqrs.1 @@ -241,6 +241,18 @@ Produce verbose output .B \-m, \-\-mode \fI\fP Permissions (octal) to create the queue with (default: 0644) .RE +.SS list [FLAGS] +Print a list of all existing SysV IPC message queues. +.TP 8 +.SS FLAGS +.RS +.TP 8 +.B \-h, \-\-help +Prints help information +.TP 8 +.B \-v, \-\-verbose +Produce verbose output +.RE .SS unlink [FLAGS] [OPTIONS] Delete an existing SysV IPC message queue. It is mandatory to pass exactly one OPTION. diff --git a/src/main.rs b/src/main.rs index 5e4db83..854ae95 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ enum PosixCommand { #[derive(Clap, Debug)] enum SysvCommand { Create(sysv::Create), + List(sysv::List), Unlink(sysv::Unlink), } @@ -69,6 +70,7 @@ fn main() -> Result<()> { }, Backend::Sysv(s) => match s { SysvCommand::Create(c) => c.run()?, + SysvCommand::List(l) => l.run()?, SysvCommand::Unlink(u) => u.run()?, }, } diff --git a/src/sysv.rs b/src/sysv.rs index 91ee1a5..05edc1e 100644 --- a/src/sysv.rs +++ b/src/sysv.rs @@ -1,5 +1,7 @@ mod create; +mod list; mod unlink; pub use create::Create; +pub use list::List; pub use unlink::Unlink; diff --git a/src/sysv/list.rs b/src/sysv/list.rs new file mode 100644 index 0000000..f7e6ff7 --- /dev/null +++ b/src/sysv/list.rs @@ -0,0 +1,26 @@ +use anyhow::Result; +use clap::Clap; +use std::{ + fs::File, + io::{BufRead, BufReader}, +}; + +/// Print a list of existing message queues +#[derive(Clap, Debug)] +pub struct List {} + +impl List { + pub fn run(&self) -> Result<()> { + let file = BufReader::new(File::open("/proc/sysvipc/msg")?); + + for line in file.lines() { + for field in line?.split_whitespace().collect::>() { + print!("{0: <10}", field); + } + + println!(); + } + + Ok(()) + } +} From 9666e0788df1be34813787edfeaa284f29080e19 Mon Sep 17 00:00:00 2001 From: finga Date: Thu, 8 Jul 2021 17:44:46 +0200 Subject: [PATCH 5/6] Implement `info` command for SysV IPC mqs The `list` command was refactored a little bit as well and the man page and readme were updated. --- README.md | 6 +++++ mqrs.1 | 58 +++++++++++++++++++++++++++++++++++++--------- src/main.rs | 2 ++ src/sysv.rs | 2 ++ src/sysv/info.rs | 53 ++++++++++++++++++++++++++++++++++++++++++ src/sysv/list.rs | 4 +--- src/sysv/unlink.rs | 4 ++-- 7 files changed, 113 insertions(+), 16 deletions(-) create mode 100644 src/sysv/info.rs diff --git a/README.md b/README.md index 5f68f7c..9e73663 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,12 @@ queue. Following optional arguments are supported: - `-m`, `--mode`: Permissions (octal) to create the queue with. Default: 0644. +#### Print information about a message queue +Use the `info` command to print further information about a message +queue. Exactly of the following arguments is mandatory: +- `-i`, `--id id`: Id of the queue +- `-k`, `--key key`: Key of the queue + #### List all message queues Use the `list` command to print a list of all message queues. No further arguments are supported. diff --git a/mqrs.1 b/mqrs.1 index af46d24..45116a5 100644 --- a/mqrs.1 +++ b/mqrs.1 @@ -41,7 +41,7 @@ The POSIX backend supports six commands: and .B recv . -.SS create [FLAGS] [OPTIONS] \fI\fP +.SS posix create [FLAGS] [OPTIONS] \fI\fP Create a new POSIX message queue. .TP 8 .SS ARGS @@ -72,7 +72,7 @@ Message size in bytes .B \-m, \-\-mode \fI\fP Permissions (octal) to create the queue with .RE -.SS help [SUBCOMMAND] +.SS posix help [SUBCOMMAND] Prints this message or the help of the given subcommand. .TP 8 .SS ARGS @@ -81,7 +81,7 @@ Prints this message or the help of the given subcommand. .B \fI\fP Show help for \fISUBCOMMAND\fP .RE -.SS info [FLAGS] \fI\fP +.SS posix info [FLAGS] \fI\fP Print further information about an existing message queue. .TP 8 .SS ARGS @@ -100,7 +100,7 @@ Prints help information .B \-v, \-\-verbose Produce verbose output .RE -.SS list [FLAGS] +.SS posix list [FLAGS] Print a list of all existing POSIX message queues. .TP 8 .SS FLAGS @@ -115,7 +115,7 @@ Produce verbose output .B \-a, \-\-all Print all available information .RE -.SS recv [FLAGS] [OPTIONS] \fI\fP +.SS posix recv [FLAGS] [OPTIONS] \fI\fP Receive and print one or more messages message from a message queue. .TP 8 .SS ARGS @@ -153,7 +153,7 @@ Deadline until messages are received (format: "%Y-%m-%d %H:%M:%S") .B \-o, \-\-timeout \fI\fP Timeout as for example in "5h 23min 42ms" .RE -.SS send [FLAGS] [OPTIONS] \fI\fP \fI\fP +.SS posix send [FLAGS] [OPTIONS] \fI\fP \fI\fP Send a message to a message queue. .TP 8 .SS ARGS @@ -191,7 +191,7 @@ Set a different priority than default, priority >= 0 [default: 0] .B \-o, \-\-timeout \fI\fP Timeout as for example in "5h 23min 42ms" .RE -.SS unlink [FLAGS] \fI\fP +.SS posix unlink [FLAGS] \fI\fP Delete an existing POSIX message queue. .TP 8 .SS ARGS @@ -211,12 +211,16 @@ Prints help information Produce verbose output .RE .SH SYSV IPC MESSAGE QUEUE SUBCOMMANDS -The SysV IPC backend supports two commands: +The SysV IPC backend supports four commands: .B create\ +, +.B info\ +, +.B list and .B unlink\ . -.SS create [FLAGS] [OPTIONS] \fI\fP +.SS sysv create [FLAGS] [OPTIONS] \fI\fP Create a new SysV IPC message queue. .TP 8 .SS ARGS @@ -241,7 +245,39 @@ Produce verbose output .B \-m, \-\-mode \fI\fP Permissions (octal) to create the queue with (default: 0644) .RE -.SS list [FLAGS] +.SS sysv help [SUBCOMMAND] +Prints this message or the help of the given subcommand. +.TP 8 +.SS ARGS +.RS +.TP 8 +.B \fI\fP +Show help for \fISUBCOMMAND\fP +.RE +.SS sysv info [FLAGS] [OPTIONS] +Print further information about an existing message queue. Exactly of +the OPTION arguments is mandatory. +.TP 8 +.SS FLAGS +.RS +.TP 8 +.B \-h, \-\-help +Prints help information +.TP 8 +.B \-v, \-\-verbose +Produce verbose output +.RE +.TP 8 +.SS OPTIONS +.RS +.TP 8 +.B \-i, \-\-id \fI\fP +Id of the queue +.TP 8 +.B \-k, \-\-key \fI\fP +Key of the queue +.RE +.SS sysv list [FLAGS] Print a list of all existing SysV IPC message queues. .TP 8 .SS FLAGS @@ -253,7 +289,7 @@ Prints help information .B \-v, \-\-verbose Produce verbose output .RE -.SS unlink [FLAGS] [OPTIONS] +.SS sysv unlink [FLAGS] [OPTIONS] Delete an existing SysV IPC message queue. It is mandatory to pass exactly one OPTION. .TP 8 diff --git a/src/main.rs b/src/main.rs index 854ae95..b2dc94b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ enum PosixCommand { #[derive(Clap, Debug)] enum SysvCommand { Create(sysv::Create), + Info(sysv::Info), List(sysv::List), Unlink(sysv::Unlink), } @@ -70,6 +71,7 @@ fn main() -> Result<()> { }, Backend::Sysv(s) => match s { SysvCommand::Create(c) => c.run()?, + SysvCommand::Info(i) => i.run()?, SysvCommand::List(l) => l.run()?, SysvCommand::Unlink(u) => u.run()?, }, diff --git a/src/sysv.rs b/src/sysv.rs index 05edc1e..7270e78 100644 --- a/src/sysv.rs +++ b/src/sysv.rs @@ -1,7 +1,9 @@ mod create; +mod info; mod list; mod unlink; pub use create::Create; +pub use info::Info; pub use list::List; pub use unlink::Unlink; diff --git a/src/sysv/info.rs b/src/sysv/info.rs new file mode 100644 index 0000000..42d9fac --- /dev/null +++ b/src/sysv/info.rs @@ -0,0 +1,53 @@ +use anyhow::Result; +use clap::Clap; +use std::{ + fs::File, + io::{BufRead, BufReader}, +}; + +/// Print information about an existing message queue +#[derive(Clap, Debug)] +pub struct Info { + /// Id of the queue + #[clap(short, long, required_unless_present_any = &["key"], conflicts_with = "key")] + id: Option, + /// Key of the queue + #[clap(short, long, required_unless_present_any = &["id"], conflicts_with = "id")] + key: Option, +} + +fn print_line(line: &str) { + for field in line.split_whitespace().collect::>() { + print!("{0: <10}", field); + } + + println!(); +} + +impl Info { + pub fn run(&self) -> Result<()> { + let mut lines = BufReader::new(File::open("/proc/sysvipc/msg")?).lines(); + + print_line(&lines.nth(0).unwrap_or(Ok(String::new()))?); + + for line in lines { + let line = line?; + + if let Some(id) = self.id { + if id == line.split_whitespace().collect::>()[1].parse::()? { + print_line(&line); + + break; + } + } else if let Some(key) = self.key { + if key == line.split_whitespace().collect::>()[0].parse::()? { + print_line(&line); + + break; + } + } + } + + Ok(()) + } +} diff --git a/src/sysv/list.rs b/src/sysv/list.rs index f7e6ff7..9f66951 100644 --- a/src/sysv/list.rs +++ b/src/sysv/list.rs @@ -11,9 +11,7 @@ pub struct List {} impl List { pub fn run(&self) -> Result<()> { - let file = BufReader::new(File::open("/proc/sysvipc/msg")?); - - for line in file.lines() { + for line in BufReader::new(File::open("/proc/sysvipc/msg")?).lines() { for field in line?.split_whitespace().collect::>() { print!("{0: <10}", field); } diff --git a/src/sysv/unlink.rs b/src/sysv/unlink.rs index 981289b..8723d20 100644 --- a/src/sysv/unlink.rs +++ b/src/sysv/unlink.rs @@ -7,14 +7,14 @@ use log::info; pub struct Unlink { /// Id of the queue #[clap( - long, short, + long, required_unless_present_any = &["key"], conflicts_with = "key" )] id: Option, /// Key of the queue - #[clap(long, short, required_unless_present_any = &["id"], conflicts_with = "id")] + #[clap(short, long, required_unless_present_any = &["id"], conflicts_with = "id")] key: Option, } From ecd5ee5a36f9d1b5e0ded62bde3952dff52c157a Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 9 Jul 2021 00:31:51 +0200 Subject: [PATCH 6/6] Add functions to print information about SysV mqs Not needed yet but maybe useful.. --- sysvmq/src/lib.rs | 62 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/sysvmq/src/lib.rs b/sysvmq/src/lib.rs index b9de136..298a48e 100644 --- a/sysvmq/src/lib.rs +++ b/sysvmq/src/lib.rs @@ -1,21 +1,15 @@ 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, + 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, num::ParseIntError, ptr}; +use std::{marker::PhantomData, mem::MaybeUninit, 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 @@ -78,6 +72,56 @@ pub fn id_from_key(key: i32) -> Result { } } +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,