From 6c3ec751cca14013309392a1ea98eba9fccbbbb5 Mon Sep 17 00:00:00 2001 From: Zhao Mengmeng Date: Fri, 5 Jul 2024 14:15:22 +0800 Subject: [PATCH] test: fix cargo test failed testcases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. testcase daemon::tests::test_process_config_arm failed. Adopt new init config style to pass the test 2. there is no need to seperate arm and x86, the only deference is ld-linux-aarch64.so.1 vs ld-linux-x86-64.so.2,which should be handled in detect_so. Use a new function ignored_so to handle this. 3. On x86, when run `cargo test`, there are build errors: error[E0308]: mismatched types --> netlink_client.rs:98:37 | 98 | let data = core::str::from_utf8(slice).unwrap(); | -------------------- ^^^^^ expected `u8`, found `i8` | | | arguments to this function are incorrect | = note: expected reference `&[u8]` found reference `&[i8]` note: function defined here fix this casting slice to *const u8. 4. test_check_elf_files_modify_1 and test_check_elf_files_modify_2 can failed the first time to run test, the reason is Command::new().spawn() won't wait the subprocess to finish, causing: ---- daemon::tests::test_check_elf_files_modify_1 stdout ---- thread 'daemon::tests::test_check_elf_files_modify_1' panicked at 'Failed to add watch.: Os { code: 2, kind: NotFound, message: "No such file or directory" }', daemon.rs:246:61 5. use rustfmt to farmat code. --- src/sysboostd/aot.rs | 23 +----- src/sysboostd/config.rs | 79 +++++++++++---------- src/sysboostd/daemon.rs | 120 ++++++++++---------------------- src/sysboostd/netlink_client.rs | 2 +- 4 files changed, 81 insertions(+), 143 deletions(-) diff --git a/src/sysboostd/aot.rs b/src/sysboostd/aot.rs index 1d18ef1..15b7d54 100644 --- a/src/sysboostd/aot.rs +++ b/src/sysboostd/aot.rs @@ -9,13 +9,13 @@ // See the Mulan PSL v2 for more details. // Create: 2023-8-26 -use crate::{common::SYSBOOST_PATH, daemon::db_add_link}; use crate::config::RtoConfig; use crate::lib::fs_ext; use crate::lib::process_ext::run_child; +use crate::{common::SYSBOOST_PATH, daemon::db_add_link}; use goblin::elf::Elf; -use std::{env, fs}; +use std::env; // Obtain the full path from real path, environment variable PATH, current dir fn get_lib_full_path(lib: &str, confpaths: Vec<&str>, rpaths: Vec<&str>, paths: Vec<&str>) -> Option { @@ -50,25 +50,6 @@ fn get_lib_full_path(lib: &str, confpaths: Vec<&str>, rpaths: Vec<&str>, paths: None } -// read elf file as using readelf -pub fn parse_elf_file(elf_path: &str) -> Option { - let elf_bytes = match fs::read(&elf_path) { - Ok(elf_bytes) => elf_bytes, - Err(_e) => { - log::info!("Error: read elf file fault, please check config."); - return None; - } - }; - match Elf::parse(&elf_bytes) { - Ok(elf) => Some(elf), - Err(_e) => { - log::info!("Error: parse elf file fault, please check the elf file"); - None - } - }; - None -} - pub fn find_libs(conf: &RtoConfig, elf: &Elf) -> Vec { let mut libs = conf.libs.clone(); diff --git a/src/sysboostd/config.rs b/src/sysboostd/config.rs index 173dbc4..9f02817 100644 --- a/src/sysboostd/config.rs +++ b/src/sysboostd/config.rs @@ -11,13 +11,14 @@ use crate::common::SYSBOOST_PATH; -use ini::Properties; -use serde::Deserialize; use ini::Ini; +use ini::Properties; use lazy_static::lazy_static; -use std::sync::RwLock; +use serde::Deserialize; use std::io::{BufRead, BufReader}; +use std::path::Path; use std::process::{Command, Stdio}; +use std::sync::RwLock; pub const SYSBOOST_CONFIG_PATH: &str = "/etc/sysboost.d/sysboost.ini"; // only 10 program can use boost @@ -31,7 +32,7 @@ pub struct RtoConfig { // 优化模式 pub mode: String, // 依赖的动态库路径 - pub libs: Vec, // TODO: 修改为字符串, 列表形式影响可读性 + pub libs: Vec, // TODO: 修改为字符串, 列表形式影响可读性 // profile文件路径 pub profile_path: Option, // 环境变量 @@ -55,23 +56,27 @@ pub struct GeneralSection { // libs = /usr/lib64/libtinfo.so.6, xxxx pub struct InitConfig { pub general: GeneralSection, // use inner value to get mutable access - pub elfsections: Vec + pub elfsections: Vec, } // 考虑内部可变性和线程安全 // 可使用Mutex和RwLock // 性能:sysboost只在全局配置文件解析写,其余都只读 lazy_static! { - pub static ref INIT_CONF: RwLock = RwLock::new( - InitConfig { - general: GeneralSection{coredump_monitor_flag: true}, - elfsections: Vec::new() - } - ); + pub static ref INIT_CONF: RwLock = RwLock::new(InitConfig { + general: GeneralSection { coredump_monitor_flag: true }, + elfsections: Vec::new() + }); +} + +fn ignored_so(input: &str) -> bool { + // on x86_64, ignore /lib64/ld-linux-x86-64.so.2 + // on aarch64, ignore /lib/ld-linux-aarch64.so.1 + input == "/usr/lib64/libc.so.6" || input.contains("ld-linux-") } fn detect_so(path: &String, rtoconfig: &mut RtoConfig) { - let args: &Vec = &vec![path.to_string();1]; + let args: &Vec = &vec![path.to_string(); 1]; let mut run_thread = match Command::new("/usr/bin/ldd").args(args).stdout(Stdio::piped()).spawn() { Ok(run_thread) => run_thread, Err(e) => { @@ -90,27 +95,31 @@ fn detect_so(path: &String, rtoconfig: &mut RtoConfig) { for line in reader.lines() { let line = line.unwrap_or_else(|_| "".to_owned()); let start = match line.find('/') { - Some(s) => {s}, - None => continue + Some(s) => s, + None => continue, }; let end = match line.find('(') { - Some(e) => {e}, - None => continue + Some(e) => e, + None => continue, }; let lib_path = line[start..end].trim(); - if lib_path == "/usr/lib64/libc.so.6" || lib_path == "/lib/ld-linux-aarch64.so.1" { + if ignored_so(lib_path) { continue; } rtoconfig.libs.push(lib_path.to_string()); } - log::debug!("Automatically detect {} dependent so files: {:?}",rtoconfig.name, &rtoconfig.libs); + log::debug!("Automatically detect {} dependent so files: {:?}", rtoconfig.name, &rtoconfig.libs); } pub fn parse_sysinit_config() { - let conf_file = match Ini::load_from_file(SYSBOOST_CONFIG_PATH){ - Ok(c) => {c} + parse_init_config(SYSBOOST_CONFIG_PATH) +} + +pub fn parse_init_config(path: impl AsRef) { + let conf_file = match Ini::load_from_file(path) { + Ok(c) => c, Err(e) => { - log::info!("load file {} error: {}",SYSBOOST_CONFIG_PATH, e); + log::info!("load file {} error: {}", SYSBOOST_CONFIG_PATH, e); return; } }; @@ -123,13 +132,13 @@ pub fn parse_sysinit_config() { match sec { Some("general") => { parse_general(prop); - }, + } Some(elf_section) => { parse_rto_config(elf_section.to_string(), prop); i += 1; log::info!("parse elf section config {}", i); - }, - None => continue + } + None => continue, } } } @@ -138,7 +147,7 @@ fn parse_general(prop: &Properties) { match prop.get("coredump_monitor_flag") { Some("false") => { INIT_CONF.write().unwrap().general.coredump_monitor_flag = false; - }, + } _ => {} } } @@ -146,16 +155,15 @@ fn parse_general(prop: &Properties) { fn is_mode_invalid(mode: String) -> bool { if mode != "static" && mode != "static-nolibc" && mode != "share" && mode != "bolt" { true - } - else { + } else { false } } fn parse_rto_config(sec: String, prop: &Properties) { - let sec_name:Vec<&str> = sec.as_str().split("/").collect(); + let sec_name: Vec<&str> = sec.as_str().split("/").collect(); let mut rtoconf = RtoConfig { - name: sec_name[sec_name.len()-1].to_string(), + name: sec_name[sec_name.len() - 1].to_string(), elf_path: sec.clone(), mode: prop.get("mode").unwrap().to_string(), // 需要处理配置文件中libs = ;和没有libs属性的情况 @@ -163,18 +171,17 @@ fn parse_rto_config(sec: String, prop: &Properties) { Some(p) => { if p.trim().is_empty() { Vec::new() - } - else { + } else { p.split(",").map(|s| s.to_string()).collect() } } - None => {Vec::new()} - }, - profile_path: prop.get("profile_path").map(|s| s.to_string()), + None => Vec::new(), + }, + profile_path: prop.get("profile_path").map(|s| s.to_string()), path: prop.get("path").map(|s| s.to_string()), watch_paths: Vec::new(), }; - if rtoconf.elf_path == SYSBOOST_PATH || is_mode_invalid(rtoconf.mode.clone()){ + if rtoconf.elf_path == SYSBOOST_PATH || is_mode_invalid(rtoconf.mode.clone()) { log::error!("invalid config in {}", &sec); return; } @@ -188,4 +195,4 @@ fn parse_rto_config(sec: String, prop: &Properties) { rtoconf.watch_paths.push(lib.split_whitespace().collect()); } INIT_CONF.write().unwrap().elfsections.push(rtoconf); -} \ No newline at end of file +} diff --git a/src/sysboostd/daemon.rs b/src/sysboostd/daemon.rs index 06a138b..cbd6894 100644 --- a/src/sysboostd/daemon.rs +++ b/src/sysboostd/daemon.rs @@ -12,9 +12,10 @@ use crate::aot::gen_app_rto; use crate::aot::set_app_link_flag; use crate::bolt::bolt_optimize; -use crate::config::SYSBOOST_CONFIG_PATH; -use crate::config::INIT_CONF; +use crate::config::parse_init_config; use crate::config::RtoConfig; +use crate::config::INIT_CONF; +use crate::config::SYSBOOST_CONFIG_PATH; use crate::coredump_monitor::is_app_crashed; use crate::kmod_util::insmod_sysboost_ko; use crate::kmod_util::set_hpage_rto_flag; @@ -22,17 +23,16 @@ use crate::kmod_util::set_ko_rto_flag; use crate::kmod_util::test_kmod; use crate::lib::fs_ext; +use ini::Ini; use inotify::{EventMask, Inotify, WatchMask}; use log::{self}; use std::fs; use std::os::unix::fs as UnixFs; -use std::path::{Path}; +use std::path::Path; use std::thread; use std::time::Duration; pub const SYSBOOST_DB_PATH: &str = "/var/lib/sysboost/"; -//const LDSO: &str = "ld-"; -//const LIBCSO: &str = "libc.so"; // sleep some time wait for next event const MIN_SLEEP_TIME: u64 = 10000; @@ -62,7 +62,7 @@ pub fn db_remove_link(path: &String) { // TODO: use bolt to optimize dynamic library and then merge them fn sysboost_core_process(conf: &RtoConfig) -> i32 { - let mut ret= 0; + let mut ret = 0; match conf.mode.as_str() { "bolt" => { ret = bolt_optimize(&conf); @@ -77,7 +77,7 @@ fn sysboost_core_process(conf: &RtoConfig) -> i32 { log::error!("Error: generate rto start fault."); return ret; } - log::info!("generate {} rto success.",&conf.name); + log::info!("generate {} rto success.", &conf.name); } _ => { log::info!("Warning: read elf file fault, please check config."); @@ -120,7 +120,7 @@ fn clean_last_rto() { continue; } }; - set_app_link_flag(&format!("{}",real_path.to_string_lossy()), false); + set_app_link_flag(&format!("{}", real_path.to_string_lossy()), false); db_remove_link(&p); match fs::remove_file(format!("{}.rto", real_path.to_string_lossy())) { Ok(_) => log::info!("remove {} success", format!("{}.rto", real_path.to_string_lossy())), @@ -237,46 +237,56 @@ mod tests { #[test] fn test_check_elf_files_modify_1() { let mut elf_inotify = Inotify::init().expect("Failed to init inotify."); + let log = "xxx.log"; // create file, link to it - Command::new("/usr/bin/touch").arg("xxx.log").spawn().expect("Fail to run cmd"); + Command::new("/usr/bin/touch").arg(log).status().expect("Fail to run cmd"); // watch it - let file_path = Path::new("xxx.log"); + let file_path = Path::new(log); elf_inotify.add_watch(file_path, WatchMask::MODIFY).expect("Failed to add watch."); - // modity it, touch can not trigger evnet - Command::new("bash").arg("-c").arg("echo 1 >> xxx.log").spawn().expect("Fail to run cmd"); + // modity it, touch can not trigger event + let cmd = format!("echo 1 >> {}", log); + Command::new("bash").arg("-c").arg(cmd).status().expect("Fail to run cmd"); // wait modify happen thread::sleep(Duration::from_secs(1)); let is_elf_modify = check_files_modify(&mut elf_inotify); assert_eq!(is_elf_modify, true); + + Command::new("/usr/bin/rm").arg("-f").arg("xxx.log").status().expect("Fail to run cmd"); } #[test] fn test_check_elf_files_modify_2() { let mut elf_inotify = Inotify::init().expect("Failed to init inotify."); + let log = "xxx.log"; + let link = "xxx.link"; // create file, link to it - Command::new("/usr/bin/touch").arg("xxx.log").spawn().expect("Fail to run cmd"); - std::mem::forget(UnixFs::symlink("xxx.log", "xxx.link")); + Command::new("/usr/bin/touch").arg(log).status().expect("Fail to run cmd"); + std::mem::forget(UnixFs::symlink(log, link)); // watch link file - let file_path = Path::new("xxx.link"); + let file_path = Path::new(link); // let canonical_path = fs::canonicalize(file_path).expect("fail"); // println!("{} -- {}", file_path.display(), canonical_path.to_str().unwrap()); elf_inotify.add_watch(file_path, WatchMask::MODIFY).expect("Failed to add watch."); - // modity it, touch can not trigger evnet - Command::new("bash").arg("-c").arg("echo 1 >> xxx.log").spawn().expect("Fail to run cmd"); + // modity it, touch can not trigger event + let cmd = format!("echo 1 >> {}", log); + Command::new("bash").arg("-c").arg(cmd).status().expect("Fail to run cmd"); // wait modify happen thread::sleep(Duration::from_secs(1)); let is_elf_modify = check_files_modify(&mut elf_inotify); assert_eq!(is_elf_modify, true); + + Command::new("/usr/bin/rm").arg("-f").arg(log).status().expect("Fail to run cmd"); + Command::new("/usr/bin/rm").arg("-f").arg(link).status().expect("Fail to run cmd"); } #[test] @@ -291,8 +301,7 @@ mod tests { } #[test] - #[cfg(target_arch = "aarch64")] - fn test_process_config_arm() { + fn test_parse_init_config() { // Create a temporary directory for testing let temp_dir = tempfile::tempdir().unwrap(); @@ -301,78 +310,19 @@ mod tests { let elf_path = temp_dir.path().join("bash"); std::fs::copy(&bash_path, &elf_path).unwrap(); - // Create a temporary config file for testing - let config_path = temp_dir.path().join("test.toml"); - std::fs::write(&config_path, "elf_path = './bash' mode = 'static' PATH = '/usr/lib64:/usr/bin'").unwrap(); - - let conf_e = read_config(&config_path.clone()); - let conf = match conf_e { - Some(conf) => conf, - None => return, - }; - - let elf = match parse_elf_file(&conf.elf_path) { - Some(elf) => elf, - None => return, - }; - - let libs = find_libs(&conf, &elf); - let mut libs_nolibc = find_libs(&conf, &elf); - libs_nolibc.retain(|s| !s.contains(LDSO)); - libs_nolibc.retain(|s| !s.contains(LIBCSO)); - - let bash_libs = vec![ - String::from("/usr/lib64/libtinfo.so.6"), - String::from("/usr/lib64/libc.so.6"), - String::from("/lib/ld-linux-aarch64.so.1"), - ]; - - let bash_libs_nolibc = vec![String::from("/usr/lib64/libtinfo.so.6")]; - - assert_eq!(libs, bash_libs); - assert_eq!(libs_nolibc, bash_libs_nolibc); - } - - #[test] - #[cfg(target_arch = "x86_64")] - fn test_process_config_x86() { - // Create a temporary directory for testing - let temp_dir = tempfile::tempdir().unwrap(); - - // Create a temporary ELF file for testing - let bash_path = "/usr/bin/bash"; - let elf_path = temp_dir.path().join("bash"); - std::fs::copy(&bash_path, &elf_path).unwrap(); + let mut init_conf = Ini::new(); + init_conf.with_section(Some(elf_path.to_string_lossy())).set("mode", "static").set("PATH", "/usr/lib64:/usr/bin"); // Create a temporary config file for testing - let config_path = temp_dir.path().join("test.toml"); - std::fs::write(&config_path, "elf_path = './bash' mode = 'static' PATH = '/usr/lib64:/usr/bin'").unwrap(); - - let conf_e = read_config(&config_path.clone()); - let conf = match conf_e { - Some(conf) => conf, - None => return, - }; - - let elf = match parse_elf_file(&conf.elf_path) { - Some(elf) => elf, - None => return, - }; + let config_path = temp_dir.path().join("sysboost.ini"); + init_conf.write_to_file(config_path.clone()).unwrap(); - let libs = find_libs(&conf, &elf); - let mut libs_nolibc = find_libs(&conf, &elf); - libs_nolibc.retain(|s| !s.contains(LDSO)); - libs_nolibc.retain(|s| !s.contains(LIBCSO)); + parse_init_config(config_path); - let bash_libs = vec![ - String::from("/usr/lib64/libtinfo.so.6"), - String::from("/usr/lib64/libc.so.6"), - String::from("/lib64/ld-linux-x86-64.so.2"), - ]; + let conf = &INIT_CONF.read().unwrap().elfsections[0]; let bash_libs_nolibc = vec![String::from("/usr/lib64/libtinfo.so.6")]; - assert_eq!(libs, bash_libs); - assert_eq!(libs_nolibc, bash_libs_nolibc); + assert_eq!(conf.libs, bash_libs_nolibc); } } diff --git a/src/sysboostd/netlink_client.rs b/src/sysboostd/netlink_client.rs index 89535f8..367bead 100644 --- a/src/sysboostd/netlink_client.rs +++ b/src/sysboostd/netlink_client.rs @@ -94,7 +94,7 @@ pub fn read_event(sock: i32) -> Result { } let header = buffer.as_ptr() as *const libc::nlmsghdr; let msg = (header as usize + nlmsg_length(0)) as *const crash_info; - let slice = unsafe{core::slice::from_raw_parts((*msg).path.as_ptr(), (*msg).len as usize)}; + let slice = unsafe{core::slice::from_raw_parts((*msg).path.as_ptr() as *const u8, (*msg).len as usize)}; let data = core::str::from_utf8(slice).unwrap(); return Ok(data.to_string()); } \ No newline at end of file -- Gitee