1use crate::cronjob::CronJob;
2use std::{
3 process::Command,
4 str,
5 sync::{Arc, Mutex},
6};
7
8pub struct Crontab {
9 jobs: Vec<CronJob>,
10 lines: Vec<String>,
11}
12
13impl Crontab {
14 pub fn get_instance() -> Arc<Mutex<Crontab>> {
17 static mut INSTANCE: Option<Arc<Mutex<Crontab>>> = None;
18 unsafe {
19 INSTANCE
20 .get_or_insert_with(|| {
21 Arc::new(Mutex::new(Crontab {
22 jobs: vec![],
23 lines: vec![],
24 }))
25 })
26 .clone()
27 }
28 }
29}
30
31impl Crontab {
32 pub fn load(&mut self) -> Result<Vec<CronJob>, String> {
33 let output = Command::new("crontab")
35 .arg("-l")
36 .output()
37 .map_err(|err| format!("Failed to execute crontab command: {}", err))?;
38
39 if output.status.success() {
41 let stdout = str::from_utf8(&output.stdout)
43 .map_err(|err| format!("Failed to parse crontab output: {}", err))?;
44
45 let lines: Vec<String> = stdout
47 .lines()
48 .filter(|line| !line.trim().is_empty())
49 .map(|line| line.to_string())
50 .collect();
51 self.lines = lines.clone();
52 let mut jobs: Vec<CronJob> = vec![];
53 for line in lines {
54 jobs.push(CronJob::new(line));
55 }
56 self.jobs = jobs.clone();
57 Ok(jobs)
58 } else {
59 let stderr = str::from_utf8(&output.stderr)
61 .map_err(|err| format!("Failed to read error message: {}", err))?;
62 Err(stderr.to_string())
63 }
64 }
65
66 pub fn save(&mut self, jobs: Vec<CronJob>) -> Result<(), String> {
67 let lines: Vec<String> = jobs.iter().map(|job| job.to_string()).collect();
69 self.lines = lines.clone();
70 let lines = lines.join("\n");
72 let mut child = std::process::Command::new("crontab")
74 .stdin(std::process::Stdio::piped())
75 .spawn()
76 .map_err(|err| format!("Failed to execute crontab command: {}", err))?;
77
78 if let Some(mut stdin) = child.stdin.take() {
80 use std::io::Write;
81 stdin
82 .write_all(lines.as_bytes())
83 .map_err(|err| format!("Failed to write to crontab stdin: {}", err))?;
84 }
85
86 let output = child
88 .wait()
89 .map_err(|err| format!("Failed to wait on crontab process: {}", err))?;
90
91 if output.success() {
92 Ok(())
93 } else {
94 Err("Failed to update crontab".to_string())
95 }
96 }
97}