tav 1.1.0

Terminal anti-virus
Documentation
use std::{collections::HashMap, thread};
use std::path::Path;
use std::time::Duration;
use sysinfo::{
    Process, Signal, System, Users
};

const INTERVAL: u64 = 250;

pub fn handle(watchlist: &Vec<String>, blacklist: &Vec<String>, prohibited: &HashMap<String, Vec<String>>, handles: &mut Vec<thread::JoinHandle<()>>) {
    let l1 = watchlist.clone();
    let p1 = thread::spawn(move || {
        let mut sys = System::new_all();

        loop {
            sys.refresh_all();
            for (_pid, process) in sys.processes() {
                for p in &l1 {
                    if ps_match(&process, p) {
                        ps_log(process, "FOUND");
                    }
                }
            }
            thread::sleep(Duration::from_millis(INTERVAL));
        }
    });

    handles.push(p1);

    let l2 = blacklist.clone();
    let p2 = thread::spawn(move || {
        let mut sys = System::new_all();

        loop {
            sys.refresh_all();
            for (_pid, process) in sys.processes() {
                for p in &l2 {
                    if ps_match(&process, p) {
                        process.kill_with(Signal::Kill);
                        ps_log(process, "KILLED");
                    }
                }
            }
            thread::sleep(Duration::from_millis(INTERVAL));
        }
    });

    handles.push(p2);

    let l3 = prohibited.clone();
    let p3 = thread::spawn(move || {
        let mut sys = System::new_all();
        let users = Users::new_with_refreshed_list();

        loop {
            sys.refresh_all();
            for (_pid, process) in sys.processes() {
                if let Some(uid) = process.effective_user_id() {
                    let user = users.get_user_by_id(uid).unwrap();
                    for (key, value) in l3.clone().into_iter() {
                        if key == user.name() {
                            for p in &value {
                                if ps_match(&process, p) {
                                    process.kill_with(Signal::Kill);
                                    ps_log(process, "KILLED");
                                }
                            }
                        }
                    }
                }
            }
            thread::sleep(Duration::from_millis(INTERVAL));
        }
    });

    handles.push(p3);
}

pub fn ps_log(process: &Process, prefix: &str) {
    let pid = process.pid();
    let users = Users::new_with_refreshed_list();

    if let Some(uid) = process.effective_user_id() {
        let user = users.get_user_by_id(uid).unwrap();
        println!("{prefix}: [{pid}] {} ({}) {}", process.name(), process.cmd().join(" "), user.name());
    } else {
        println!("{prefix}: [{pid}] {} ({})", process.name(), process.cmd().join(" "));
    }
}

pub fn ps_match(process: &Process, blacklisted: &String) -> bool {
    let cmd = process.cmd().join(" ").to_lowercase();
    let exe = process.exe().unwrap_or_else(|| Path::new("")).to_str().unwrap_or_else(|| "").to_lowercase();
    let name = process.name().to_lowercase();
    let search = blacklisted.to_lowercase();

    return cmd.contains(&search) || exe.contains(&search) || name.contains(&search);
}