From e9e9c53f19a750852f124a4c1d977d3e5aa22f22 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Fri, 20 Jan 2023 23:53:28 -0500 Subject: [PATCH] Add `mkfifo` applet --- README.md | 1 + src/cmd/mkfifo/mod.rs | 72 +++++++++++++++++++++++++++++++++++++++++++ src/cmd/mod.rs | 5 ++- 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/cmd/mkfifo/mod.rs diff --git a/README.md b/README.md index 0b2acd5..cd0e33b 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ code between applets, making for an overall smaller binary. - head - hostname - link +- mkfifo - mountpoint - nologin - nproc diff --git a/src/cmd/mkfifo/mod.rs b/src/cmd/mkfifo/mod.rs new file mode 100644 index 0000000..ee69fd0 --- /dev/null +++ b/src/cmd/mkfifo/mod.rs @@ -0,0 +1,72 @@ +use super::Cmd; +use crate::mode::Parser; +use clap::{Arg, ArgAction, ArgMatches, Command}; +use std::{error::Error, ffi::CString, io}; + +#[derive(Debug, Default)] +pub struct MkFifo; + +impl Cmd for MkFifo { + fn cli(&self) -> clap::Command { + Command::new("mkfifo") + .about("make FIFO special files") + .author("Nathan Fisher") + .version(env!("CARGO_PKG_VERSION")) + .args([ + Arg::new("mode") + .help( + "Set the file permission bits of the newly-created \ + FIFO to the specified mode value.", + ) + .long_help( + "Set the file permission bits of the newly-created \ + FIFO to the specified mode value. The mode option-argument \ + shall be the same as the mode operand defined for the \ + chmod utility. In the symbolic_mode strings, the op \ + characters '+' and '-' shall be interpreted relative to \ + an assumed initial mode of a=rw.", + ) + .short('m') + .long("mode") + .value_name("MODE") + .num_args(1), + Arg::new("verbose") + .help("print a diagnostic for every pipe created") + .short('v') + .long("verbose") + .action(ArgAction::SetTrue), + Arg::new("file").num_args(1..).required(true), + ]) + } + + fn run(&self, matches: Option<&ArgMatches>) -> Result<(), Box> { + let Some(matches) = matches else { + return Err(io::Error::new(io::ErrorKind::Other, "no input").into()); + }; + let mode = if let Some(m) = matches.get_one::("mode") { + Parser::new(0o666).parse(m)? + } else { + 0o666 + }; + if let Some(files) = matches.get_many::("file") { + for f in files { + let fname = CString::new(f.as_str())?; + let res = unsafe { libc::mkfifo(fname.as_ptr(), mode) }; + if res != 0 { + return Err(io::Error::last_os_error().into()); + } + if matches.get_flag("verbose") { + println!( + "{}: created pipe '{f}' with mode {mode:o}", + self.cli().get_name() + ); + } + } + } + Ok(()) + } + + fn path(&self) -> Option { + Some(crate::Path::UsrBin) + } +} diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index 426884e..90b20bd 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -25,6 +25,7 @@ mod hostname; mod link; mod ln; mod ls; +mod mkfifo; mod mountpoint; mod mv; mod nologin; @@ -77,6 +78,7 @@ pub fn get(name: &str) -> Option> { "groups" => Some(Box::new(groups::Groups::default())), "head" => Some(Box::new(head::Head::default())), "link" => Some(Box::new(link::Link::default())), + "mkfifo" => Some(Box::new(mkfifo::MkFifo::default())), "mountpoint" => Some(Box::new(mountpoint::Mountpoint::default())), "nologin" => Some(Box::new(nologin::Nologin::default())), "nproc" => Some(Box::new(nproc::Nproc::default())), @@ -96,7 +98,7 @@ pub fn get(name: &str) -> Option> { } } -pub static COMMANDS: [&str; 32] = [ +pub static COMMANDS: [&str; 33] = [ "base32", "base64", "basename", @@ -114,6 +116,7 @@ pub static COMMANDS: [&str; 32] = [ "head", "hostname", "link", + "mkfifo", "mountpoint", "nologin", "nproc",