diff --git a/Cargo.lock b/Cargo.lock index 377d845f81..0a5d85d3b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3824,6 +3824,7 @@ dependencies = [ [[package]] name = "procinfo" version = "0.1.0" +source = "git+https://github.com/zed-industries/wezterm?rev=40a7dbf93542fbe4178c2e4b4bd438126a6432b9#40a7dbf93542fbe4178c2e4b4bd438126a6432b9" dependencies = [ "libc", "log", diff --git a/crates/procinfo/Cargo.toml b/crates/procinfo/Cargo.toml deleted file mode 100644 index 567b390bf4..0000000000 --- a/crates/procinfo/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "procinfo" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[features] - -[dependencies] -libc = "0.2" -log = "0.4" - -[target."cfg(windows)".dependencies] -ntapi = "0.3" -winapi = { version = "0.3", features = [ - "handleapi", - "memoryapi", - "psapi", - "processthreadsapi", - "shellapi", - "tlhelp32", -]} - diff --git a/crates/procinfo/src/lib.rs b/crates/procinfo/src/lib.rs deleted file mode 100644 index cfbec762b8..0000000000 --- a/crates/procinfo/src/lib.rs +++ /dev/null @@ -1,93 +0,0 @@ -use std::collections::{HashMap, HashSet}; -use std::path::PathBuf; -mod linux; -mod macos; -mod windows; - -#[derive(Debug, Copy, Clone)] -pub enum LocalProcessStatus { - Idle, - Run, - Sleep, - Stop, - Zombie, - Tracing, - Dead, - Wakekill, - Waking, - Parked, - LockBlocked, - Unknown, -} - -#[derive(Debug, Clone)] -pub struct LocalProcessInfo { - /// The process identifier - pub pid: u32, - /// The parent process identifier - pub ppid: u32, - /// The COMM name of the process. May not bear any relation to - /// the executable image name. May be changed at runtime by - /// the process. - /// Many systems truncate this - /// field to 15-16 characters. - pub name: String, - /// Path to the executable image - pub executable: PathBuf, - /// The argument vector. - /// Some systems allow changing the argv block at runtime - /// eg: setproctitle(). - pub argv: Vec, - /// The current working directory for the process, or an empty - /// path if it was not accessible for some reason. - pub cwd: PathBuf, - /// The status of the process. Not all possible values are - /// portably supported on all systems. - pub status: LocalProcessStatus, - /// A clock value in unspecified system dependent units that - /// indicates the relative age of the process. - pub start_time: u64, - /// The console handle associated with the process, if any. - #[cfg(windows)] - pub console: u64, - /// Child processes, keyed by pid - pub children: HashMap, -} -#[cfg(feature = "lua")] -luahelper::impl_lua_conversion_dynamic!(LocalProcessInfo); - -impl LocalProcessInfo { - /// Walk this sub-tree of processes and return a unique set - /// of executable base names. eg: `foo/bar` and `woot/bar` - /// produce a set containing just `bar`. - pub fn flatten_to_exe_names(&self) -> HashSet { - let mut names = HashSet::new(); - - fn flatten(item: &LocalProcessInfo, names: &mut HashSet) { - if let Some(exe) = item.executable.file_name() { - names.insert(exe.to_string_lossy().into_owned()); - } - for proc in item.children.values() { - flatten(proc, names); - } - } - - flatten(self, &mut names); - names - } - - #[cfg(not(any(target_os = "macos", target_os = "linux", windows)))] - pub fn with_root_pid(_pid: u32) -> Option { - None - } - - #[cfg(not(any(target_os = "macos", target_os = "linux", windows)))] - pub fn current_working_dir(_pid: u32) -> Option { - None - } - - #[cfg(not(any(target_os = "macos", target_os = "linux", windows)))] - pub fn executable_path(_pid: u32) -> Option { - None - } -} diff --git a/crates/procinfo/src/linux.rs b/crates/procinfo/src/linux.rs deleted file mode 100644 index 9211f61551..0000000000 --- a/crates/procinfo/src/linux.rs +++ /dev/null @@ -1,139 +0,0 @@ -#![cfg(target_os = "linux")] -use super::*; - -impl From<&str> for LocalProcessStatus { - fn from(s: &str) -> Self { - match s { - "R" => Self::Run, - "S" => Self::Sleep, - "D" => Self::Idle, - "Z" => Self::Zombie, - "T" => Self::Stop, - "t" => Self::Tracing, - "X" | "x" => Self::Dead, - "K" => Self::Wakekill, - "W" => Self::Waking, - "P" => Self::Parked, - _ => Self::Unknown, - } - } -} - -impl LocalProcessInfo { - pub fn current_working_dir(pid: u32) -> Option { - std::fs::read_link(format!("/proc/{}/cwd", pid)).ok() - } - - pub fn executable_path(pid: u32) -> Option { - std::fs::read_link(format!("/proc/{}/exe", pid)).ok() - } - - pub fn with_root_pid(pid: u32) -> Option { - use libc::pid_t; - - let pid = pid as pid_t; - - fn all_pids() -> Vec { - let mut pids = vec![]; - if let Ok(dir) = std::fs::read_dir("/proc") { - for entry in dir { - if let Ok(entry) = entry { - if let Ok(file_type) = entry.file_type() { - if file_type.is_dir() { - if let Some(name) = entry.file_name().to_str() { - if let Ok(pid) = name.parse::() { - pids.push(pid); - } - } - } - } - } - } - } - pids - } - - struct LinuxStat { - pid: pid_t, - name: String, - status: String, - ppid: pid_t, - // Time process started after boot, measured in ticks - starttime: u64, - } - - fn info_for_pid(pid: pid_t) -> Option { - let data = std::fs::read_to_string(format!("/proc/{}/stat", pid)).ok()?; - let (_pid_space, name) = data.split_once('(')?; - let (name, fields) = name.rsplit_once(')')?; - let fields = fields.split_whitespace().collect::>(); - - Some(LinuxStat { - pid, - name: name.to_string(), - status: fields.get(0)?.to_string(), - ppid: fields.get(1)?.parse().ok()?, - starttime: fields.get(20)?.parse().ok()?, - }) - } - - fn exe_for_pid(pid: pid_t) -> PathBuf { - std::fs::read_link(format!("/proc/{}/exe", pid)).unwrap_or_else(|_| PathBuf::new()) - } - - fn cwd_for_pid(pid: pid_t) -> PathBuf { - LocalProcessInfo::current_working_dir(pid as u32).unwrap_or_else(|| PathBuf::new()) - } - - fn parse_cmdline(pid: pid_t) -> Vec { - let data = match std::fs::read(format!("/proc/{}/cmdline", pid)) { - Ok(data) => data, - Err(_) => return vec![], - }; - - let mut args = vec![]; - - let data = data.strip_suffix(&[0]).unwrap_or(&data); - - for arg in data.split(|&c| c == 0) { - args.push(String::from_utf8_lossy(arg).to_owned().to_string()); - } - - args - } - - let procs: Vec<_> = all_pids().into_iter().filter_map(info_for_pid).collect(); - - fn build_proc(info: &LinuxStat, procs: &[LinuxStat]) -> LocalProcessInfo { - let mut children = HashMap::new(); - - for kid in procs { - if kid.ppid == info.pid { - children.insert(kid.pid as u32, build_proc(kid, procs)); - } - } - - let executable = exe_for_pid(info.pid); - let name = info.name.clone(); - let argv = parse_cmdline(info.pid); - - LocalProcessInfo { - pid: info.pid as _, - ppid: info.ppid as _, - name, - executable, - cwd: cwd_for_pid(info.pid), - argv, - start_time: info.starttime, - status: info.status.as_str().into(), - children, - } - } - - if let Some(info) = procs.iter().find(|info| info.pid == pid) { - Some(build_proc(info, &procs)) - } else { - None - } - } -} diff --git a/crates/procinfo/src/macos.rs b/crates/procinfo/src/macos.rs deleted file mode 100644 index 5d2de1c399..0000000000 --- a/crates/procinfo/src/macos.rs +++ /dev/null @@ -1,231 +0,0 @@ -#![cfg(target_os = "macos")] -use super::*; -use std::ffi::{OsStr, OsString}; -use std::os::unix::ffi::{OsStrExt, OsStringExt}; - -impl From for LocalProcessStatus { - fn from(s: u32) -> Self { - match s { - 1 => Self::Idle, - 2 => Self::Run, - 3 => Self::Sleep, - 4 => Self::Stop, - 5 => Self::Zombie, - _ => Self::Unknown, - } - } -} - -impl LocalProcessInfo { - pub fn current_working_dir(pid: u32) -> Option { - let mut pathinfo: libc::proc_vnodepathinfo = unsafe { std::mem::zeroed() }; - let size = std::mem::size_of_val(&pathinfo) as libc::c_int; - let ret = unsafe { - libc::proc_pidinfo( - pid as _, - libc::PROC_PIDVNODEPATHINFO, - 0, - &mut pathinfo as *mut _ as *mut _, - size, - ) - }; - if ret != size { - return None; - } - - // Workaround a workaround for an old rustc version supported by libc; - // the type of vip_path should just be [c_char; MAXPATHLEN] but it - // is defined as a horrible nested array by the libc crate: - // `[[c_char; 32]; 32]`. - // Urgh. Let's re-cast it as the correct kind of slice. - let vip_path = unsafe { - std::slice::from_raw_parts( - pathinfo.pvi_cdir.vip_path.as_ptr() as *const u8, - libc::MAXPATHLEN as usize, - ) - }; - let nul = vip_path.iter().position(|&c| c == 0)?; - Some(OsStr::from_bytes(&vip_path[0..nul]).into()) - } - - pub fn executable_path(pid: u32) -> Option { - let mut buffer: Vec = Vec::with_capacity(libc::PROC_PIDPATHINFO_MAXSIZE as _); - let x = unsafe { - libc::proc_pidpath( - pid as _, - buffer.as_mut_ptr() as *mut _, - libc::PROC_PIDPATHINFO_MAXSIZE as _, - ) - }; - if x <= 0 { - return None; - } - - unsafe { buffer.set_len(x as usize) }; - Some(OsString::from_vec(buffer).into()) - } - - pub fn with_root_pid(pid: u32) -> Option { - /// Enumerate all current process identifiers - fn all_pids() -> Vec { - let num_pids = unsafe { libc::proc_listallpids(std::ptr::null_mut(), 0) }; - if num_pids < 1 { - return vec![]; - } - - // Give a bit of padding to avoid looping if processes are spawning - // rapidly while we're trying to collect this info - const PADDING: usize = 32; - let mut pids: Vec = Vec::with_capacity(num_pids as usize + PADDING); - loop { - let n = unsafe { - libc::proc_listallpids( - pids.as_mut_ptr() as *mut _, - (pids.capacity() * std::mem::size_of::()) as _, - ) - }; - - if n < 1 { - return vec![]; - } - - let n = n as usize; - - if n > pids.capacity() { - pids.reserve(n + PADDING); - continue; - } - - unsafe { pids.set_len(n) }; - return pids; - } - } - - /// Obtain info block for a pid. - /// Note that the process could have gone away since we first - /// observed the pid and the time we call this, so we must - /// be able to tolerate this failing. - fn info_for_pid(pid: libc::pid_t) -> Option { - let mut info: libc::proc_bsdinfo = unsafe { std::mem::zeroed() }; - let wanted_size = std::mem::size_of::() as _; - let res = unsafe { - libc::proc_pidinfo( - pid, - libc::PROC_PIDTBSDINFO, - 0, - &mut info as *mut _ as *mut _, - wanted_size, - ) - }; - - if res == wanted_size { - Some(info) - } else { - None - } - } - - fn cwd_for_pid(pid: libc::pid_t) -> PathBuf { - LocalProcessInfo::current_working_dir(pid as _).unwrap_or_else(PathBuf::new) - } - - fn exe_and_args_for_pid_sysctl(pid: libc::pid_t) -> Option<(PathBuf, Vec)> { - use libc::c_int; - let mut size = 64 * 1024; - let mut buf: Vec = Vec::with_capacity(size); - let mut mib = [libc::CTL_KERN, libc::KERN_PROCARGS2, pid as c_int]; - - let res = unsafe { - libc::sysctl( - mib.as_mut_ptr(), - mib.len() as _, - buf.as_mut_ptr() as *mut _, - &mut size, - std::ptr::null_mut(), - 0, - ) - }; - if res == -1 { - return None; - } - if size < (std::mem::size_of::() * 2) { - // Not big enough - return None; - } - unsafe { buf.set_len(size) }; - - // The data in our buffer is laid out like this: - // argc - c_int - // exe_path - NUL terminated string - // argv[0] - NUL terminated string - // argv[1] - NUL terminated string - // ... - // argv[n] - NUL terminated string - // envp[0] - NUL terminated string - // ... - - let mut ptr = &buf[0..size]; - - let argc: c_int = unsafe { std::ptr::read(ptr.as_ptr() as *const c_int) }; - ptr = &ptr[std::mem::size_of::()..]; - - fn consume_cstr(ptr: &mut &[u8]) -> Option { - let nul = ptr.iter().position(|&c| c == 0)?; - let s = String::from_utf8_lossy(&ptr[0..nul]).to_owned().to_string(); - *ptr = ptr.get(nul + 1..)?; - Some(s) - } - - let exe_path = consume_cstr(&mut ptr)?.into(); - - let mut args = vec![]; - for _ in 0..argc { - args.push(consume_cstr(&mut ptr)?); - } - - dbg!(&exe_path); - dbg!(&args); - Some((exe_path, args)) - } - - fn exe_for_pid(pid: libc::pid_t) -> PathBuf { - LocalProcessInfo::executable_path(pid as _).unwrap_or_else(PathBuf::new) - } - - let procs: Vec<_> = all_pids().into_iter().filter_map(info_for_pid).collect(); - - fn build_proc(info: &libc::proc_bsdinfo, procs: &[libc::proc_bsdinfo]) -> LocalProcessInfo { - let mut children = HashMap::new(); - - for kid in procs { - if kid.pbi_ppid == info.pbi_pid { - children.insert(kid.pbi_pid, build_proc(kid, procs)); - } - } - - let (executable, argv) = exe_and_args_for_pid_sysctl(info.pbi_pid as _) - .unwrap_or_else(|| (exe_for_pid(info.pbi_pid as _), vec![])); - - let name = unsafe { std::ffi::CStr::from_ptr(info.pbi_comm.as_ptr() as _) }; - let name = name.to_str().unwrap_or("").to_string(); - - LocalProcessInfo { - pid: info.pbi_pid, - ppid: info.pbi_ppid, - name, - executable, - cwd: cwd_for_pid(info.pbi_pid as _), - argv, - start_time: info.pbi_start_tvsec, - status: LocalProcessStatus::from(info.pbi_status), - children, - } - } - - if let Some(info) = procs.iter().find(|info| info.pbi_pid == pid) { - Some(build_proc(info, &procs)) - } else { - None - } - } -} diff --git a/crates/procinfo/src/windows.rs b/crates/procinfo/src/windows.rs deleted file mode 100644 index bebcd0157a..0000000000 --- a/crates/procinfo/src/windows.rs +++ /dev/null @@ -1,419 +0,0 @@ -#![cfg(windows)] -use super::*; -use ntapi::ntpebteb::PEB; -use ntapi::ntpsapi::{ - NtQueryInformationProcess, ProcessBasicInformation, ProcessWow64Information, - PROCESS_BASIC_INFORMATION, -}; -use ntapi::ntrtl::RTL_USER_PROCESS_PARAMETERS; -use ntapi::ntwow64::RTL_USER_PROCESS_PARAMETERS32; -use std::ffi::OsString; -use std::mem::MaybeUninit; -use std::os::windows::ffi::OsStringExt; -use winapi::shared::minwindef::{DWORD, FILETIME, LPVOID, MAX_PATH}; -use winapi::shared::ntdef::{FALSE, NT_SUCCESS}; -use winapi::um::handleapi::CloseHandle; -use winapi::um::memoryapi::ReadProcessMemory; -use winapi::um::processthreadsapi::{GetCurrentProcessId, GetProcessTimes, OpenProcess}; -use winapi::um::shellapi::CommandLineToArgvW; -use winapi::um::tlhelp32::*; -use winapi::um::winbase::{LocalFree, QueryFullProcessImageNameW}; -use winapi::um::winnt::{HANDLE, PROCESS_QUERY_INFORMATION, PROCESS_VM_READ}; - -/// Manages a Toolhelp32 snapshot handle -struct Snapshot(HANDLE); - -impl Snapshot { - pub fn new() -> Option { - let handle = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) }; - if handle.is_null() { - None - } else { - Some(Self(handle)) - } - } - - pub fn iter(&self) -> ProcIter { - ProcIter { - snapshot: &self, - first: true, - } - } - - pub fn entries() -> Vec { - match Self::new() { - Some(snapshot) => snapshot.iter().collect(), - None => vec![], - } - } -} - -impl Drop for Snapshot { - fn drop(&mut self) { - unsafe { CloseHandle(self.0) }; - } -} - -struct ProcIter<'a> { - snapshot: &'a Snapshot, - first: bool, -} - -impl<'a> Iterator for ProcIter<'a> { - type Item = PROCESSENTRY32W; - - fn next(&mut self) -> Option { - let mut entry: PROCESSENTRY32W = unsafe { std::mem::zeroed() }; - entry.dwSize = std::mem::size_of::() as _; - let res = if self.first { - self.first = false; - unsafe { Process32FirstW(self.snapshot.0, &mut entry) } - } else { - unsafe { Process32NextW(self.snapshot.0, &mut entry) } - }; - if res == 0 { - None - } else { - Some(entry) - } - } -} - -fn wstr_to_path(slice: &[u16]) -> PathBuf { - match slice.iter().position(|&c| c == 0) { - Some(nul) => OsString::from_wide(&slice[..nul]), - None => OsString::from_wide(slice), - } - .into() -} - -fn wstr_to_string(slice: &[u16]) -> String { - wstr_to_path(slice).to_string_lossy().into_owned() -} - -struct ProcParams { - argv: Vec, - cwd: PathBuf, - console: HANDLE, -} - -/// A handle to an opened process -struct ProcHandle { - pid: u32, - proc: HANDLE, -} - -impl ProcHandle { - pub fn new(pid: u32) -> Option { - if pid == unsafe { GetCurrentProcessId() } { - // Avoid the potential for deadlock if we're examining ourselves - log::trace!("ProcHandle::new({}): skip because it is my own pid", pid); - return None; - } - let options = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; - log::trace!("ProcHandle::new({}): OpenProcess", pid); - let handle = unsafe { OpenProcess(options, FALSE as _, pid) }; - log::trace!("ProcHandle::new({}): OpenProcess -> {:?}", pid, handle); - if handle.is_null() { - return None; - } - Some(Self { pid, proc: handle }) - } - - /// Returns the executable image for the process - pub fn executable(&self) -> Option { - let mut buf = [0u16; MAX_PATH + 1]; - let mut len = buf.len() as DWORD; - let res = unsafe { QueryFullProcessImageNameW(self.proc, 0, buf.as_mut_ptr(), &mut len) }; - if res == 0 { - None - } else { - Some(wstr_to_path(&buf)) - } - } - - /// Wrapper around NtQueryInformationProcess that fetches `what` as `T` - fn query_proc(&self, what: u32) -> Option { - let mut data = MaybeUninit::::uninit(); - let res = unsafe { - NtQueryInformationProcess( - self.proc, - what, - data.as_mut_ptr() as _, - std::mem::size_of::() as _, - std::ptr::null_mut(), - ) - }; - if !NT_SUCCESS(res) { - return None; - } - let data = unsafe { data.assume_init() }; - Some(data) - } - - /// Read a `T` from the target process at the specified address - fn read_struct(&self, addr: LPVOID) -> Option { - let mut data = MaybeUninit::::uninit(); - let res = unsafe { - ReadProcessMemory( - self.proc, - addr as _, - data.as_mut_ptr() as _, - std::mem::size_of::() as _, - std::ptr::null_mut(), - ) - }; - if res == 0 { - return None; - } - let data = unsafe { data.assume_init() }; - Some(data) - } - - /// If the process is a 32-bit process running on Win64, return the address - /// of its process parameters. - /// Otherwise, return None to indicate a native win64 process. - fn get_peb32_addr(&self) -> Option { - let peb32_addr: LPVOID = self.query_proc(ProcessWow64Information)?; - if peb32_addr.is_null() { - None - } else { - Some(peb32_addr) - } - } - - /// Returns the cwd and args for the process - pub fn get_params(&self) -> Option { - match self.get_peb32_addr() { - Some(peb32) => self.get_params_32(peb32), - None => self.get_params_64(), - } - } - - fn get_basic_info(&self) -> Option { - self.query_proc(ProcessBasicInformation) - } - - fn get_peb(&self, info: &PROCESS_BASIC_INFORMATION) -> Option { - self.read_struct(info.PebBaseAddress as _) - } - - fn get_proc_params(&self, peb: &PEB) -> Option { - self.read_struct(peb.ProcessParameters as _) - } - - /// Returns the cwd and args for a 64 bit process - fn get_params_64(&self) -> Option { - let info = self.get_basic_info()?; - let peb = self.get_peb(&info)?; - let params = self.get_proc_params(&peb)?; - - let cmdline = self.read_process_wchar( - params.CommandLine.Buffer as _, - params.CommandLine.Length as _, - )?; - let cwd = self.read_process_wchar( - params.CurrentDirectory.DosPath.Buffer as _, - params.CurrentDirectory.DosPath.Length as _, - )?; - - Some(ProcParams { - argv: cmd_line_to_argv(&cmdline), - cwd: wstr_to_path(&cwd), - console: params.ConsoleHandle, - }) - } - - fn get_proc_params_32(&self, peb32: LPVOID) -> Option { - self.read_struct(peb32) - } - - /// Returns the cwd and args for a 32 bit process - fn get_params_32(&self, peb32: LPVOID) -> Option { - let params = self.get_proc_params_32(peb32)?; - - let cmdline = self.read_process_wchar( - params.CommandLine.Buffer as _, - params.CommandLine.Length as _, - )?; - let cwd = self.read_process_wchar( - params.CurrentDirectory.DosPath.Buffer as _, - params.CurrentDirectory.DosPath.Length as _, - )?; - - Some(ProcParams { - argv: cmd_line_to_argv(&cmdline), - cwd: wstr_to_path(&cwd), - console: params.ConsoleHandle as _, - }) - } - - /// Copies a sized WSTR from the address in the process - fn read_process_wchar(&self, ptr: LPVOID, byte_size: usize) -> Option> { - if byte_size > MAX_PATH * 4 { - // Defend against implausibly large paths, just in - // case we're reading the wrong offset into a kernel struct - return None; - } - - let mut buf = vec![0u16; byte_size / 2]; - let mut bytes_read = 0; - - let res = unsafe { - ReadProcessMemory( - self.proc, - ptr as _, - buf.as_mut_ptr() as _, - byte_size, - &mut bytes_read, - ) - }; - if res == 0 { - return None; - } - - // In the unlikely event that we have a short read, - // truncate the buffer to fit. - let wide_chars_read = bytes_read / 2; - buf.resize(wide_chars_read, 0); - - // Ensure that it is NUL terminated - match buf.iter().position(|&c| c == 0) { - Some(n) => { - // Truncate to include existing NUL but no later chars - buf.resize(n + 1, 0); - } - None => { - // Add a NUL - buf.push(0); - } - } - - Some(buf) - } - - /// Retrieves the start time of the process - fn start_time(&self) -> Option { - const fn empty() -> FILETIME { - FILETIME { - dwLowDateTime: 0, - dwHighDateTime: 0, - } - } - - let mut start = empty(); - let mut exit = empty(); - let mut kernel = empty(); - let mut user = empty(); - - let res = - unsafe { GetProcessTimes(self.proc, &mut start, &mut exit, &mut kernel, &mut user) }; - if res == 0 { - return None; - } - - Some((start.dwHighDateTime as u64) << 32 | start.dwLowDateTime as u64) - } -} - -/// Parse a command line string into an argv array -fn cmd_line_to_argv(buf: &[u16]) -> Vec { - let mut argc = 0; - let argvp = unsafe { CommandLineToArgvW(buf.as_ptr(), &mut argc) }; - if argvp.is_null() { - return vec![]; - } - - let argv = unsafe { std::slice::from_raw_parts(argvp, argc as usize) }; - let mut args = vec![]; - for &arg in argv { - let len = unsafe { libc::wcslen(arg) }; - let arg = unsafe { std::slice::from_raw_parts(arg, len) }; - args.push(wstr_to_string(arg)); - } - unsafe { LocalFree(argvp as _) }; - args -} - -impl Drop for ProcHandle { - fn drop(&mut self) { - log::trace!("ProcHandle::drop(pid={} proc={:?})", self.pid, self.proc); - unsafe { CloseHandle(self.proc) }; - } -} - -impl LocalProcessInfo { - pub fn current_working_dir(pid: u32) -> Option { - log::trace!("current_working_dir({})", pid); - let proc = ProcHandle::new(pid)?; - let params = proc.get_params()?; - Some(params.cwd) - } - - pub fn executable_path(pid: u32) -> Option { - log::trace!("executable_path({})", pid); - let proc = ProcHandle::new(pid)?; - proc.executable() - } - - pub fn with_root_pid(pid: u32) -> Option { - log::trace!("LocalProcessInfo::with_root_pid({}), getting snapshot", pid); - let procs = Snapshot::entries(); - log::trace!("Got snapshot"); - - fn build_proc(info: &PROCESSENTRY32W, procs: &[PROCESSENTRY32W]) -> LocalProcessInfo { - let mut children = HashMap::new(); - - for kid in procs { - if kid.th32ParentProcessID == info.th32ProcessID { - children.insert(kid.th32ProcessID, build_proc(kid, procs)); - } - } - - let mut executable = None; - let mut start_time = 0; - let mut cwd = PathBuf::new(); - let mut argv = vec![]; - let mut console = 0; - - if let Some(proc) = ProcHandle::new(info.th32ProcessID) { - if let Some(exe) = proc.executable() { - executable.replace(exe); - } - if let Some(params) = proc.get_params() { - cwd = params.cwd; - argv = params.argv; - console = params.console as _; - } - if let Some(start) = proc.start_time() { - start_time = start; - } - } - - let executable = executable.unwrap_or_else(|| wstr_to_path(&info.szExeFile)); - let name = match executable.file_name() { - Some(name) => name.to_string_lossy().into_owned(), - None => String::new(), - }; - - LocalProcessInfo { - pid: info.th32ProcessID, - ppid: info.th32ParentProcessID, - name, - executable, - cwd, - argv, - start_time, - status: LocalProcessStatus::Run, - children, - console, - } - } - - if let Some(info) = procs.iter().find(|info| info.th32ProcessID == pid) { - Some(build_proc(info, &procs)) - } else { - None - } - } -} diff --git a/crates/terminal/Cargo.toml b/crates/terminal/Cargo.toml index 6c49fb81bd..5910a2897c 100644 --- a/crates/terminal/Cargo.toml +++ b/crates/terminal/Cargo.toml @@ -9,7 +9,7 @@ doctest = false [dependencies] alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "4e1f0c6177975a040b37f942dfb0e723e46a9971" } -procinfo = { path = "../procinfo" } +procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "40a7dbf93542fbe4178c2e4b4bd438126a6432b9", default-features = false } editor = { path = "../editor" } util = { path = "../util" } gpui = { path = "../gpui" } diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index a6c2e6aa9a..639670fc15 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -3,7 +3,7 @@ pub mod modal; pub mod terminal_container_view; pub mod terminal_element; pub mod terminal_view; -// procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "40a7dbf93542fbe4178c2e4b4bd438126a6432b9", default-features = false } + use alacritty_terminal::{ ansi::{ClearMode, Handler}, config::{Config, Program, PtyConfig, Scrolling}, @@ -522,7 +522,6 @@ impl Terminal { AlacTermEvent::Wakeup => { cx.emit(Event::Wakeup); - dbg!("*********"); if self.update_process_info() { cx.emit(Event::TitleChanged) } @@ -1024,49 +1023,5 @@ fn make_search_matches<'a, T>( #[cfg(test)] mod tests { - use libc::c_int; - pub mod terminal_test_context; - - #[test] - pub fn wez_test() { - fn test() -> Option> { - let size = 28; - - //Test data pulled from running the code - let buf = [ - 2, 0, 0, 0, 47, 98, 105, 110, 47, 115, 108, 101, 101, 112, 0, 0, 0, 0, 0, 0, 115, - 108, 101, 101, 112, 0, 53, 0, - ]; - - let mut ptr = &buf[0..size]; - - let argc: c_int = unsafe { std::ptr::read(ptr.as_ptr() as *const c_int) }; - ptr = &ptr[std::mem::size_of::()..]; - - fn consume_cstr(ptr: &mut &[u8]) -> Option { - let nul = ptr.iter().position(|&c| c == 0)?; - let s = String::from_utf8_lossy(&ptr[0..nul]).to_owned().to_string(); - *ptr = ptr.get(nul + 1..)?; - Some(s) - } - - let _exe_path: Option = consume_cstr(&mut ptr)?.into(); - - //Clear out the trailing null pointers - while ptr[0] == 0 { - ptr = ptr.get(1..)?; - } - - let mut args = vec![]; - for _ in 0..argc { - args.push(consume_cstr(&mut ptr)?); - } - Some(args) - } - - assert_eq!(test(), Some(vec!["sleep".to_string(), "5".to_string()])); - } } - -mod wez_proc_info {} diff --git a/crates/terminal/src/terminal_container_view.rs b/crates/terminal/src/terminal_container_view.rs index 6e3d85f5f7..a9d2876e98 100644 --- a/crates/terminal/src/terminal_container_view.rs +++ b/crates/terminal/src/terminal_container_view.rs @@ -246,12 +246,13 @@ impl Item for TerminalContainer { .as_ref() .map(|fpi| { format!( - "{} - {}", + "{} - {} {}", fpi.cwd .file_name() .map(|name| name.to_string_lossy().to_string()) .unwrap_or_default(), fpi.name, + (&fpi.argv[1..]).join(" ") ) }) .unwrap_or_else(|| "Terminal".to_string()),