ptools 0.2.7

Utilities for inspecting Linux processes
use roff::{bold, roman, Roff};
use std::fs;
use std::path::Path;

fn render_man_page(
    name: &str,
    about: &str,
    description: &str,
    synopsis: &str,
    options: &[(&str, &str)],
    out_dir: &Path,
) {
    let version = env!("CARGO_PKG_VERSION");
    let upper_name = name.to_uppercase();
    let date_version = format!("{name} {version}");
    let mut roff = Roff::default();
    roff.control("TH", [upper_name.as_str(), "1", date_version.as_str()]);
    roff.control("SH", ["NAME"]);
    roff.text([roman(format!("{name} - {about}"))]);
    roff.control("SH", ["SYNOPSIS"]);
    roff.text([bold(name), roman(format!(" {synopsis}"))]);
    roff.control("SH", ["DESCRIPTION"]);
    roff.text([roman(description)]);
    if !options.is_empty() {
        roff.control("SH", ["OPTIONS"]);
        for (flag, help) in options {
            roff.control("TP", []);
            roff.text([bold(*flag)]);
            roff.text([roman(*help)]);
        }
    }
    fs::write(out_dir.join(format!("{name}.1")), roff.to_roff()).unwrap();
}

fn main() {
    let out_dir = Path::new("target/man");
    fs::create_dir_all(out_dir).unwrap();

    render_man_page(
        "pargs",
        "Print process arguments",
        "Examine a target process and print arguments, environment variables and values, \
         or the process auxiliary vector.",
        "[-l] [-a|--args] [-e|--env] [-x|--auxv] PID...",
        &[
            (
                "-l",
                "Display the arguments as a single command line, suitable for \
                 interpretation by /bin/sh.",
            ),
            (
                "-a, --args",
                "Print process arguments as contained in /proc/pid/cmdline (default).",
            ),
            (
                "-e, --env",
                "Print process environment variables and values as contained in \
                 /proc/pid/environ.",
            ),
            (
                "-x, --auxv",
                "Print the process auxiliary vector as contained in /proc/pid/auxv.",
            ),
        ],
        out_dir,
    );

    render_man_page(
        "penv",
        "Print process environment variables",
        "Examine a target process and print environment variables and values.",
        "PID...",
        &[],
        out_dir,
    );

    render_man_page(
        "pfiles",
        "Print information for all open files in each process",
        "Print fstat(2) and fcntl(2) information for all open files in each process. \
         For network endpoints, provide local address information and peer address \
         information when connected. For sockets, provide the socket type, socket options, \
         and send and receive buffer sizes. Also print a path to the file when that \
         information is available from /proc/pid/fd. Do not assume this is the same name \
         used to open the file. See proc(5) for more information.",
        "[-n] PID...",
        &[(
            "-n",
            "Set non-verbose mode. Do not display verbose information for each file \
             descriptor. Instead, limit output to the information that the process would \
             retrieve by applying fstat(2) to each of its file descriptors.",
        )],
        out_dir,
    );

    render_man_page(
        "psig",
        "Print process signal actions",
        "Print the signal actions and handlers of each process.",
        "PID...",
        &[],
        out_dir,
    );

    render_man_page(
        "pflags",
        "Print process status flags",
        "Print the process status flags, the pending and held signals, and other status \
         information for each process or specified threads in each process. If a thread \
         has a non-empty signal mask, it will be printed.",
        "PID[/TID]...",
        &[],
        out_dir,
    );

    render_man_page(
        "pstop",
        "Stop processes with SIGSTOP",
        "Stop each process by sending SIGSTOP.",
        "PID...",
        &[],
        out_dir,
    );

    render_man_page(
        "prun",
        "Set stopped processes running with SIGCONT",
        "Set running each process by sending SIGCONT (the inverse of pstop).",
        "PID...",
        &[],
        out_dir,
    );

    render_man_page(
        "pwait",
        "Wait for processes to terminate",
        "Wait for all of the specified processes to terminate.",
        "[-v] PID...",
        &[("-v", "Verbose. Reports terminations to standard output.")],
        out_dir,
    );

    render_man_page(
        "ptree",
        "Print process trees",
        "Print process trees containing the specified pids or users, with child processes \
         indented from their respective parent processes. Treat an argument of all digits \
         as a process ID (PID); otherwise, treat it as a user login name. Default to all \
         processes.",
        "[-a|--all] [pid|user]...",
        &[(
            "-a, --all",
            "All. Print all processes, including children of process ID 0.",
        )],
        out_dir,
    );

    println!("cargo:rerun-if-changed=build.rs");
}