xref: /DragonReach/src/systemctl/listener/mod.rs (revision 2069cc0dc0984a2981454b00316ba607f88ac512)
1 use std::fs::{self, File};
2 use std::io::Read;
3 use std::os::fd::FromRawFd;
4 use std::sync::{Arc, Mutex};
5 
6 use lazy_static::lazy_static;
7 
8 use crate::error::ErrorFormat;
9 use crate::manager::ctl_manager::CtlManager;
10 
11 use super::ctl_parser::{CommandOperation, CtlParser, Pattern};
12 use super::{ctl_path, DRAGON_REACH_CTL_PIPE};
13 
14 lazy_static! {
15     static ref CTL_READER: Mutex<Arc<File>> = {
16         let file = Systemctl::init_listener();
17         Mutex::new(Arc::new(file))
18     };
19 }
20 
21 pub struct Command {
22     pub(crate) operation: CommandOperation,
23     pub(crate) args: Option<Vec<String>>,
24     pub(crate) patterns: Vec<Pattern>,
25 }
26 
27 impl Command {
28     #[allow(dead_code)]
new(op: CommandOperation, patterns: Vec<Pattern>, args: Option<Vec<String>>) -> Self29     fn new(op: CommandOperation, patterns: Vec<Pattern>, args: Option<Vec<String>>) -> Self {
30         Command {
31             operation: op,
32             args,
33             patterns: patterns,
34         }
35     }
36 }
37 
38 impl Default for Command {
default() -> Self39     fn default() -> Self {
40         Command {
41             operation: CommandOperation::None,
42             args: None,
43             patterns: Vec::new(),
44         }
45     }
46 }
47 
48 pub struct Systemctl;
49 
50 impl Systemctl {
51     /// # 初始化系统服务控制 - 初始化系统服务控制管道
init()52     pub fn init() {
53         Self::init_ctl_pipe();
54     }
55     /// # 初始化监听器 - 初始化系统服务控制命令监听器
56     ///
57     /// 打开系统服务控制命令的管道文件描述符,并设置为非阻塞模式。
58     ///
init_listener() -> File59     pub fn init_listener() -> File {
60         let fd = unsafe { libc::open(ctl_path().as_ptr(), libc::O_RDONLY | libc::O_NONBLOCK) };
61         if fd < 0 {
62             panic!("open ctl pipe error");
63         }
64         unsafe { File::from_raw_fd(fd) }
65     }
66     /// # 监听控制命令 - 监听系统服务控制命令
67     ///
68     /// 持续从系统服务控制管道中读取命令。
69     ///
ctl_listen()70     pub fn ctl_listen() {
71         let mut guard = CTL_READER.lock().unwrap();
72         let mut s = String::new();
73         if let Ok(size) = guard.read_to_string(&mut s) {
74             if size == 0 {
75                 return;
76             }
77             match CtlParser::parse_ctl(&s) {
78                 Ok(cmd) => {
79                     let _ = CtlManager::exec_ctl(cmd);
80                 }
81                 Err(err) => {
82                     eprintln!("parse tcl command error: {}", err.error_format());
83                 }
84             }
85         }
86     }
87 
88     /// # 检查控制管道是否存在 - 检查系统服务控制管道文件是否存在
89     ///
90     /// 返回管道文件是否存在。
91     ///
is_ctl_exists() -> bool92     fn is_ctl_exists() -> bool {
93         if let Ok(metadata) = fs::metadata(DRAGON_REACH_CTL_PIPE) {
94             metadata.is_file()
95         } else {
96             false
97         }
98     }
99 
init_ctl_pipe()100     fn init_ctl_pipe() {
101         if !Self::is_ctl_exists() {
102             let path = ctl_path();
103             let ret = unsafe { libc::mkfifo(path.as_ptr(), 0o666) };
104             if ret != 0 {
105                 // 创建管道失败打日志
106                 panic!("create ctl pipe failed, err: {ret}");
107             }
108         }
109     }
110 }
111