diff --git a/01_phase_rust_src/sv/src/executor.rs b/01_phase_rust_src/sv/src/executor.rs new file mode 100644 index 0000000..eae1327 --- /dev/null +++ b/01_phase_rust_src/sv/src/executor.rs @@ -0,0 +1,41 @@ + + +pub mod sent_signal; + +use crate::status_obj; + +pub fn execute(svdir_var: String, svwait_var: i32, verbose: i8, command: &str, services: Vec) -> i32{ + + let mut exit_code: i32 = 0; + + for sv in services { + let ch1 = sv.chars().next().unwrap(); + let ch2_row = &sv.chars().collect::>()[..2]; + let ch2: String = ch2_row.into_iter().collect(); + let path; + + if ch1 == '/' || ch2 == "~/"{ + // case absolute path for the service + // + path = sv.clone(); + } else { + // case relative path for the service. + // + path = svdir_var.clone() + "/" + &sv; + } + + let status_option = status_obj::StatusObj::new(path, sv); + match status_option { + Some(status) => { + exit_code += sent_signal::sent_signal(svwait_var, verbose, command, status); + }, + None => { + if exit_code < 99 { + exit_code += 1; + } + }, + }; + } + return exit_code + +} diff --git a/01_phase_rust_src/sv/src/executor/sent_signal.rs b/01_phase_rust_src/sv/src/executor/sent_signal.rs new file mode 100644 index 0000000..bee4cb3 --- /dev/null +++ b/01_phase_rust_src/sv/src/executor/sent_signal.rs @@ -0,0 +1,48 @@ + + +use crate::status_obj; + +pub fn sent_signal( svwait_var: i32, verbose: i8, command: &str, mut sv: status_obj::StatusObj) -> i32 { + // Return 0 in case everything worked fine, return 1 if timeout or error. + + dbg!(svwait_var); + dbg!(verbose); + + // execute command. + if command == "s" { + // case command is status + let mut status_sv = sv.get_status_string(); + let is_log = sv.get_log(); + if is_log { + let log_option = sv.get_obj_log(); + match log_option { + Some(mut log) => { + status_sv = status_sv + "; " + &log.get_status_string(); + }, + None => {// TODO: Do nothing for now, eventually, increase by one exit code. + }, + }; + } + println!("{}", status_sv); + return 0; + } + + //let service = fs::OpenOptions::new().append(true).open("supervise/control"); + + //if ! service.is_ok() { + // println!("warning: {}: unable to append to supervise/control: file does not exist", sv.clone()); + // return make_exit_code(exit_code); + //} + //let mut control = match service { + // Ok(file) => file, + // Err(..) => panic!("Shouln't goes there, the programmer is trash."), + //}; + + + // TODO + // sent the proper signal to supervise/control + // + // if verbose = 1, wait for the service to reach the proper state or timeout. + println!("Error, command not implemented."); + return 1; +} diff --git a/01_phase_rust_src/sv/src/main.rs b/01_phase_rust_src/sv/src/main.rs index 8f722c3..66f78d3 100644 --- a/01_phase_rust_src/sv/src/main.rs +++ b/01_phase_rust_src/sv/src/main.rs @@ -1,5 +1,7 @@ mod parser; +mod executor; +pub mod status_obj; use std::env; use std::process::exit; @@ -23,29 +25,24 @@ fn main() { Err(..) => 7, }; - let mut verbose = 0; - - dbg!(svdir_var); - dbg!(svwait_var); - + let mut verbose: i8 = 0; // run the parser let args: Vec = env::args().collect(); let arg_parser: Vec = parser::parse_args(args); - //dbg!(arg_parser); - - let mut i = 0; - let mut command; + let mut command = "INVALID"; + let mut services: Vec = Vec::new(); + + // make data from parser. for val in arg_parser.iter() { if i == 0 { if val == "-v" { verbose = 1; - dbg!(verbose); } else if val == "-w" { i = 3; @@ -55,32 +52,39 @@ fn main() { i += 1; } else { - if val.len() == 2 { - println!("sv: illegal option -- {}", val.chars().nth(1).unwrap() ); - // TODO: thread NOT pannic if it is not an ASCII character. + if val.len() >= 2 { + let mut j = 0; + for ch in val.chars() { + if j == 1 { + println!("sv: illegal option -- {}", ch ); + } + j += 1; + } } parser::misc::usage(); exit(100); } } else if i == 1 { + // Set the command as first arguments. command = val; - dbg!(command); i += 1; } - // TODO: Exec the command on all given services. + else if i == 2 { + // add services to control. + services.push(val.to_string()); + } else if i == 3 { + // change svwait after flag -w svwait_var = match val.parse::() { Ok(val) => val, Err(..) => svwait_var, }; - dbg!(svwait_var); i = 0; } } - - - - + // Exit after all services are correctly executed. + exit(executor::execute(svdir_var, svwait_var, verbose, command, services)); + } diff --git a/01_phase_rust_src/sv/src/parser.rs b/01_phase_rust_src/sv/src/parser.rs index 5c9c18e..cb09545 100644 --- a/01_phase_rust_src/sv/src/parser.rs +++ b/01_phase_rust_src/sv/src/parser.rs @@ -52,6 +52,7 @@ pub fn parse_args(args: Vec) -> Vec{ } } + return parser; } @@ -71,7 +72,7 @@ fn phase2(arg: &String) -> String { pub fn parse_args_1(arg: &String) -> String{ // Get a string - // Return a vect ('first_char', 'length', 'entry_necessary') + // Return the flag. let ch1 = arg.chars().next().unwrap(); @@ -79,12 +80,13 @@ pub fn parse_args_1(arg: &String) -> String{ //println!("{}", ch1); if ch1 == '-' && arg.len() >= 2{ - return (&arg[..2]).to_string() + let retour = &arg.chars().collect::>()[..2]; + return retour.into_iter().collect(); } else if ch1 == '-' { return ch1.to_string() } - println!("{}",arg); + //println!("{}",arg); return "".to_string() @@ -95,15 +97,12 @@ pub fn parse_args_2(arg: &String) -> String{ const POSSIBLE: &'static [&'static str] = &["start", "stop", "reload", "restart", "shutdown", "force-stop", "force-reload", "force-restart", "force-shutdown", "try-restart"]; const CPOSSIBLE: &'static [char] = &['s', 'u', 'd', 'o', 'p', 'c', 'h', 'a', 'i', 'q', '1', '2', 't', 'k']; - - for var in POSSIBLE.iter() { if arg == var { return var.to_string() } } - let ch1 = arg.chars().next().unwrap(); @@ -113,7 +112,6 @@ pub fn parse_args_2(arg: &String) -> String{ } } - return "INVALID".to_string() diff --git a/01_phase_rust_src/sv/src/status_obj.rs b/01_phase_rust_src/sv/src/status_obj.rs new file mode 100644 index 0000000..a87ff49 --- /dev/null +++ b/01_phase_rust_src/sv/src/status_obj.rs @@ -0,0 +1,192 @@ + +mod misc; + +use std::path::Path; +use std::env::set_current_dir; +use std::fs; +use std::io::prelude::*; +use std::time::SystemTime; + + + +pub struct StatusObj { + svname: String, // Service name + svpath: String, // Service path + time: u64, // 0 -> 7 + //nano_seconds: u32, // 8 -> 11 + pid: u32, // 12 -> 15 + pause_run: bool, // 16 + up_down: char, // 17 + term_sig: bool, // 18 + run_finish: bool, // 19 + down: bool, // is down file ? + log: bool, // is log/supervise/ok exists ? +} + +impl StatusObj { + pub fn new(path_string: String, sv: String ) -> Option { + // if error when making the status_obj, return None, + // Else, return the status_obj. + // + + let path = Path::new(&path_string); + + if ! set_current_dir(path).is_ok() { + println!("fail: {}: unable to change to service directory: file does not exist", sv); + return None + } + let ok_option = Path::new("supervise/ok"); + if ! ok_option.exists() { + println!("warning: {}: unable to open supervise/ok: file does not exist", sv); + return None; + } + + + // TODO: check if there is a process reading the pipe. + // piste : https://docs.rs/tokio/latest/tokio/net/unix/pipe/struct.OpenOptions.html + //let mut control_option = fs::File::open("supervise/control"); + //let status_option = fs::OpenOptions::new().read(true).open("supervise/control"); + //match control_option { + // Ok(_file) => {}, + // Err(ee) => { + // println!("fail: {}: runsv not running {}", sv, ee); + // return None; + // }, + //}; + let status_option = fs::OpenOptions::new().read(true).open("supervise/status"); + let mut status = match status_option { + Ok(file) => file, + Err(..) => { + println!("warning: {}: unable to open supervise/status: file does not exist", sv); + return None; + }, + }; + let mut contents: Vec = Vec::new(); + let option_size = status.read_to_end(&mut contents); + + let size = match option_size { + Ok(size) => size, + Err(..) => { + println!("warning: {}: couldn't read supervise/status", sv); + return None + }, + }; + + if size != 20 { + dbg!(size); + dbg!(contents); + println!("warning: {}: bad supervise/status format", sv); + return None + } + + let is_down; + if Path::new("down").exists() { + is_down = true + } else { + is_down = false + } + + let log_exists; + if Path::new("log/supervise/ok").exists() { + log_exists = true + } else { + log_exists = false + } + + let time_buf: Vec = contents[0..8].to_vec(); + //let nano_buf: Vec = contents[8..12].to_vec(); + let pid_buf: Vec = contents[12..16].to_vec(); + + let seconds = misc::return_u8_in_u64(time_buf); + //let nano = misc::return_u8_in_u32(nano_buf); + let pid_found = misc::return_reverse_u8_in_u32(pid_buf); + + let pause_run_raw = misc::make_pause_run(contents[16]); // done + let up_down_raw = misc::make_up_down(contents[17]); // done + let term_sig_raw = misc::make_term_sig(contents[18]); // done + let run_finish_raw = misc::make_run_finish(contents[19]); // done + + Some(StatusObj { + svname: sv, + svpath: path_string, + time: seconds, + //nano_seconds: nano, + pid: pid_found, + pause_run: pause_run_raw, + up_down: up_down_raw, + term_sig: term_sig_raw, + run_finish: run_finish_raw, + down: is_down, + log: log_exists, + }) + } + pub fn get_status_string(&mut self) -> String { + + let status_sv; + let pid_string: String; + let down_string; + let pause_string; + let ud_string; + let term_string; + if self.run_finish == false { + status_sv = "down:"; + pid_string = "".to_owned(); + if self.down == false { + down_string = ", normally up"; + } else { + down_string = ""; + } + if self.up_down == 'u' { + ud_string = ", want up"; + } else { + ud_string = ""; + } + } else { + status_sv = "run:"; + pid_string = "(pid ".to_owned() + &self.pid.to_string() + ") "; + if self.down == true { + down_string = ", normally down"; + } else { + down_string = ""; + } + if self.up_down == 'd' { + ud_string = ", want down"; + } else { + ud_string = ""; + } + } + if self.pause_run == true { + pause_string = ", paused"; + } else { + pause_string = ""; + } + if self.term_sig == true { + term_string = ", got TERM"; + } else { + term_string = ""; + } + + let time_repaired: u64 = self.time - 4611686018427387914; + let sys_time_result = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH); + let sys_time = match sys_time_result { + Ok(x) => x.as_secs(), + Err(..) => time_repaired, + }; + let dif_time = sys_time - time_repaired; + + // Make the string to return + let return_string: String = status_sv.to_owned() + " " + &self.svname + ": " + &pid_string + &dif_time.to_string() + "s" + down_string + pause_string + ud_string + term_string; + + return return_string; + } + + pub fn get_log(&mut self) -> bool { + return self.log; + } + + pub fn get_obj_log(&mut self) -> Option { + return StatusObj::new(self.svpath.clone() + "/log", "log".to_string()); + } +} + + diff --git a/01_phase_rust_src/sv/src/status_obj/misc.rs b/01_phase_rust_src/sv/src/status_obj/misc.rs new file mode 100644 index 0000000..896e2d5 --- /dev/null +++ b/01_phase_rust_src/sv/src/status_obj/misc.rs @@ -0,0 +1,74 @@ + +pub fn make_pause_run(pr_int: u8) -> bool { + if pr_int == 0 { + return false // run + } else { + return true // pause. + } +} + +pub fn make_up_down(ud_int: u8) -> char { + if ud_int == 117 { + return 'u' + } else { + return 'd' + } +} + +pub fn make_term_sig(ts_int: u8) -> bool{ + if ts_int == 0 { + return false // Normal + } else { + return true // Got Term + } +} + +pub fn make_run_finish(rf_int: u8) -> bool { + if rf_int == 0 { + return false // service finish. + } else { + return true // service run + } +} + +pub fn return_reverse_u8_in_u32(mut table: Vec) -> u32 { + // Table make 4 values u8 in one u32 + if table.len() != 4 { + return 0 + } + let mut r: u32 = 0; + table.reverse(); + for i in table.iter() { + r = r * 256; + r += >::into(*i); + } + return r +} + +#[allow(dead_code)] +pub fn return_u8_in_u32(table: Vec) -> u32 { + // Table make 4 values u8 in one u32 + if table.len() != 4 { + return 0 + } + let mut r: u32 = 0; + for i in table.iter() { + r = r * 256; + r += >::into(*i); + } + return r +} + +pub fn return_u8_in_u64(table: Vec) -> u64 { + // Table make 8 values u8 in one u64 + if table.len() != 8 { + return 0 + } + let mut r: u64 = 0; + for i in table.iter() { + r = r * 256; + r += >::into(*i); + } + return r +} +