Added README.md, CONTRIBUTING.md and LICENSE. Added /sbin/nologin
applet.
This commit is contained in:
parent
1af14e7ff7
commit
cf99f2005a
71
CONTRIBUTING.md
Normal file
71
CONTRIBUTING.md
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
Contents
|
||||||
|
========
|
||||||
|
* [The **Cmd** trait](#the-cmd-trait)
|
||||||
|
* [A simple example applet](#a-simple-example-applet)
|
||||||
|
* [Incorporating a new applet](#incorporating-a-new-applet)
|
||||||
|
|
||||||
|
## The Cmd trait
|
||||||
|
The `Cmd` trait is defined in `src/cmd/mod.rs`. All applets should live in their
|
||||||
|
own submodule under `crate::cmd` and include a struct with the name of the command,
|
||||||
|
in snake case. This struct must implement `Cmd`. It is recommended that this struct
|
||||||
|
have at least the fields `name: &'static str` and `path: crate::Path`. The
|
||||||
|
trait methods `name` and `path` can then just return the corresponding fields.
|
||||||
|
|
||||||
|
The applet module should further contain a constant which is basically the
|
||||||
|
default instance for this struct.
|
||||||
|
|
||||||
|
## A Simple Example Applet
|
||||||
|
```Rust
|
||||||
|
// src/cmd/myapplet/mod.rs
|
||||||
|
use clap::Command;
|
||||||
|
use super::Cmd;
|
||||||
|
|
||||||
|
pub struct MyApplet {
|
||||||
|
name: &'static str,
|
||||||
|
path: crate::Path,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MYAPPLET: MyApplet = MyApplet {
|
||||||
|
name: "myapplet",
|
||||||
|
path: crate::Path::UsrBin,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Cmd for MyApplet {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cli(&self) -> clap::Command {
|
||||||
|
Command::new(self.name)
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
.author("Zaphod Beeblebrox")
|
||||||
|
.about("Does sketchy things")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _matches: Option<&clap::ArgMatches>) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
println!("If there's anything more important than my ego around, I want it caught and shot now.");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path(&self) -> Option<crate::Path> {
|
||||||
|
self.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Incorporating a new applet
|
||||||
|
Each command module should be public in `src/cmd/mod.rs` and both the struct which
|
||||||
|
implements `Cmd` and the constant which is an instance of that struct should be
|
||||||
|
exported as public in that file.
|
||||||
|
|
||||||
|
There are several other files which must also be edited to fully integrate a new
|
||||||
|
command. Expect improvements to this process as the Api evolves.
|
||||||
|
|
||||||
|
- src/lib.rs: The function `run` has a match statement which checks the name with
|
||||||
|
which the program was invoked. A new match arm must be added here.
|
||||||
|
- src/cmd/bootstrap/mod.rs: The `run` method has a `Vec` of trait objects representing
|
||||||
|
all of the available applets. The constant which is an instance of the struct implementing
|
||||||
|
`Cmd` should be added to this `Vec`.
|
||||||
|
-src/cmd/shitbox/mod.rs: The `cli` method will need `MYAPPLET.cli()` added in to
|
||||||
|
the `clap` subcommands. The `run` method has a match statement which checks the
|
||||||
|
subcommand that has been asked to run. A new match arm must also be added here.
|
||||||
|
|
28
LICENSE
Normal file
28
LICENSE
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
-----------------------------------------------------------------------------
|
||||||
|
"THE BEER-WARE LICENSE" (Revision 42):
|
||||||
|
<jeang3nie@HitchHiker-Linux.org> wrote this program. As long as you retain
|
||||||
|
this notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
|
and you think this stuff is worth it, you can buy me a beer in return.
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
88888b d888b 888b 88 8P 888888 88888b 888 888b 88 88 d888b 88
|
||||||
|
88 88 88 88 88`8b 88 88 88 88 88 88 88`8b 88 88 88 ` 88
|
||||||
|
88 88 88 88 88 88 88 88 88888P 88 88 88 88 88 88 88 88
|
||||||
|
88 88 88 88 88 `8b88 88 88 d8888888b 88 `8b88 88 88 , ""
|
||||||
|
88888P `888P 88 `888 88 88 88 `8b 88 `888 88 `888P 88
|
||||||
|
|
||||||
|
nnnmmm
|
||||||
|
\||\ ;;;;%%%@@@@@@ \ //,
|
||||||
|
V|/ %;;%%%%%@@@@@@@@@@ ===Y//
|
||||||
|
68=== ;;;;%%%%%%@@@@@@@@@@@@ @Y
|
||||||
|
;Y ;;%;%%%%%%@@@@@@@@@@@@@@ Y
|
||||||
|
;Y ;;;+;%%%%%%@@@@@@@@@@@@@@@ Y
|
||||||
|
;Y__;;;+;%%%%%%@@@@@@@@@@@@@@i;;__Y
|
||||||
|
iiY"";; "uu%@@@@@@@@@@uu" @"";;;>
|
||||||
|
Y "UUUUUUUUU" @@
|
||||||
|
`; ___ _ @
|
||||||
|
`;. ,====\\=. .;'
|
||||||
|
``""""`==\\=='
|
||||||
|
`;=====
|
||||||
|
===
|
||||||
|
|
48
README.md
Normal file
48
README.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
Contents
|
||||||
|
========
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Scope](#scope)
|
||||||
|
* [Installation](#installation)
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
*Shitbox* is inspired by the project [busybox](https://busybox.net/) but with a
|
||||||
|
much more limited scope. While Busybox aims to be "*The swiss army knife of
|
||||||
|
embedded linux*" you can think of shitbox as being more like "*The Harbor Freight
|
||||||
|
multi tool of embedded linux*".
|
||||||
|
|
||||||
|
All joking aside the utilities which are present function mostly as expected and
|
||||||
|
the code aims to be robust. It's written in Rust, not C, for whatever that's
|
||||||
|
worth. Like Busybox it is a multi-call binary which is therefore able to share
|
||||||
|
code between applets, making for an overall smaller binary.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
*Shitbox* does not aim to supply an entire system of utilities, but rather a
|
||||||
|
a subset of the most common Unix shell utilities. Things which are out of scope
|
||||||
|
for the project include:
|
||||||
|
- Shells
|
||||||
|
- Network servers
|
||||||
|
- Kernel module handling utilities
|
||||||
|
The code aims to be portable across **Unix** variants, ie Linux and BSD, but not
|
||||||
|
MacOS or Windows. Development occurs on Linux, so if your OS is more exotic then
|
||||||
|
YMMV.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
Building is done using the official Rust toolchain. It is recommended that you
|
||||||
|
install your toolchain using Rustup rather than distro packages, as old compiler
|
||||||
|
versions are not supported.
|
||||||
|
```Sh
|
||||||
|
cargo build --release
|
||||||
|
```
|
||||||
|
The `bootstrap` applet provides facility for installing the binary, creating all
|
||||||
|
required symlinks and installing some nice to haves such as **Unix man pages**
|
||||||
|
and **shell completions** [see below].
|
||||||
|
```Sh
|
||||||
|
target/release/shitbox help bootstrap
|
||||||
|
```
|
||||||
|
### Supported shells for completions
|
||||||
|
- Bash
|
||||||
|
- Fish
|
||||||
|
- NuShell
|
||||||
|
- PowerShell
|
||||||
|
- Zsh
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
use super::{Cmd, ECHO, FALSE, HEAD, HOSTNAME, SHITBOX, SLEEP, TRUE};
|
use super::{Cmd, ECHO, FALSE, HEAD, HOSTNAME, SHITBOX, SLEEP, TRUE, NOLOGIN};
|
||||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||||
use clap_complete::{generate_to, shells, Generator};
|
use clap_complete::{generate_to, shells, Generator};
|
||||||
use clap_complete_nushell::Nushell;
|
use clap_complete_nushell::Nushell;
|
||||||
@ -48,16 +48,59 @@ impl Cmd for Bootstrap {
|
|||||||
.short('u')
|
.short('u')
|
||||||
.long("usr")
|
.long("usr")
|
||||||
.action(ArgAction::SetTrue),
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("soft")
|
||||||
|
.help("Install soft links instead of hardlinks")
|
||||||
|
.short('s')
|
||||||
|
.long("soft")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
])
|
])
|
||||||
.subcommands([
|
.subcommands([
|
||||||
Command::new("all").about("Install everything"),
|
Command::new("all").about("Install everything")
|
||||||
|
.args([
|
||||||
|
Arg::new("soft")
|
||||||
|
.help("Install soft links instead of hardlinks")
|
||||||
|
.short('s')
|
||||||
|
.long("soft")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("all")
|
||||||
|
.help("Install completions for all supported shells")
|
||||||
|
.short('a')
|
||||||
|
.long("all")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("bash")
|
||||||
|
.help("Bash shell completions")
|
||||||
|
.short('b')
|
||||||
|
.long("bash")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("fish")
|
||||||
|
.help("Fish shell completions")
|
||||||
|
.short('f')
|
||||||
|
.long("fish")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("nu")
|
||||||
|
.help("Nushell completions")
|
||||||
|
.short('n')
|
||||||
|
.long("nu")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("pwsh")
|
||||||
|
.help("PowerShell completions")
|
||||||
|
.short('p')
|
||||||
|
.long("pwsh")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("zsh")
|
||||||
|
.help("Zshell completions")
|
||||||
|
.short('z')
|
||||||
|
.long("zsh")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
]),
|
||||||
Command::new("links")
|
Command::new("links")
|
||||||
.about("Install links for each applet")
|
.about("Install links for each applet")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("soft")
|
Arg::new("soft")
|
||||||
.help("Install soft links instead of hardlinks")
|
.help("Install soft links instead of hardlinks")
|
||||||
.short('s')
|
.short('s')
|
||||||
.long("soft"),
|
.long("soft")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
),
|
),
|
||||||
Command::new("manpages")
|
Command::new("manpages")
|
||||||
.about("Install Unix man pages")
|
.about("Install Unix man pages")
|
||||||
@ -91,6 +134,11 @@ impl Cmd for Bootstrap {
|
|||||||
.short('p')
|
.short('p')
|
||||||
.long("pwsh")
|
.long("pwsh")
|
||||||
.action(ArgAction::SetTrue),
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("zsh")
|
||||||
|
.help("Zshell completions")
|
||||||
|
.short('z')
|
||||||
|
.long("zsh")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
@ -104,10 +152,22 @@ impl Cmd for Bootstrap {
|
|||||||
if let Some(prefix) = matches.get_one::<String>("prefix") {
|
if let Some(prefix) = matches.get_one::<String>("prefix") {
|
||||||
let commands: Commands = Commands {
|
let commands: Commands = Commands {
|
||||||
items: vec![
|
items: vec![
|
||||||
&BOOTSTRAP, &ECHO, &FALSE, &HEAD, &HOSTNAME, &TRUE, &SLEEP, &SHITBOX,
|
&BOOTSTRAP, &ECHO, &FALSE, &HEAD, &HOSTNAME, &NOLOGIN, &TRUE, &SLEEP, &SHITBOX,
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
let usr = matches.get_flag("usr");
|
let usr = matches.get_flag("usr");
|
||||||
|
if let Some(progpath) = crate::progpath() {
|
||||||
|
let mut outpath = PathBuf::from(prefix);
|
||||||
|
outpath.push("bin");
|
||||||
|
println!("Installing binary:");
|
||||||
|
if !outpath.exists() {
|
||||||
|
fs::create_dir_all(&outpath)?;
|
||||||
|
println!(" mkdir: {}", outpath.display());
|
||||||
|
}
|
||||||
|
outpath.push(env!("CARGO_PKG_NAME"));
|
||||||
|
fs::copy(&progpath, &outpath)?;
|
||||||
|
println!(" install: {} -> {}", progpath.display(), outpath.display());
|
||||||
|
}
|
||||||
match matches.subcommand() {
|
match matches.subcommand() {
|
||||||
Some(("links", matches)) => {
|
Some(("links", matches)) => {
|
||||||
commands.links(prefix, usr, matches)?;
|
commands.links(prefix, usr, matches)?;
|
||||||
@ -118,7 +178,8 @@ impl Cmd for Bootstrap {
|
|||||||
Some(("completions", matches)) => {
|
Some(("completions", matches)) => {
|
||||||
commands.completions(prefix, matches)?;
|
commands.completions(prefix, matches)?;
|
||||||
}
|
}
|
||||||
Some(("all", _matches)) => {
|
Some(("all", matches)) => {
|
||||||
|
commands.links(prefix, usr, matches)?;
|
||||||
commands.manpages(prefix)?;
|
commands.manpages(prefix)?;
|
||||||
commands.completions(prefix, matches)?;
|
commands.completions(prefix, matches)?;
|
||||||
}
|
}
|
||||||
@ -216,6 +277,33 @@ impl<'a> Commands<'a> {
|
|||||||
|
|
||||||
fn links(&self, prefix: &str, usr: bool, cmd: &ArgMatches) -> Result<(), Box<dyn Error>> {
|
fn links(&self, prefix: &str, usr: bool, cmd: &ArgMatches) -> Result<(), Box<dyn Error>> {
|
||||||
println!("Generating links:");
|
println!("Generating links:");
|
||||||
|
let mut binpath = PathBuf::from(prefix);
|
||||||
|
binpath.push("bin");
|
||||||
|
if !binpath.exists() {
|
||||||
|
fs::create_dir_all(&binpath)?;
|
||||||
|
println!(" mkdir: {}", binpath.display());
|
||||||
|
}
|
||||||
|
binpath.pop();
|
||||||
|
binpath.push("sbin");
|
||||||
|
if !binpath.exists() {
|
||||||
|
fs::create_dir_all(&binpath)?;
|
||||||
|
println!(" mkdir: {}", binpath.display());
|
||||||
|
}
|
||||||
|
if usr {
|
||||||
|
binpath.pop();
|
||||||
|
binpath.push("usr");
|
||||||
|
binpath.push("bin");
|
||||||
|
if !binpath.exists() {
|
||||||
|
fs::create_dir_all(&binpath)?;
|
||||||
|
println!(" mkdir: {}", binpath.display());
|
||||||
|
}
|
||||||
|
binpath.pop();
|
||||||
|
binpath.push("sbin");
|
||||||
|
if !binpath.exists() {
|
||||||
|
fs::create_dir_all(&binpath)?;
|
||||||
|
println!(" mkdir: {}", binpath.display());
|
||||||
|
}
|
||||||
|
}
|
||||||
let soft = cmd.get_flag("soft");
|
let soft = cmd.get_flag("soft");
|
||||||
self.items
|
self.items
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -16,6 +16,7 @@ mod ln;
|
|||||||
mod ls;
|
mod ls;
|
||||||
mod mountpoint;
|
mod mountpoint;
|
||||||
mod mv;
|
mod mv;
|
||||||
|
pub mod nologin;
|
||||||
mod pwd;
|
mod pwd;
|
||||||
mod rm;
|
mod rm;
|
||||||
mod rmdir;
|
mod rmdir;
|
||||||
@ -28,8 +29,9 @@ pub use {
|
|||||||
self::hostname::{Hostname, HOSTNAME},
|
self::hostname::{Hostname, HOSTNAME},
|
||||||
bootstrap::{Bootstrap, BOOTSTRAP},
|
bootstrap::{Bootstrap, BOOTSTRAP},
|
||||||
echo::{Echo, ECHO},
|
echo::{Echo, ECHO},
|
||||||
head::{Head, HEAD},
|
|
||||||
r#false::{False, FALSE},
|
r#false::{False, FALSE},
|
||||||
|
head::{Head, HEAD},
|
||||||
|
nologin::{Nologin, NOLOGIN},
|
||||||
r#true::{True, TRUE},
|
r#true::{True, TRUE},
|
||||||
shitbox::{Shitbox, SHITBOX},
|
shitbox::{Shitbox, SHITBOX},
|
||||||
sleep::{Sleep, SLEEP},
|
sleep::{Sleep, SLEEP},
|
||||||
@ -85,15 +87,14 @@ pub trait Cmd {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
symlink(binpath, linkpath)?;
|
symlink(&binpath, &linkpath)?;
|
||||||
|
println!(" symlink: {} -> {}", binpath, linkpath.display());
|
||||||
} else {
|
} else {
|
||||||
let mut binpath = PathBuf::from(prefix);
|
let mut binpath = PathBuf::from(prefix);
|
||||||
if usr {
|
|
||||||
binpath.push("usr");
|
|
||||||
}
|
|
||||||
binpath.push("bin");
|
binpath.push("bin");
|
||||||
binpath.push("shitbox");
|
binpath.push(env!("CARGO_PKG_NAME"));
|
||||||
fs::hard_link(binpath, linkpath)?;
|
fs::hard_link(&binpath, &linkpath)?;
|
||||||
|
println!(" link: {} -> {}", binpath.display(), linkpath.display());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
35
src/cmd/nologin/mod.rs
Normal file
35
src/cmd/nologin/mod.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use clap::Command;
|
||||||
|
use std::process;
|
||||||
|
use super::Cmd;
|
||||||
|
|
||||||
|
pub struct Nologin {
|
||||||
|
name: &'static str,
|
||||||
|
path: Option<crate::Path>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const NOLOGIN: Nologin = Nologin {
|
||||||
|
name: "nologin",
|
||||||
|
path: Some(crate::Path::Sbin),
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Cmd for Nologin {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cli(&self) -> clap::Command {
|
||||||
|
Command::new(self.name)
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
.author("Nathan Fisher")
|
||||||
|
.about("Denies a user account login ability")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _matches: Option<&clap::ArgMatches>) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
eprintln!("I'm sorry, I can't let you do that, Dave");
|
||||||
|
process::exit(42);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path(&self) -> Option<crate::Path> {
|
||||||
|
self.path
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
use super::{Cmd, BOOTSTRAP, ECHO, FALSE, HEAD, HOSTNAME, SLEEP, TRUE};
|
use super::{Cmd, BOOTSTRAP, ECHO, FALSE, HEAD, HOSTNAME, SLEEP, TRUE, NOLOGIN};
|
||||||
use clap::Command;
|
use clap::Command;
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
@ -30,6 +30,7 @@ impl Cmd for Shitbox {
|
|||||||
ECHO.cli(),
|
ECHO.cli(),
|
||||||
FALSE.cli(),
|
FALSE.cli(),
|
||||||
HEAD.cli(),
|
HEAD.cli(),
|
||||||
|
NOLOGIN.cli(),
|
||||||
HOSTNAME.cli(),
|
HOSTNAME.cli(),
|
||||||
SLEEP.cli(),
|
SLEEP.cli(),
|
||||||
TRUE.cli(),
|
TRUE.cli(),
|
||||||
@ -43,9 +44,11 @@ impl Cmd for Shitbox {
|
|||||||
return Err(Box::new(io::Error::new(ErrorKind::Other, "No input")));
|
return Err(Box::new(io::Error::new(ErrorKind::Other, "No input")));
|
||||||
};
|
};
|
||||||
match matches.subcommand() {
|
match matches.subcommand() {
|
||||||
|
Some(("bootstrap", matches)) => BOOTSTRAP.run(Some(matches))?,
|
||||||
Some(("echo", _matches)) => ECHO.run(None)?,
|
Some(("echo", _matches)) => ECHO.run(None)?,
|
||||||
Some(("false", _matches)) => FALSE.run(None)?,
|
Some(("false", _matches)) => FALSE.run(None)?,
|
||||||
Some(("head", matches)) => HEAD.run(Some(matches))?,
|
Some(("head", matches)) => HEAD.run(Some(matches))?,
|
||||||
|
Some(("nologin", _matches)) => NOLOGIN.run(None)?,
|
||||||
Some(("hostname", matches)) => HOSTNAME.run(Some(matches))?,
|
Some(("hostname", matches)) => HOSTNAME.run(Some(matches))?,
|
||||||
Some(("sleep", matches)) => SLEEP.run(Some(matches))?,
|
Some(("sleep", matches)) => SLEEP.run(Some(matches))?,
|
||||||
Some(("true", _matches)) => TRUE.run(None)?,
|
Some(("true", _matches)) => TRUE.run(None)?,
|
||||||
|
11
src/lib.rs
11
src/lib.rs
@ -2,7 +2,7 @@
|
|||||||
use std::{env, error::Error, path::PathBuf, string::ToString};
|
use std::{env, error::Error, path::PathBuf, string::ToString};
|
||||||
|
|
||||||
pub mod cmd;
|
pub mod cmd;
|
||||||
use cmd::{Cmd, ECHO, FALSE, HEAD, HOSTNAME, SHITBOX, SLEEP, TRUE};
|
use cmd::{Cmd, ECHO, FALSE, HEAD, HOSTNAME, SHITBOX, SLEEP, TRUE, NOLOGIN};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Path {
|
pub enum Path {
|
||||||
@ -24,6 +24,14 @@ pub fn progname() -> Option<String> {
|
|||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn progpath() -> Option<PathBuf> {
|
||||||
|
match progname() {
|
||||||
|
Some(s) if s == "shitbox" => env::args().next().map(PathBuf::from),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run() -> Result<(), Box<dyn Error>> {
|
pub fn run() -> Result<(), Box<dyn Error>> {
|
||||||
if let Some(progname) = progname() {
|
if let Some(progname) = progname() {
|
||||||
match progname.as_str() {
|
match progname.as_str() {
|
||||||
@ -33,6 +41,7 @@ pub fn run() -> Result<(), Box<dyn Error>> {
|
|||||||
HEAD.run(Some(&HEAD.cli().get_matches()))?;
|
HEAD.run(Some(&HEAD.cli().get_matches()))?;
|
||||||
}
|
}
|
||||||
"hostname" => HOSTNAME.run(Some(&HOSTNAME.cli().get_matches()))?,
|
"hostname" => HOSTNAME.run(Some(&HOSTNAME.cli().get_matches()))?,
|
||||||
|
"nologin" => NOLOGIN.run(None)?,
|
||||||
"true" => TRUE.run(None)?,
|
"true" => TRUE.run(None)?,
|
||||||
"shitbox" => {
|
"shitbox" => {
|
||||||
SHITBOX.run(Some(&SHITBOX.cli().get_matches()))?;
|
SHITBOX.run(Some(&SHITBOX.cli().get_matches()))?;
|
||||||
|
Loading…
Reference in New Issue
Block a user