proc_cli/commands/
freeze.rs1#[cfg(unix)]
11use crate::core::{parse_targets, resolve_in_dir, resolve_targets_excluding_self};
12use crate::error::{ProcError, Result};
13#[cfg(unix)]
14use crate::ui::{OutputFormat, Printer};
15use clap::Args;
16#[cfg(unix)]
17use dialoguer::Confirm;
18#[cfg(unix)]
19use std::path::PathBuf;
20
21#[derive(Args, Debug)]
23pub struct FreezeCommand {
24 #[arg(required = true)]
26 pub target: String,
27
28 #[arg(long, short = 'y')]
30 pub yes: bool,
31
32 #[arg(long)]
34 pub dry_run: bool,
35
36 #[arg(long, short = 'j')]
38 pub json: bool,
39
40 #[arg(long, short = 'v')]
42 pub verbose: bool,
43
44 #[arg(long = "in", short = 'i', num_args = 0..=1, default_missing_value = ".")]
46 pub in_dir: Option<String>,
47
48 #[arg(long = "by", short = 'b')]
50 pub by_name: Option<String>,
51}
52
53impl FreezeCommand {
54 #[cfg(unix)]
56 pub fn execute(&self) -> Result<()> {
57 use nix::sys::signal::Signal;
58
59 let format = if self.json {
60 OutputFormat::Json
61 } else {
62 OutputFormat::Human
63 };
64 let printer = Printer::new(format, self.verbose);
65
66 let targets = parse_targets(&self.target);
67 let (mut processes, not_found) = resolve_targets_excluding_self(&targets);
68
69 if !not_found.is_empty() {
70 printer.warning(&format!("Not found: {}", not_found.join(", ")));
71 }
72
73 let in_dir_filter = resolve_in_dir(&self.in_dir);
75 processes.retain(|p| {
76 if let Some(ref dir_path) = in_dir_filter {
77 if let Some(ref cwd) = p.cwd {
78 if !PathBuf::from(cwd).starts_with(dir_path) {
79 return false;
80 }
81 } else {
82 return false;
83 }
84 }
85 if let Some(ref name) = self.by_name {
86 if !p.name.to_lowercase().contains(&name.to_lowercase()) {
87 return false;
88 }
89 }
90 true
91 });
92
93 if processes.is_empty() {
94 return Err(ProcError::ProcessNotFound(self.target.clone()));
95 }
96
97 if self.dry_run {
98 printer.print_processes(&processes);
99 printer.warning(&format!(
100 "Dry run: would freeze {} process{}",
101 processes.len(),
102 if processes.len() == 1 { "" } else { "es" }
103 ));
104 return Ok(());
105 }
106
107 if !self.yes && !self.json {
108 printer.print_confirmation("freeze", &processes);
109
110 let prompt = format!(
111 "Freeze {} process{}?",
112 processes.len(),
113 if processes.len() == 1 { "" } else { "es" }
114 );
115
116 if !Confirm::new()
117 .with_prompt(prompt)
118 .default(false)
119 .interact()?
120 {
121 printer.warning("Aborted");
122 return Ok(());
123 }
124 }
125
126 let mut succeeded = Vec::new();
127 let mut failed = Vec::new();
128
129 for proc in &processes {
130 match proc.send_signal(Signal::SIGSTOP) {
131 Ok(()) => succeeded.push(proc.clone()),
132 Err(e) => failed.push((proc.clone(), e.to_string())),
133 }
134 }
135
136 printer.print_action_result("Frozen", &succeeded, &failed);
137
138 Ok(())
139 }
140
141 #[cfg(not(unix))]
143 pub fn execute(&self) -> Result<()> {
144 Err(ProcError::NotSupported(
145 "freeze (SIGSTOP) is not supported on Windows".to_string(),
146 ))
147 }
148}