Skip to content

Instantly share code, notes, and snippets.

@sharkdp
Last active December 10, 2022 20:26
Show Gist options
  • Save sharkdp/b1273e71c44f14625ffddae1235c7df6 to your computer and use it in GitHub Desktop.
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
// 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