xref: /DragonReach/src/systemctl/listener/mod.rs (revision 909e4d102ffeb8646e7346c10b007cb0861226a4)
1 use lazy_static::lazy_static;
2 use std::fs::{self, File};
3 use std::io::Read;
4 use std::os::fd::FromRawFd;
5 use std::string::String;
6 use std::sync::{Arc, Mutex};
7 use std::vec::Vec;
8 use std::{eprint, eprintln, libc};
9 
10 use crate::error::ErrorFormat;
11 use crate::manager::ctl_manager::CtlManager;
12 
13 use super::ctl_parser::{CommandOperation, CtlParser, Pattern};
14 use super::{ctl_path, DRAGON_REACH_CTL_PIPE};
15 
16 lazy_static! {
17     static ref CTL_READER: Mutex<Arc<File>> = {
18         let file = Systemctl::init_listener();
19         Mutex::new(Arc::new(file))
20     };
21 }
22 
23 pub struct Command {
24     pub(crate) operation: CommandOperation,
25     pub(crate) args: Option<Vec<String>>,
26     pub(crate) patterns: Vec<Pattern>,
27 }
28 
29 impl Command {
30     #[allow(dead_code)]
31     fn new(op: CommandOperation, patterns: Vec<Pattern>, args: Option<Vec<String>>) -> Self {
32         Command {
33             operation: op,
34             args,
35             patterns: patterns,
36         }
37     }
38 }
39 
40 impl Default for Command {
41     fn default() -> Self {
42         Command {
43             operation: CommandOperation::None,
44             args: None,
45             patterns: Vec::new(),
46         }
47     }
48 }
49 
50 pub struct Systemctl;
51 
52 impl Systemctl {
53     pub fn init() {
54         Self::init_ctl_pipe();
55     }
56 
57     pub fn init_listener() -> File {
58         let fd = unsafe { libc::open(ctl_path().as_ptr(), libc::O_RDONLY | libc::O_NONBLOCK) };
59         if fd < 0 {
60             panic!("open ctl pipe error");
61         }
62         unsafe { File::from_raw_fd(fd) }
63     }
64 
65     pub fn ctl_listen() {
66         let mut guard = CTL_READER.lock().unwrap();
67         let mut s = String::new();
68         if let Ok(size) = guard.read_to_string(&mut s) {
69             if size == 0 {
70                 return;
71             }
72             match CtlParser::parse_ctl(&s) {
73                 Ok(cmd) => {
74                     let _ = CtlManager::exec_ctl(cmd);
75                 }
76                 Err(err) => {
77                     eprintln!("parse tcl command error: {}", err.error_format());
78                 }
79             }
80         }
81     }
82 
83     fn is_ctl_exists() -> bool {
84         if let Ok(metadata) = fs::metadata(DRAGON_REACH_CTL_PIPE) {
85             metadata.is_file()
86         } else {
87             false
88         }
89     }
90 
91     fn init_ctl_pipe() {
92         if !Self::is_ctl_exists() {
93             let path = ctl_path();
94             let ret = unsafe { libc::mkfifo(path.as_ptr(), 0o666) };
95             if ret != 0 {
96                 // 创建管道失败打日志
97                 panic!("create ctl pipe failed");
98             }
99         }
100     }
101 }
102