1 use lazy_static::lazy_static; 2 use std::fs::File; 3 use std::os::fd::FromRawFd; 4 use std::string::String; 5 use std::string::ToString; 6 use std::sync::Arc; 7 use std::{eprint, eprintln, format}; 8 use std::{libc, print, println}; 9 use std::{sync::Mutex, vec::Vec}; 10 11 use crate::error::runtime_error::RuntimeError; 12 use crate::error::runtime_error::RuntimeErrorType; 13 use crate::error::ErrorFormat; 14 use crate::parse::parse_util::UnitParseUtil; 15 use crate::systemctl::ctl_parser::Pattern; 16 use crate::systemctl::ctl_path; 17 use crate::systemctl::listener::Command; 18 use crate::unit::Unit; 19 use crate::unit::UnitState; 20 21 use super::{UnitManager, ID_TO_UNIT_MAP}; 22 pub struct CtlManager; 23 24 lazy_static! { 25 static ref CTL_WRITER: Mutex<Arc<File>> = { 26 let file = CtlManager::init_ctl_writer(); 27 Mutex::new(Arc::new(file)) 28 }; 29 } 30 31 impl CtlManager { 32 pub fn exec_ctl(cmd: Command) -> Result<(), RuntimeError> { 33 // TODO:目前假设一个时刻只有一个进程使用systemdctl,后续应该使用DBus等更灵活的进程通信方式 34 match cmd.operation { 35 crate::systemctl::ctl_parser::CommandOperation::ListUnits => { 36 Self::list_unit(cmd.patterns) 37 } 38 crate::systemctl::ctl_parser::CommandOperation::Start => Self::start(cmd.args.unwrap()), 39 crate::systemctl::ctl_parser::CommandOperation::Restart => { 40 Self::restart(cmd.args.unwrap(), false) 41 } 42 crate::systemctl::ctl_parser::CommandOperation::Stop => Self::stop(cmd.args.unwrap()), 43 crate::systemctl::ctl_parser::CommandOperation::Reboot => Ok(Self::reboot()), 44 crate::systemctl::ctl_parser::CommandOperation::ListSockets => todo!(), 45 crate::systemctl::ctl_parser::CommandOperation::ListTimers => todo!(), 46 crate::systemctl::ctl_parser::CommandOperation::Reload => todo!(), 47 crate::systemctl::ctl_parser::CommandOperation::TryRestart => { 48 Self::restart(cmd.args.unwrap(), true) 49 } 50 crate::systemctl::ctl_parser::CommandOperation::ReloadOrRestart => todo!(), 51 crate::systemctl::ctl_parser::CommandOperation::ReloadOrTryRestart => todo!(), 52 crate::systemctl::ctl_parser::CommandOperation::Isolate => todo!(), 53 crate::systemctl::ctl_parser::CommandOperation::Kill => todo!(), 54 crate::systemctl::ctl_parser::CommandOperation::IsActive => { 55 let mut patterns = cmd.patterns.clone(); 56 patterns.push(Pattern::State(UnitState::Active)); 57 Self::list_unit(patterns) 58 } 59 crate::systemctl::ctl_parser::CommandOperation::IsFailed => { 60 let mut patterns = cmd.patterns.clone(); 61 patterns.push(Pattern::State(UnitState::Failed)); 62 Self::list_unit(patterns) 63 } 64 crate::systemctl::ctl_parser::CommandOperation::Status => todo!(), 65 crate::systemctl::ctl_parser::CommandOperation::Show => todo!(), 66 crate::systemctl::ctl_parser::CommandOperation::Cat => todo!(), 67 crate::systemctl::ctl_parser::CommandOperation::SetProperty => todo!(), 68 crate::systemctl::ctl_parser::CommandOperation::Help => todo!(), 69 crate::systemctl::ctl_parser::CommandOperation::ResetFailed => todo!(), 70 crate::systemctl::ctl_parser::CommandOperation::ListDependencies => todo!(), 71 crate::systemctl::ctl_parser::CommandOperation::ListUnitFiles => todo!(), 72 crate::systemctl::ctl_parser::CommandOperation::Enable => todo!(), 73 crate::systemctl::ctl_parser::CommandOperation::Disable => todo!(), 74 crate::systemctl::ctl_parser::CommandOperation::Reenable => todo!(), 75 crate::systemctl::ctl_parser::CommandOperation::Preset => todo!(), 76 crate::systemctl::ctl_parser::CommandOperation::PresetAll => todo!(), 77 crate::systemctl::ctl_parser::CommandOperation::IsEnabled => todo!(), 78 crate::systemctl::ctl_parser::CommandOperation::Mask => todo!(), 79 crate::systemctl::ctl_parser::CommandOperation::UnMask => todo!(), 80 crate::systemctl::ctl_parser::CommandOperation::Link => todo!(), 81 crate::systemctl::ctl_parser::CommandOperation::AddWants => todo!(), 82 crate::systemctl::ctl_parser::CommandOperation::AddRequires => todo!(), 83 crate::systemctl::ctl_parser::CommandOperation::Edit => todo!(), 84 crate::systemctl::ctl_parser::CommandOperation::GetDefault => todo!(), 85 crate::systemctl::ctl_parser::CommandOperation::SetDefault => todo!(), 86 crate::systemctl::ctl_parser::CommandOperation::ListMachines => todo!(), 87 crate::systemctl::ctl_parser::CommandOperation::ListJobs => todo!(), 88 crate::systemctl::ctl_parser::CommandOperation::Cancel => todo!(), 89 crate::systemctl::ctl_parser::CommandOperation::Snapshot => todo!(), 90 crate::systemctl::ctl_parser::CommandOperation::Delete => todo!(), 91 crate::systemctl::ctl_parser::CommandOperation::ShowEnvironment => todo!(), 92 crate::systemctl::ctl_parser::CommandOperation::SetEnvironment => todo!(), 93 crate::systemctl::ctl_parser::CommandOperation::UnsetEnvironment => todo!(), 94 crate::systemctl::ctl_parser::CommandOperation::ImportEnvironment => todo!(), 95 crate::systemctl::ctl_parser::CommandOperation::DeamonReload => todo!(), 96 crate::systemctl::ctl_parser::CommandOperation::DeamonReexec => todo!(), 97 crate::systemctl::ctl_parser::CommandOperation::IsSystemRunning => todo!(), 98 crate::systemctl::ctl_parser::CommandOperation::Default => todo!(), 99 crate::systemctl::ctl_parser::CommandOperation::Rescue => todo!(), 100 crate::systemctl::ctl_parser::CommandOperation::Emergency => todo!(), 101 crate::systemctl::ctl_parser::CommandOperation::Halt => todo!(), 102 crate::systemctl::ctl_parser::CommandOperation::Poweroff => todo!(), 103 crate::systemctl::ctl_parser::CommandOperation::Kexec => todo!(), 104 crate::systemctl::ctl_parser::CommandOperation::Exit => todo!(), 105 crate::systemctl::ctl_parser::CommandOperation::SwitchRoot => todo!(), 106 crate::systemctl::ctl_parser::CommandOperation::Suspend => todo!(), 107 crate::systemctl::ctl_parser::CommandOperation::Hibernate => todo!(), 108 crate::systemctl::ctl_parser::CommandOperation::HybridSleep => todo!(), 109 crate::systemctl::ctl_parser::CommandOperation::UnSupported => todo!(), 110 crate::systemctl::ctl_parser::CommandOperation::None => { 111 println!("No such command!"); 112 return Err(RuntimeError::new(RuntimeErrorType::InvalidInput)); 113 } 114 } 115 } 116 117 pub fn list_unit(pattern: Vec<Pattern>) -> Result<(), RuntimeError> { 118 let units = Self::filter_units(pattern)?; 119 120 let mut res = "UNIT\t\t\t\tLOAD\t\tACTIVE\t\tSUB\t\tDESCRIPTION".to_string(); 121 res.push_str("\n----------------------------------------------------------------------------------------------"); 122 for unit in units { 123 res = format!("{}\n{}", res, unit.lock().unwrap().unit_base().unit_info()); 124 } 125 126 // if let Err(err) = CTL_WRITER.lock().unwrap().write_all(res.as_bytes()) { 127 // eprintln!("write ctl error :{}", err); 128 // } 129 println!("{}", res); 130 Ok(()) 131 } 132 133 pub fn stop(names: Vec<String>) -> Result<(), RuntimeError> { 134 // TODO:打日志 135 for name in names { 136 match UnitManager::get_unit_with_name(&name) { 137 Some(unit) => { 138 unit.lock().unwrap().exit(); 139 } 140 None => { 141 eprintln!("{} is not a unit", name); 142 return Err(RuntimeError::new(RuntimeErrorType::FileNotFound)); 143 } 144 } 145 } 146 Ok(()) 147 } 148 149 pub fn start(names: Vec<String>) -> Result<(), RuntimeError> { 150 // TODO:打日志 151 for name in names { 152 match UnitManager::get_unit_with_name(&name) { 153 Some(unit) => unit.lock().unwrap().run()?, 154 None => match UnitParseUtil::parse_unit_no_type(&name) { 155 Ok(i) => { 156 let unit = UnitManager::get_unit_with_id(&i).unwrap(); 157 let mut unit = unit.lock().unwrap(); 158 unit.run()?; 159 } 160 Err(err) => { 161 eprintln!("parse unit {} error :{}", name, err.error_format()); 162 } 163 }, 164 } 165 } 166 Ok(()) 167 } 168 169 pub fn reboot() { 170 #[cfg(target_os = "dragonos")] 171 unsafe { 172 dsc::syscall!(SYS_REBOOT) 173 }; 174 } 175 176 pub fn restart(names: Vec<String>, is_try: bool) -> Result<(), RuntimeError> { 177 // TODO:打日志 178 for name in names { 179 match UnitManager::get_unit_with_name(&name) { 180 Some(unit) => { 181 let mut unit = unit.lock().unwrap(); 182 if is_try && *unit.unit_base().state() == UnitState::Active { 183 unit.restart()?; 184 } else { 185 unit.restart()?; 186 } 187 } 188 None => match UnitParseUtil::parse_unit_no_type(&name) { 189 Ok(i) => { 190 let unit = UnitManager::get_unit_with_id(&i).unwrap(); 191 unit.lock().unwrap().run()?; 192 } 193 Err(err) => { 194 eprintln!("parse unit {} error :{}", name, err.error_format()); 195 return Err(RuntimeError::new(RuntimeErrorType::InvalidFileFormat)); 196 } 197 }, 198 } 199 } 200 Ok(()) 201 } 202 203 pub fn init_ctl_writer() -> File { 204 let fd = unsafe { libc::open(ctl_path().as_ptr(), libc::O_WRONLY) }; 205 if fd < 0 { 206 panic!("open ctl pipe error"); 207 } 208 unsafe { File::from_raw_fd(fd) } 209 } 210 211 pub fn filter_units(patterns: Vec<Pattern>) -> Result<Vec<Arc<Mutex<dyn Unit>>>, RuntimeError> { 212 let reader = ID_TO_UNIT_MAP.read().unwrap(); 213 214 // TODO: 这里可以优化 215 let bindings = reader.values().collect::<Vec<_>>(); 216 let mut units = Vec::new(); 217 for unit in bindings { 218 units.push(unit.clone()); 219 } 220 for pat in patterns { 221 match pat { 222 Pattern::Type(t) => { 223 units = units 224 .into_iter() 225 .filter(|x| x.lock().unwrap().unit_type() == t) 226 .collect::<Vec<_>>() 227 } 228 Pattern::State(s) => { 229 units = units 230 .into_iter() 231 .filter(|x| *x.lock().unwrap().unit_base().state() == s) 232 .collect::<Vec<_>>() 233 } 234 Pattern::None => {} 235 _ => { 236 return Err(RuntimeError::new(RuntimeErrorType::InvalidInput)); 237 } 238 } 239 } 240 Ok(units) 241 } 242 } 243