Detailed changes
@@ -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",
@@ -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",
-]}
-
@@ -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<String>,
- /// 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<u32, LocalProcessInfo>,
-}
-#[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<String> {
- let mut names = HashSet::new();
-
- fn flatten(item: &LocalProcessInfo, names: &mut HashSet<String>) {
- 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<Self> {
- None
- }
-
- #[cfg(not(any(target_os = "macos", target_os = "linux", windows)))]
- pub fn current_working_dir(_pid: u32) -> Option<PathBuf> {
- None
- }
-
- #[cfg(not(any(target_os = "macos", target_os = "linux", windows)))]
- pub fn executable_path(_pid: u32) -> Option<PathBuf> {
- None
- }
-}
@@ -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<PathBuf> {
- std::fs::read_link(format!("/proc/{}/cwd", pid)).ok()
- }
-
- pub fn executable_path(pid: u32) -> Option<PathBuf> {
- std::fs::read_link(format!("/proc/{}/exe", pid)).ok()
- }
-
- pub fn with_root_pid(pid: u32) -> Option<Self> {
- use libc::pid_t;
-
- let pid = pid as pid_t;
-
- fn all_pids() -> Vec<pid_t> {
- 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::<pid_t>() {
- 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<LinuxStat> {
- 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::<Vec<_>>();
-
- 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<String> {
- 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
- }
- }
-}
@@ -1,231 +0,0 @@
-#![cfg(target_os = "macos")]
-use super::*;
-use std::ffi::{OsStr, OsString};
-use std::os::unix::ffi::{OsStrExt, OsStringExt};
-
-impl From<u32> 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<PathBuf> {
- 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<PathBuf> {
- let mut buffer: Vec<u8> = 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<Self> {
- /// Enumerate all current process identifiers
- fn all_pids() -> Vec<libc::pid_t> {
- 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<libc::pid_t> = 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::<libc::pid_t>()) 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<libc::proc_bsdinfo> {
- let mut info: libc::proc_bsdinfo = unsafe { std::mem::zeroed() };
- let wanted_size = std::mem::size_of::<libc::proc_bsdinfo>() 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<String>)> {
- use libc::c_int;
- let mut size = 64 * 1024;
- let mut buf: Vec<u8> = 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::<c_int>() * 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::<c_int>()..];
-
- fn consume_cstr(ptr: &mut &[u8]) -> Option<String> {
- 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
- }
- }
-}
@@ -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<Self> {
- 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<PROCESSENTRY32W> {
- 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<Self::Item> {
- let mut entry: PROCESSENTRY32W = unsafe { std::mem::zeroed() };
- entry.dwSize = std::mem::size_of::<PROCESSENTRY32W>() 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<String>,
- cwd: PathBuf,
- console: HANDLE,
-}
-
-/// A handle to an opened process
-struct ProcHandle {
- pid: u32,
- proc: HANDLE,
-}
-
-impl ProcHandle {
- pub fn new(pid: u32) -> Option<Self> {
- 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<PathBuf> {
- 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<T>(&self, what: u32) -> Option<T> {
- let mut data = MaybeUninit::<T>::uninit();
- let res = unsafe {
- NtQueryInformationProcess(
- self.proc,
- what,
- data.as_mut_ptr() as _,
- std::mem::size_of::<T>() 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<T>(&self, addr: LPVOID) -> Option<T> {
- let mut data = MaybeUninit::<T>::uninit();
- let res = unsafe {
- ReadProcessMemory(
- self.proc,
- addr as _,
- data.as_mut_ptr() as _,
- std::mem::size_of::<T>() 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<LPVOID> {
- 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<ProcParams> {
- match self.get_peb32_addr() {
- Some(peb32) => self.get_params_32(peb32),
- None => self.get_params_64(),
- }
- }
-
- fn get_basic_info(&self) -> Option<PROCESS_BASIC_INFORMATION> {
- self.query_proc(ProcessBasicInformation)
- }
-
- fn get_peb(&self, info: &PROCESS_BASIC_INFORMATION) -> Option<PEB> {
- self.read_struct(info.PebBaseAddress as _)
- }
-
- fn get_proc_params(&self, peb: &PEB) -> Option<RTL_USER_PROCESS_PARAMETERS> {
- self.read_struct(peb.ProcessParameters as _)
- }
-
- /// Returns the cwd and args for a 64 bit process
- fn get_params_64(&self) -> Option<ProcParams> {
- 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<RTL_USER_PROCESS_PARAMETERS32> {
- self.read_struct(peb32)
- }
-
- /// Returns the cwd and args for a 32 bit process
- fn get_params_32(&self, peb32: LPVOID) -> Option<ProcParams> {
- 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<Vec<u16>> {
- 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<u64> {
- 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<String> {
- 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<PathBuf> {
- 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<PathBuf> {
- log::trace!("executable_path({})", pid);
- let proc = ProcHandle::new(pid)?;
- proc.executable()
- }
-
- pub fn with_root_pid(pid: u32) -> Option<Self> {
- 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
- }
- }
-}
@@ -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" }
@@ -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<Vec<String>> {
- 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::<c_int>()..];
-
- fn consume_cstr(ptr: &mut &[u8]) -> Option<String> {
- 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<String> = 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 {}
@@ -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()),