xref: /DragonReach/src/unit/service/mod.rs (revision b40b6b4d2f72c30a382f9f18740fa73d7fc90721)
1 use super::{BaseUnit, Unit};
2 use crate::error::runtime_error::RuntimeError;
3 use crate::error::{parse_error::ParseError, parse_error::ParseErrorType};
4 use crate::executor::service_executor::ServiceExecutor;
5 use crate::executor::ExitStatus;
6 
7 use crate::parse::parse_service::ServiceParser;
8 use crate::parse::parse_util::UnitParseUtil;
9 use crate::parse::{Segment, SERVICE_UNIT_ATTR_TABLE};
10 use crate::task::cmdtask::CmdTask;
11 
12 #[cfg(target_os = "dragonos")]
13 use drstd as std;
14 
15 use std::string::{String, ToString};
16 
17 use std::vec::Vec;
18 #[derive(Clone, Debug)]
19 pub struct ServiceUnit {
20     unit_base: BaseUnit,
21     service_part: ServicePart,
22 }
23 
24 impl Default for ServiceUnit {
25     fn default() -> Self {
26         let mut sp = ServicePart::default();
27         sp.working_directory = String::from("/");
28         Self {
29             unit_base: BaseUnit::default(),
30             service_part: sp,
31         }
32     }
33 }
34 
35 #[derive(Debug, Clone, Copy)]
36 pub enum ServiceType {
37     Simple,
38     Forking,
39     OneShot,
40     Dbus,
41     Notify,
42     Idle,
43 }
44 
45 impl Default for ServiceType {
46     fn default() -> Self {
47         ServiceType::Simple
48     }
49 }
50 
51 #[derive(Debug, Clone, Copy, PartialEq)]
52 pub enum RestartOption {
53     AlwaysRestart, //总是重启
54     OnSuccess,     //在该服务正常退出时
55     OnFailure,     //在该服务启动失败时
56     OnAbnormal,    //在该服务以非0错误码退出时
57     OnAbort,       //在该服务显示退出时(通过DragonReach手动退出)
58     OnWatchdog,    //定时观测进程无响应时(当前未实现)
59     None,          //不重启
60 }
61 
62 impl Default for RestartOption {
63     fn default() -> Self {
64         Self::None
65     }
66 }
67 
68 impl RestartOption {
69     pub fn is_restart(&self, exit_status: &ExitStatus) -> bool {
70         if *self == Self::AlwaysRestart {
71             return true;
72         }
73 
74         match (*self, *exit_status) {
75             (Self::OnSuccess, ExitStatus::Success) => {
76                 return true;
77             }
78             (Self::OnAbnormal, ExitStatus::Abnormal) => {
79                 return true;
80             }
81             (Self::OnAbort, ExitStatus::Abort) => {
82                 return true;
83             }
84             (Self::OnFailure, ExitStatus::Failure) => {
85                 return true;
86             }
87             (Self::OnWatchdog, ExitStatus::Watchdog) => {
88                 return true;
89             }
90             _ => {
91                 return false;
92             }
93         }
94     }
95 }
96 
97 #[derive(Debug, Clone, Copy)]
98 pub enum MountFlag {
99     Shared,
100     Slave,
101     Private,
102 }
103 
104 impl Default for MountFlag {
105     fn default() -> Self {
106         Self::Private
107     }
108 }
109 
110 #[derive(Default, Debug, Clone)]
111 pub struct ServicePart {
112     //生命周期相关
113     service_type: ServiceType,
114     ///
115     remain_after_exit: bool,
116     exec_start: CmdTask,
117     exec_start_pre: Vec<CmdTask>,
118     exec_start_pos: Vec<CmdTask>,
119     exec_reload: Vec<CmdTask>,
120     exec_stop: Vec<CmdTask>,
121     exec_stop_post: Vec<CmdTask>,
122     restart_sec: u64,
123     restart: RestartOption,
124     timeout_start_sec: u64,
125     timeout_stop_sec: u64,
126     //上下文配置相关
127     environment: Vec<(String, String)>,
128     nice: i8,
129     working_directory: String,
130     root_directory: String,
131     user: String,
132     group: String,
133     mount_flags: MountFlag,
134     //LimitCPU / LimitSTACK / LimitNOFILE / LimitNPROC 等,后续支持再添加
135 }
136 
137 impl Unit for ServiceUnit {
138     fn as_any(&self) -> &dyn core::any::Any {
139         self
140     }
141 
142     fn from_path(path: &str) -> Result<usize, ParseError>
143     where
144         Self: Sized,
145     {
146         return ServiceParser::parse(path);
147     }
148 
149     fn set_attr(&mut self, segment: Segment, attr: &str, val: &str) -> Result<(), ParseError> {
150         if segment != Segment::Service {
151             return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
152         }
153         let attr_type = SERVICE_UNIT_ATTR_TABLE.get(attr).ok_or(ParseError::new(
154             ParseErrorType::EINVAL,
155             String::new(),
156             0,
157         ));
158         return self.service_part.set_attr(attr_type.unwrap(), val);
159     }
160 
161     fn set_unit_base(&mut self, base: BaseUnit) {
162         self.unit_base = base;
163     }
164 
165     fn unit_type(&self) -> super::UnitType {
166         return self.unit_base.unit_type;
167     }
168 
169     fn unit_base(&self) -> &BaseUnit {
170         return &self.unit_base;
171     }
172 
173     fn unit_id(&self) -> usize {
174         return self.unit_base.unit_id;
175     }
176 
177     fn run(&mut self) -> Result<(), RuntimeError> {
178         self.exec()
179     }
180 
181     fn mut_unit_base(&mut self) -> &mut BaseUnit {
182         return &mut self.unit_base;
183     }
184 
185     fn after_exit(&mut self, exit_status: ExitStatus) {
186         ServiceExecutor::after_exit(self, exit_status);
187     }
188 
189     fn init(&mut self) {
190         let part = &mut self.service_part;
191         for cmd in part.exec_reload.iter_mut() {
192             cmd.dir = part.working_directory.to_string();
193             cmd.envs = part.environment.clone();
194         }
195         part.exec_start.dir = part.working_directory.to_string();
196         part.exec_start.envs = part.environment.clone();
197         for cmd in part.exec_start_pos.iter_mut() {
198             cmd.dir = part.working_directory.to_string();
199             cmd.envs = part.environment.clone();
200         }
201         for cmd in part.exec_start_pre.iter_mut() {
202             cmd.dir = part.working_directory.to_string();
203             cmd.envs = part.environment.clone();
204         }
205         for cmd in part.exec_stop.iter_mut() {
206             cmd.dir = part.working_directory.to_string();
207             cmd.envs = part.environment.clone();
208         }
209         for cmd in part.exec_stop_post.iter_mut() {
210             cmd.dir = part.working_directory.to_string();
211             cmd.envs = part.environment.clone();
212         }
213     }
214 
215     fn as_mut_any(&mut self) -> &mut dyn std::any::Any {
216         self
217     }
218 
219     fn exit(&mut self) {
220         ServiceExecutor::exit(self);
221     }
222 }
223 
224 impl ServiceUnit {
225     pub fn unit_base(&self) -> &BaseUnit {
226         return &self.unit_base;
227     }
228 
229     pub fn service_part(&self) -> &ServicePart {
230         return &self.service_part;
231     }
232 
233     pub fn mut_service_part(&mut self) -> &mut ServicePart {
234         return &mut self.service_part;
235     }
236 
237     fn exec(&mut self) -> Result<(), RuntimeError> {
238         ServiceExecutor::exec(self)
239     }
240 }
241 
242 unsafe impl Sync for ServiceUnit {}
243 
244 unsafe impl Send for ServiceUnit {}
245 
246 pub enum ServiceUnitAttr {
247     None,
248     //Service段
249     //定义启动时的进程行为
250     Type,
251     //
252     RemainAfterExit,
253     //启动命令
254     ExecStart,
255     //启动当前服务之前执行的命令
256     ExecStartPre,
257     //启动当前服务之后执行的命令
258     ExecStartPos,
259     //重启当前服务时执行的命令
260     ExecReload,
261     //停止当前服务时执行的命令
262     ExecStop,
263     //停止当其服务之后执行的命令
264     ExecStopPost,
265     //自动重启当前服务间隔的秒数
266     RestartSec,
267     //定义何种情况 Systemd 会自动重启当前服务
268     Restart,
269     //启动服务时等待的秒数
270     TimeoutStartSec,
271     //停止服务时的等待秒数,如果超过这个时间仍然没有停止,应该使用 SIGKILL 信号强行杀死服务的进程
272     TimeoutStopSec,
273     //为服务指定环境变量
274     Environment,
275     //指定加载一个包含服务所需的环境变量的列表的文件,文件中的每一行都是一个环境变量的定义
276     EnvironmentFile,
277     //服务的进程优先级,值越小优先级越高,默认为 0。其中 -20 为最高优先级,19 为最低优先级
278     Nice,
279     //指定服务的工作目录
280     WorkingDirectory,
281     //指定服务进程的根目录(/ 目录)。如果配置了这个参数,服务将无法访问指定目录以外的任何文件
282     RootDirectory,
283     //指定运行服务的用户
284     User,
285     //指定运行服务的用户组
286     Group,
287     //服务的 Mount Namespace 配置,会影响进程上下文中挂载点的信息
288     MountFlags,
289 }
290 
291 impl ServicePart {
292     pub fn set_attr(&'_ mut self, attr: &ServiceUnitAttr, val: &str) -> Result<(), ParseError> {
293         match attr {
294             ServiceUnitAttr::Type => match val {
295                 "simple" => self.service_type = ServiceType::Simple,
296                 "forking" => self.service_type = ServiceType::Forking,
297                 "oneshot" => self.service_type = ServiceType::OneShot,
298                 "dbus" => self.service_type = ServiceType::Dbus,
299                 "notify" => self.service_type = ServiceType::Notify,
300                 "idle" => self.service_type = ServiceType::Idle,
301                 _ => {
302                     return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
303                 }
304             },
305             ServiceUnitAttr::RemainAfterExit => {
306                 self.remain_after_exit = UnitParseUtil::parse_boolean(val)?
307             }
308             ServiceUnitAttr::ExecStart => {
309                 self.exec_start = UnitParseUtil::parse_cmd_task(val)?[0].clone();
310             }
311             ServiceUnitAttr::ExecStartPre => {
312                 self.exec_start_pre
313                     .extend(UnitParseUtil::parse_cmd_task(val)?);
314             }
315             ServiceUnitAttr::ExecStartPos => {
316                 self.exec_start_pos
317                     .extend(UnitParseUtil::parse_cmd_task(val)?);
318             }
319             ServiceUnitAttr::ExecReload => {
320                 self.exec_reload.extend(UnitParseUtil::parse_cmd_task(val)?);
321             }
322             ServiceUnitAttr::ExecStopPost => {
323                 self.exec_stop_post
324                     .extend(UnitParseUtil::parse_cmd_task(val)?);
325             }
326             ServiceUnitAttr::ExecStop => {
327                 self.exec_stop.extend(UnitParseUtil::parse_cmd_task(val)?);
328             }
329             ServiceUnitAttr::RestartSec => self.restart_sec = UnitParseUtil::parse_sec(val)?,
330             ServiceUnitAttr::Restart => match val {
331                 "always" => self.restart = RestartOption::AlwaysRestart,
332                 "on-success" => self.restart = RestartOption::OnSuccess,
333                 "on-failure" => self.restart = RestartOption::OnFailure,
334                 "on-abnormal" => self.restart = RestartOption::OnAbnormal,
335                 "on-abort" => self.restart = RestartOption::OnAbort,
336                 "on-watchdog" => self.restart = RestartOption::OnWatchdog,
337                 _ => {
338                     return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
339                 }
340             },
341             ServiceUnitAttr::TimeoutStartSec => {
342                 self.timeout_start_sec = UnitParseUtil::parse_sec(val)?
343             }
344             ServiceUnitAttr::TimeoutStopSec => {
345                 self.timeout_stop_sec = UnitParseUtil::parse_sec(val)?
346             }
347             ServiceUnitAttr::Environment => {
348                 self.environment.push(UnitParseUtil::parse_env(val)?);
349             }
350             ServiceUnitAttr::EnvironmentFile => {
351                 if !UnitParseUtil::is_valid_file(val) {
352                     return Err(ParseError::new(ParseErrorType::EFILE, String::new(), 0));
353                 }
354                 self.environment
355                     .extend(UnitParseUtil::parse_environment_file(val)?);
356             }
357             ServiceUnitAttr::Nice => {
358                 self.nice = UnitParseUtil::parse_nice(val)?;
359             }
360             ServiceUnitAttr::WorkingDirectory => {
361                 if !UnitParseUtil::is_dir(val) {
362                     return Err(ParseError::new(ParseErrorType::ENODIR, String::new(), 0));
363                 }
364                 self.working_directory = String::from(val);
365             }
366             ServiceUnitAttr::User => {
367                 //TODO: 检查系统是否存在这个用户
368                 self.user = String::from(val);
369             }
370             ServiceUnitAttr::Group => {
371                 //TODO: 检查系统是否存在该用户组
372                 self.group = String::from(val);
373             }
374             ServiceUnitAttr::MountFlags => match val {
375                 "shared" => self.mount_flags = MountFlag::Shared,
376                 "slave" => self.mount_flags = MountFlag::Slave,
377                 "private" => self.mount_flags = MountFlag::Private,
378                 _ => {
379                     return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
380                 }
381             },
382             _ => {
383                 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
384             }
385         }
386         return Ok(());
387     }
388 
389     // 生命周期相关
390     pub fn service_type(&self) -> &ServiceType {
391         &self.service_type
392     }
393 
394     pub fn remain_after_exit(&self) -> bool {
395         self.remain_after_exit
396     }
397 
398     pub fn exec_start(&self) -> &CmdTask {
399         &self.exec_start
400     }
401 
402     pub fn exec_start_pre(&self) -> &Vec<CmdTask> {
403         &self.exec_start_pre
404     }
405 
406     pub fn exec_start_pos(&self) -> &Vec<CmdTask> {
407         &self.exec_start_pos
408     }
409 
410     pub fn exec_reload(&self) -> &Vec<CmdTask> {
411         &self.exec_reload
412     }
413 
414     pub fn exec_stop(&self) -> &Vec<CmdTask> {
415         &self.exec_stop
416     }
417 
418     pub fn exec_stop_post(&mut self) -> &mut Vec<CmdTask> {
419         &mut self.exec_stop_post
420     }
421 
422     pub fn mut_exec_start_pre(&mut self) -> &mut Vec<CmdTask> {
423         &mut self.exec_start_pre
424     }
425 
426     pub fn mut_exec_start_pos(&mut self) -> &mut Vec<CmdTask> {
427         &mut self.exec_start_pos
428     }
429 
430     pub fn mut_exec_reload(&mut self) -> &mut Vec<CmdTask> {
431         &mut self.exec_reload
432     }
433 
434     pub fn mut_exec_stop(&mut self) -> &mut Vec<CmdTask> {
435         &mut self.exec_stop
436     }
437 
438     pub fn mut_exec_stop_post(&mut self) -> &mut Vec<CmdTask> {
439         &mut self.exec_stop_post
440     }
441 
442     pub fn restart_sec(&self) -> u64 {
443         self.restart_sec
444     }
445 
446     pub fn restart(&self) -> &RestartOption {
447         &self.restart
448     }
449 
450     pub fn timeout_start_sec(&self) -> u64 {
451         self.timeout_start_sec
452     }
453 
454     pub fn timeout_stop_sec(&self) -> u64 {
455         self.timeout_stop_sec
456     }
457 
458     // 上下文配置相关
459     pub fn environment(&self) -> &[(String, String)] {
460         &self.environment
461     }
462 
463     pub fn nice(&self) -> i8 {
464         self.nice
465     }
466 
467     pub fn working_directory(&self) -> &str {
468         &self.working_directory
469     }
470 
471     pub fn root_directory(&self) -> &str {
472         &self.root_directory
473     }
474 
475     pub fn user(&self) -> &str {
476         &self.user
477     }
478 
479     pub fn group(&self) -> &str {
480         &self.group
481     }
482 
483     pub fn mount_flags(&self) -> &MountFlag {
484         &self.mount_flags
485     }
486 }
487