Last active
December 10, 2022 20:26
-
-
Save sharkdp/b1273e71c44f14625ffddae1235c7df6 to your computer and use it in GitHub Desktop.
A demo program to find processes at the other end of a pipe
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// For background, see: https://unix.stackexchange.com/questions/405485/name-of-the-process-on-the-other-end-of-a-unix-pipe | |
use std::ffi::{OsStr, OsString}; | |
use std::fs::{self, File}; | |
use std::io::prelude::*; | |
use std::io::Result; | |
use std::os::unix::ffi::OsStrExt; | |
use std::path::Path; | |
#[derive(Debug, Clone, Copy)] | |
enum PipeType { | |
Stdin, | |
Stdout, | |
} | |
impl PipeType { | |
fn opposite(self) -> Self { | |
match self { | |
PipeType::Stdin => PipeType::Stdout, | |
PipeType::Stdout => PipeType::Stdin, | |
} | |
} | |
fn handle(self) -> &'static str { | |
match self { | |
PipeType::Stdin => &"0", | |
PipeType::Stdout => &"1", | |
} | |
} | |
} | |
fn get_process_on(pipe_type: PipeType) -> Result<Option<Vec<OsString>>> { | |
let pipe_node_id = fs::read_link(Path::new("/proc/self/fd").join(pipe_type.handle()))?; | |
if !pipe_node_id.as_os_str().as_bytes().starts_with(b"pipe:") { | |
return Ok(None); | |
} | |
// Find the process on the other end of the pipe | |
for entry in glob::glob("/proc/[0-9]*").expect("glob error") { | |
if let Ok(path) = entry { | |
let handle_path = path.join("fd").join(pipe_type.opposite().handle()); | |
let handle_path_resolved = fs::read_link(&handle_path); | |
if handle_path_resolved | |
.map(|node_id| node_id == pipe_node_id) | |
.unwrap_or(false) | |
{ | |
// We found the other process. Get its command line string: | |
let mut f = File::open(path.join("cmdline"))?; | |
let mut buffer = vec![]; | |
f.read_to_end(&mut buffer)?; | |
let parts: Vec<_> = buffer | |
.split(|b| *b == 0) | |
.map(|part: &[u8]| OsStr::from_bytes(part).to_os_string()) | |
.filter(|part| !part.is_empty()) | |
.collect(); | |
return Ok(Some(parts)); | |
} | |
} | |
} | |
Ok(None) | |
} | |
fn format_command(parts: &Vec<OsString>) -> String { | |
parts | |
.iter() | |
.map(|s| s.to_string_lossy()) | |
.collect::<Vec<_>>() | |
.join(" ") | |
} | |
fn run() -> Result<()> { | |
if let Some(cmd_stdin) = get_process_on(PipeType::Stdin)? { | |
eprint!("{} | ", format_command(&cmd_stdin)); | |
} | |
eprint!("magic"); | |
if let Some(cmd_stdout) = get_process_on(PipeType::Stdout)? { | |
eprint!(" | {}", format_command(&cmd_stdout)); | |
} | |
eprintln!(); | |
Ok(()) | |
} | |
fn main() { | |
let res = run(); | |
if let Err(e) = res { | |
eprintln!("{}", e); | |
std::process::exit(1); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment