diff --git a/Cargo.lock b/Cargo.lock index eadf5218..a751f5fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -329,6 +329,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "clap" version = "4.5.1" @@ -1212,12 +1218,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ "bitflags 2.4.2", "cfg-if", + "cfg_aliases", "libc", ] diff --git a/samply/Cargo.toml b/samply/Cargo.toml index 1132b9a2..41c54294 100644 --- a/samply/Cargo.toml +++ b/samply/Cargo.toml @@ -64,7 +64,7 @@ sysctl = "0.5.4" parking_lot = "0.12.1" num_cpus = "1.13.1" uname = "0.1.1" -nix = { version = "0.27.1", features = ["fs", "process"] } +nix = { version = "0.28", features = ["fs", "process"] } [dependencies.object] default-features = false diff --git a/samply/src/linux/process.rs b/samply/src/linux/process.rs index 298cb33f..5989f405 100644 --- a/samply/src/linux/process.rs +++ b/samply/src/linux/process.rs @@ -1,6 +1,9 @@ use libc::execvp; +use nix::sys::wait::WaitStatus; +use nix::unistd::Pid; use std::ffi::{CString, OsStr, OsString}; +use std::os::fd::{AsFd, AsRawFd, IntoRawFd, OwnedFd}; use std::os::raw::c_char; use std::os::unix::prelude::{ExitStatusExt, OsStrExt}; use std::process::ExitStatus; @@ -8,9 +11,9 @@ use std::process::ExitStatus; /// Allows launching a command in a suspended state, so that we can know its /// pid and initialize profiling before proceeding to execute the command. pub struct SuspendedLaunchedProcess { - pid: u32, - send_end_of_resume_pipe: i32, - recv_end_of_execerr_pipe: i32, + pid: Pid, + send_end_of_resume_pipe: OwnedFd, + recv_end_of_execerr_pipe: OwnedFd, } impl SuspendedLaunchedProcess { @@ -34,16 +37,15 @@ impl SuspendedLaunchedProcess { match unsafe { nix::unistd::fork() }.expect("Fork failed") { nix::unistd::ForkResult::Child => { // std::panic::always_abort(); - nix::unistd::close(resume_sp).unwrap(); - nix::unistd::close(execerr_rp).unwrap(); + nix::unistd::close(resume_sp.into_raw_fd()).unwrap(); + nix::unistd::close(execerr_rp.into_raw_fd()).unwrap(); Self::run_child(resume_rp, execerr_sp, &argv) } nix::unistd::ForkResult::Parent { child } => { - nix::unistd::close(resume_rp)?; - nix::unistd::close(execerr_sp)?; - let pid = child.as_raw() as u32; + nix::unistd::close(resume_rp.into_raw_fd())?; + nix::unistd::close(execerr_sp.into_raw_fd())?; Ok(Self { - pid, + pid: child, send_end_of_resume_pipe: resume_sp, recv_end_of_execerr_pipe: execerr_rp, }) @@ -52,21 +54,22 @@ impl SuspendedLaunchedProcess { } pub fn pid(&self) -> u32 { - self.pid + self.pid.as_raw() as u32 } const EXECERR_MSG_FOOTER: [u8; 4] = *b"NOEX"; pub fn unsuspend_and_run(self) -> std::io::Result { // Send a byte to the child process. - nix::unistd::write(self.send_end_of_resume_pipe, &[0x42])?; - nix::unistd::close(self.send_end_of_resume_pipe)?; + nix::unistd::write(self.send_end_of_resume_pipe.as_fd(), &[0x42])?; + nix::unistd::close(self.send_end_of_resume_pipe.into_raw_fd())?; // Wait for the child to indicate success or failure of the execve call. // loop for EINTR loop { let mut bytes = [0; 8]; - let read_result = nix::unistd::read(self.recv_end_of_execerr_pipe, &mut bytes); + let read_result = + nix::unistd::read(self.recv_end_of_execerr_pipe.as_raw_fd(), &mut bytes); // The parent has replied! Or exited. match read_result { @@ -85,10 +88,7 @@ impl SuspendedLaunchedProcess { "Validation on the execerr pipe failed: {bytes:?}", ); let errno = i32::from_be_bytes([errno[0], errno[1], errno[2], errno[3]]); - let mut exit_status: i32 = 0; - let _pid = unsafe { - libc::waitpid(self.pid as i32, &mut exit_status as *mut libc::c_int, 0) - }; + let _wait_status = nix::sys::wait::waitpid(self.pid, None); return Err(std::io::Error::from_raw_os_error(errno)); } Ok(_) => { @@ -98,11 +98,8 @@ impl SuspendedLaunchedProcess { // This case is very unexpected and we will panic, after making sure that the child has // fully executed. - let mut exit_status: i32 = 0; - let waitpid_res = unsafe { - libc::waitpid(self.pid as i32, &mut exit_status as *mut libc::c_int, 0) - }; - nix::errno::Errno::result(waitpid_res).expect("waitpid should always succeed"); + let _status = nix::sys::wait::waitpid(self.pid, None) + .expect("waitpid should always succeed"); panic!("short read on the execerr pipe") } @@ -116,8 +113,8 @@ impl SuspendedLaunchedProcess { /// Executed in the forked child process. This function never returns. fn run_child( - recv_end_of_resume_pipe: i32, - send_end_of_execerr_pipe: i32, + recv_end_of_resume_pipe: OwnedFd, + send_end_of_execerr_pipe: OwnedFd, argv: &[*const c_char], ) -> ! { // Wait for the parent to send us a byte through the pipe. @@ -126,7 +123,7 @@ impl SuspendedLaunchedProcess { // loop to handle EINTR loop { let mut buf = [0]; - let read_result = nix::unistd::read(recv_end_of_resume_pipe, &mut buf); + let read_result = nix::unistd::read(recv_end_of_resume_pipe.as_raw_fd(), &mut buf); // The parent has replied! Or exited. match read_result { @@ -146,7 +143,7 @@ impl SuspendedLaunchedProcess { // But we got here! This can happen if the command doesn't exist. // Return the error number via the "execerr" pipe. - let errno = nix::errno::errno().to_be_bytes(); + let errno = nix::errno::Errno::last_raw().to_be_bytes(); let bytes = [ errno[0], errno[1], @@ -172,16 +169,18 @@ impl SuspendedLaunchedProcess { } pub struct RunningProcess { - pid: u32, + pid: Pid, } impl RunningProcess { pub fn wait(self) -> Result { - let mut exit_status: i32 = 0; - let _pid = - unsafe { libc::waitpid(self.pid as i32, &mut exit_status as *mut libc::c_int, 0) }; - nix::errno::Errno::result(nix::errno::errno())?; - let exit_status = ExitStatus::from_raw(exit_status); + let wait_status = nix::sys::wait::waitpid(self.pid, None)?; + let exit_status = match wait_status { + WaitStatus::Exited(_pid, exit_code) => ExitStatus::from_raw(exit_code), + wait_status => { + panic!("Unexpected waitpid result: {wait_status:?}"); + } + }; Ok(exit_status) } }