···6677Some of them do useful things, some of them were just written for fun. Please do not have the expectation that these are written in a super robust fashion; most were written for one-off tasks and experiments.
8899-If you want to play around with these programs, you just need [Rust][rust] and [cargo-eval][cargo-eval].
99+If you want to play around with these programs, you just need [Rust][rust]. Scripting support is currently available only on Nightly (current as of 1.93.0), but once stabilized I'll remove the +nightly flags. Please note that these scripts are built in debug mode, not release. This makes it easy to make quick changes but performance will suffer for more involved tasks, though these scripts aren't meant for that kind of work.
10101111Be aware that dev work for this repo is done on UNIX-y systems, so they might not work on Windows.
12121313[stb]: https://www.youtube.com/watch?v=eAhWIO1Ra6M
1414[rust]: https://www.rust-lang.org/tools/install
1515-[cargo-eval]: https://github.com/reitermarkus/cargo-eval
-55
cidrcheck
···11-#!/usr/bin/env -S cargo eval --
22-33-// cargo-deps: argh = "0.1", cidr = "0.2.1"
44-55-use std::net::IpAddr;
66-use std::str::FromStr;
77-88-use argh::FromArgs;
99-use cidr::IpCidr;
1010-1111-#[derive(FromArgs)]
1212-#[argh(description = "Display the ip range for a CIDR and check if an ip falls within.")]
1313-struct App {
1414- #[argh(
1515- option,
1616- description = "ip that will be checked against the provided CIDR.",
1717- from_str_fn(parse_ip)
1818- )]
1919- ip: Option<IpAddr>,
2020-2121- #[argh(positional, description = "CIDR to inspect", from_str_fn(parse_cidr))]
2222- cidr: IpCidr,
2323-}
2424-2525-fn main() {
2626- let App { ip, cidr } = argh::from_env();
2727- println!(
2828- "CIDR {} has a range of: {} to {}",
2929- cidr,
3030- cidr.first_address(),
3131- cidr.last_address()
3232- );
3333-3434- println!("CIDR {} has a netmask of {}", cidr, cidr.mask());
3535-3636- if let Some(ip) = ip {
3737- print!("IP {}", ip);
3838- let falls_within = cidr.contains(&ip);
3939- if falls_within {
4040- print!(" falls ");
4141- } else {
4242- print!(" does not fall ");
4343- }
4444-4545- println!("within {}", cidr);
4646- }
4747-}
4848-4949-fn parse_ip(value: &str) -> Result<IpAddr, String> {
5050- IpAddr::from_str(value).map_err(|e| format!("{}", e))
5151-}
5252-5353-fn parse_cidr(value: &str) -> Result<IpCidr, String> {
5454- IpCidr::from_str(value).map_err(|e| format!("{}", e))
5555-}
+61
cidrcheck.rs
···11+#!/usr/bin/env -S cargo +nightly -Zscript
22+33+---
44+[package]
55+edition = "2024"
66+[dependencies]
77+argh = "0.1"
88+cidr = "0.2.1"
99+---
1010+1111+use std::net::IpAddr;
1212+use std::str::FromStr;
1313+1414+use argh::FromArgs;
1515+use cidr::IpCidr;
1616+1717+#[derive(FromArgs)]
1818+#[argh(description = "Display the ip range for a CIDR and check if an ip falls within.")]
1919+struct App {
2020+ #[argh(
2121+ option,
2222+ description = "ip that will be checked against the provided CIDR.",
2323+ from_str_fn(parse_ip)
2424+ )]
2525+ ip: Option<IpAddr>,
2626+2727+ #[argh(positional, description = "CIDR to inspect", from_str_fn(parse_cidr))]
2828+ cidr: IpCidr,
2929+}
3030+3131+fn main() {
3232+ let App { ip, cidr } = argh::from_env();
3333+ println!(
3434+ "CIDR {} has a range of: {} to {}",
3535+ cidr,
3636+ cidr.first_address(),
3737+ cidr.last_address()
3838+ );
3939+4040+ println!("CIDR {} has a netmask of {}", cidr, cidr.mask());
4141+4242+ if let Some(ip) = ip {
4343+ print!("IP {}", ip);
4444+ let falls_within = cidr.contains(&ip);
4545+ if falls_within {
4646+ print!(" falls ");
4747+ } else {
4848+ print!(" does not fall ");
4949+ }
5050+5151+ println!("within {}", cidr);
5252+ }
5353+}
5454+5555+fn parse_ip(value: &str) -> Result<IpAddr, String> {
5656+ IpAddr::from_str(value).map_err(|e| format!("{}", e))
5757+}
5858+5959+fn parse_cidr(value: &str) -> Result<IpCidr, String> {
6060+ IpCidr::from_str(value).map_err(|e| format!("{}", e))
6161+}
-43
dbg_server
···11-#!/usr/bin/env -S cargo eval --
22-33-// cargo-deps: argh = "0.1"
44-55-use std::io::{BufRead, BufReader};
66-use std::net::TcpListener;
77-use std::str;
88-99-use argh::FromArgs;
1010-1111-#[derive(FromArgs)]
1212-#[argh(description = "simple debug server which logs the data sent to it.")]
1313-struct App {
1414- #[argh(
1515- option,
1616- description = "interface to listen on.",
1717- default = "\"0.0.0.0\".to_string()"
1818- )]
1919- host: String,
2020-2121- #[argh(option, description = "port to listen on.", default = "7331")]
2222- port: u16,
2323-}
2424-2525-fn main() {
2626- let app: App = argh::from_env();
2727-2828- let address = format!("{}:{}", app.host, app.port);
2929- let listener = TcpListener::bind(&address).expect("should be able to start server");
3030-3131- println!("Listening on {}", address);
3232-3333- for stream in listener.incoming() {
3434- let stream = stream.expect("stream should be present");
3535- let mut stream = BufReader::new(stream);
3636-3737- // This is not the "best" way to get the data sent over
3838- // but it sure is the easiest :^)
3939- let data = stream.fill_buf().expect("should have data");
4040- let output = str::from_utf8(data).expect("should be able to parse data as text");
4141- println!("{}", output);
4242- }
4343-}
+48
dbg_server.rs
···11+#!/usr/bin/env -S cargo +nightly -Zscript
22+33+---
44+[package]
55+edition = "2024"
66+[dependencies]
77+argh = "0.1"
88+---
99+1010+use std::io::{BufRead, BufReader};
1111+use std::net::TcpListener;
1212+use std::str;
1313+1414+use argh::FromArgs;
1515+1616+#[derive(FromArgs)]
1717+#[argh(description = "simple debug server which logs the data sent to it.")]
1818+struct App {
1919+ #[argh(
2020+ option,
2121+ description = "interface to listen on.",
2222+ default = "\"0.0.0.0\".to_string()"
2323+ )]
2424+ host: String,
2525+2626+ #[argh(option, description = "port to listen on.", default = "7331")]
2727+ port: u16,
2828+}
2929+3030+fn main() {
3131+ let app: App = argh::from_env();
3232+3333+ let address = format!("{}:{}", app.host, app.port);
3434+ let listener = TcpListener::bind(&address).expect("should be able to start server");
3535+3636+ println!("Listening on {}", address);
3737+3838+ for stream in listener.incoming() {
3939+ let stream = stream.expect("stream should be present");
4040+ let mut stream = BufReader::new(stream);
4141+4242+ // This is not the "best" way to get the data sent over
4343+ // but it sure is the easiest :^)
4444+ let data = stream.fill_buf().expect("should have data");
4545+ let output = str::from_utf8(data).expect("should be able to parse data as text");
4646+ println!("{}", output);
4747+ }
4848+}
···11-#!/usr/bin/env -S cargo eval --
22-33-// cargo-deps: argh = "0.1", humantime = "2.1.0"
44-55-use std::thread;
66-use std::time::{Duration, Instant};
77-88-use argh::FromArgs;
99-1010-#[derive(FromArgs)]
1111-#[argh(description = "Keep track of how long a task runs or set a timer for some period of time.")]
1212-struct App {
1313- #[argh(
1414- option,
1515- description = "how long to wait before starting the stopwatch."
1616- )]
1717- delay: Option<humantime::Duration>,
1818-1919- #[argh(
2020- option,
2121- description = "how long to wait between timer updates.",
2222- default = "\"1ms\".parse::<humantime::Duration>().unwrap()"
2323- )]
2424- pause: humantime::Duration,
2525-2626- #[argh(option, description = "how long to run the stopwatch.")]
2727- duration: Option<humantime::Duration>,
2828-}
2929-3030-fn main() {
3131- let app: App = argh::from_env();
3232-3333- let delay: Option<Duration> = app.delay.map(|d| d.into());
3434- let pause = app.pause.into();
3535- let duration = app
3636- .duration
3737- .map(|d| d.into())
3838- .unwrap_or_else(|| Duration::new(u64::MAX, 0));
3939-4040- if let Some(delay) = delay {
4141- println!("Waiting {:?}...", delay);
4242- thread::sleep(delay);
4343- }
4444-4545- let now = Instant::now();
4646-4747- let mut elapsed = now.elapsed();
4848- while elapsed < duration {
4949- print!("\x1B[2K\rElapsed: {}", humantime::format_duration(elapsed));
5050- thread::sleep(pause);
5151- elapsed = now.elapsed();
5252- }
5353-5454- print!(
5555- "\x1B[2K\rElapsed: {}\nStopped\x07",
5656- humantime::format_duration(elapsed)
5757- );
5858-}
+64
stopwatch.rs
···11+#!/usr/bin/env -S cargo +nightly -Zscript
22+33+---
44+[package]
55+edition = "2024"
66+[dependencies]
77+argh = "0.1"
88+humantime = "2.1.0"
99+---
1010+1111+use std::thread;
1212+use std::time::{Duration, Instant};
1313+1414+use argh::FromArgs;
1515+1616+#[derive(FromArgs)]
1717+#[argh(description = "Keep track of how long a task runs or set a timer for some period of time.")]
1818+struct App {
1919+ #[argh(
2020+ option,
2121+ description = "how long to wait before starting the stopwatch."
2222+ )]
2323+ delay: Option<humantime::Duration>,
2424+2525+ #[argh(
2626+ option,
2727+ description = "how long to wait between timer updates.",
2828+ default = "\"1ms\".parse::<humantime::Duration>().unwrap()"
2929+ )]
3030+ pause: humantime::Duration,
3131+3232+ #[argh(option, description = "how long to run the stopwatch.")]
3333+ duration: Option<humantime::Duration>,
3434+}
3535+3636+fn main() {
3737+ let app: App = argh::from_env();
3838+3939+ let delay: Option<Duration> = app.delay.map(|d| d.into());
4040+ let pause = app.pause.into();
4141+ let duration = app
4242+ .duration
4343+ .map(|d| d.into())
4444+ .unwrap_or_else(|| Duration::new(u64::MAX, 0));
4545+4646+ if let Some(delay) = delay {
4747+ println!("Waiting {:?}...", delay);
4848+ thread::sleep(delay);
4949+ }
5050+5151+ let now = Instant::now();
5252+5353+ let mut elapsed = now.elapsed();
5454+ while elapsed < duration {
5555+ print!("\x1B[2K\rElapsed: {}", humantime::format_duration(elapsed));
5656+ thread::sleep(pause);
5757+ elapsed = now.elapsed();
5858+ }
5959+6060+ print!(
6161+ "\x1B[2K\rElapsed: {}\nStopped\x07",
6262+ humantime::format_duration(elapsed)
6363+ );
6464+}
-111
strs
···11-#!/usr/bin/env -S cargo eval --
22-33-// cargo-deps: argh = "0.1", object = "0.24.0"
44-55-use std::fs::OpenOptions;
66-use std::io::{self, BufReader, Read, Write};
77-use std::path::PathBuf;
88-99-use argh::FromArgs;
1010-use object::{File, Object, ObjectSection, SectionKind};
1111-1212-const MIN_STR_LEN: usize = 4;
1313-1414-const ELF_SIG: [u8; 4] = [0x7F, 0x45, 0x4C, 0x46];
1515-const MACH_O_32_SIG: [u8; 4] = [0xFE, 0xED, 0xFA, 0xCE];
1616-const MACH_O_64_SIG: [u8; 4] = [0xFE, 0xED, 0xFA, 0xCF];
1717-const MACH_O_FAT_SIG: [u8; 4] = [0xCA, 0xFE, 0xBA, 0xBE];
1818-const MACH_O_32_REV_SIG: [u8; 4] = [0xCE, 0xFA, 0xED, 0xFE];
1919-const MACH_O_64_REV_SIG: [u8; 4] = [0xCF, 0xFA, 0xED, 0xFE];
2020-2121-#[derive(FromArgs)]
2222-#[argh(description = "Rust clone of strings(1).")]
2323-struct App {
2424- #[argh(
2525- switch,
2626- description = "ignore heuristics and read all sections of an object file."
2727- )]
2828- all: bool,
2929-3030- #[argh(
3131- option,
3232- description = "the minimum length a valid string needs to be in order to be printed.",
3333- default = "MIN_STR_LEN"
3434- )]
3535- min_length: usize,
3636-3737- #[argh(positional, description = "input file.")]
3838- file: PathBuf,
3939-}
4040-4141-fn main() {
4242- let app: App = argh::from_env();
4343-4444- let file = OpenOptions::new()
4545- .read(true)
4646- .open(app.file)
4747- .expect("could not open source");
4848-4949- let mut reader = BufReader::new(file);
5050-5151- // Preallocate 4MB of space since we're usually dealing with files
5252- let mut contents = Vec::with_capacity(1024 * 1024 * 4);
5353- reader.read_to_end(&mut contents);
5454-5555- let stdout = io::stdout();
5656- let mut handle = stdout.lock();
5757-5858- let mut magic = [0, 0, 0, 0];
5959- if contents.len() >= 4 {
6060- magic.copy_from_slice(&contents[..4]);
6161- }
6262-6363- if is_object_file(&magic) {
6464- print_object_strings(&mut handle, &contents, app.all, app.min_length);
6565- } else {
6666- print_strings(&mut handle, &contents, app.min_length);
6767- }
6868-}
6969-7070-fn is_object_file(magic: &[u8; 4]) -> bool {
7171- magic == &ELF_SIG
7272- || magic == &MACH_O_FAT_SIG
7373- || magic == &MACH_O_32_SIG
7474- || magic == &MACH_O_64_SIG
7575- || magic == &MACH_O_32_REV_SIG
7676- || magic == &MACH_O_64_REV_SIG
7777-}
7878-7979-fn print_object_strings(handle: &mut impl Write, contents: &[u8], all: bool, min_length: usize) {
8080- // We could also read this in a lazy fashion but... I'm lazy at the moment ;)
8181- let object = File::parse(contents).expect("Could not parse object file");
8282- object
8383- .sections()
8484- .filter(|section| all || section.kind() == SectionKind::Data)
8585- .for_each(|section| {
8686- let contents = section.data().expect("section should have data");
8787- print_strings(handle, contents, min_length);
8888- });
8989-}
9090-9191-fn print_strings(handle: &mut impl Write, contents: &[u8], min_length: usize) {
9292- let mut start = 0;
9393- let mut end = 0;
9494-9595- for c in contents.iter() {
9696- let is_printable = c.is_ascii_graphic() || c.is_ascii_whitespace();
9797- let has_minimum_len = (end - start) >= min_length;
9898-9999- if !is_printable && has_minimum_len {
100100- handle.write(&contents[start..end]);
101101- handle.write(&[b'\n']);
102102- start = end + 1;
103103- } else if !is_printable {
104104- start = end + 1;
105105- }
106106-107107- end += 1;
108108- }
109109-110110- handle.flush();
111111-}
+117
strs.rs
···11+#!/usr/bin/env -S cargo +nightly -Zscript
22+33+---
44+[package]
55+edition = "2024"
66+[dependencies]
77+argh = "0.1"
88+object = "0.24.0"
99+---
1010+1111+use std::fs::OpenOptions;
1212+use std::io::{self, BufReader, Read, Write};
1313+use std::path::PathBuf;
1414+1515+use argh::FromArgs;
1616+use object::{File, Object, ObjectSection, SectionKind};
1717+1818+const MIN_STR_LEN: usize = 4;
1919+2020+const ELF_SIG: [u8; 4] = [0x7F, 0x45, 0x4C, 0x46];
2121+const MACH_O_32_SIG: [u8; 4] = [0xFE, 0xED, 0xFA, 0xCE];
2222+const MACH_O_64_SIG: [u8; 4] = [0xFE, 0xED, 0xFA, 0xCF];
2323+const MACH_O_FAT_SIG: [u8; 4] = [0xCA, 0xFE, 0xBA, 0xBE];
2424+const MACH_O_32_REV_SIG: [u8; 4] = [0xCE, 0xFA, 0xED, 0xFE];
2525+const MACH_O_64_REV_SIG: [u8; 4] = [0xCF, 0xFA, 0xED, 0xFE];
2626+2727+#[derive(FromArgs)]
2828+#[argh(description = "Rust clone of strings(1).")]
2929+struct App {
3030+ #[argh(
3131+ switch,
3232+ description = "ignore heuristics and read all sections of an object file."
3333+ )]
3434+ all: bool,
3535+3636+ #[argh(
3737+ option,
3838+ description = "the minimum length a valid string needs to be in order to be printed.",
3939+ default = "MIN_STR_LEN"
4040+ )]
4141+ min_length: usize,
4242+4343+ #[argh(positional, description = "input file.")]
4444+ file: PathBuf,
4545+}
4646+4747+fn main() {
4848+ let app: App = argh::from_env();
4949+5050+ let file = OpenOptions::new()
5151+ .read(true)
5252+ .open(app.file)
5353+ .expect("could not open source");
5454+5555+ let mut reader = BufReader::new(file);
5656+5757+ // Preallocate 4MB of space since we're usually dealing with files
5858+ let mut contents = Vec::with_capacity(1024 * 1024 * 4);
5959+ reader.read_to_end(&mut contents);
6060+6161+ let stdout = io::stdout();
6262+ let mut handle = stdout.lock();
6363+6464+ let mut magic = [0, 0, 0, 0];
6565+ if contents.len() >= 4 {
6666+ magic.copy_from_slice(&contents[..4]);
6767+ }
6868+6969+ if is_object_file(&magic) {
7070+ print_object_strings(&mut handle, &contents, app.all, app.min_length);
7171+ } else {
7272+ print_strings(&mut handle, &contents, app.min_length);
7373+ }
7474+}
7575+7676+fn is_object_file(magic: &[u8; 4]) -> bool {
7777+ magic == &ELF_SIG
7878+ || magic == &MACH_O_FAT_SIG
7979+ || magic == &MACH_O_32_SIG
8080+ || magic == &MACH_O_64_SIG
8181+ || magic == &MACH_O_32_REV_SIG
8282+ || magic == &MACH_O_64_REV_SIG
8383+}
8484+8585+fn print_object_strings(handle: &mut impl Write, contents: &[u8], all: bool, min_length: usize) {
8686+ // We could also read this in a lazy fashion but... I'm lazy at the moment ;)
8787+ let object = File::parse(contents).expect("Could not parse object file");
8888+ object
8989+ .sections()
9090+ .filter(|section| all || section.kind() == SectionKind::Data)
9191+ .for_each(|section| {
9292+ let contents = section.data().expect("section should have data");
9393+ print_strings(handle, contents, min_length);
9494+ });
9595+}
9696+9797+fn print_strings(handle: &mut impl Write, contents: &[u8], min_length: usize) {
9898+ let mut start = 0;
9999+ let mut end = 0;
100100+101101+ for c in contents.iter() {
102102+ let is_printable = c.is_ascii_graphic() || c.is_ascii_whitespace();
103103+ let has_minimum_len = (end - start) >= min_length;
104104+105105+ if !is_printable && has_minimum_len {
106106+ handle.write(&contents[start..end]);
107107+ handle.write(&[b'\n']);
108108+ start = end + 1;
109109+ } else if !is_printable {
110110+ start = end + 1;
111111+ }
112112+113113+ end += 1;
114114+ }
115115+116116+ handle.flush();
117117+}
-28
tag_release
···11-#!/usr/bin/env -S cargo eval --
22-33-// cargo-deps: argh = "0.1", chrono = "0.4"
44-55-use argh::FromArgs;
66-use chrono::prelude::*;
77-88-#[derive(FromArgs)]
99-#[argh(description = "Simple program to kill a process listening on a specific port.")]
1010-struct App {
1111- #[argh(
1212- option,
1313- description = "how to format the date tag.",
1414- default = "\"v%Y%m%d-%H%M\".to_string()"
1515- )]
1616- format: String,
1717-}
1818-1919-fn main() {
2020- let app: App = argh::from_env();
2121-2222- let tag = Utc::now().format(&app.format).to_string();
2323-2424- println!("# Run the following to tag and release this version");
2525- println!();
2626- println!("git tag -a {} -m \"\"", tag);
2727- println!("git push origin --tags");
2828-}
+34
tag_release.rs
···11+#!/usr/bin/env -S cargo +nightly -Zscript
22+33+---
44+[package]
55+edition = "2024"
66+[dependencies]
77+argh = "0.1"
88+crono = "0.4"
99+---
1010+1111+use argh::FromArgs;
1212+use chrono::prelude::*;
1313+1414+#[derive(FromArgs)]
1515+#[argh(description = "Utility to help tag a git release.")]
1616+struct App {
1717+ #[argh(
1818+ option,
1919+ description = "how to format the date tag.",
2020+ default = "\"v%Y%m%d-%H%M\".to_string()"
2121+ )]
2222+ format: String,
2323+}
2424+2525+fn main() {
2626+ let app: App = argh::from_env();
2727+2828+ let tag = Utc::now().format(&app.format).to_string();
2929+3030+ println!("# Run the following to tag and release this version");
3131+ println!();
3232+ println!("git tag -a {} -m \"\"", tag);
3333+ println!("git push origin --tags");
3434+}