xref: /DragonReach/src/manager/ctl_manager/mod.rs (revision 2069cc0dc0984a2981454b00316ba607f88ac512)
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