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