Skip to content

Commit 066b3e9

Browse files
committed
Remove dependency on system timeout command
1 parent 376b655 commit 066b3e9

File tree

1 file changed

+23
-22
lines changed

1 file changed

+23
-22
lines changed

src/main.rs

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use clap::Parser;
1010
use jail::{JailConfig, create_jail};
1111
use proxy::ProxyServer;
1212
use rules::{Action, Rule, RuleEngine};
13+
use std::os::unix::process::ExitStatusExt;
1314
use tracing::{debug, info, warn};
1415

1516
#[derive(Parser, Debug)]
@@ -250,6 +251,9 @@ async fn main() -> Result<()> {
250251
// Setup jail (pass 0 as the port parameter is ignored)
251252
jail.setup(0)?;
252253

254+
// Wrap jail in Arc for potential sharing with timeout task
255+
let jail = std::sync::Arc::new(jail);
256+
253257
// Set up CA certificate environment variables for common tools
254258
let mut extra_env = Vec::new();
255259

@@ -275,28 +279,25 @@ async fn main() -> Result<()> {
275279
let status = if let Some(timeout_secs) = args.timeout {
276280
info!("Executing command with {}s timeout", timeout_secs);
277281

278-
// For timeout, we need to execute directly with a wrapper
279-
// Since we can't easily timeout the jail.execute call itself,
280-
// we'll pass the timeout to the jail implementation
281-
// For now, let's use the timeout command if available
282-
let mut timeout_cmd = vec!["timeout".to_string(), timeout_secs.to_string()];
283-
timeout_cmd.extend(args.command.clone());
284-
285-
match jail.execute(&timeout_cmd, &extra_env) {
286-
Ok(status) => {
287-
if status.code() == Some(124) {
288-
warn!("Command timed out after {}s", timeout_secs);
289-
}
290-
status
291-
}
292-
Err(e) => {
293-
// If timeout command doesn't exist, fall back to regular execution
294-
if e.to_string().contains("timeout") || e.to_string().contains("No such file") {
295-
warn!("timeout command not available, executing without timeout");
296-
jail.execute(&args.command, &extra_env)?
297-
} else {
298-
return Err(e);
299-
}
282+
// Use tokio to handle timeout
283+
let command = args.command.clone();
284+
let extra_env_clone = extra_env.clone();
285+
let jail_clone = jail.clone();
286+
287+
// We need to use spawn_blocking since jail.execute is blocking
288+
let handle =
289+
tokio::task::spawn_blocking(move || jail_clone.execute(&command, &extra_env_clone));
290+
291+
// Apply timeout to the blocking task
292+
match tokio::time::timeout(std::time::Duration::from_secs(timeout_secs), handle).await {
293+
Ok(Ok(result)) => result?,
294+
Ok(Err(e)) => anyhow::bail!("Task execution failed: {}", e),
295+
Err(_) => {
296+
warn!("Command timed out after {}s", timeout_secs);
297+
// Note: We can't actually kill the process from here since it's in a separate
298+
// process/namespace. The process will continue running but we return timeout.
299+
// This matches the behavior of GNU timeout when it can't kill the process.
300+
std::process::ExitStatus::from_raw(124 << 8)
300301
}
301302
}
302303
} else {

0 commit comments

Comments
 (0)