← Back to context

Comment by da-x

18 days ago

Alternative, you can check whether there are duplicates under $PATH resolutions - binaries that can come from more than one place in $PATH.

    #!/usr/bin/env -S cargo eval --
    // cargo-deps: derive-error="0", is_executable="0"
    // vi: ft=rust

    use derive_error::Error;
    use is_executable::IsExecutable;
    use std::collections::{BTreeMap, HashSet, btree_map};
    use std::os::unix::fs::MetadataExt;
    use std::path::{Path, PathBuf};

    #[derive(Debug, Error)]
    pub enum Error {
        VarEnv(std::env::VarError),
        Io(std::io::Error),
    }

    fn main() -> Result<(), Error> {
        let mut paths_seen = HashSet::new();
        let mut path_fileid_seen = HashSet::new();
        let mut exes_seen = BTreeMap::new();

        for path in std::env::var("PATH")?.split(":") {
            let path = PathBuf::from(path);
            if !path.is_dir() {
                continue;
            }
            if !path_fileid_seen.insert(path.metadata()?.ino()) {
                continue;
            }
            if paths_seen.insert(path.clone()) {
                match std::fs::read_dir(&path) {
                    Err(_) => {
                        eprintln!("error listing {:?}", path);
                    }
                    Ok(readdir) => {
                        for entry in readdir {
                            let entry = entry?;
                            if entry.path().is_executable() {
                                let mut item = match exes_seen.entry(
                                    String::from(entry.path().file_name()
                                        .unwrap().to_string_lossy().as_ref()))
                                {
                                    btree_map::Entry::Vacant(v) => v.insert(vec![]),
                                    btree_map::Entry::Occupied(o) => o.into_mut(),
                                };
                                item.push(path.clone());
                            }
                        }
                    }
                }
            }
        }

        for (exe, paths) in exes_seen.into_iter() {
            if paths.len() == 2 {
                let mut strs = vec![];
                for path in paths.iter() {
                    strs.push(path.to_str().unwrap());
                }
                if strs.as_slice() == ["/usr/bin", "/usr/sbin"] {
                    continue;
                }
            }
            if paths.len() > 1 {
                println!("{}: ", exe);
                for path in paths {
                    println!("    {}", path.to_str().unwrap());
                }
                println!("");
            }
        }

        Ok(())
    }