// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>

/**
 * get_process_cgroup - Get the cgroup path of a process
 * @pid: Process ID
 * @buffer: Pre-allocated buffer to store cgroup path
 * @buffer_size: Size of the buffer
 *
 * Returns: 0 on success, -1 on failure
 * Note: The caller must provide a buffer to avoid memory allocation
 */
int get_process_cgroup(pid_t pid, char *buffer, size_t buffer_size)
{
    char path[64];
    FILE *fp;
    char *line = NULL;
    size_t len = 0;
    ssize_t read;
    int ret = -1;

    if (!buffer || buffer_size == 0) {
        return -1;
    }

    buffer[0] = '\0';

    snprintf(path, sizeof(path), "/proc/%d/cgroup", pid);
    fp = fopen(path, "r");
    if (!fp) {
        // log_warning("Failed to open %s: %s", path, strerror(errno));
        return -1;
    }

    // Read the first line (or find the unified cgroup v2 line)
    // Format: hierarchy-ID:controller-list:cgroup-path
    // For cgroup v2: 0::/path
    while ((read = getline(&line, &len, fp)) != -1) {
        // Look for cgroup v2 (starts with "0::")
        if (strncmp(line, "0::", 3) == 0) {
            // Skip "0::" prefix
            char *cgroup_path = line + 3;
            // Remove trailing newline
            char *newline = strchr(cgroup_path, '\n');
            if (newline) {
                *newline = '\0';
            }
            snprintf(buffer, buffer_size, "%s", cgroup_path);
            ret = 0;
            break;
        }
        // Fallback: use the first line if no cgroup v2 found
        if (ret != 0) {
            char *cgroup_path = strrchr(line, ':');
            if (cgroup_path) {
                cgroup_path++; // Skip the ':'
                // Remove trailing newline
                char *newline = strchr(cgroup_path, '\n');
                if (newline) {
                    *newline = '\0';
                }
                snprintf(buffer, buffer_size, "%s", cgroup_path);
                ret = 0;
            }
        }
    }

    free(line);
    fclose(fp);
    return ret;
}

/**
 * get_process_cmdline - Get the command line of a process
 * @pid: Process ID
 * @buffer: Pre-allocated buffer to store cmdline
 * @buffer_size: Size of the buffer
 * @comm_fallback: Fallback comm string if cmdline is unavailable
 *
 * Returns: 0 on success, -1 on failure
 * Note: Converts null bytes to spaces in cmdline
 */
int get_process_cmdline(pid_t pid, char *buffer, size_t buffer_size, const char *comm_fallback)
{
    char path[64];
    FILE *fp;
    size_t len;

    if (!buffer || buffer_size == 0) {
        return -1;
    }

    buffer[0] = '\0';

    snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
    fp = fopen(path, "r");
    if (!fp) {
        // Fallback to comm if cmdline file cannot be opened
        if (comm_fallback && comm_fallback[0]) {
            snprintf(buffer, buffer_size, "%s", comm_fallback);
            return 0;
        }
        return -1;
    }

    len = fread(buffer, 1, buffer_size - 1, fp);
    fclose(fp);

    if (len > 0) {
        buffer[len] = '\0';
        // Convert null bytes to spaces
        for (size_t i = 0; i < len - 1; i++) {
            if (buffer[i] == '\0') {
                buffer[i] = ' ';
            }
        }
        return 0;
    }

    // Fallback to comm if cmdline is empty
    if (comm_fallback && comm_fallback[0]) {
        snprintf(buffer, buffer_size, "%s", comm_fallback);
        return 0;
    }

    return -1;
}
