single tool

This commit is contained in:
cool-mist
2026-07-11 08:48:08 +05:30
parent cc5e33c31a
commit 4b52bdce76
17 changed files with 168 additions and 168 deletions
Generated
-11
View File
@@ -5,14 +5,3 @@ version = 4
[[package]]
name = "wolz"
version = "0.0.1"
dependencies = [
"wolz-lib",
]
[[package]]
name = "wolz-lib"
version = "0.0.1"
[[package]]
name = "wolzd"
version = "0.0.1"
+4 -5
View File
@@ -1,5 +1,4 @@
[workspace]
members = [
"crates/*",
]
resolver = "2"
[package]
name = "wolz"
version = "0.0.1"
edition = "2024"
-7
View File
@@ -1,7 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "wolz"
version = "0.0.1"
-7
View File
@@ -1,7 +0,0 @@
[package]
name = "wolz"
version = "0.0.1"
edition = "2024"
[dependencies]
wolz-lib = { path = "../wolz-lib" }
-47
View File
@@ -1,47 +0,0 @@
use std::env::args;
use wolz_lib::{error::WResult, wolz::Wolz};
fn main() -> WResult<()> {
let arg_1 = args().nth(1);
let Some(arg_1) = arg_1 else {
print_usage();
return Ok(());
};
match arg_1.as_str() {
"-h" | "--help" => {
print_usage();
return Ok(());
}
_ => {
let wolz = Wolz::create()?;
wolz.wake_up(&arg_1)?;
Ok(())
}
}
}
fn print_usage() {
println!(
"{}",
r#"usage: woly ARG
Options:
ARG Either the mac address of the device to send the wol magic
packet to, or a nickname specified in woly.conf to lookup
the mac. See details about config file below.
Eg: woly aa:bb:cc:dd:ee:ff
Eg: woly potato
Config file:
Filename woly.conf
Location $WOLY_CONFIG_DIR/woly.conf, then $XDG_CONFIG_DIR/woly.conf,
then $HOME/woly.conf
Format KEY=VALUE
one per line without spaces, no comments allowed
Example potato=aa:bb:cc:dd:ee:ff
idly=12:34:23:e2:3d:ff
"#
);
}
-4
View File
@@ -1,4 +0,0 @@
[package]
name = "wolzd"
version = "0.0.1"
edition = "2024"
-28
View File
@@ -1,28 +0,0 @@
use std::{fmt::Display, process::Output};
pub type DResult<T> = Result<T, DError>;
#[derive(Debug)]
pub(crate) enum DError {
InvalidRequest(String),
TcpBindError(std::io::Error),
ConnectionReadError(std::io::Error),
CommandError(String),
CommandExecutionError(Output),
}
impl Display for DError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DError::CommandError(s) => write!(f, "Failed to execute command {}", s),
DError::CommandExecutionError(output) => {
writeln!(f, "Exit Code : {}", output.status.code().unwrap())?;
writeln!(f, "Stdout : {}", String::from_utf8_lossy(&output.stdout))?;
writeln!(f, "Stderr : {}", String::from_utf8_lossy(&output.stderr))
},
DError::TcpBindError(e) => write!(f, "Failed to create tcp listener {}", e),
DError::ConnectionReadError(e) => write!(f, "Error while reading from the socket {}", e),
DError::InvalidRequest(s) => write!(f, "Command '{}' in request is invalid, dropping it", s),
}
}
}
-4
View File
@@ -1,4 +0,0 @@
[package]
name = "wolz-lib"
version = "0.0.1"
edition = "2024"
-32
View File
@@ -1,32 +0,0 @@
use std::fmt::Display;
pub type WResult<T> = std::result::Result<T, WError>;
#[derive(Debug)]
pub enum WError {
ParseMacError(String),
NotAMac(String),
NickNotAlphanumeric(String),
NickNotMapped(String),
InvalidConfigDir(String),
ConfigDirInitError(String),
ConfigFileFormatError(String),
UdpSocketBindError(String),
}
impl Display for WError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let to_write = match self {
WError::ParseMacError(s) => format!("{}", s),
WError::NotAMac(s) => format!("'{}' is not a valid MAC", s),
WError::NickNotAlphanumeric(s) => format!("{}", s),
WError::NickNotMapped(s) => format!("{}", s),
WError::InvalidConfigDir(s) => format!("{}", s),
WError::ConfigDirInitError(s) => format!("{}", s),
WError::ConfigFileFormatError(s) => format!("{}", s),
WError::UdpSocketBindError(s) => format!("{}", s),
};
write!(f, "{}", to_write)
}
}
-5
View File
@@ -1,5 +0,0 @@
pub mod error;
pub(crate) mod mac;
pub(crate) mod config;
mod ifaddrs;
pub mod wolz;
@@ -1,6 +1,4 @@
mod error;
use crate::error::{DError, DResult};
use crate::error::{WError, WResult};
use std::{
io::Read,
net::{TcpListener, TcpStream},
@@ -8,9 +6,9 @@ use std::{
time::Duration,
};
fn main() -> DResult<()> {
pub fn daemon() -> WResult<()> {
let address = "0.0.0.0:21367";
let listener = TcpListener::bind(address).map_err(DError::TcpBindError)?;
let listener = TcpListener::bind(address).map_err(WError::DaemonSocketBindError)?;
println!("Listening for TCP packets at {}", address);
for mut stream in listener.incoming() {
match &mut stream {
@@ -26,39 +24,43 @@ fn main() -> DResult<()> {
Ok(())
}
fn handle_connection(stream: &mut TcpStream) -> DResult<()> {
fn handle_connection(stream: &mut TcpStream) -> WResult<()> {
// TODO: Slowloris
stream
.set_read_timeout(Some(Duration::from_secs(5)))
.map_err(DError::ConnectionReadError)?;
.map_err(WError::DaemonConnectionReadError)?;
let command = read_command(stream)?;
match command.as_str() {
"shutdown" => execute_shutdown_command(),
_ => Err(DError::InvalidRequest(command)),
_ => Err(WError::DaemonInvalidRequest(command)),
}
}
fn execute_shutdown_command() -> DResult<()> {
fn execute_shutdown_command() -> WResult<()> {
let mut shutdown_cmd = build_shutdown_cmd();
shutdown_cmd.stdout(Stdio::piped());
shutdown_cmd.stderr(Stdio::piped());
let output = shutdown_cmd.output().map_err(|e| DError::CommandError(e.to_string()))?;
let output = shutdown_cmd
.output()
.map_err(|e| WError::DaemonCommandError(e.to_string()))?;
let status_code = output
.status
.code()
.ok_or(DError::CommandError("No exit code returned!".to_string()))?;
.ok_or(WError::DaemonCommandError("No exit code returned!".to_string()))?;
if status_code != 0 {
return Err(DError::CommandExecutionError(output));
return Err(WError::DaemonCommandExecutionError(output));
};
Ok(())
}
fn read_command(stream: &mut TcpStream) -> DResult<String> {
fn read_command(stream: &mut TcpStream) -> WResult<String> {
let mut buf = Vec::new();
let read = stream.read_to_end(&mut buf).map_err(DError::ConnectionReadError)?;
let read = stream
.read_to_end(&mut buf)
.map_err(WError::DaemonConnectionReadError)?;
let command = String::from_utf8_lossy(&buf[..read]).to_string();
Ok(command)
}
+52
View File
@@ -0,0 +1,52 @@
use std::fmt::Display;
pub type WResult<T> = std::result::Result<T, WError>;
#[derive(Debug)]
pub enum WError {
// LIB
ParseMacError(String),
NotAMac(String),
NickNotAlphanumeric(String),
NickNotMapped(String),
InvalidConfigDir(String),
ConfigDirInitError(String),
ConfigFileFormatError(String),
UdpSocketBindError(String),
InvalidCommandString(String),
DaemonSocketBindError(std::io::Error),
DaemonConnectionReadError(std::io::Error),
DaemonInvalidRequest(String),
DaemonCommandError(String),
DaemonCommandExecutionError(std::process::Output),
}
impl Display for WError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let to_write = match self {
WError::ParseMacError(s) => format!("{}", s),
WError::NotAMac(s) => format!("'{}' is not a valid MAC", s),
WError::NickNotAlphanumeric(s) => format!("{}", s),
WError::NickNotMapped(s) => format!("{}", s),
WError::InvalidConfigDir(s) => format!("{}", s),
WError::ConfigDirInitError(s) => format!("{}", s),
WError::ConfigFileFormatError(s) => format!("{}", s),
WError::UdpSocketBindError(s) => format!("{}", s),
WError::InvalidCommandString(s) => format!("Command string '{}' is unknown", s),
WError::DaemonCommandError(s) => format!("Failed to execute command {}", s),
WError::DaemonCommandExecutionError(output) => format!(
"\nExit Code : {}\nStdout : {}\nStderr : {}",
output.status.code().unwrap(),
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
),
WError::DaemonSocketBindError(e) => format!("Failed to create tcp listener {}", e),
WError::DaemonConnectionReadError(e) => format!("Error while reading from the socket {}", e),
WError::DaemonInvalidRequest(s) => format!("Command '{}' in request is invalid, dropping it", s),
};
write!(f, "{}", to_write)
}
}
+71
View File
@@ -0,0 +1,71 @@
mod config;
mod daemon;
mod error;
mod ifaddrs;
mod mac;
mod wolz;
use error::WResult;
use std::env::args;
use wolz::Wolz;
use crate::wolz::WCommand;
fn main() -> WResult<()> {
let mut args = args();
let arg_1 = args.next();
let Some(arg_1) = arg_1 else {
return print_usage();
};
match arg_1.as_str() {
"-h" | "--help" | "help" => {
return print_usage();
}
_ => {
let command = args.next();
let Some(command) = command else {
return print_usage();
};
match command.as_str() {
"daemon" => daemon::daemon(),
_ => {
let arg = args.next();
let Some(arg) = arg else {
return print_usage();
};
let wolz = Wolz::create()?;
wolz.execute(&WCommand::create(command, arg))
}
}
}
}
}
fn print_usage() -> WResult<()> {
println!(
"{}",
r#"usage: woly ARG
Options:
ARG Either the mac address of the device to send the wol magic
packet to, or a nickname specified in woly.conf to lookup
the mac. See details about config file below.
Eg: woly aa:bb:cc:dd:ee:ff
Eg: woly potato
Config file:
Filename woly.conf
Location $WOLY_CONFIG_DIR/woly.conf, then $XDG_CONFIG_DIR/woly.conf,
then $HOME/woly.conf
Format KEY=VALUE
one per line without spaces, no comments allowed
Example potato=aa:bb:cc:dd:ee:ff
idly=12:34:23:e2:3d:ff
"#
);
Ok(())
}
+25 -4
View File
@@ -1,22 +1,39 @@
use std::net::UdpSocket;
use crate::{
config::Config,
error::{WError, WResult},
ifaddrs::{self},
config::Config, daemon, error::{WError, WResult}, ifaddrs::{self},
};
pub struct Wolz {
config: Config,
}
pub struct WCommand {
name: String,
arg: String,
}
impl WCommand {
pub fn create(name: String, arg: String) -> Self {
Self { name, arg }
}
}
impl Wolz {
pub fn create() -> WResult<Self> {
let config = Config::create()?;
Ok(Self { config })
}
pub fn wake_up(&self, mac_or_nick: &str) -> WResult<()> {
pub fn execute(&self, command: &WCommand) -> WResult<()> {
match command.name.as_str() {
"up" => self.wake_up(&command.arg),
"down" => self.shut_down(&command.arg),
_ => Err(WError::InvalidCommandString(command.name.to_string())),
}
}
fn wake_up(&self, mac_or_nick: &str) -> WResult<()> {
let mac = self.config.get_mac(mac_or_nick)?;
let mut magic_bytes = [0u8; 102];
mac.copy_magic_bytes(&mut magic_bytes);
@@ -55,6 +72,10 @@ impl Wolz {
Ok(())
}
pub fn shut_down(&self, mac_or_nick: &str) -> WResult<()> {
todo!()
}
}
fn try_send_magic_bytes(magic_bytes: &[u8; 102], send_addr: &str, broadcast_addr: &str) -> WResult<()> {