shutdown WIP

This commit is contained in:
2026-07-09 17:22:32 +05:30
parent 0cd38d041e
commit 0d9af8f605
7 changed files with 123 additions and 5 deletions
+4
View File
@@ -0,0 +1,4 @@
[package]
name = "wolzd"
version = "0.0.1"
edition = "2024"
+28
View File
@@ -0,0 +1,28 @@
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),
}
}
}
+72
View File
@@ -0,0 +1,72 @@
mod error;
use crate::error::{DError, DResult};
use std::{
io::Read,
net::{TcpListener, TcpStream},
process::{Command, Stdio},
time::Duration,
};
fn main() -> DResult<()> {
let address = "0.0.0.0:21367";
let listener = TcpListener::bind(address).map_err(DError::TcpBindError)?;
println!("Listening on {}", address);
for mut stream in listener.incoming() {
match &mut stream {
Ok(stream) => {
if let Err(e) = handle_connection(stream) {
eprintln!("Failed to handle request {}", e);
}
}
Err(e) => eprintln!("{}", e),
}
}
Ok(())
}
fn handle_connection(stream: &mut TcpStream) -> DResult<()> {
// TODO: Slowloris
stream
.set_read_timeout(Some(Duration::from_secs(5)))
.map_err(DError::ConnectionReadError)?;
let command = read_command(stream)?;
match command.as_str() {
"shutdown" => execute_shutdown_command(),
_ => Err(DError::InvalidRequest(command)),
}
}
fn execute_shutdown_command() -> DResult<()> {
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 status_code = output
.status
.code()
.ok_or(DError::CommandError("No exit code returned!".to_string()))?;
if status_code != 0 {
return Err(DError::CommandExecutionError(output));
};
Ok(())
}
fn read_command(stream: &mut TcpStream) -> DResult<String> {
let mut buf = Vec::new();
let read = stream.read_to_end(&mut buf).map_err(DError::ConnectionReadError)?;
let command = String::from_utf8_lossy(&buf[..read]).to_string();
Ok(command)
}
fn build_shutdown_cmd() -> Command {
let mut cmd = Command::new("systemctl");
cmd.arg("-k");
cmd.arg("poweroff");
cmd
}