diff --git a/01_phase_rust_src/sv-rustit/src/executor.rs b/01_phase_rust_src/sv-rustit/src/executor.rs index eae1327..bcd588e 100644 --- a/01_phase_rust_src/sv-rustit/src/executor.rs +++ b/01_phase_rust_src/sv-rustit/src/executor.rs @@ -1,41 +1,17 @@ -pub mod sent_signal; - -use crate::status_obj; +pub mod execute_service; pub fn execute(svdir_var: String, svwait_var: i32, verbose: i8, command: &str, services: Vec) -> i32{ + // split a service vector into different sv. 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; + exit_code += execute_service::execute_service(svdir_var.clone(), svwait_var, verbose, command, sv); + if exit_code > 99 { + exit_code = 99; } - - 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-rustit/src/executor/execute_service.rs b/01_phase_rust_src/sv-rustit/src/executor/execute_service.rs new file mode 100644 index 0000000..db675ac --- /dev/null +++ b/01_phase_rust_src/sv-rustit/src/executor/execute_service.rs @@ -0,0 +1,22 @@ + +mod sent_signal; +mod make_path; + +use crate::status_obj; + +pub fn execute_service(svdir_var: String, svwait_var: i32, verbose: i8, command: &str, sv: String) -> i32 { + // make a sv object from a string, svdir_var, and sent it the command signal. + + let path = make_path::make_path(svdir_var, sv.clone()); + + let status_option = status_obj::StatusObj::new(path, sv); + match status_option { + Some(status) => { + return sent_signal::sent_signal(svwait_var, verbose, command, status); + }, + None => { + return 1; + }, + }; +} + diff --git a/01_phase_rust_src/sv-rustit/src/executor/execute_service/make_path.rs b/01_phase_rust_src/sv-rustit/src/executor/execute_service/make_path.rs new file mode 100644 index 0000000..2e807c1 --- /dev/null +++ b/01_phase_rust_src/sv-rustit/src/executor/execute_service/make_path.rs @@ -0,0 +1,17 @@ + +pub fn make_path(svdir_var: String, sv: String) -> String { + 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; + } else { + // case relative path for the service. + path = svdir_var + "/" + &sv; + } + + return path +} diff --git a/01_phase_rust_src/sv-rustit/src/executor/execute_service/sent_signal.rs b/01_phase_rust_src/sv-rustit/src/executor/execute_service/sent_signal.rs new file mode 100644 index 0000000..4004b85 --- /dev/null +++ b/01_phase_rust_src/sv-rustit/src/executor/execute_service/sent_signal.rs @@ -0,0 +1,68 @@ + +mod misc; + +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. + + match command { + "s" => { + // case command is status + return misc::print_status(sv); + }, + "u" => { + // case where command is up + return misc::run_verbose(sv.sent_signal(b"u"), true, verbose, svwait_var, sv); + }, + "d" => { + // case where command is up + return misc::run_verbose(sv.sent_signal(b"d"), false, verbose, svwait_var, sv); + }, + "o" => { + // case where command is run once. + return misc::run_verbose(sv.sent_signal(b"o"), true, verbose, svwait_var, sv); + }, + "p" => { + // case where it's the pause command which is entered. + return misc::pause_verbose(sv.sent_signal(b"p"), true, verbose, svwait_var, sv); + }, + "c" => { + // case where it's the continue command which is entered. + return misc::pause_verbose(sv.sent_signal(b"c"), false, verbose, svwait_var, sv); + }, + "h" => { + return misc::noexcept_verbose(sv.sent_signal(b"h"), verbose, sv); + }, + "a" => { + return misc::noexcept_verbose(sv.sent_signal(b"a"), verbose, sv); + }, + "i" => { + return misc::noexcept_verbose(sv.sent_signal(b"i"), verbose, sv); + }, + "q" => { + return misc::noexcept_verbose(sv.sent_signal(b"q"), verbose, sv); + }, + "1" => { + return misc::noexcept_verbose(sv.sent_signal(b"1"), verbose, sv); + }, + "2" => { + return misc::noexcept_verbose(sv.sent_signal(b"2"), verbose, sv); + }, + "t" => { + return misc::term_verbose(sv.sent_signal(b"t"), false, verbose, svwait_var, sv); + }, + "k" => { + return misc::kill_verbose(sv.sent_signal(b"k"), verbose, svwait_var, sv); + }, + "e" | "x" => { + return misc::exit_verbose(sv.sent_signal(b"x"), verbose, svwait_var, sv); + }, + other => { + println!("Error, command {} not implemented.", other); // TODO : Put the real error + // message. + return 1; + } + }; +} + diff --git a/01_phase_rust_src/sv-rustit/src/executor/execute_service/sent_signal/misc.rs b/01_phase_rust_src/sv-rustit/src/executor/execute_service/sent_signal/misc.rs new file mode 100644 index 0000000..f93636f --- /dev/null +++ b/01_phase_rust_src/sv-rustit/src/executor/execute_service/sent_signal/misc.rs @@ -0,0 +1,196 @@ + +use crate::status_obj; + +use std::thread::sleep; +use std::time::Duration; + +pub fn print_status(mut sv: status_obj::StatusObj) -> i32 { + // The status code is the one who will be + 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 => { + return 1 + }, + }; + } + println!("{}", status_sv); + return 0; +} + + +pub fn run_verbose(sent_signal: bool, expected: bool, verbose: i8, svwait_var: i32, mut sv: status_obj::StatusObj) -> i32 { + // if the excepted is true, wait for the service to run. + // If the excepted is false, wait for the service to down. + if sent_signal && verbose == 1 { + sleep(Duration::from_secs_f32(0.0005)); + let mut time_wait = 0; + loop { + let status = sv.update_status(); + if status == 1 { + return 1; + } + if sv.is_up() == expected { + println!("ok: {}", sv.get_status_string()); + return 0 + } + if time_wait >= svwait_var*2 { + println!("timeout: {}", sv.get_status_string()); + return 1 + } + time_wait += 1; + sleep(Duration::from_secs_f32(0.5)); + } + } else if sent_signal && verbose == 0 { + return 0 + } else { + // Case sent_signal != true. + return 1 + } +} + +pub fn pause_verbose(sent_signal: bool, expected: bool, verbose: i8, svwait_var: i32, mut sv: status_obj::StatusObj) -> i32 { + // if the excepted is true, wait for the service to pause. + // if the excepted is false, wait for the service to continue. + if sent_signal && verbose == 1 { + sleep(Duration::from_secs_f32(0.0005)); + let mut time_wait = 0; + loop { + let status = sv.update_status(); + if status == 1 { + return 1; + } + if sv.is_paused() == expected { + println!("ok: {}", sv.get_status_string()); + return 0 + } + if time_wait >= svwait_var*2 { + println!("timeout: {}", sv.get_status_string()); + return 1 + } + time_wait += 1; + sleep(Duration::from_secs_f32(0.5)); + } + } else if sent_signal && verbose == 0 { + return 0 + } else { + // Case sent_signal != true. + return 1 + } +} + +pub fn term_verbose(sent_signal: bool, expected: bool, verbose: i8, svwait_var: i32, mut sv: status_obj::StatusObj) -> i32 { + // if the excepted is true, wait for the service to get term signal. + // if the excepted is false, wait for the service to interpret the term signal. + if sent_signal && verbose == 1 { + sleep(Duration::from_secs_f32(0.0005)); + let mut time_wait = 0; + loop { + let status = sv.update_status(); + if status == 1 { + return 1; + } + if sv.is_term() == expected { + println!("ok: {}", sv.get_status_string()); + return 0 + } + if time_wait >= svwait_var*2 { + println!("timeout: {}", sv.get_status_string()); + return 1 + } + time_wait += 1; + sleep(Duration::from_secs_f32(0.5)); + } + } else if sent_signal && verbose == 0 { + return 0 + } else { + // Case sent_signal != true. + return 1 + } +} + +pub fn kill_verbose(sent_signal: bool, verbose: i8, svwait_var: i32, mut sv: status_obj::StatusObj) -> i32 { + if sent_signal && verbose == 1 { + sleep(Duration::from_secs_f32(0.0005)); + let mut time_wait = 0; + if ! sv.get_run_finish() { + println!("ok: {}", sv.get_status_string()); + return 0; + } + let pid = sv.get_pid(); + let time = sv.get_time(); + loop { + let status = sv.update_status(); + if status == 1 { + return 1; + } + if pid != sv.get_pid() || time > sv.get_time() { + println!("ok: {}", sv.get_status_string()); + return 0 + } + if time_wait >= svwait_var*2 { + println!("timeout: {}", sv.get_status_string()); + return 1 + } + time_wait += 1; + sleep(Duration::from_secs_f32(0.5)); + } + } else if sent_signal && verbose == 0 { + return 0 + } else { + // Case sent_signal != true. + return 1 + } +} + +pub fn exit_verbose(sent_signal: bool, verbose: i8, svwait_var: i32, mut sv: status_obj::StatusObj) -> i32 { + // if the excepted is true, wait for the service to get term signal. + // if the excepted is false, wait for the service to interpret the term signal. + if sent_signal && verbose == 1 { + sleep(Duration::from_secs_f32(0.0005)); + let mut time_wait = 0; + loop { + let status = sv.update_status(); + if status == 1 { + return 1; + } + if sv.is_exited() == true { + println!("ok: {}", sv.get_status_string()); + return 0 + } + if time_wait >= svwait_var*2 { + println!("timeout: {}", sv.get_status_string()); + return 1 + } + time_wait += 1; + sleep(Duration::from_secs_f32(0.5)); + } + } else if sent_signal && verbose == 0 { + return 0 + } else { + // Case sent_signal != true. + return 1 + } +} + +pub fn noexcept_verbose(sent_signal: bool, verbose: i8, mut sv: status_obj::StatusObj) -> i32 { + if sent_signal && verbose == 1 { + sleep(Duration::from_secs_f32(0.0005)); + let status = sv.update_status(); + if status == 1 { + return 1; + } + println!("ok: {}", sv.get_status_string()); + return 0 + } else if sent_signal && verbose == 0 { + return 0 + } else { + // Case sent_signal != true. + return 1 + } +} diff --git a/01_phase_rust_src/sv-rustit/src/executor/sent_signal.rs b/01_phase_rust_src/sv-rustit/src/executor/sent_signal.rs deleted file mode 100644 index 9955f42..0000000 --- a/01_phase_rust_src/sv-rustit/src/executor/sent_signal.rs +++ /dev/null @@ -1,85 +0,0 @@ - -mod misc; - -use crate::status_obj; - -use std::thread::sleep; -use std::time::Duration; - -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. - - let mut time_wait = 0; - - // execute command. - if command == "s" { - // case command is status - return misc::print_status(sv); - } - - if command == "u" { - // case where command is up - if sv.sent_signal(b"u") { - if verbose == 1 { - loop { - let status = sv.update_status(); - if status == 1 { - return 1; - } - if sv.is_up() == true { - misc::print_status(sv); - return 0 - } - if time_wait >= svwait_var { - println!("fail: {}: timeout", sv.get_name()); - return 1 - } - - time_wait += 1; - sleep(Duration::from_secs(1)); - } - } else { - return 0; - } - } else { - return 1; - } - } - - if command == "d" { - // case where command is up - if sv.sent_signal(b"d") { - if verbose == 1 { - loop { - let status = sv.update_status(); - if status == 1 { - return 1; - } - if sv.is_up() == false { - misc::print_status(sv); - return 0 - } - if time_wait >= svwait_var { - println!("fail: {}: timeout", sv.get_name()); - return 1 - } - - time_wait += 1; - sleep(Duration::from_secs(1)); - } - } else { - return 0; - } - } else { - return 1; - } - } - - - // 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-rustit/src/executor/sent_signal/misc.rs b/01_phase_rust_src/sv-rustit/src/executor/sent_signal/misc.rs deleted file mode 100644 index 7a8e2a5..0000000 --- a/01_phase_rust_src/sv-rustit/src/executor/sent_signal/misc.rs +++ /dev/null @@ -1,21 +0,0 @@ - -use crate::status_obj; - -pub fn print_status(mut sv: status_obj::StatusObj) -> i32 { - // The status code is the one who will be - 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 => { - return 1 - }, - }; - } - println!("{}", status_sv); - return 0; -} diff --git a/01_phase_rust_src/sv-rustit/src/parser.rs b/01_phase_rust_src/sv-rustit/src/parser.rs index cb09545..b2cf51b 100644 --- a/01_phase_rust_src/sv-rustit/src/parser.rs +++ b/01_phase_rust_src/sv-rustit/src/parser.rs @@ -95,7 +95,7 @@ pub fn parse_args_1(arg: &String) -> String{ 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']; + const CPOSSIBLE: &'static [char] = &['s', 'u', 'd', 'o', 'p', 'c', 'h', 'a', 'i', 'q', '1', '2', 't', 'k', 'e', 'x']; for var in POSSIBLE.iter() { if arg == var { diff --git a/01_phase_rust_src/sv-rustit/src/status_obj.rs b/01_phase_rust_src/sv-rustit/src/status_obj.rs index 10a26b3..a37fa86 100644 --- a/01_phase_rust_src/sv-rustit/src/status_obj.rs +++ b/01_phase_rust_src/sv-rustit/src/status_obj.rs @@ -1,5 +1,7 @@ mod misc; +mod sent_signal; +mod check_test; use std::path::Path; use std::env::set_current_dir; @@ -37,14 +39,30 @@ impl StatusObj { } // Check if supervise/control and supervise/ok exists, and if runsv running. - let control_exists = misc::check_fifo(sv.clone(), "supervise/ok"); - if control_exists == false { - return None; - } - let control_exists = misc::check_fifo(sv.clone(), "supervise/control"); - if control_exists == false { - return None; - } + let control_exists = sent_signal::check_fifo("supervise/ok"); + match control_exists { + 1 => { + println!("fail: {sv}: runsv not running"); + return None; + }, + 2 => { + println!("warning: {sv}: unable to open {path_string}: file does not exist"); + return None + }, + _other => {}, + }; + let control_exists = sent_signal::check_fifo("supervise/control"); + match control_exists { + 1 => { + println!("fail: {sv}: runsv not running"); + return None; + }, + 2 => { + println!("warning: {sv}: unable to open {path_string}: file does not exist"); + return None + }, + _other => {}, + }; let status_option = fs::OpenOptions::new().read(true).open("supervise/status"); @@ -166,6 +184,10 @@ impl StatusObj { pub fn get_status_string(&mut self) -> String { // return the status for this service in particular. + + if self.is_exited() { + return self.svname.clone() + ": runsv not running"; + } let status_sv; let pid_string: String; @@ -200,7 +222,7 @@ impl StatusObj { ud_string = ""; } } - if self.pause_run == true { + if self.pause_run == true && self.run_finish { pause_string = ", paused"; } else { pause_string = ""; @@ -211,6 +233,7 @@ impl StatusObj { 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 { @@ -226,11 +249,42 @@ impl StatusObj { } pub fn sent_signal(&mut self, signal: &[u8]) -> bool { - return misc::sent_signal(signal); + return sent_signal::sent_signal(signal); } pub fn is_up(&mut self) -> bool { - return self.run_finish; + let check = fs::File::open("check"); + match check { + Ok(file) => { + return check_test::check_test(file, self.run_finish) + }, + Err(..) => return self.run_finish, + }; + } + + pub fn is_paused(&mut self) -> bool { + if self.pause_run == true { + return true + } else { + return false + } + } + + pub fn is_term(&mut self) -> bool { + if self.term_sig == true { + return true + } else { + return false + } + } + + pub fn is_exited(&mut self) -> bool { + let control_exists = sent_signal::check_fifo("supervise/ok"); + if control_exists == 1 || control_exists == 2 { + return true; + } + return false; + } pub fn get_name(&mut self) -> String { @@ -245,6 +299,18 @@ impl StatusObj { return self.log; } + pub fn get_pid(&mut self) -> u32 { + return self.pid; + } + + pub fn get_time(&mut self) -> u64 { + return self.time; + } + + pub fn get_run_finish(&mut self) -> bool { + return self.run_finish; + } + 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-rustit/src/status_obj/check_test.rs b/01_phase_rust_src/sv-rustit/src/status_obj/check_test.rs new file mode 100644 index 0000000..1bddbd6 --- /dev/null +++ b/01_phase_rust_src/sv-rustit/src/status_obj/check_test.rs @@ -0,0 +1,33 @@ + +use std::fs::File; +use std::process::Command; +use std::os::unix::fs::PermissionsExt; + + +pub fn check_test(file: File, run_finish: bool) -> bool { + // Check the permission, and return the result of check + let meta = file.metadata(); + match meta { + Ok(m) => { + let permissions = m.permissions(); + //println!("permissions: {:o}", permissions.mode() & 0o100700); + if permissions.mode() & 0o100700 == 0o100700 { + // Execute script + let mut command = Command::new("sh"); + let status = command.arg("check").status(); + match status { + Ok(s) => { + if s.success() { + return true + } else { + return false + } + }, + Err(..) => {} + }; + } + }, + Err(..) => {}, + }; + return run_finish; +} diff --git a/01_phase_rust_src/sv-rustit/src/status_obj/misc.rs b/01_phase_rust_src/sv-rustit/src/status_obj/misc.rs index 731d92f..45a20ba 100644 --- a/01_phase_rust_src/sv-rustit/src/status_obj/misc.rs +++ b/01_phase_rust_src/sv-rustit/src/status_obj/misc.rs @@ -1,7 +1,4 @@ -use tokio::net::unix::pipe; -use tokio::runtime::Runtime; -use std::io::ErrorKind; pub fn make_pause_run(pr_int: u8) -> bool { if pr_int == 0 { @@ -76,58 +73,3 @@ pub fn return_u8_in_u64(table: Vec) -> u64 { return r } -pub fn check_fifo(sv: String, path: &str) -> bool { - // Check if fifo is available. If yes, return true. - // If no, return false. - let rt = Runtime::new().unwrap(); - let _guard = rt.enter(); - - let sender = pipe::OpenOptions::new().open_sender(path); - match sender { - Ok(..) => return true, - Err(e) if e.raw_os_error() == Some(libc::ENXIO) => { - println!("fail: {sv}: runsv not running"); - return false; - }, - Err(..) => { - println!("warning: {sv}: unable to open {path}: file does not exist"); - return false; - }, - }; -} - -pub fn sent_signal(signal: &[u8]) -> bool { - // sent the char to supervise/control. - // return true in case everything worked fine, false if there was any errors. - let rt = Runtime::new().unwrap(); - let _guard = rt.enter(); - - let sender = pipe::OpenOptions::new().open_sender("supervise/control"); - match sender { - Ok(tx) => { - loop { - match tx.try_write(signal) { - Ok(..) => { - return true; - }, - Err(e) if e.kind() == ErrorKind::WouldBlock => { - continue; - }, - Err(e) => { - dbg!(e); - println!("Impossible Error while writing on pipe."); - return false; - }, - }; - }; - }, - Err(e) if e.raw_os_error() == Some(libc::ENXIO) => { - println!("fail: sv: runsv not running"); - return false; - }, - Err(..) => { - println!("warning: sv: unable to open path: file does not exist"); - return false; - }, - }; -} diff --git a/01_phase_rust_src/sv-rustit/src/status_obj/sent_signal.rs b/01_phase_rust_src/sv-rustit/src/status_obj/sent_signal.rs new file mode 100644 index 0000000..76e42fb --- /dev/null +++ b/01_phase_rust_src/sv-rustit/src/status_obj/sent_signal.rs @@ -0,0 +1,62 @@ + +use tokio::net::unix::pipe; +use tokio::runtime::Runtime; +use std::io::ErrorKind; + + +pub fn check_fifo( path: &str) -> u32 { + // Check if fifo is available. If yes, return true. + // If no, return false. + let rt = Runtime::new().unwrap(); + let _guard = rt.enter(); + + let sender = pipe::OpenOptions::new().open_sender(path); + match sender { + Ok(..) => return 0, + Err(e) if e.raw_os_error() == Some(libc::ENXIO) => { + //println!("fail: {sv}: runsv not running"); + return 1; + }, + Err(..) => { + //println!("warning: {sv}: unable to open {path}: file does not exist"); + return 2; + }, + }; +} + +pub fn sent_signal(signal: &[u8]) -> bool { + // sent the char to supervise/control. + // return true in case everything worked fine, false if there was any errors. + let rt = Runtime::new().unwrap(); + let _guard = rt.enter(); + + let sender = pipe::OpenOptions::new().open_sender("supervise/control"); + match sender { + Ok(tx) => { + loop { + match tx.try_write(signal) { + Ok(..) => { + return true; + }, + Err(e) if e.kind() == ErrorKind::WouldBlock => { + continue; + }, + Err(e) => { + dbg!(e); + println!("Unable to write to supervise/control"); + return false; + }, + }; + }; + }, + Err(e) if e.raw_os_error() == Some(libc::ENXIO) => { + println!("fail: sv: runsv not running"); + return false; + }, + Err(..) => { + println!("warning: sv: unable to open path: file does not exist"); + return false; + }, + }; +} +