Vain attempts to stop script
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
pub mod structured;
|
||||
pub use structured::{StructuredCommand, MessageLevel, FormField, FormFieldType};
|
||||
pub use structured::{StructuredCommand, MessageLevel, FormFieldType};
|
||||
|
||||
// Здесь могут быть функции для download, http и т.д.
|
||||
|
||||
@@ -28,7 +28,9 @@ pub enum StructuredCommand {
|
||||
text: String,
|
||||
},
|
||||
Progress {
|
||||
percent: u8,
|
||||
/// Some(n) = deterministic bar (0-100).
|
||||
/// None = indeterminate spinner (percent omitted from JSON).
|
||||
percent: Option<u8>,
|
||||
message: Option<String>,
|
||||
},
|
||||
/// A list of checkboxes and radio buttons.
|
||||
@@ -86,6 +88,7 @@ pub fn spawn(
|
||||
tokio::sync::oneshot::Receiver<i32>,
|
||||
UnboundedSender<String>,
|
||||
tokio::sync::oneshot::Sender<()>, // kill signal
|
||||
Option<u32>, // bash PID for direct kill
|
||||
)> {
|
||||
let mut child = Command::new("bash")
|
||||
.arg("-c")
|
||||
@@ -93,10 +96,22 @@ pub fn spawn(
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
// Create a new process group (PGID = bash PID) so that
|
||||
// kill(-pid, SIGKILL) kills bash AND all its children
|
||||
// (grep, php, mysql, etc.) without touching the parent ostiary.
|
||||
.process_group(0)
|
||||
.spawn()?;
|
||||
|
||||
// Capture the PID before moving child into tasks (needed for kill).
|
||||
let pid = child.id();
|
||||
dbg_kill(format!("spawn: bash pid={:?}", pid));
|
||||
// Log the actual process group bash landed in.
|
||||
#[cfg(unix)]
|
||||
if let Some(p) = pid {
|
||||
let pgid = unsafe { libc::getpgid(p as libc::pid_t) };
|
||||
let my_pgid = unsafe { libc::getpgid(0) };
|
||||
dbg_kill(format!(" bash pgid={pgid} ostiary pgid={my_pgid}"));
|
||||
}
|
||||
|
||||
let stdin = child.stdin.take().unwrap();
|
||||
let stdout = child.stdout.take().unwrap();
|
||||
@@ -160,20 +175,33 @@ pub fn spawn(
|
||||
let _ = finished_tx.send(code);
|
||||
});
|
||||
|
||||
// Kill-watcher: when kill_tx fires, send SIGTERM to the entire process
|
||||
// group so bash AND all its children (mysqldump, php, etc.) are killed.
|
||||
// Kill-watcher: when kill_tx fires, send SIGKILL to the entire process
|
||||
// group so bash AND all its children are unconditionally terminated.
|
||||
tokio::spawn(async move {
|
||||
if kill_rx.await.is_ok() {
|
||||
let recv = kill_rx.await;
|
||||
dbg_kill(format!("kill-watcher: recv={:?} pid={:?}", recv.is_ok(), pid));
|
||||
if recv.is_ok() {
|
||||
if let Some(pid) = pid {
|
||||
#[cfg(unix)]
|
||||
unsafe {
|
||||
libc::kill(-(pid as libc::pid_t), libc::SIGTERM);
|
||||
{
|
||||
let r1 = unsafe { libc::kill(-(pid as libc::pid_t), libc::SIGKILL) };
|
||||
let r2 = unsafe { libc::kill(pid as libc::pid_t, libc::SIGKILL) };
|
||||
dbg_kill(format!(" kill-watcher kill(-{pid})={r1}, kill({pid})={r2}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok((output_rx, cmd_rx, finished_rx, reply_tx, kill_tx))
|
||||
Ok((output_rx, cmd_rx, finished_rx, reply_tx, kill_tx, pid))
|
||||
}
|
||||
|
||||
fn dbg_kill(msg: String) {
|
||||
use std::io::Write;
|
||||
if let Ok(mut f) = std::fs::OpenOptions::new()
|
||||
.create(true).append(true).open("/tmp/ostiary-kill.log")
|
||||
{
|
||||
let _ = writeln!(f, "{}", msg);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_command(json_str: &str, cmd_tx: UnboundedSender<StructuredCommand>) -> Result<()> {
|
||||
@@ -218,7 +246,8 @@ fn parse_command(json_str: &str, cmd_tx: UnboundedSender<StructuredCommand>) ->
|
||||
StructuredCommand::Message { level, text }
|
||||
}
|
||||
"progress" => {
|
||||
let percent = v["percent"].as_u64().unwrap_or(0) as u8;
|
||||
// percent absent or null → None (indeterminate spinner)
|
||||
let percent = v["percent"].as_u64().map(|n| n.min(100) as u8);
|
||||
let message = v["message"].as_str().map(String::from);
|
||||
StructuredCommand::Progress { percent, message }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user