(
cmd_string: &str,
ipc_server_name: Option<String>,
out_dir: &Path,
)
| 70 | } |
| 71 | |
| 72 | fn track_command( |
| 73 | cmd_string: &str, |
| 74 | ipc_server_name: Option<String>, |
| 75 | out_dir: &Path, |
| 76 | ) -> anyhow::Result<std::process::ExitStatus> { |
| 77 | // First, establish IPC connection if needed to avoid timeouts on the runner because |
| 78 | // creating the Tracker instance takes some time. |
| 79 | let ipc_channel = if let Some(server_name) = ipc_server_name { |
| 80 | debug!("Connecting to IPC server: {server_name}"); |
| 81 | |
| 82 | let (tx, rx) = ipc::channel::<MemtrackIpcMessage>()?; |
| 83 | let sender = ipc::IpcSender::connect(server_name)?; |
| 84 | sender.send(tx)?; |
| 85 | |
| 86 | Some(rx) |
| 87 | } else { |
| 88 | None |
| 89 | }; |
| 90 | |
| 91 | let tracker = Tracker::new()?; |
| 92 | let tracker_arc = Arc::new(Mutex::new(tracker)); |
| 93 | |
| 94 | // Spawn IPC handler thread with the now-available tracker |
| 95 | let ipc_handle = if let Some(rx) = ipc_channel { |
| 96 | let tracker_clone = tracker_arc.clone(); |
| 97 | Some(thread::spawn(move || { |
| 98 | while let Ok(msg) = rx.recv() { |
| 99 | handle_ipc_message(msg, &tracker_clone); |
| 100 | } |
| 101 | })) |
| 102 | } else { |
| 103 | // Without IPC, nothing toggles the tracking_enabled map, so events would |
| 104 | // be dropped by the eBPF is_enabled() check. Enable it up front. |
| 105 | tracker_arc.lock().unwrap().enable()?; |
| 106 | None |
| 107 | }; |
| 108 | |
| 109 | // Start the target command using bash to handle shell syntax |
| 110 | let mut cmd = Command::new("bash"); |
| 111 | cmd.arg("-c").arg(cmd_string); |
| 112 | |
| 113 | // Drop privileges if running under sudo. This is required to avoid permission issues |
| 114 | // when the target command tries to access files or directories that the current user |
| 115 | // does not have permission to access. |
| 116 | if let Some((uid, gid)) = get_user_uid_gid() { |
| 117 | debug!("Running under sudo, dropping privileges to uid={uid}, gid={gid}"); |
| 118 | cmd.uid(uid).gid(gid); |
| 119 | } |
| 120 | |
| 121 | let mut child = cmd |
| 122 | .spawn() |
| 123 | .map_err(|e| anyhow!("Failed to spawn child process: {e}"))?; |
| 124 | let root_pid = child.id() as i32; |
| 125 | let event_rx = { tracker_arc.lock().unwrap().track(root_pid)? }; |
| 126 | debug!("Spawned child with pid {root_pid}"); |
| 127 | |
| 128 | // Generate output file name and create file for streaming events |
| 129 | let file_name = MemtrackArtifact::file_name(Some(root_pid)); |
no test coverage detected