xref: /DragonReach/src/executor/service_executor/mod.rs (revision 17ae4661898f9f5bdb95f865ac453f4508b9e876)
1 #[cfg(target_os = "dragonos")]
2 use drstd as std;
3 
4 use crate::{
5     error::{
6         runtime_error::{RuntimeError, RuntimeErrorType},
7         ErrorFormat,
8     },
9     manager::{RunningUnit, UnitManager},
10     parse::{parse_util::UnitParseUtil, Segment, UnitParser},
11     task::cmdtask::CmdTask,
12     unit::{
13         service::RestartOption,
14         service::{ServiceType, ServiceUnit},
15         Unit, UnitState, UnitType,
16     },
17 };
18 use std::os::unix::process::CommandExt;
19 use std::sync::Mutex;
20 use std::vec::Vec;
21 use std::{
22     borrow::BorrowMut,
23     cell::RefCell,
24     eprint, eprintln,
25     io::{Error, ErrorKind},
26     print, println,
27 };
28 use std::{io::BufRead, process::Command, sync::Arc};
29 use std::{process::Stdio, string::ToString};
30 
31 use super::ExitStatus;
32 
33 pub struct ServiceExecutor;
34 
35 impl ServiceExecutor {
36     pub fn exec(service: &mut ServiceUnit) -> Result<(), RuntimeError> {
37         match *service.service_part().service_type() {
38             ServiceType::Simple => {
39                 return Self::exec_simple(service);
40             }
41             ServiceType::Forking => {
42                 return Self::exec_forking(service);
43             }
44             ServiceType::Dbus => {
45                 return Self::exec_dbus(service);
46             }
47             ServiceType::Notify => {
48                 return Self::exec_notify(service);
49             }
50             ServiceType::Idle => {
51                 return Self::exec_idle(service);
52             }
53             ServiceType::OneShot => {
54                 return Self::exec_one_shot(service);
55             }
56         }
57     }
58     pub fn exec_simple(service: &mut ServiceUnit) -> Result<(), RuntimeError> {
59         //处理conflict
60         let conflicts = service.unit_base().unit_part().conflicts();
61         for u in conflicts {
62             // 如果有冲突项enable的时候,该unit不能启动
63             let mutex = UnitManager::get_unit_with_id(u).unwrap();
64             let unit = mutex.lock().unwrap();
65             if *unit.unit_base().state() == UnitState::Enabled {
66                 eprintln!(
67                     "{}: Service startup failed: conflict unit",
68                     unit.unit_base().unit_part().description()
69                 );
70                 return Err(RuntimeError::new(RuntimeErrorType::ExecFailed));
71             }
72         }
73 
74         //获取环境变量
75         //先获取指定的环境变量
76         let mut envs = Vec::from(service.service_part().environment());
77 
78         //若指定了环境变量文件,则解析环境变量文件
79         let env_file = service.service_part().environment_file();
80         if env_file.len() > 0 {
81             let env_reader = match UnitParser::get_reader(env_file, UnitType::Unknown) {
82                 Ok(reader) => reader,
83                 Err(_) => {
84                     return Err(RuntimeError::new(RuntimeErrorType::Custom(
85                         "Incorrect environment variable configuration file".to_string(),
86                     )));
87                 }
88             };
89             for line in env_reader.lines() {
90                 if let Ok(line) = line {
91                     let x = match UnitParseUtil::parse_env(line.as_str()) {
92                         Ok(v) => v,
93                         Err(_) => {
94                             return Err(RuntimeError::new(RuntimeErrorType::Custom(
95                                 "Failed to parse environment variable configuration file"
96                                     .to_string(),
97                             )));
98                         }
99                     };
100                     envs.push(x);
101                 }
102             }
103         }
104 
105         //服务配置环境变量,配置工作目录
106         //获取工作目录
107         let mut dir = service.service_part().working_directory();
108         if dir.is_empty() {
109             dir = "/";
110         }
111         //获取启动命令
112         let exec_start = service.service_part().exec_start();
113         println!("exec:{}", exec_start.path);
114         //处理ExecStartsPre,准备在服务启动前执行的命令
115         //TODO:设置uid与gid
116         let cmds = service.service_part().exec_start_pre().clone();
117         let proc = unsafe {
118             Command::new(&exec_start.path)
119                 .args(&exec_start.cmd)
120                 .current_dir(dir)
121                 .envs(envs)
122                 .stderr(Stdio::inherit())
123                 .stdout(Stdio::inherit())
124                 .stdin(Stdio::inherit())
125                 .pre_exec(move || {
126                     for cmdtask in cmds.clone() {
127                         match cmdtask.exec() {
128                             Ok(_) => (),
129                             Err(e) => {
130                                 eprintln!("{}", e.error_format());
131                                 return Err(Error::new(
132                                     ErrorKind::Interrupted,
133                                     "ExecStartPreFailed",
134                                 ));
135                             }
136                         };
137                     }
138                     Ok(())
139                 })
140                 .spawn()
141         };
142 
143         match proc {
144             Ok(p) => {
145                 println!("Service running...");
146                 //修改service状态
147                 service.mut_unit_base().set_state(UnitState::Enabled);
148                 //启动成功后将Child加入全局管理的进程表
149                 UnitManager::push_running(RunningUnit::new(p, service.unit_id()));
150                 //执行启动后命令
151                 Self::exec_start_pos(service)?;
152             }
153             Err(err) => {
154                 eprintln!("{}: Service startup failed: {}", exec_start.path, err);
155                 return Err(RuntimeError::new(RuntimeErrorType::ExecFailed));
156             }
157         }
158         Ok(())
159     }
160 
161     fn exec_dbus(service: &ServiceUnit) -> Result<(), RuntimeError> {
162         Ok(())
163     }
164 
165     fn exec_forking(service: &ServiceUnit) -> Result<(), RuntimeError> {
166         Ok(())
167     }
168 
169     // 此方法会改变service的启动模式为simple
170     fn exec_idle(service: &mut ServiceUnit) -> Result<(), RuntimeError> {
171         // 将该service加入等待运行队列
172         let _ = service.set_attr(Segment::Service, "Type", "simple");
173         UnitManager::push_a_idle_service(service.unit_id());
174         Ok(())
175     }
176 
177     fn exec_notify(service: &ServiceUnit) -> Result<(), RuntimeError> {
178         Ok(())
179     }
180 
181     fn exec_one_shot(service: &ServiceUnit) -> Result<(), RuntimeError> {
182         Ok(())
183     }
184 
185     fn exec_start_pos(service: &ServiceUnit) -> Result<(), RuntimeError> {
186         let cmds = service.service_part().exec_start_pos();
187         for cmd in cmds {
188             cmd.exec()?;
189         }
190         Ok(())
191     }
192 
193     //显式停止时执行的命令
194     fn exec_stop(service: &mut ServiceUnit) -> Result<(), RuntimeError> {
195         let cmds = service.service_part().exec_stop();
196         for cmd in cmds {
197             cmd.exec()?;
198         }
199         Ok(())
200     }
201 
202     //停止后执行的命令
203     fn exec_stop_post(service: &mut ServiceUnit) -> Result<(), RuntimeError> {
204         let cmds = service.service_part().exec_stop_post();
205         for cmd in cmds {
206             cmd.exec()?;
207         }
208         Ok(())
209     }
210 
211     //服务退出执行的逻辑(包括自然退出及显式退出)
212     pub fn after_exit(service: &mut ServiceUnit, exit_status: ExitStatus) {
213         //TODO: 需要考虑是否需要在此处执行退出后代码,还是只需要显式退出时才执行
214         let _ = Self::exec_stop_post(service);
215 
216         //判断是否需要restart,需要则再次启动服务
217         if service.service_part().restart().is_restart(&exit_status) {
218             let _ = service.run();
219             return;
220         }
221 
222         //如果该进程标记了RemainAfterExit,则将其加入特殊标记表
223         if service.service_part().remain_after_exit() {
224             UnitManager::push_flag_running(service.unit_id());
225         }
226     }
227 }
228