use std::{error::Error, os::unix::process::CommandExt, process::Command};
use log::debug;
use pam_client::{conv_cli::Conversation, Session};
pub(crate) struct CmdData<'a> {
pub(crate) program: String,
pub(crate) args: Vec<&'a str>,
}
impl<'a> CmdData<'a> {
pub(crate) fn new(mut command: Vec<&'a str>) -> Result<Self, Box<dyn Error>> {
let mut program = String::new();
debug!("Extract the first word then remove it after verifying its existence");
let data = match command.get(0) {
Some(data) => data,
None => {
return Err(From::from(
"Command is empty! Please give Rudo something to launch",
))
}
};
program.push_str(data);
command.remove(0);
let args = command;
debug!("Return the new Command structure");
Ok(Self { program, args })
}
}
pub(crate) fn start_command(
data: CmdData<'_>,
session: &Session<'_, Conversation>,
user: &users::User,
) -> Result<(), Box<dyn Error>> {
debug!("Start of the command");
let mut child = Command::new(data.program)
.args(data.args)
.envs(session.envlist().iter_tuples()) .uid(user.uid()) .gid(user.primary_group_id()) .spawn()?;
child.wait()?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::{CmdData, Error};
#[test]
fn test_command_new() -> Result<(), Box<dyn Error>> {
let command = CmdData::new(vec!["test"]);
if command.is_ok() {
Ok(())
} else {
Err(From::from("Test failed to create structure"))
}
}
#[test]
fn test_command_new_empty() -> Result<(), Box<dyn Error>> {
let command = CmdData::new(vec![]);
if command.is_err() {
Ok(())
} else {
Err(From::from("Test failed to see an empty vector"))
}
}
#[test]
fn test_command_new_full() -> Result<(), Box<dyn Error>> {
let command = CmdData::new(vec!["test", "command", "full"])?;
if command.program == "test" && command.args == vec!["command", "full"] {
Ok(())
} else {
Err(From::from("Test failed to reproduced structure"))
}
}
}