Added doc comments

This commit is contained in:
Nathan Fisher 2023-01-14 10:36:08 -05:00
parent b401aaad47
commit c6e162ebc8
6 changed files with 119 additions and 30 deletions

1
src/chmod/mod.rs Normal file
View File

@ -0,0 +1 @@
//! Functions for parsing and managing permissions

View File

@ -1,44 +1,45 @@
use clap::ArgMatches; use clap::ArgMatches;
use std::{error::Error, fmt}; use std::{error::Error, fmt};
pub mod base32; mod base32;
pub mod base64; mod base64;
pub mod basename; mod basename;
pub mod bootstrap; mod bootstrap;
mod cat; mod cat;
mod chmod; mod chmod;
pub mod clear; mod clear;
mod cp; mod cp;
pub mod cut; mod cut;
mod date; mod date;
mod dd; mod dd;
pub mod dirname; mod dirname;
pub mod echo; mod echo;
pub mod factor; mod factor;
pub mod r#false; mod r#false;
pub mod fold; mod fold;
mod getty; mod getty;
pub mod groups; mod groups;
pub mod head; mod head;
pub mod hostname; mod hostname;
pub mod link; mod link;
mod ln; mod ln;
mod ls; mod ls;
pub mod mountpoint; mod mountpoint;
mod mv; mod mv;
pub mod nologin; mod nologin;
pub mod nproc; mod nproc;
mod pwd; mod pwd;
pub mod rev; mod rev;
mod rm; mod rm;
mod rmdir; mod rmdir;
pub mod shitbox; mod shitbox;
pub mod sleep; mod sleep;
pub mod sync; mod sync;
pub mod r#true; mod r#true;
pub mod which; mod unlink;
pub mod whoami; mod which;
pub mod yes; mod whoami;
mod yes;
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub use { pub use {
@ -46,15 +47,24 @@ pub use {
bootstrap::Bootstrap, clear::Clear, cut::Cut, dirname::Dirname, echo::Echo, factor::Factor, bootstrap::Bootstrap, clear::Clear, cut::Cut, dirname::Dirname, echo::Echo, factor::Factor,
fold::Fold, groups::Groups, head::Head, link::Link, mountpoint::Mountpoint, nologin::Nologin, fold::Fold, groups::Groups, head::Head, link::Link, mountpoint::Mountpoint, nologin::Nologin,
nproc::Nproc, r#false::False, r#true::True, rev::Rev, shitbox::Shitbox, sleep::Sleep, nproc::Nproc, r#false::False, r#true::True, rev::Rev, shitbox::Shitbox, sleep::Sleep,
sync::Sync as SyncCmd, which::Which, whoami::Whoami, yes::Yes, sync::Sync as SyncCmd, unlink::Unlink, which::Which, whoami::Whoami, yes::Yes,
}; };
/// Defines a command or applet, it's cli interface, and it's installation directory
/// relative to the binary
pub trait Cmd: fmt::Debug + Sync { pub trait Cmd: fmt::Debug + Sync {
/// Defines the cli of the applet
fn cli(&self) -> clap::Command; fn cli(&self) -> clap::Command;
/// Runs the applet
/// # Errors
/// Bubbles up any errors to the caller
fn run(&self, matches: Option<&ArgMatches>) -> Result<(), Box<dyn Error>>; fn run(&self, matches: Option<&ArgMatches>) -> Result<(), Box<dyn Error>>;
/// Returns the path relative to the binary where the link to this applet
/// will be installed
fn path(&self) -> Option<crate::Path>; fn path(&self) -> Option<crate::Path>;
} }
/// Parses a string into a command to run
#[must_use] #[must_use]
#[allow(clippy::box_default)] #[allow(clippy::box_default)]
pub fn get(name: &str) -> Option<Box<dyn Cmd>> { pub fn get(name: &str) -> Option<Box<dyn Cmd>> {
@ -81,6 +91,7 @@ pub fn get(name: &str) -> Option<Box<dyn Cmd>> {
"sleep" => Some(Box::new(Sleep::default())), "sleep" => Some(Box::new(Sleep::default())),
"sync" => Some(Box::new(SyncCmd::default())), "sync" => Some(Box::new(SyncCmd::default())),
"true" => Some(Box::new(True::default())), "true" => Some(Box::new(True::default())),
"unlink" => Some(Box::new(Unlink::default())),
"which" => Some(Box::new(Which::default())), "which" => Some(Box::new(Which::default())),
"whoami" => Some(Box::new(Whoami::default())), "whoami" => Some(Box::new(Whoami::default())),
"yes" => Some(Box::new(Yes::default())), "yes" => Some(Box::new(Yes::default())),
@ -88,7 +99,7 @@ pub fn get(name: &str) -> Option<Box<dyn Cmd>> {
} }
} }
pub static COMMANDS: [&str; 26] = [ pub static COMMANDS: [&str; 27] = [
"base32", "base32",
"base64", "base64",
"basename", "basename",
@ -112,6 +123,7 @@ pub static COMMANDS: [&str; 26] = [
"shitbox", "shitbox",
"sync", "sync",
"true", "true",
"unlink",
"which", "which",
"whoami", "whoami",
"yes", "yes",

50
src/cmd/unlink/mod.rs Normal file
View File

@ -0,0 +1,50 @@
use clap::{Arg, ArgAction, Command};
use std::{io, ffi::CString, process};
use super::Cmd;
#[derive(Debug, Default)]
pub struct Unlink;
impl Cmd for Unlink {
fn cli(&self) -> clap::Command {
Command::new("unlink")
.about("call the unlink function to remove the specified file")
.author("Nathan Fisher")
.version(env!("CARGO_PKG_VERSION"))
.args([
Arg::new("verbose")
.help("display user feedback upon success")
.short('v')
.long("verbose")
.action(ArgAction::SetTrue),
Arg::new("file")
.value_name("FILE")
.required(true)
.num_args(1..),
])
}
fn run(&self, matches: Option<&clap::ArgMatches>) -> Result<(), Box<dyn std::error::Error>> {
let Some(matches) = matches else {
return Err(Box::new(io::Error::new(io::ErrorKind::Other, "no input")));
};
if let Some(files) = matches.get_many::<String>("file") {
for f in files {
let fname = CString::new(f.as_str())?;
let ret = unsafe { libc::unlink(fname.as_ptr()) };
if matches.get_flag("verbose") && ret == 0 {
println!("unlink: {f}");
} else if ret != 0 {
let err = io::Error::last_os_error();
eprintln!("unlink: cannot unlink {f}: {err}");
process::exit(ret);
}
}
}
Ok(())
}
fn path(&self) -> Option<crate::Path> {
Some(crate::Path::UsrBin)
}
}

View File

@ -1,17 +1,22 @@
#![warn(clippy::all, clippy::pedantic)] #![warn(clippy::all, clippy::pedantic)]
use std::{env, path::PathBuf, process, string::ToString}; use std::{env, path::PathBuf, process, string::ToString};
pub mod cmd; pub mod chmod;
mod cmd;
pub use cmd::Cmd; pub use cmd::Cmd;
pub mod math; pub mod math;
/// User and group related functionality
pub mod pw; pub mod pw;
/// Defines the location relative to the binary where a command will be installed
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Path { pub enum Path {
/// /bin
Bin, Bin,
/// /sbin
Sbin, Sbin,
/// /usr/bin
UsrBin, UsrBin,
/// /usr/sbin
UsrSbin, UsrSbin,
} }
@ -27,6 +32,7 @@ impl Path {
} }
} }
/// Returns the basename of the command as it was called
#[must_use] #[must_use]
pub fn progname() -> Option<String> { pub fn progname() -> Option<String> {
env::args() env::args()
@ -39,6 +45,9 @@ pub fn progname() -> Option<String> {
.flatten() .flatten()
} }
/// Returns the path to the binary, if called as "shitbox". Used in the bootstrap
/// applet to find the binary location in order to install it into it's permanent
/// location
#[must_use] #[must_use]
pub fn progpath() -> Option<PathBuf> { pub fn progpath() -> Option<PathBuf> {
match progname() { match progname() {
@ -47,6 +56,7 @@ pub fn progpath() -> Option<PathBuf> {
} }
} }
/// The entry point of the program
pub fn run() { pub fn run() {
if let Some(progname) = progname() { if let Some(progname) = progname() {
if let Some(command) = cmd::get(&progname) { if let Some(command) = cmd::get(&progname) {

View File

@ -1,3 +1,4 @@
//! Math related functions not included in std
#[must_use] #[must_use]
pub fn is_prime(num: u64) -> bool { pub fn is_prime(num: u64) -> bool {
match num { match num {

View File

@ -1,9 +1,13 @@
//! Wraps certain libc functions around groups and users
use std::{ use std::{
error::Error, error::Error,
ffi::{c_int, CStr, CString}, ffi::{c_int, CStr, CString},
io, num, io, num,
}; };
/// Gets the current username of this process
/// # Errors
/// The user name must be valid utf8
pub fn get_username<'a>() -> Result<&'a str, std::str::Utf8Error> { pub fn get_username<'a>() -> Result<&'a str, std::str::Utf8Error> {
let user = unsafe { let user = unsafe {
let uid = libc::getuid(); let uid = libc::getuid();
@ -14,6 +18,9 @@ pub fn get_username<'a>() -> Result<&'a str, std::str::Utf8Error> {
user.to_str() user.to_str()
} }
/// Gets the current effective user name of this process
/// # Errors
/// The user name must be valid utf8
pub fn get_eusername<'a>() -> Result<&'a str, std::str::Utf8Error> { pub fn get_eusername<'a>() -> Result<&'a str, std::str::Utf8Error> {
let user = unsafe { let user = unsafe {
let uid = libc::geteuid(); let uid = libc::geteuid();
@ -24,6 +31,7 @@ pub fn get_eusername<'a>() -> Result<&'a str, std::str::Utf8Error> {
user.to_str() user.to_str()
} }
/// Gets the uid associated with the given name
#[must_use] #[must_use]
pub fn get_uid_for_name(name: &str) -> Option<u32> { pub fn get_uid_for_name(name: &str) -> Option<u32> {
let Ok(user) = CString::new(name.as_bytes()) else { return None }; let Ok(user) = CString::new(name.as_bytes()) else { return None };
@ -37,6 +45,7 @@ pub fn get_uid_for_name(name: &str) -> Option<u32> {
} }
} }
/// Gets the gid for the main group associated with the given user
#[must_use] #[must_use]
pub fn get_pgid_for_name(name: &str) -> Option<u32> { pub fn get_pgid_for_name(name: &str) -> Option<u32> {
let Ok(user) = CString::new(name.as_bytes()) else { return None }; let Ok(user) = CString::new(name.as_bytes()) else { return None };
@ -50,6 +59,9 @@ pub fn get_pgid_for_name(name: &str) -> Option<u32> {
} }
} }
/// Gets the main group name for the current process
/// # Errors
/// The name must be valid utf8
pub fn get_grpname<'a>() -> Result<&'a str, std::str::Utf8Error> { pub fn get_grpname<'a>() -> Result<&'a str, std::str::Utf8Error> {
let group = unsafe { let group = unsafe {
let gid = libc::getgid(); let gid = libc::getgid();
@ -60,6 +72,9 @@ pub fn get_grpname<'a>() -> Result<&'a str, std::str::Utf8Error> {
group.to_str() group.to_str()
} }
/// Gets the effective group for the current process
/// # Errors
/// The name must be valid utf8
pub fn get_egrpname<'a>() -> Result<&'a str, std::str::Utf8Error> { pub fn get_egrpname<'a>() -> Result<&'a str, std::str::Utf8Error> {
let group = unsafe { let group = unsafe {
let gid = libc::getegid(); let gid = libc::getegid();