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