mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 05:12:40 +03:00
procinfo: reorg a bit; enable cwd probing on windows
Likely breaks the mac and windows builds
This commit is contained in:
parent
e16a27dfb3
commit
1ad4015f9c
@ -331,77 +331,20 @@ impl Pane for LocalPane {
|
||||
.or_else(|| self.divine_current_working_dir())
|
||||
}
|
||||
|
||||
#[cfg(not(any(windows, target_os = "linux", target_os = "macos")))]
|
||||
fn get_foreground_process_name(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn get_foreground_process_name(&self) -> Option<String> {
|
||||
let leader = self.pty.borrow().process_group_leader()?;
|
||||
|
||||
let mut buffer: Vec<u8> = Vec::with_capacity(libc::PROC_PIDPATHINFO_MAXSIZE as _);
|
||||
let x = unsafe {
|
||||
libc::proc_pidpath(
|
||||
leader,
|
||||
buffer.as_mut_ptr() as *mut _,
|
||||
libc::PROC_PIDPATHINFO_MAXSIZE as _,
|
||||
)
|
||||
};
|
||||
if x > 0 {
|
||||
unsafe { buffer.set_len(x as usize) };
|
||||
String::from_utf8(buffer).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_foreground_process_name(&self) -> Option<String> {
|
||||
#[cfg(unix)]
|
||||
if let Some(pid) = self.pty.borrow().process_group_leader() {
|
||||
if let Ok(path) = std::fs::read_link(format!("/proc/{}/exe", pid)) {
|
||||
if let Ok(path) = LocalProcessInfo::executable_path(pid) {
|
||||
return Some(path.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn get_foreground_process_name(&self) -> Option<String> {
|
||||
// Windows doesn't have any job control or session concept,
|
||||
// so we infer that the equivalent to the process group
|
||||
// leader is the most recently spawned program running
|
||||
// in the console
|
||||
if let Some(root_proc) = self.divine_process_list(false) {
|
||||
let mut youngest = &root_proc;
|
||||
|
||||
fn find_youngest<'a>(proc: &'a LocalProcessInfo, youngest: &mut &'a LocalProcessInfo) {
|
||||
if proc.start_time >= youngest.start_time {
|
||||
// start_time has only 1 second granularity, and spawning
|
||||
// a child process will typically spawn a console host at
|
||||
// the same time.
|
||||
// We might traverse one snapshot of the tree differently
|
||||
// from another due to random seeds in the hash table,
|
||||
// so we do a little bit of targeted workaround here
|
||||
// to suppress the console hosts from candidate child
|
||||
// processes.
|
||||
let ignore = proc.name == "OpenConsole.exe" || proc.name == "conhost.exe";
|
||||
if !ignore {
|
||||
*youngest = proc;
|
||||
}
|
||||
}
|
||||
|
||||
for child in proc.children.values() {
|
||||
find_youngest(child, youngest);
|
||||
}
|
||||
}
|
||||
|
||||
find_youngest(&root_proc, &mut youngest);
|
||||
|
||||
Some(youngest.executable.to_string_lossy().to_string())
|
||||
} else {
|
||||
None
|
||||
#[cfg(windows)]
|
||||
if let Some(fg) = self.divine_foreground_process() {
|
||||
return Some(fg.executable.to_string_lossy().to_string());
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn can_close_without_prompting(&self, _reason: CloseReason) -> bool {
|
||||
@ -783,50 +726,17 @@ impl LocalPane {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn divine_current_working_dir_macos(&self) -> Option<Url> {
|
||||
fn divine_current_working_dir(&self) -> Option<Url> {
|
||||
#[cfg(unix)]
|
||||
if let Some(pid) = self.pty.borrow().process_group_leader() {
|
||||
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,
|
||||
libc::PROC_PIDVNODEPATHINFO,
|
||||
0,
|
||||
&mut pathinfo as *mut _ as *mut _,
|
||||
size,
|
||||
)
|
||||
};
|
||||
if ret == size {
|
||||
let path =
|
||||
unsafe { std::ffi::CStr::from_ptr(pathinfo.pvi_cdir.vip_path.as_ptr() as _) };
|
||||
if let Ok(s) = path.to_str() {
|
||||
return Url::parse(&format!("file://localhost{}", s)).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn divine_current_working_dir_linux(&self) -> Option<Url> {
|
||||
if let Some(pid) = self.pty.borrow().process_group_leader() {
|
||||
if let Ok(path) = std::fs::read_link(format!("/proc/{}/cwd", pid)) {
|
||||
if let Some(path) = LocalProcessInfo::current_working_dir(pid) {
|
||||
return Url::parse(&format!("file://localhost{}", path.display())).ok();
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn divine_current_working_dir(&self) -> Option<Url> {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
return self.divine_current_working_dir_linux();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
return self.divine_current_working_dir_macos();
|
||||
#[cfg(windows)]
|
||||
if let Some(fg) = self.divine_foreground_process() {
|
||||
return Url::parse(&format!("file://localhost{}", fg.cwd.display())).ok();
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
@ -839,6 +749,43 @@ impl LocalPane {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn divine_foreground_process(&self) -> Option<LocalProcessInfo> {
|
||||
// Windows doesn't have any job control or session concept,
|
||||
// so we infer that the equivalent to the process group
|
||||
// leader is the most recently spawned program running
|
||||
// in the console
|
||||
if let Some(root_proc) = self.divine_process_list(false) {
|
||||
let mut youngest = &root_proc;
|
||||
|
||||
fn find_youngest<'a>(proc: &'a LocalProcessInfo, youngest: &mut &'a LocalProcessInfo) {
|
||||
if proc.start_time >= youngest.start_time {
|
||||
// start_time has only 1 second granularity, and spawning
|
||||
// a child process will typically spawn a console host at
|
||||
// the same time.
|
||||
// We might traverse one snapshot of the tree differently
|
||||
// from another due to random seeds in the hash table,
|
||||
// so we do a little bit of targeted workaround here
|
||||
// to suppress the console hosts from candidate child
|
||||
// processes.
|
||||
let ignore = proc.name == "OpenConsole.exe" || proc.name == "conhost.exe";
|
||||
if !ignore {
|
||||
*youngest = proc;
|
||||
}
|
||||
}
|
||||
|
||||
for child in proc.children.values() {
|
||||
find_youngest(child, youngest);
|
||||
}
|
||||
}
|
||||
|
||||
find_youngest(&root_proc, &mut youngest);
|
||||
|
||||
Some(youngest.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for LocalPane {
|
||||
|
@ -57,4 +57,9 @@ impl LocalProcessInfo {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,14 @@ impl From<&str> for LocalProcessStatus {
|
||||
}
|
||||
|
||||
impl LocalProcessInfo {
|
||||
pub fn current_working_dir(pid: u32) -> Option<PathBuf> {
|
||||
std::fs::read_link(format!("/proc/{}/cwd", pid)).ok()
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -73,7 +81,7 @@ impl LocalProcessInfo {
|
||||
std::fs::read_link(format!("/proc/{}/exe", pid)).unwrap_or_else(|_| PathBuf::new())
|
||||
}
|
||||
fn cwd_for_pid(pid: pid_t) -> PathBuf {
|
||||
std::fs::read_link(format!("/proc/{}/cwd", pid)).unwrap_or_else(|_| PathBuf::new())
|
||||
current_working_dir(pid).unwrap_or_else(|| PathBuf::new())
|
||||
}
|
||||
|
||||
fn parse_cmdline(pid: pid_t) -> Vec<String> {
|
||||
|
@ -15,6 +15,44 @@ impl From<u32> for LocalProcessStatus {
|
||||
}
|
||||
|
||||
impl LocalProcessInfo {
|
||||
pub fn current_working_dir(pid: libc::pid_t) -> 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,
|
||||
libc::PROC_PIDVNODEPATHINFO,
|
||||
0,
|
||||
&mut pathinfo as *mut _ as *mut _,
|
||||
size,
|
||||
)
|
||||
};
|
||||
if ret != size {
|
||||
return None;
|
||||
}
|
||||
|
||||
let nul = pathinfo.pvi_cdir.vip_path.iter().position(|&c| c == 0)?;
|
||||
|
||||
Some(OsStr::from_bytes(&pathinfo.pvi_cdir.vip_path[0..nul]).into())
|
||||
}
|
||||
|
||||
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> {
|
||||
|
@ -315,6 +315,17 @@ impl Drop for ProcHandle {
|
||||
}
|
||||
|
||||
impl LocalProcessInfo {
|
||||
pub fn current_working_dir(pid: u32) -> Option<PathBuf> {
|
||||
let proc = ProcHandle::new(pid)?;
|
||||
let params = proc.get_params()?;
|
||||
Some(params.cwd)
|
||||
}
|
||||
|
||||
pub fn executable_path(pid: u32) -> Option<PathBuf> {
|
||||
let proc = ProcHandle::new(pid)?;
|
||||
proc.executable()
|
||||
}
|
||||
|
||||
pub fn with_root_pid(pid: u32) -> Option<Self> {
|
||||
let snapshot = Snapshot::new()?;
|
||||
let procs: Vec<_> = snapshot.iter().collect();
|
||||
|
Loading…
Reference in New Issue
Block a user