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