Prv8 Shell
Server : Apache
System : Linux ecngx264.inmotionhosting.com 4.18.0-553.77.1.lve.el8.x86_64 #1 SMP Wed Oct 8 14:21:00 UTC 2025 x86_64
User : lonias5 ( 3576)
PHP Version : 7.3.33
Disable Function : NONE
Directory :  /proc/self/root/proc/thread-self/root/opt/sharedrads/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : //proc/self/root/proc/thread-self/root/opt/sharedrads/check_pacct
#!/usr/lib/rads/venv/bin/python3
import argparse
import re
import subprocess
from collections import defaultdict
from datetime import datetime, timedelta

from prettytable import PrettyTable

from rads import is_cpuser, get_plan


def parse_args():
    parser = argparse.ArgumentParser(
        description="Process pacct files and total CPU time for cPanel users."
    )
    parser.add_argument(
        "--days",
        type=int,
        default=10,
        help="Number of pacct files to process (default: 10)",
    )
    parser.add_argument(
        "-l",
        "--limit-users",
        type=int,
        default=5,
        help="Number users to display (default: 5)",
    )
    parser.add_argument(
        "--date",
        type=str,
        default=datetime.today().strftime("%Y-%m-%d"),
        help="Start date in format YYYY-MM-DD (default: today)",
    )
    return parser.parse_args()


def get_pacct_files(start_date: str, days: int):
    """
    Generate a list of process accounting (pacct) file paths
    for a given number of days.

    Args:
        start_date (str): The start date in 'YYYY-MM-DD' format.
        days (int): The number of days of pacct files to retrieve.

    Returns:
        list[str]: A list of file paths to the compressed pacct
                   logs in `/var/account/`, named in the format
                   `pacct-YYYYMMDD.gz`.

    Raises:
        ValueError: If `start_date` is not in the correct 'YYYY-MM-DD' format.

    Notes:
        - If `start_date` is today, the function returns files from
          the previous `days` days.
        - Otherwise, it returns files counting backward from the given
          `start_date`.
    """
    try:
        start = datetime.strptime(start_date, "%Y-%m-%d")
    except ValueError as exc:
        raise ValueError("Date must be in YYYY-MM-DD format.") from exc

    today = datetime.today().date()
    start_date_obj = start.date()
    files = []

    if start_date_obj == today:
        for i in range(1, days + 1):
            day = today - timedelta(days=i)
            files.append(f"/var/account/pacct-{day.strftime('%Y%m%d')}.gz")
    else:
        for i in range(days):
            day = start_date_obj - timedelta(days=i)
            files.append(f"/var/account/pacct-{day.strftime('%Y%m%d')}.gz")

    return files


def process_pacct_file(file_path):
    """
    Run 'zcat' on a compressed pacct file and pipe the output to 'sa -cmi -'.
    Returns the output lines from the 'sa' command as a list of strings.
    """
    try:
        with subprocess.Popen(
            ["zcat", file_path], stdout=subprocess.PIPE
        ) as zcat_proc:
            with subprocess.Popen(
                ["sa", "-cmi", "-"],
                stdin=zcat_proc.stdout,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True,
            ) as sa_proc:
                zcat_proc.stdout.close()
                stdout, stderr = sa_proc.communicate()

                if sa_proc.returncode != 0:
                    print("Error running sa:", stderr)
                    return []

        return stdout.splitlines()

    except Exception as e:
        print(f"Failed to process {file_path}: {str(e)}")
        return []


def main():
    args = parse_args()

    pacct_files = get_pacct_files(args.date, args.days)
    sa_cp_data = defaultdict(float)
    sa_proc_data = defaultdict(int)
    sa_top_user = defaultdict(int)

    for file_path in pacct_files:
        pacct_data = process_pacct_file(file_path)
        try:
            i = 1
            for line in pacct_data:
                columns = re.split(r"\s+", line.strip())
                if is_cpuser(columns[0]):
                    try:
                        username = columns[0]
                        num_proc = int(columns[1])
                        cpu_time = float(columns[5].replace("cp", ""))
                        sa_cp_data[username] += cpu_time
                        sa_proc_data[username] += num_proc
                        if i <= args.limit_users:
                            sa_top_user[username] += 1
                        i += 1
                    except ValueError:
                        continue
        except Exception as e:
            print(f"Failed to process {file_path}: {str(e)}")

    top_users = sorted(sa_cp_data.items(), key=lambda x: x[1], reverse=True)

    table = PrettyTable()
    table.field_names = [
        "Username",
        "Total CPU",
        "Average CPU/day",
        "Total Procs",
        "Average Procs/day",
        f"Days in top {args.limit_users}",
        "Plan",
    ]

    num_days = len(pacct_files)
    for (
        username,
        total_cpu_time,
    ) in top_users[: args.limit_users]:
        table.add_row(
            [
                username,
                f"{total_cpu_time:.2f}cp",
                f"{(total_cpu_time / num_days):.2f}cp",
                f"{sa_proc_data[username]}",
                f"{(sa_proc_data[username] / num_days):.2f}",
                f"{sa_top_user[username]}/{num_days}",
                get_plan(username),
            ]
        )
    print(table)


if __name__ == "__main__":
    main()

@StableExploit - 2025