use std::error::Error; use std::fmt; use std::io::Error as IoError; use command_runner::CommandRunner; use symbols::Symbol; #[derive(Debug, PartialEq)] pub enum UserAdderError { AlreadyExists, UnknownError, ImplError(E) } impl Error for UserAdderError { fn description(&self) -> &str { match self { &UserAdderError::AlreadyExists => "User already exists", &UserAdderError::UnknownError => "Unknown error", &UserAdderError::ImplError(_) => "User adding error" } } fn cause(&self) -> Option<&Error> { match self { &UserAdderError::ImplError(ref e) => Some(e), _ => None } } } impl fmt::Display for UserAdderError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.cause() { Some(e) => write!(f, "{} (cause: {})", self.description(), e), None => write!(f, "{}", self.description()) } } } pub trait UserAdder { type SubE: Error; fn add_user(&self, user_name: &str) -> Result<(), UserAdderError>; } #[derive(Debug, PartialEq)] pub enum UserError { GenericError, ExecError(E) } impl Error for UserError { fn description(&self) -> &str { match self { &UserError::GenericError => "Could not find out if user exists", &UserError::ExecError(_) => "Error executing symbol" } } fn cause(&self) -> Option<&Error> { match self { &UserError::ExecError(ref e) => Some(e), _ => None } } } impl fmt::Display for UserError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.cause() { Some(e) => write!(f, "{} (cause: {})", self.description(), e), None => write!(f, "{}", self.description()) } } } pub struct User<'a, E, A> where E: Error + Sized, A: 'a + UserAdder { user_name: &'a str, command_runner: &'a CommandRunner, user_adder: &'a A } impl<'a, E: Error + Sized, A: 'a + UserAdder> User<'a, E, A> { pub fn new(user_name: &'a str, command_runner: &'a CommandRunner, user_adder: &'a A) -> User<'a, E, A> { User { user_name: user_name, command_runner: command_runner, user_adder: user_adder } } } impl<'a, E: Error, A: UserAdder> fmt::Display for User<'a, E, A> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "User {}", self.user_name) } } impl<'a, E: Error, A: UserAdder> Symbol for User<'a, E, A> { type Error = UserError>; fn target_reached(&self) -> Result { let output = self.command_runner.run_with_args("getent", &["passwd", self.user_name]); match output { Ok(output) => match output.status.code() { Some(2) => Ok(false), Some(0) => Ok(true), _ => Err(UserError::GenericError) }, Err(_) => Err(UserError::GenericError) } } fn execute(&self) -> Result<(), Self::Error> { self.user_adder.add_user(self.user_name).map_err(|e| UserError::ExecError(e)) } } pub struct SystemUserAdder<'a> { command_runner: &'a CommandRunner } impl<'a> SystemUserAdder<'a> { pub fn new(command_runner: &'a CommandRunner) -> SystemUserAdder<'a> { SystemUserAdder { command_runner: command_runner } } } impl<'a> UserAdder for SystemUserAdder<'a> { type SubE = IoError; fn add_user(&self, user_name: &str) -> Result<(), UserAdderError> { let output = self.command_runner.run_with_args("adduser", &["--system", "--disabled-login", "--disabled-password", user_name]); match output { Ok(output) => match output.status.code() { Some(0) => Ok(()), Some(1) => Err(UserAdderError::AlreadyExists), Some(_) => Err(UserAdderError::UnknownError), None => Err(UserAdderError::UnknownError), }, Err(e) => Err(UserAdderError::ImplError(e)) } } } #[cfg(test)] mod test { use std::error::Error; use std::fmt; use command_runner::StdCommandRunner; use symbols::Symbol; use symbols::user::User; use symbols::user::UserAdder; use symbols::user::UserAdderError; #[derive(Debug, PartialEq)] struct DummyError; impl Error for DummyError { fn description(&self) -> &str { "DummyError" } } impl fmt::Display for DummyError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "DummyError") } } struct DummyUserAdder; impl UserAdder for DummyUserAdder { type SubE = DummyError; fn add_user(&self, user_name: &str) -> Result<(), UserAdderError> { Ok(()) } } #[test] fn test_target_reached_nonexisting() { let symbol = User { user_name: "nonexisting", command_runner: &StdCommandRunner, user_adder: &DummyUserAdder }; assert_eq!(symbol.target_reached(), Ok(false)); } #[test] fn test_target_reached_root() { let symbol = User { user_name: "root", command_runner: &StdCommandRunner, user_adder: &DummyUserAdder }; assert_eq!(symbol.target_reached(), Ok(true)); } }