/*
 * libkysdk-system's Library
 *
 * Copyright (C) 2023-2025, KylinSoft Co., Ltd.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this library.  If not, see <https://www.gnu.org/licenses/>.
 *
 * Authors: ZhiMin Shao <shaozhimin@kylinos.cn>
 *
 */

#include "libkyprocess.h"
#include <cstring-extension.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <linux/param.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <locale.h>
#include <sys/stat.h>
#include <libkylog.h>
#include <errno.h>
#include <limits.h>
#include <libgen.h>
#include <pwd.h>
#include <sys/wait.h>

#define PRG_SOCKET_PFX "socket:["
#define PRG_SOCKET_PFXl (strlen(PRG_SOCKET_PFX))
#define PRG_SOCKET_PFX2 "[0000]:"
#define PRG_SOCKET_PFX2l (strlen(PRG_SOCKET_PFX2))

#ifndef STRNLEN_MAX
#define STRNLEN_MAX 1024 * 1024 * 1024
#endif

#define LINE_MAX 4096

#define STAT_FILE "/proc/stat"
#define COLWID 240
#define UPTIME_FILE "/proc/uptime"
#define MEMINFO "/proc/meminfo"
#define MAX_PF_NAME 1024
#define PROC_DIR "/proc"
#define MAX_PROC_NUM 1024
#define PROC_NUM 1024 * 5
#define BUF_SIZE 1024
static int uptime_fd = -1;
static int stat_fd = -1;
#define LC_NUMERIC __LC_NUMERIC
#define __LC_NUMERIC 1
static char buf[8192];
#define O_RDONLY 00
#define BAD_OPEN_MESSAGE                                           \
    "Error: /proc must be mounted\n"                               \
    "  To mount /proc at boot you need an /etc/fstab line like:\n" \
    "      proc   /proc   proc    defaults\n"                      \
    "  In the meantime, run \"mount proc /proc -t proc\"\n"

#define FILE_TO_BUF(filename, fd)                                           \
    do                                                                      \
    {                                                                       \
        static int local_n;                                                 \
        if (fd == -1 && (fd = open(filename, O_RDONLY)) == -1)              \
        {                                                                   \
            klog_err(BAD_OPEN_MESSAGE);                                     \
            fflush(NULL);                                                   \
            _exit(102);                                                     \
        }                                                                   \
        lseek(fd, 0L, SEEK_SET);                                            \
        if ((local_n = read(fd, buf, sizeof buf - 1)) < 0)                  \
        {                                                                   \
            klog_err("Failed to read %s: %s\n", filename, strerror(errno)); \
            fflush(NULL);                                                   \
            _exit(103);                                                     \
        }                                                                   \
        buf[local_n] = '\0';                                                \
    } while (0)

#define SET_IF_DESIRED(x, y) \
    do                       \
    {                        \
        if (x)               \
            *(x) = (y);      \
    } while (0)

/**
 * 命令输出回调函数类型
 * @param data 读取到的数据块
 * @param size 数据块大小
 * @param user_data 用户自定义数据指针
 * @return 0 继续读取，非 0 停止读取
 */
typedef int (*execve_output_callback_t)(const char *data, size_t size, void *user_data);

struct pstat
{
    long unsigned int utime_ticks;
    long unsigned int stime_ticks;
    long unsigned int cpu_total_time;
};

/* 进程信息 */
typedef struct process_info
{
    long proc_pid;           // 进程id
    char proc_name[128];     // 进程名
    char proc_command[1024]; // 进程启动的命令行,包含启动参数
    char proc_uid[128];      // 进程所属用户　用户uid
    char start_time[128];    // 进程启动的时间 (char * ctime(time_t time) 函数返回值Tue Jul 28 08:50:26 2020)
    long utime;              // 进程cpu使用时间,单位s
    double proc_cpu;         // 进程cpu使用率 %
    double proc_mem;         // 进程mem使用量 %
    char proc_state[20];     // 进程状态
    char proc_time[50];      // 进程运行时间
    char proc_port[20];      // 进程端口号

} process_info;

#define PROCESS_ITEM 14
#define PROC_COMD_NUM 11520
#define PATH_MAX_PROC 4096
#define FREE(ptr)      \
    {                  \
        if (ptr)       \
            free(ptr); \
        ptr = NULL;    \
    }

static unsigned long lookup_num(char *buffer, const char *key, unsigned long *res)
{
    if (strstartswith(buffer, key) == 0)
    {
        char *val = buffer;
        val += strnlen(key, STRNLEN_MAX) + 1;
        *res = atol(strskipblank(val));
        return 1;
    }
    return 0;
}

static int lookup(char *line, char *pattern, char **value)
{
    char *p, *v;
    int len = strnlen(pattern, STRNLEN_MAX);

    /* pattern */
    if (strncmp(line, pattern, len))
        return 0;

    /* white spaces */
    for (p = line + len; isspace(*p); p++)
        ;

    /* separator */
    if (*p != ':')
        return 0;

    /* white spaces */
    for (++p; isspace(*p); p++)
        ;

    /* value */
    if (!*p)
        return 0;
    v = p;

    /* end of value */
    len = strnlen(line, STRNLEN_MAX) - 1;
    for (p = line + len; isspace(*(p - 1)); p--)
        ;
    *p = '\0';

    *value = strdup(v);
    return 1;
}

static int isnumber(char *c)
{
    char *i = c;

    while (*i != '\0')
    {
        if (!isdigit(*i))
            return 0;
        i++;
    }
    return 1;
}

// static size_t strlcpy(char *dst, const char *src, size_t siz)
// {
//     char *d = dst;
//     const char *s = src;
//     size_t n = siz;

//     /* Copy as many bytes as will fit */
//     if (n != 0 && --n != 0)
//     {
//         do
//         {
//             if ((*d++ = *s++) == 0)
//                 break;
//         } while (--n != 0);
//     }

//     /* Not enough room in dst, add NUL and traverse rest of src */
//     if (n == 0)
//     {
//         if (siz != 0)
//             *d = '\0'; /* NUL-terminate dst */
//         while (*s++)
//             ;
//     }

//     return (s - src - 1); /* count does not include NUL */
// }

// 获取第N项开始的指针
// const char *get_items(const char *buffer, unsigned int item)
// {

//     const char *p = buffer;

//     int len = strlen(buffer);
//     int count = 0;

//     for (int i = 0; i < len; i++)
//     {
//         if (' ' == *p)
//         {
//             count++;
//             if (count == item - 1)
//             {
//                 p++;
//                 break;
//             }
//         }
//         p++;
//     }

//     return p;
// }

static uint verify_file(char *pFileName)
{
    return !strncmp(pFileName, "/proc", strnlen("/proc", STRNLEN_MAX));
}

static int get_ppid(pid_t pid)
{
    char path[64];
    snprintf(path, sizeof(path), "/proc/%d/stat", pid);

    FILE *fp = fopen(path, "r");
    if (!fp)
    {
        klog_err("Failed to open %s: %s\n", path, strerror(errno));
        return -1;
    }

    int ppid;
    fscanf(fp, "%*d %*s %*c %d", &ppid);

    fclose(fp);
    return ppid;
}

static int read_kare_deb_name(const char *data, size_t size, void *user_data)
{
    char **ptr = (char **)user_data;
    *ptr = strndup(data, size);
    return 1;
}

static int _execve_cmd(const char *exec, char *const argv[], char *const envp[])
{
    int ret = 0;

    pid_t child_pid = fork();
    if (child_pid == -1)
    {
        klog_err("fork 调用失败, errno:%d (%s)\n", errno, strerror(errno));
        ret = -1;
    }
    else if (child_pid == 0)
    {
        execve(exec, argv, envp);

        // 如果 execve 执行失败,记录错误并退出
        klog_err("execve 调用失败, errno:%d (%s)\n", errno, strerror(errno));
        _exit(127);
    }
    else
    {
        // 父进程：等待子进程完成
        int status;
        if (waitpid(child_pid, &status, 0) == -1)
        {
            klog_err("waitpid 调用失败, errno:%d (%s)\n", errno, strerror(errno));
            ret = -1;
        }
        else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
        {
            klog_err("命令执行失败，退出码: %d\n", WEXITSTATUS(status));
            ret = -1;
        }
    }

    return ret;
}

/**
 * 从管道读取数据并逐行调用回调函数处理
 * @param pipe_fd 管道读取端文件描述符
 * @param callback 输出回调函数,每读取到一行数据调用一次
 * @param user_data 用户自定义数据
 * @return 0 成功，-1 读取错误，1 回调要求停止
 */
static int _read_pipe_and_process(int pipe_fd, execve_output_callback_t callback, void *user_data)
{
    const size_t buffer_size = 4096;
    char read_buffer[buffer_size];
    char line_buffer[buffer_size];
    size_t line_pos = 0;
    ssize_t bytes_read;

    while ((bytes_read = read(pipe_fd, read_buffer, sizeof(read_buffer))) > 0)
    {
        // 处理读取到的数据
        for (ssize_t i = 0; i < bytes_read; i++)
        {
            if (read_buffer[i] == '\n')
            {
                // 遇到换行符，处理当前行
                line_buffer[line_pos] = '\0';

                // 去除末尾的回车符
                if (line_pos > 0 && line_buffer[line_pos - 1] == '\r')
                {
                    line_buffer[line_pos - 1] = '\0';
                }

                // 调用回调函数处理该行
                if (callback)
                {
                    int ret = callback(line_buffer, strlen(line_buffer), user_data);
                    if (ret != 0)
                    {
                        // 回调要求停止读取
                        return 1;
                    }
                }

                // 重置行缓冲区
                line_pos = 0;
            }
            else
            {
                // 添加到行缓冲区
                if (line_pos < buffer_size - 1)
                {
                    line_buffer[line_pos++] = read_buffer[i];
                }
                else
                {
                    // 行缓冲区溢出，强制处理
                    line_buffer[line_pos] = '\0';
                    if (callback)
                    {
                        int ret = callback(line_buffer, line_pos, user_data);
                        if (ret != 0)
                        {
                            return 1;
                        }
                    }
                    line_pos = 0;
                }
            }
        }
    }

    // 检查读取错误
    if (bytes_read == -1)
    {
        klog_err("读取管道失败, errno:%d (%s)\n", errno, strerror(errno));
        return -1;
    }

    // 处理最后一行（如果没有换行符结尾）
    if (line_pos > 0 && callback)
    {
        line_buffer[line_pos] = '\0';
        callback(line_buffer, line_pos, user_data);
    }

    return 0;
}

/**
 * 通过 execve 执行命令并通过管道捕获标准输出，使用回调函数处理输出
 * @param exec 可执行文件路径
 * @param argv 参数数组（以 NULL 结尾）
 * @param envp 环境变量数组（以 NULL 结尾）
 * @param callback 输出回调函数，每读取一行数据调用一次
 *                 回调返回 0 继续读取，非 0 停止读取
 * @param user_data 用户自定义数据，传递给回调函数
 * @return 0 成功，-1 失败
 *
 */
static int _execve_cmd_pipe(const char *exec, char *const argv[], char *const envp[],
                            execve_output_callback_t callback, void *user_data)
{
    if (!exec || !argv)
    {
        klog_err("无效的参数: exec 或 argv 为空\n");
        return -1;
    }

    int pipefd[2];
    if (pipe(pipefd) == -1)
    {
        klog_err("创建管道失败, errno:%d (%s)\n", errno, strerror(errno));
        return -1;
    }

    pid_t child_pid = fork();
    if (child_pid == -1)
    {
        klog_err("fork 调用失败, errno:%d (%s)\n", errno, strerror(errno));
        close(pipefd[0]);
        close(pipefd[1]);
        return -1;
    }
    else if (child_pid == 0)
    {
        // 子进程：关闭读端，将写端重定向到 stdout
        close(pipefd[0]);
        if (dup2(pipefd[1], STDOUT_FILENO) == -1)
        {
            klog_err("dup2 调用失败, errno:%d (%s)\n", errno, strerror(errno));
            _exit(127);
        }
        close(pipefd[1]);

        // 执行命令
        execve(exec, argv, envp);

        // 如果 execve 执行失败
        klog_err("execve 调用失败, errno:%d (%s)\n", errno, strerror(errno));
        _exit(127);
    }
    else
    {
        // 父进程：关闭写端
        close(pipefd[1]);

        // 从管道读取数据并处理
        int read_result = _read_pipe_and_process(pipefd[0], callback, user_data);
        close(pipefd[0]);

        // 等待子进程完成
        int status;
        pid_t wait_result = waitpid(child_pid, &status, 0);
        if (wait_result == -1)
        {
            if (errno == ECHILD)
            {
                if (read_result == -1)
                {
                    klog_warning("子进程 %d 已被回收或不存在 (errno: ECHILD)\n", child_pid);
                    return -1;
                }
            }
            else
            {
                klog_err("waitpid 调用失败, pid:%d, errno:%d (%s)\n", child_pid, errno, strerror(errno));
                return -1;
            }
        }
        else
        {
            // 只有当 waitpid 成功时才检查退出状态
            if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
            {
                klog_warning("命令执行失败，退出码: %d\n", WEXITSTATUS(status));
            }
        }

        // 如果读取出错，返回失败
        if (read_result == -1)
        {
            return -1;
        }

        return 0;
    }
}

static KdkRuntimeEnv _kdk_get_process_kaiming_env(int pid)
{
    KdkRuntimeEnv env = KDK_ENV_UNKNOWN;
    int ppid = pid;
    FILE *fp = NULL;
    const char *var_name = "KAIMING_ID=";
    const size_t var_len = 11;

    while (ppid > 1)
    {
        char path[256];
        int ret = snprintf(path, sizeof(path), "/proc/%d/environ", ppid);

        if (ret < 0 || (size_t)ret >= sizeof(path))
        {
            klog_err("Path buffer overflow or encoding error for pid %d\n", ppid);
            break;
        }

        fp = fopen(path, "r");
        if (!fp)
        {
            ppid = get_ppid(ppid);
            if (ppid <= 0)
                break; // 获取父进程失败或到达根进程
            continue;
        }

        char *line = NULL;
        size_t len = 0;
        ssize_t read_bytes;
        int found = 0;

        while ((read_bytes = getdelim(&line, &len, '\0', fp)) != -1)
        {
            if (read_bytes >= (ssize_t)var_len && strncmp(line, var_name, var_len) == 0)
            {
                env = KDK_ENV_KAIMING;
                found = 1;
                break;
            }
        }

        free(line);
        fclose(fp);

        if (found)
        {
            return env;
        }

        int next_ppid = get_ppid(ppid);
        if (next_ppid <= 0 || next_ppid == ppid)
        {
            break;
        }
        ppid = next_ppid;
    }

    return env;
}

static KdkRuntimeEnv _kdk_get_process_kare_env(int pid)
{
    KdkRuntimeEnv env = KDK_ENV_UNKNOWN;

    char path[256];
    const char *var_name = "KARE_PACKAGE_PATH=";
    const size_t var_len = 18;

    int ret = snprintf(path, sizeof(path), "/proc/%d/environ", pid);
    if (ret < 0 || (size_t)ret >= sizeof(path))
    {
        klog_err("Path buffer overflow or encoding error for pid %d\n", pid);
        return KDK_ENV_UNKNOWN;
    }

    FILE *fp = fopen(path, "r");
    if (!fp)
    {
        return env;
    }

    char *line = NULL;
    size_t len = 0;
    ssize_t read_bytes;
    char keyword[256] = "\0";

    while ((read_bytes = getdelim(&line, &len, '\0', fp)) != -1)
    {
        if (read_bytes >= (ssize_t)var_len && strncmp(line, var_name, var_len) == 0)
        {
            // 找到目标变量
            char *value = line + var_len;
            if (extract_keyword_manual(value, keyword, sizeof(keyword)) == 0)
            {
                if (strcmp(keyword, "shadow") == 0)
                {
                    env = KDK_ENV_KARE_SHADOW;
                }
                else if (strcmp(keyword, "v10sp1") == 0)
                {
                    env = KDK_ENV_KARE_V10SP1;
                }
            }
            break;
        }
    }

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

char *kdk_get_process_name(int proc_num)
{
    char path[100] = "\0";
    char *name = NULL;
    char link[64] = "\0";
    char buffer[1025] = "\0";
    snprintf(path, sizeof(path), "/proc/%d/exe", proc_num);

    int count = readlink(path, link, sizeof(link));
    if (count != -1)
    {
        name = calloc(1, strnlen(basename(link), STRNLEN_MAX) + 1);
        if (NULL == name)
            return NULL;
        strncpy(name, basename(link), strnlen(basename(link), STRNLEN_MAX) + 1);
    }
    else
    {
        memset(path, 0, sizeof(path));
        snprintf(path, sizeof(path), "/proc/%d/status", proc_num);
        FILE *fp = fopen(path, "rt");
        if (!fp)
        {
            free(name);
            return NULL;
        }

        while (fgets(buffer, sizeof(buffer), fp))
        {
            if (lookup(buffer, "Name", &name))
                break;
        }

        fclose(fp);
    }
    return name;
}

int kdk_get_process_id(char *proc_name)
{
    DIR *dir;
    struct dirent *ptr;
    FILE *fp;
    char path[512] = "\0";
    int i = 0;
    char *realpath_res = NULL;
    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;
    char line[1024] = {0};
    char *name = NULL;
    char link[128] = "\0";
    int res = 0;

    dir = opendir("/proc");
    if (NULL != dir)
    {
        while ((ptr = readdir(dir)) != NULL) // 循环读取/proc下的每一个文件/文件夹
        {
            // 如果读取到的是"."或者".."则跳过，读取到的不是文件夹名字也跳过
            if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0))
                continue;
            if (DT_DIR != ptr->d_type)
                continue;

            snprintf(path, sizeof(path), "/proc/%s/exe", ptr->d_name); // 生成要读取的文件的路径
            memset(link, 0, sizeof(link));
            int count = readlink(path, link, sizeof(link));
            if (count != -1)
            {
                if ((strcmp(basename(link), proc_name)) == 0)
                {
                    sscanf(ptr->d_name, "%d", &res);
                }
            }
            else
            {
                memset(path, 0, sizeof(path));
                snprintf(path, sizeof(path), "/proc/%s/status", ptr->d_name);
                if (path_size > 0)
                {
                    canonical_filename = malloc(path_size);
                    if (canonical_filename == NULL)
                    {
                        FREE(canonical_filename);
                        continue;
                    }
                    realpath_res = realpath(path, canonical_filename);
                }
                if (canonical_filename == NULL)
                {
                    FREE(canonical_filename);
                    continue;
                }
                if (!verify_file(canonical_filename))
                {
                    FREE(canonical_filename);
                    continue;
                }

                fp = fopen(canonical_filename, "r");
                if (fp == NULL)
                {
                    FREE(canonical_filename);
                    continue;
                }
                else
                {
                    while (fgets(line, sizeof(line), fp))
                    {
                        if (lookup(line, "Name", &name))
                            break;
                    }
                    FREE(canonical_filename);
                    fclose(fp);
                }

                if ((strcmp(name, proc_name)) == 0)
                {
                    sscanf(ptr->d_name, "%d", &res);
                }
                FREE(name);
            }
        }
        closedir(dir);
    }
    return res;
}

int *kdk_get_process_id_nums(char *proc_name)
{
    DIR *dir;
    struct dirent *ptr;
    FILE *fp;
    char path[512] = "\0";
    int i = 0;
    char *realpath_res = NULL;
    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;
    char line[1024] = {0};
    char *name = NULL;
    char link[128] = "\0";
    int *res = NULL;

    dir = opendir("/proc");
    if (NULL != dir)
    {
        int *tmp = realloc(res, sizeof(int) * 128);
        if (!tmp)
        {
            closedir(dir);
        }
        res = tmp;
        memset(res, 0, sizeof(int) * 128);

        while ((ptr = readdir(dir)) != NULL) // 循环读取/proc下的每一个文件/文件夹
        {
            // 如果读取到的是"."或者".."则跳过，读取到的不是文件夹名字也跳过
            if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0))
                continue;
            if (DT_DIR != ptr->d_type)
                continue;

            snprintf(path, sizeof(path), "/proc/%s/exe", ptr->d_name); // 生成要读取的文件的路径
            memset(link, 0, sizeof(link));
            int count = readlink(path, link, sizeof(link));
            if (count != -1)
            {
                if ((strcmp(basename(link), proc_name)) == 0)
                {
                    int id = 0;
                    sscanf(ptr->d_name, "%d", &id);
                    res[i] = id;
                    i++;
                }
            }
            else
            {
                memset(path, 0, sizeof(path));
                snprintf(path, sizeof(path), "/proc/%s/status", ptr->d_name);
                if (path_size > 0)
                {
                    canonical_filename = malloc(path_size);
                    if (canonical_filename == NULL)
                    {
                        FREE(canonical_filename);
                        continue;
                    }
                    realpath_res = realpath(path, canonical_filename);
                }
                if (canonical_filename == NULL)
                {
                    FREE(canonical_filename);
                    continue;
                }
                if (!verify_file(canonical_filename))
                {
                    FREE(canonical_filename);
                    continue;
                }

                fp = fopen(canonical_filename, "r");
                if (fp == NULL)
                {
                    FREE(canonical_filename);
                    continue;
                }
                else
                {
                    while (fgets(line, sizeof(line), fp))
                    {
                        if (lookup(line, "Name", &name))
                            break;
                    }
                    FREE(canonical_filename);
                    fclose(fp);
                }

                if ((strcmp(name, proc_name)) == 0)
                {
                    int id = 0;
                    sscanf(ptr->d_name, "%d", &id);
                    res[i] = id;
                    i++;
                }
                FREE(name);
            }
        }
        closedir(dir);
    }
    return res;
}

static unsigned long long Hertz;
static long smp_num_cpus; /* number of CPUs */

static void old_Hertz_hack(void)
{
    unsigned long long user_j, nice_j, sys_j, other_j, wait_j, hirq_j, sirq_j, stol_j; /* jiffies (clock ticks) */
    double up_1, up_2, seconds;
    unsigned long long jiffies;
    unsigned h;
    char *savelocale;
    long hz;

#ifdef _SC_CLK_TCK
    if ((hz = sysconf(_SC_CLK_TCK)) > 0)
    {
        Hertz = hz;
        return;
    }
#endif

    wait_j = hirq_j = sirq_j = stol_j = 0;
    savelocale = strdup(setlocale(LC_NUMERIC, NULL));
    setlocale(LC_NUMERIC, "C");
    do
    {
        FILE_TO_BUF(UPTIME_FILE, uptime_fd);
        sscanf(buf, "%lf", &up_1);
        /* uptime(&up_1, NULL); */
        FILE_TO_BUF(STAT_FILE, stat_fd);
        sscanf(buf, "cpu %llu %llu %llu %llu %llu %llu %llu %llu", &user_j, &nice_j, &sys_j, &other_j, &wait_j, &hirq_j, &sirq_j, &stol_j);
        FILE_TO_BUF(UPTIME_FILE, uptime_fd);
        sscanf(buf, "%lf", &up_2);
        /* uptime(&up_2, NULL); */
    } while ((long long)((up_2 - up_1) * 1000.0 / up_1)); /* want under 0.1% error */
    setlocale(LC_NUMERIC, savelocale);
    free(savelocale);
    jiffies = user_j + nice_j + sys_j + other_j + wait_j + hirq_j + sirq_j + stol_j;
    seconds = (up_1 + up_2) / 2;
    h = (unsigned)((double)jiffies / seconds / smp_num_cpus);
    /* actual values used by 2.4 kernels: 32 64 100 128 1000 1024 1200 */
    switch (h)
    {
    case 9 ... 11:
        Hertz = 10;
        break; /* S/390 (sometimes) */
    case 18 ... 22:
        Hertz = 20;
        break; /* user-mode Linux */
    case 30 ... 34:
        Hertz = 32;
        break; /* ia64 emulator */
    case 48 ... 52:
        Hertz = 50;
        break;
    case 58 ... 61:
        Hertz = 60;
        break;
    case 62 ... 65:
        Hertz = 64;
        break; /* StrongARM /Shark */
    case 95 ... 105:
        Hertz = 100;
        break; /* normal Linux */
    case 124 ... 132:
        Hertz = 128;
        break; /* MIPS, ARM */
    case 195 ... 204:
        Hertz = 200;
        break; /* normal << 1 */
    case 247 ... 252:
        Hertz = 250;
        break;
    case 253 ... 260:
        Hertz = 256;
        break;
    case 393 ... 408:
        Hertz = 400;
        break; /* normal << 2 */
    case 410 ... 600:
        Hertz = 500;
        break; /* SMP WinNT */
    case 790 ... 808:
        Hertz = 800;
        break; /* normal << 3 */
    case 990 ... 1010:
        Hertz = 1000;
        break; /* ARM */
    case 1015 ... 1035:
        Hertz = 1024;
        break; /* Alpha, ia64 */
    case 1180 ... 1220:
        Hertz = 1200;
        break; /* Alpha */
    default:
#ifdef HZ
        Hertz = (unsigned long long)HZ; /* <asm/param.h> */
#else
        /* If 32-bit or big-endian (not Alpha or ia64), assume HZ is 100. */
        Hertz = (sizeof(long) == sizeof(int) || htons(999) == 999) ? 100UL : 1024UL;
#endif
        klog_warning("Unknown HZ value! (%d) Assume %Ld.\n", h, Hertz);
    }
}

static int uptime(double *restrict uptime_secs, double *restrict idle_secs)
{
    double up = 0, idle = 0;
    char *savelocale;

    FILE_TO_BUF(UPTIME_FILE, uptime_fd);
    savelocale = strdup(setlocale(LC_NUMERIC, NULL));
    setlocale(LC_NUMERIC, "C");
    if (sscanf(buf, "%lf %lf", &up, &idle) < 2)
    {
        setlocale(LC_NUMERIC, savelocale);
        free(savelocale);
        klog_err("bad data in " UPTIME_FILE "\n");
        return 0;
    }
    setlocale(LC_NUMERIC, savelocale);
    free(savelocale);
    SET_IF_DESIRED(uptime_secs, up);
    SET_IF_DESIRED(idle_secs, idle);
    return up; /* assume never be zero seconds in practice */
}

float kdk_get_process_cpu_usage_percent(int proc_num)
{
    FILE *file = NULL;
    char path[1024] = "\0";
    char buf[1024] = "\0";
    float cpu_usage = 0.0;
    unsigned long long total_time; /* jiffies used by this process */
    unsigned pcpu = 0;             /* scaled %cpu, 999 means 99.9% */
    unsigned long long seconds;    /* seconds of process life */
    unsigned long long utime;      // user time
    unsigned long long stime;      // kernel time
    unsigned long long cutime;     // all user time
    unsigned long long cstime;     // all dead time
    unsigned long long start_time;
    char canonical_filename[4096] = "\0";

    time_t seconds_since_boot;
    seconds_since_boot = uptime(0, 0);

    // Read process stats
    snprintf(path, sizeof(path), "/proc/%d/stat", proc_num);
    if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
    {
        return cpu_usage;
    }
    file = fopen(canonical_filename, "r");
    if (file == NULL)
    {
        return cpu_usage;
    }
    if (fgets(buf, sizeof(buf) - 1, file) == NULL)
    {
        fclose(file);
        return cpu_usage;
    }
    fclose(file);
    strstripspace(buf);

    // Parse the required fields
    sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*lu %*lu %*lu %*lu %*lu %llu %llu %llu %llu %*ld %*ld %*d %*ld %llu", &utime, &stime, &cutime, &cstime, &start_time);

    total_time = utime + stime;

    old_Hertz_hack();

    char outbuf[240] = "\0";
    seconds = (((unsigned long long)seconds_since_boot >= (start_time / Hertz)) ? ((unsigned long long)seconds_since_boot - (start_time / Hertz)) : 0);
    if (seconds)
        pcpu = (total_time * 1000ULL / Hertz) / seconds;
    if (pcpu > 999U)
    {
        snprintf(outbuf, COLWID, "%u", pcpu / 10U);
        cpu_usage = atof(outbuf);
    }
    else
    {
        snprintf(outbuf, COLWID, "%u.%u", pcpu / 10U, pcpu % 10U);
        cpu_usage = atof(outbuf);
    }

    return cpu_usage;
}

float kdk_get_process_mem_usage_percent(int proc_num)
{
    char path[100] = {0};
    float percent = 0.00;
    unsigned long memTotal = 0, memRSS = 0;
    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    snprintf(path, sizeof(path), "/proc/%d/status", proc_num);
    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            return 0.00;
        }
        if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
        {
            FREE(canonical_filename);
            return 0.00;
        }
    }

    FILE *fp = fopen(canonical_filename, "r");
    if (!fp)
        goto err;

    char buffer[1025];
    char buffers[1025];

    while (fgets(buffer, 1024, fp))
    {
        if (lookup_num(buffer, "VmRSS", &memRSS))
            break;
    }
    fseek(fp, 0, SEEK_SET);
    fclose(fp);

    FILE *fb = fopen(MEMINFO, "rt");
    if (!fb)
        goto err;
    while (fgets(buffers, 1024, fb))
    {
        if (lookup_num(buffers, "MemTotal", &memTotal))
            break;
    }
    if (memTotal)
        percent = ((float)memRSS / (float)memTotal) * 100;

    fseek(fb, 0, SEEK_SET);
    fclose(fb);
    FREE(canonical_filename);
    return percent;

err:
    FREE(canonical_filename);
    return 0.00;
}

char *kdk_get_process_status(int proc_num)
{
    char path[100] = {0};
    char *name = NULL;
    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    snprintf(path, sizeof(path), "/proc/%d/status", proc_num);

    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            return NULL;
        }
        if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
        {
            FREE(canonical_filename);
            return NULL;
        }
    }

    FILE *fp = fopen(canonical_filename, "r");
    if (!fp)
        goto err;

    char buffer[1025] = {0};

    while (fgets(buffer, 1024, fp))
    {
        if (lookup(buffer, "State", &name))
            break;
    }
    fseek(fp, 0, SEEK_SET);
    fclose(fp);
    FREE(canonical_filename);
    return name;

err:
    FREE(canonical_filename);
    return NULL;
}

static int extract_type_1_socket_inode(const char lname[], unsigned long *inode_p)
{

    /* If lname is of the form "socket:[12345]", extract the "12345"
       as *inode_p.  Otherwise, return -1 as *inode_p.
       */

    if (lname[strnlen(lname, STRNLEN_MAX) - 1] != ']')
        return -1;

    {
        char inode_str[strnlen(lname + 1, STRNLEN_MAX)]; /* e.g. "12345" */
        const int inode_str_len = strnlen(lname, STRNLEN_MAX) - PRG_SOCKET_PFXl - 1;
        char *serr;

        strncpy(inode_str, lname + PRG_SOCKET_PFXl, sizeof(inode_str));
        inode_str[inode_str_len] = '\0';
        *inode_p = strtoul(inode_str, &serr, 0);
        if (!serr || *serr || *inode_p == ~0)
            return -1;
    }
    return 0;
}

static int extract_type_2_socket_inode(const char lname[], unsigned long *inode_p)
{

    /* If lname is of the form "[0000]:12345", extract the "12345"
       as *inode_p.  Otherwise, return -1 as *inode_p.
       */

    if (strnlen(lname, STRNLEN_MAX) < PRG_SOCKET_PFX2l + 1)
        return -1;
    if (memcmp(lname, PRG_SOCKET_PFX2, PRG_SOCKET_PFX2l))
        return -1;
    {
        char *serr;
        *inode_p = strtoul(lname + PRG_SOCKET_PFX2l, &serr, 0);
        if (!serr || *serr || *inode_p == ~0)
            return -1;
    }
    return 0;
}

int kdk_get_process_port(int proc_num)
{
    unsigned long rxq, txq, time_len, retr, inode;
    int num, local_port, rem_port, d, state, uid, timer_run, timeout;
    char rem_addr[128], local_addr[128];
    FILE *fd = NULL;
    char line_buff[1024] = {0};
    char line[LINE_MAX];
    int lnamelen;
    char lname[30];
    unsigned long inode_num;
    DIR *dirfd = NULL;
    struct dirent *direfd;
    char path[100] = {0};
    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    snprintf(path, sizeof(path), "/proc/%d/fd", proc_num);
    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            return 0;
        }
        if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
        {
            FREE(canonical_filename);
            return 0;
        }
    }

    dirfd = opendir(canonical_filename);

    if (!dirfd)
    {
        goto err;
    }

    while ((direfd = readdir(dirfd)))
    {
        snprintf(line, sizeof(line), "/proc/%d/fd/%s", proc_num, direfd->d_name);
        lnamelen = readlink(line, lname, sizeof(lname) - 1);
        if (lnamelen == -1)
            continue;
        lname[lnamelen] = '\0'; /*make it a null-terminated string*/

        if (extract_type_1_socket_inode(lname, &inode_num) < 0)
            if (extract_type_2_socket_inode(lname, &inode_num) < 0)
                continue;
        fd = fopen("/proc/net/tcp", "r");
        if (NULL == fd)
        {
            closedir(dirfd);
            goto err;
        }
        fseek(fd, 0, SEEK_SET);

        while (fgets(line_buff, sizeof(line_buff), fd))
        {
            num = sscanf(line_buff,
                         "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %*s\n",
                         &d, local_addr, &local_port, rem_addr, &rem_port, &state,
                         &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode);
            if (inode_num == inode)
            {
                // sprintf(proc_prot, "%d", local_port);
                fclose(fd);
                closedir(dirfd);
                FREE(canonical_filename);
                return local_port;
            }
            else
            {
                continue;
            }
        }
        fclose(fd);
        FREE(canonical_filename);
    }
    FREE(canonical_filename);
    closedir(dirfd);
    return 0;

err:
    FREE(canonical_filename);
    return 0;
}

int *kdk_get_process_port_nums(int proc_num)
{
    unsigned long rxq, txq, time_len, retr, inode;
    int num, local_port, rem_port, d, state, uid, timer_run, timeout;
    char rem_addr[128], local_addr[128];
    FILE *fd = NULL;
    char line_buff[1024] = {0};
    char line[LINE_MAX];
    int lnamelen;
    char lname[30];
    unsigned long inode_num;
    DIR *dirfd = NULL;
    struct dirent *direfd;
    char path[100] = {0};
    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;
    int i = 0;
    int *res = NULL;

    snprintf(path, sizeof(path), "/proc/%d/fd", proc_num);
    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            return NULL;
        }
        if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
        {
            FREE(canonical_filename);
            return NULL;
        }
    }

    dirfd = opendir(canonical_filename);

    if (!dirfd)
    {
        goto err;
    }

    int *tmp = realloc(res, sizeof(int) * 128);
    if (!tmp)
    {
        closedir(dirfd);
        goto err;
    }
    res = tmp;
    memset(res, 0, sizeof(int) * 128);

    while ((direfd = readdir(dirfd)))
    {
        snprintf(line, sizeof(line), "/proc/%d/fd/%s", proc_num, direfd->d_name);
        lnamelen = readlink(line, lname, sizeof(lname) - 1);
        if (lnamelen == -1)
            continue;
        lname[lnamelen] = '\0'; /*make it a null-terminated string*/

        if (extract_type_1_socket_inode(lname, &inode_num) < 0)
            if (extract_type_2_socket_inode(lname, &inode_num) < 0)
                continue;

        fd = fopen("/proc/net/tcp", "r");
        if (NULL == fd)
        {
            closedir(dirfd);
            goto err;
        }
        fseek(fd, 0, SEEK_SET);

        while (fgets(line_buff, sizeof(line_buff), fd))
        {
            num = sscanf(line_buff,
                         "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %*s\n",
                         &d, local_addr, &local_port, rem_addr, &rem_port, &state,
                         &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode);
            if (inode_num == inode)
            {
                res[i] = local_port;
                i++;
            }
        }
        fclose(fd);
    }
    FREE(canonical_filename);
    closedir(dirfd);

    return res;

err:
    FREE(canonical_filename);
    if (res)
        free(res);
    return NULL;
}

char *kdk_get_process_start_time(int proc_num)
{
    char path[100] = {0};
    char *name = (char *)malloc(sizeof(char) * 128);
    char st[128] = {0};
    if (!name)
    {
        klog_err("内存申请失败:%s\n", strerror(errno));
        return NULL;
    }
    char *t = NULL;
    char tt[1024] = {0};
    unsigned long long time1, starttime;
    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    snprintf(path, sizeof(path), "/proc/%d/stat", proc_num);
    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            free(name);
            return NULL;
        }
        if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
        {
            free(name);
            FREE(canonical_filename);
            return NULL;
        }
    }

    FILE *fpstat = fopen(canonical_filename, "r");
    if (fpstat == NULL)
    {
        goto err;
    }

    t = fgets(tt, sizeof(tt), fpstat);
    if (sscanf(t, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*u %*u %*d %*d %*d %*d %*d %*d %19llu %*u", &time1) == EOF)
    {
        fclose(fpstat);
        goto err;
    }
    fseek(fpstat, 0, SEEK_SET);
    fclose(fpstat);
    FREE(canonical_filename);

    time_t now;
    now = time(NULL);
    struct timespec time2 = {0, 0};
    clock_gettime(CLOCK_MONOTONIC, &time2);

    starttime = (unsigned long long)(time1 / HZ) + (now - time2.tv_sec) - 0.1;

    time_t time3 = starttime;

    strncpy(st, ctime(&time3), sizeof(st) - 1);
    strstripspace(st);
    strncpy(name, st, 128);
    return name;

err:
    FREE(canonical_filename);
    free(name);
    return NULL;
}

char *kdk_get_process_running_time(int proc_num)
{
    char path[1024] = {0};
    char *t = NULL;
    char tt[1024] = {0};
    unsigned long long time1;
    unsigned long long seconds;
    char *cp = (char *)calloc(240, sizeof(char));
    if (!cp)
    {
        klog_err("内存申请失败:%s\n", strerror(errno));
        return NULL;
    }
    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    snprintf(path, sizeof(path), "/proc/%d/stat", proc_num);
    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            free(cp);
            return NULL;
        }
        if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
        {
            free(cp);
            FREE(canonical_filename);
            return NULL;
        }
    }

    FILE *fpstat = fopen(canonical_filename, "r");
    if (fpstat == NULL)
    {
        goto err;
    }

    t = fgets(tt, sizeof(tt), fpstat);
    if (sscanf(t, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*u %*u %*d %*d %*d %*d %*d %*d %19llu %*u", &time1) == EOF)
    {
        fclose(fpstat);
        goto err;
    }
    fseek(fpstat, 0, SEEK_SET);
    fclose(fpstat);
    FREE(canonical_filename);

    time_t seconds_since_boot = uptime(0, 0);
    seconds = seconds_since_boot - (time1 / 100);

    unsigned dd, hh, mm, ss;
    char buff[256];
    ss = seconds % 60;
    seconds /= 60;
    mm = seconds % 60;
    seconds /= 60;
    hh = seconds % 24;
    seconds /= 24;
    dd = seconds;
    if (dd)
    {
        snprintf(cp, COLWID, "%u-", dd);
    }
    else
    {
        snprintf(cp, COLWID, "%u-", 0);
    }
    if (dd || hh)
    {
        snprintf(buff, COLWID, "%02u:", hh);
        strncat(cp, buff, 240 - strnlen(cp, STRNLEN_MAX) - 1);
    }
    else
    {
        snprintf(buff, COLWID, "%02u:", 0);
        strncat(cp, buff, 240 - strnlen(cp, STRNLEN_MAX) - 1);
    }
    memset(buff, '\0', sizeof(buff));
    snprintf(buff, COLWID, "%02u:%02u", mm, ss);
    strncat(cp, buff, 240 - strnlen(cp, STRNLEN_MAX) - 1);
    return cp;

err:
    free(cp);
    FREE(canonical_filename);
    return NULL;
}

char *kdk_get_process_cpu_time(int proc_num)
{
    char path[100] = {0};
    struct pstat result;
    unsigned long utime = 0;
    char *name = (char *)malloc(128 * sizeof(char));
    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    snprintf(path, sizeof(path), "/proc/%d/stat", proc_num);

    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            free(name);
            return NULL;
        }
        if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
        {
            FREE(canonical_filename);
            free(name);
            return NULL;
        }
    }

    FILE *fpstat = fopen(canonical_filename, "r");
    if (fpstat == NULL)
    {
        goto err;
    }

    // read values from /proc/pid/stat
    bzero(&result, sizeof(struct pstat));

    if (fscanf(fpstat, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu %*s",
               &result.utime_ticks, &result.stime_ticks) == EOF)
    {
        fclose(fpstat);
        goto err;
    }

    utime = (long)((result.utime_ticks + result.stime_ticks) / HZ);
    snprintf(name, 128, "%ld秒", utime);
    fseek(fpstat, 0, SEEK_SET);
    fclose(fpstat);
    FREE(canonical_filename);
    return name;

err:
    free(name);
    FREE(canonical_filename);
    return NULL;
}

char *kdk_get_process_command(int proc_num)
{
    FILE *fd;
    char path[128] = {0};
    char *command = (char *)malloc(1024 * sizeof(char));
    if (!command)
    {
        klog_err("内存申请失败:%s\n", strerror(errno));
        return NULL;
    }
    char line[1024] = {0};
    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    if (proc_num < 0)
    {
        free(command);
        return NULL;
    }
    else
    {
        snprintf(path, sizeof(path), "/proc/%d/cmdline", proc_num);
    }

    if (strstr(path, "../"))
    {
        free(command);
        return NULL;
    }
    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            free(command);
            return NULL;
        }
        if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
        {
            FREE(canonical_filename);
            free(command);
            return NULL;
        }
    }

    if ((fd = fopen(canonical_filename, "r")) == NULL)
    {
        goto err;
    }

    int c;
    int i = 0;
    while (1)
    {
        char a = ' ';

        c = fgetc(fd);
        if (feof(fd))
            break;
        if (c == '\0')
            line[i] = a;
        else
            line[i] = c;
        i++;
    }
    strncpy(command, line, 1024);
    fseek(fd, 0, SEEK_SET);
    fclose(fd);
    FREE(canonical_filename);
    return command;

err:
    free(command);
    FREE(canonical_filename);
    return NULL;
}

char *kdk_get_process_user(int proc_num)
{
    if (proc_num <= 0)
    {
        return NULL;
    }

    char filename[128] = {0};
    char canonical_filename[PATH_MAX_PROC] = {0};
    snprintf(filename, sizeof(filename), "/proc/%d/status", proc_num);

    if (!realpath(filename, canonical_filename) || !verify_file(canonical_filename))
    {
        return NULL;
    }

    // 读取进程状态获取 UID
    FILE *fp = fopen(canonical_filename, "r");
    if (!fp)
    {
        return NULL;
    }

    char line[256] = {0};
    uid_t uid = 0;
    int found = 0;

    while (fgets(line, sizeof(line), fp))
    {
        if (strncmp(line, "Uid:", 4) == 0)
        {
            // 解析: "Uid:\t1234\t1234\t1234\t1234"
            char *ptr = line + 4;
            while (*ptr == '\t' || *ptr == ' ')
                ptr++;
            if (sscanf(ptr, "%u", &uid) == 1)
            {
                found = 1;
            }
            break;
        }
    }
    fclose(fp);

    if (!found)
    {
        return NULL;
    }

    // 获取用户名
    struct passwd *pwd = getpwuid(uid);
    if (pwd && pwd->pw_name)
    {
        return strdup(pwd->pw_name);
    }

    return NULL;
}

static int *getPidByName(char *task_name)
{
    DIR *dir;
    struct dirent *ptr;
    FILE *fp;
    char path[512] = "\0";
    char cur_task_name[50];
    char buf[BUF_SIZE];
    int i = 0;
    char *realpath_res = NULL;
    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;
    char *name = NULL;
    char link[128] = "\0";

    int *res = NULL;
    int max_count = 0;

    dir = opendir("/proc");
    if (NULL != dir)
    {
        while ((ptr = readdir(dir)) != NULL) // 循环读取/proc下的每一个文件/文件夹
        {
            if (((max_count - 1) == i) || (max_count == 0))
            {
                max_count += 5;
                int *tmp = realloc(res, sizeof(int) * max_count);
                if (!tmp)
                {
                    klog_err("内存申请失败:%s\n", strerror(errno));
                    goto err;
                }
                res = tmp;
                memset(res + i, 0, sizeof(int) * (max_count - i));
            }

            // 如果读取到的是"."或者".."则跳过，读取到的不是文件夹名字也跳过
            if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0))
                continue;
            if (DT_DIR != ptr->d_type)
                continue;
            snprintf(path, sizeof(path), "/proc/%s/exe", ptr->d_name); // 生成要读取的文件的路径
            int count = readlink(path, link, sizeof(link));
            if (count != -1)
            {
                // 关键：添加null终止符
                link[count] = '\0';
                
                // 找到最后一个'/'的位置
                const char* last_slash = strrchr(link, '/');
                
                // 如果没有找到'/'，说明整个字符串就是文件名
                if (last_slash == NULL) {
                    continue;
                }
                
                // 如果最后一个字符是'/'，跳过
                if (*(last_slash + 1) == '\0') {
                    continue;
                }

                if (strstr(last_slash + 1, task_name))
                {
                    sscanf(ptr->d_name, "%d", res + i);
                    i++;
                }
            }
            else
            {
                memset(path, 0, sizeof(path));
                snprintf(path, sizeof(path), "/proc/%s/status", ptr->d_name);
                if (path_size > 0)
                {
                    canonical_filename = malloc(path_size);
                    if (canonical_filename == NULL)
                    {
                        FREE(canonical_filename);
                        continue;
                    }
                    realpath_res = realpath(path, canonical_filename);
                }
                if (canonical_filename == NULL)
                {
                    FREE(canonical_filename);
                    continue;
                }
                if (!verify_file(canonical_filename))
                {
                    FREE(canonical_filename);
                    continue;
                }

                fp = fopen(canonical_filename, "r");
                if (fp == NULL)
                {
                    FREE(canonical_filename);
                    continue;
                }
                else
                {
                    while (fgets(buf, sizeof(buf), fp))
                    {
                        if (lookup(buf, "Name", &name))
                            break;
                    }
                    FREE(canonical_filename);
                }

                if (strstr(name, task_name))
                {
                    sscanf(ptr->d_name, "%d", res + i);
                    i++;
                }
                FREE(name);
            }
        }
        closedir(dir);
    }
    return res;
err:
    free(res);
    closedir(dir);
    free(res);
    return NULL;
}

char **kdk_procname_get_process_infomation(char *proc_name)
{
    int *pid = getPidByName(proc_name);
    if (!pid)
    {
        return NULL;
    }
    char **res = NULL;

    char result[PROC_COMD_NUM] = "\0";
    char tmp[PROC_COMD_NUM] = "\0";
    char proc[PROC_COMD_NUM] = "\0";
    float percent = 0.00;
    int num = 0;

    int max_count = 0;
    int index = 0;
    while (pid[index])
    {
        if ((max_count - 1 == index) || (max_count == 0))
        {
            max_count += 5;
            char **tmp = realloc(res, sizeof(char *) * max_count);
            if (!tmp)
            {
                klog_err("内存申请失败:%s\n", strerror(errno));
                goto err;
            }
            res = tmp;
            memset(res + index, 0, sizeof(char *) * (max_count - index));
        }

        memset(result, 0, PROC_COMD_NUM * sizeof(char));
        memset(proc, 0, PROC_COMD_NUM * sizeof(char));

        strncat(result, "proc_pid:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        snprintf(tmp, sizeof(tmp), "%d", pid[index]);
        strncat(result, tmp, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);

        percent = kdk_get_process_cpu_usage_percent(pid[index]);
        strncat(result, "proc_cpu:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        snprintf(tmp, sizeof(tmp), "%0.1f", percent);
        strncat(result, tmp, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);

        percent = kdk_get_process_mem_usage_percent(pid[index]);
        strncat(result, "proc_mem:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        snprintf(tmp, sizeof(tmp), "%0.1f", percent);
        strncat(result, tmp, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);

        char *proc_state = kdk_get_process_status(pid[index]);
        strncat(result, "proc_state:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, proc_state, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        FREE(proc_state);

        num = kdk_get_process_port(pid[index]);
        strncat(result, "proc_port:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        snprintf(tmp, sizeof(tmp), "%d", num);
        strncat(result, tmp, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);

        char *start_time = kdk_get_process_start_time(pid[index]);
        strncat(result, "start_time:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, start_time, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        free(start_time);

        char *proc_time = kdk_get_process_running_time(pid[index]);
        strncat(result, "proc_time:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, proc_time, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        free(proc_time);

        char *cpu_time = kdk_get_process_cpu_time(pid[index]);
        strncat(result, "utime:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, cpu_time, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        free(cpu_time);

        char *proc_command = kdk_get_process_command(pid[index]);
        strncat(result, "proc_command:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, proc_command, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
        free(proc_command);

        char *proc_uid = kdk_get_process_user(pid[index]);
        // strcat(result, "proc_uid:");
        // strcat(result, proc_uid);
        FREE(proc_uid);

        res[index] = strdup(result);
        index++;
    }
    free(pid);
    return res;
err:
    free(pid);
    kdk_proc_freeall(res);
    return NULL;
}

static int get_proc_name(pid_t pid, char *name)
{
    char path[100] = "\0";
    char link[256] = "\0";
    char *tmp = NULL;
    char buffer[1025] = "\0";
    char canonical_filename[PATH_MAX_PROC] = "\0";
    if (pid < 0)
        return -1;
    snprintf(path, sizeof(path), "/proc/%d/exe", pid);

    int count = readlink(path, link, sizeof(link));
    if (count != -1)
    {
        strncpy(name, basename(link), 128);
    }
    else
    {
        memset(path, 0, sizeof(path));
        snprintf(path, sizeof(path), "/proc/%d/status", pid);

        if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
        {
            return -1;
        }
        FILE *fp = fopen(canonical_filename, "rt");
        if (!fp)
        {
            // free(name);
            return -1;
        }

        while (fgets(buffer, sizeof(buffer), fp))
        {
            if (lookup(buffer, "Name", &tmp))
                break;
        }
        strncpy(name, tmp, 128);
        FREE(tmp);

        fclose(fp);
    }
    return 0;
}

static int get_proc_state(pid_t pid, char *state)
{
    FILE *fpprocstat = NULL;
    char procstatf[128] = {0};
    char line[128] = {0};
    char *name = NULL;
    char canonical_filename[PATH_MAX_PROC] = "\0";
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    if (pid < 0)
        return -1;
    else
        snprintf(procstatf, sizeof(procstatf), "/proc/%d/status", pid);

    if (strstr(procstatf, "../"))
        return -1;

    if (path_size > 0)
    {
        if (!realpath(procstatf, canonical_filename) || !verify_file(canonical_filename))
        {
            return -1;
        }
    }

    if ((fpprocstat = fopen(canonical_filename, "r")) == NULL)
    {
        goto err;
    }
    fseek(fpprocstat, 0, SEEK_SET);

    while (fgets(line, sizeof(line), fpprocstat) != NULL)
    {
        if (lookup(line, "State", &name))
            break;
    }
    fclose(fpprocstat);
    strncpy(state, name, 20);
    FREE(name);
    return 0;

err:
    return -1;
}

static int get_proc_command(pid_t pid, char *command)
{
    FILE *fd = NULL;
    char path[128] = {0};
    char canonical_filename[PATH_MAX_PROC] = "\0";
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    if (pid < 0)
        return -1;
    else
        snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);

    if (strstr(path, "../"))
        return -1;

    if (path_size > 0)
    {
        if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
        {
            return -1;
        }
    }

    if ((fd = fopen(canonical_filename, "r")) == NULL)
    {
        goto err;
    }
    fseek(fd, 0, SEEK_SET);
    int c;
    int i = 0;
    while (1)
    {
        char a = ' ';

        c = fgetc(fd);
        if (feof(fd))
            break;
        if (c == '\0')
            command[i] = a;
        else
            command[i] = c;
        i++;
    }

    fclose(fd);
    return 0;

err:
    return -1;
}

static int get_proc_uid(pid_t pid, char *proc_uid)
{
    if (!proc_uid)
    {
        return -1;
    }

    proc_uid[0] = '\0';

    char filename[128] = {0};
    char canonical_filename[PATH_MAX_PROC] = {0};
    snprintf(filename, sizeof(filename), "/proc/%d/status", pid);

    if (!realpath(filename, canonical_filename) || !verify_file(canonical_filename))
    {
        return -1;
    }

    FILE *fp = fopen(canonical_filename, "r");
    if (!fp)
    {
        return -1;
    }

    char line[256] = {0};
    uid_t uid = 0;
    int found_uid = 0;

    while (fgets(line, sizeof(line), fp))
    {
        if (strncmp(line, "Uid:", 4) == 0)
        {
            // 格式: "Uid:\t1234\t1234\t1234\t1234"
            char *tab_pos = strchr(line, '\t');
            if (tab_pos && sscanf(tab_pos + 1, "%u", &uid) == 1)
            {
                found_uid = 1;
            }
            break;
        }
    }
    fclose(fp);

    if (!found_uid)
    {
        return -1;
    }

    struct passwd *pwd = getpwuid(uid);
    if (pwd && pwd->pw_name)
    {
        strncpy(proc_uid, pwd->pw_name, 127);
        proc_uid[127] = '\0';
        return 0;
    }
    return 0;
}

static int get_proc_mem_usage_pct(const pid_t pid, double *pct)
{
    FILE *fpmeminfo = NULL;
    FILE *fpprocstat = NULL;
    double memtotal = 1.0;
    double memproc = 0.0;
    char procstatf[128] = {0};
    char line[128] = {0};
    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    if (pid <= 0)
        return -1;

    if ((fpmeminfo = fopen(MEMINFO, "r")) == NULL)
        return -1;
    fseek(fpmeminfo, 0, SEEK_SET);
    while (fgets(line, sizeof(line), fpmeminfo) != NULL)
    {
        if (!strncmp(line, "MemTotal:", 9))
        {
            sscanf(line + 9, "%lf", &memtotal);
            break;
        }
    }
    fclose(fpmeminfo);
    snprintf(procstatf, sizeof(procstatf), "/proc/%d/status", pid);
    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            return -1;
        }
        if (!realpath(procstatf, canonical_filename) || !verify_file(canonical_filename))
        {
            FREE(canonical_filename);
            return -1;
        }
    }

    fpprocstat = fopen(canonical_filename, "r");
    if (fpprocstat == NULL)
        goto err;
    fseek(fpprocstat, 0, SEEK_SET);
    memset(line, 0, 128);
    while (fgets(line, sizeof(line), fpprocstat) != NULL)
    {
        if (!strncmp(line, "VmRSS:", 6))
        {
            sscanf(line + 6, "%lf", &memproc);
            break;
        }
    }
    fclose(fpprocstat);
    FREE(canonical_filename);
    *pct = 100 * memproc / memtotal;
    return 0;

err:
    FREE(canonical_filename);
    return -1;
}

static int get_proc_starttime(pid_t pid, char *start_time)
{
    char stat_filepath[30] = {0};
    char *t = NULL;
    char tt[1024] = {0};
    unsigned long long time1, starttime;
    char st[128] = {0};
    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    if (pid < 0)
    {
        return -1;
    }
    else
        snprintf(stat_filepath, sizeof(stat_filepath), "/proc/%d/stat", pid);

    if (strstr(stat_filepath, "../"))
    {
        return -1;
    }

    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            return -1;
        }
        if (!realpath(stat_filepath, canonical_filename) || !verify_file(canonical_filename))
        {
            FREE(canonical_filename);
            return -1;
        }
    }

    FILE *fpstat = fopen(canonical_filename, "r");
    if (fpstat == NULL)
    {
        klog_err("文件%s打开失败:%s\n", canonical_filename, strerror(errno));
        goto err;
    }
    fseek(fpstat, 0, SEEK_SET);

    t = fgets(tt, sizeof(tt), fpstat);
    if (sscanf(t, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*u %*u %*d %*d %*d %*d %*d %*d %19llu %*u", &time1) == EOF)
    {
        fclose(fpstat);
        goto err;
    }
    fclose(fpstat);
    FREE(canonical_filename);

    time_t now;
    now = time(NULL);
    struct timespec time2 = {0, 0};
    clock_gettime(CLOCK_MONOTONIC, &time2);

    starttime = (unsigned long long)(time1 / HZ) + (now - time2.tv_sec);
    time_t time3 = starttime;

    strncpy(st, ctime(&time3), 127);
    strstripspace(st);
    strncpy(start_time, st, 128);
    return 0;

err:
    FREE(canonical_filename);
    return -1;
}

static long get_proc_cpu_time(pid_t pid)
{
    char stat_filepath[30] = {0};
    struct pstat result;
    long utime = 0;

    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    if (pid < 0)
        return -1;
    else
        snprintf(stat_filepath, sizeof(stat_filepath), "/proc/%d/stat", pid);

    if (strstr(stat_filepath, "../"))
        return -1;
    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            return -1;
        }
        if (!realpath(stat_filepath, canonical_filename) || !verify_file(canonical_filename))
        {
            FREE(canonical_filename);
            return -1;
        }
    }

    FILE *fpstat = fopen(canonical_filename, "r");
    if (fpstat == NULL)
    {
        klog_err("文件%s打开失败:%s\n", canonical_filename, strerror(errno));
        goto err;
    }
    fseek(fpstat, 0, SEEK_SET);

    bzero(&result, sizeof(struct pstat));

    if (fscanf(fpstat, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu %*s",
               &result.utime_ticks, &result.stime_ticks) == EOF)
    {
        fclose(fpstat);
        goto err;
    }

    utime = (long)((result.utime_ticks + result.stime_ticks) / HZ);
    fclose(fpstat);
    FREE(canonical_filename);
    return utime;

err:
    FREE(canonical_filename);
    return -1;
}

static int get_proc_cpu_pcpu(pid_t pid, double *pcpu)
{
    char stat_filepath[30] = {0};
    struct pstat result;
    unsigned long long time1;
    long cutime, cstime;
    *pcpu = 0;

    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    if (pid < 0)
        return -1;
    else
        snprintf(stat_filepath, sizeof(stat_filepath), "/proc/%d/stat", pid);

    if (strstr(stat_filepath, "../"))
        return -1;

    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            return -1;
        }
        if (!realpath(stat_filepath, canonical_filename) || !verify_file(canonical_filename))
        {
            FREE(canonical_filename);
            return -1;
        }
    }

    FILE *fpstat = fopen(canonical_filename, "r");
    if (fpstat == NULL)
    {
        klog_err("文件%s打开失败:%s\n", canonical_filename, strerror(errno));
        goto err;
    }
    fseek(fpstat, 0, SEEK_SET);

    bzero(&result, sizeof(struct pstat));
    if (fscanf(fpstat, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu %lu %lu %*d %*d %*d %*d %llu %*u",
               &result.utime_ticks, &result.stime_ticks, &cutime, &cstime, &time1) == EOF)
    {
        fclose(fpstat);
        goto err;
    }

    struct timespec time2 = {0, 0};
    clock_gettime(CLOCK_MONOTONIC, &time2);

    long long t1, t2;
    t1 = (result.utime_ticks + result.stime_ticks) / HZ;
    t2 = time2.tv_sec - time1 / HZ;

    if (t2)
        *pcpu = (double)(100 * t1 / t2);
    fclose(fpstat);
    FREE(canonical_filename);
    return 0;

err:
    FREE(canonical_filename);
    return -1;
}

static int get_proc_running_time(pid_t pid, char *proc_time)
{
    char path[1024] = {0};
    char *t = NULL;
    char tt[1024] = {0};
    unsigned long long time1;
    unsigned long long seconds;
    char cp[240] = {0};
    char buff[240] = {0};
    if (!buff)
    {
        klog_err("内存申请失败:%s\n", strerror(errno));
        return -1;
    }

    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    snprintf(path, sizeof(path), "/proc/%d/stat", pid);
    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            return -1;
        }
        if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
        {
            FREE(canonical_filename);
            return -1;
        }
    }

    FILE *fpstat = fopen(canonical_filename, "r");
    if (fpstat == NULL)
    {
        goto err;
    }
    fseek(fpstat, 0, SEEK_SET);

    t = fgets(tt, sizeof(tt), fpstat);
    if (sscanf(t, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*u %*u %*d %*d %*d %*d %*d %*d %19llu %*u", &time1) == EOF)
    {
        fclose(fpstat);
        goto err;
    }
    fclose(fpstat);
    FREE(canonical_filename);

    time_t seconds_since_boot = uptime(0, 0);
    seconds = seconds_since_boot - (time1 / 100);

    unsigned dd, hh, mm, ss;
    ss = seconds % 60;
    seconds /= 60;
    mm = seconds % 60;
    seconds /= 60;
    hh = seconds % 24;
    seconds /= 24;
    dd = seconds;
    if (dd)
    {
        snprintf(cp, COLWID, "%u-", dd);
    }
    else
    {
        snprintf(cp, COLWID, "%u-", 0);
    }
    if (dd || hh)
    {
        snprintf(buff, COLWID, "%02u:", hh);
        strncat(cp, buff, sizeof(cp) - strnlen(cp, STRNLEN_MAX) - 1);
    }
    else
    {
        snprintf(buff, COLWID, "%02u:", 0);
        strncat(cp, buff, sizeof(cp) - strnlen(cp, STRNLEN_MAX) - 1);
    }
    memset(buff, 0, sizeof(buff));
    snprintf(buff, COLWID, "%02u:%02u", mm, ss);
    strncat(cp, buff, sizeof(cp) - strnlen(cp, STRNLEN_MAX) - 1);
    strncpy(proc_time, cp, 50);
    return 0;

err:
    FREE(canonical_filename);
    return -1;
}

static int get_proc_port(pid_t pid, char *proc_prot)
{
    unsigned long rxq, txq, time_len, retr, inode;
    int num, local_port, rem_port, d, state, uid, timer_run, timeout;
    char rem_addr[128], local_addr[128];
    FILE *fd = NULL;
    char line_buff[1024] = {0};
    char line[LINE_MAX];
    int lnamelen;
    char lname[30];
    unsigned long inode_num;
    DIR *dirfd = NULL;
    struct dirent *direfd;
    char path[100] = {0};

    char *canonical_filename = NULL;
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    snprintf(path, sizeof(path), "/proc/%d/fd", pid);
    if (path_size > 0)
    {
        canonical_filename = malloc(path_size);
        if (canonical_filename == NULL)
        {
            return -1;
        }
        if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
        {
            FREE(canonical_filename);
            return -1;
        }
    }

    dirfd = opendir(canonical_filename);
    if (!dirfd)
    {
        goto err;
    }

    while ((direfd = readdir(dirfd)))
    {
        snprintf(line, sizeof(line), "/proc/%d/fd/%s", pid, direfd->d_name);
        lnamelen = readlink(line, lname, sizeof(lname) - 1);
        if (lnamelen == -1)
            continue;
        lname[lnamelen] = '\0'; /*make it a null-terminated string*/

        if (extract_type_1_socket_inode(lname, &inode_num) < 0)
            if (extract_type_2_socket_inode(lname, &inode_num) < 0)
                continue;
        fd = fopen("/proc/net/tcp", "r");
        if (NULL == fd)
        {
            closedir(dirfd);
            goto err;
        }
        fseek(fd, 0, SEEK_SET);

        while (fgets(line_buff, sizeof(line_buff), fd))
        {
            num = sscanf(line_buff,
                         "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %*s\n",
                         &d, local_addr, &local_port, rem_addr, &rem_port, &state,
                         &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode);
            if (inode_num == inode)
            {
                snprintf(proc_prot, 20, "%d", local_port);
            }
            else
            {
                continue;
            }
        }
        fclose(fd);
    }
    FREE(canonical_filename);
    closedir(dirfd);
    return 0;

err:
    FREE(canonical_filename);
    return -1;
}

static int get_process_info(process_info *info, unsigned int *proc_num)
{
    DIR *dir;
    struct dirent *drd;
    struct stat buf;
    process_info *proc_info = info;
    char dirname[MAX_PF_NAME] = {0};

    char canonical_filename[PATH_MAX_PROC] = "\0";
    size_t path_size = 0;
    path_size = (size_t)PATH_MAX_PROC;

    int count = 0;
    *proc_num = 0;
    int i = 0;
    if ((dir = opendir(PROC_DIR)) == NULL)
        return -1;

    while ((drd = readdir(dir)) != NULL)
    {
        if (*proc_num >= MAX_PROC_NUM)
            break;
        if (isnumber(drd->d_name))
        {
            snprintf(dirname, sizeof(dirname), "%s/%s", PROC_DIR, drd->d_name);
            if (path_size > 0)
            {
                if (!realpath(dirname, canonical_filename) || !verify_file(canonical_filename))
                {
                    continue;
                }
            }

            if (stat(canonical_filename, &buf) < 0)
            {
                continue;
            }
            if (!S_ISDIR(buf.st_mode))
            {
                continue;
            }
            i++;
            memset(proc_info, 0, sizeof(process_info));
            sscanf(drd->d_name, "%ld", &(proc_info->proc_pid));
            get_proc_name(proc_info->proc_pid, proc_info->proc_name);

            get_proc_state(proc_info->proc_pid, &(proc_info->proc_state));

            get_proc_command(proc_info->proc_pid, proc_info->proc_command);

            get_proc_uid(proc_info->proc_pid, proc_info->proc_uid);

            get_proc_mem_usage_pct(proc_info->proc_pid, &(proc_info->proc_mem));

            get_proc_starttime(proc_info->proc_pid, proc_info->start_time);

            proc_info->utime = get_proc_cpu_time(proc_info->proc_pid);

            get_proc_cpu_pcpu(proc_info->proc_pid, &(proc_info->proc_cpu));

            get_proc_running_time(proc_info->proc_pid, proc_info->proc_time);

            get_proc_port(proc_info->proc_pid, proc_info->proc_port);

            proc_info++;
            ++count;
        }
    }
    *proc_num = i;
    closedir(dir);

    return 0;
}

char **kdk_get_process_all_information()
{
    process_info pp[PROC_NUM];
    unsigned int proc_num;
    char result[115200] = "\0";
    char tmp[115200] = "\0";
    size_t counts = 0;
    char **res = NULL;
    char **tmpres = NULL;
    int ret = get_process_info(pp, &proc_num);
    if (ret == 0)
    {
        for (int i = 0; i < proc_num; i++)
        {
            memset(result, 0, 115200 * sizeof(char));
            memset(tmp, 0, 115200 * sizeof(char));
            strncat(result, "process_id:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            snprintf(tmp, sizeof(tmp), "%ld", pp[i].proc_pid);
            strncat(result, tmp, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, "proc_name:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, pp[i].proc_name, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, "proc_command:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, pp[i].proc_command, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, "proc_uid:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            snprintf(tmp, sizeof(tmp), "%s", pp[i].proc_uid);
            strncat(result, tmp, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, "start_time:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, pp[i].start_time, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, "utime:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            snprintf(tmp, sizeof(tmp), "%ld", pp[i].utime);
            strncat(result, tmp, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, "proc_cpu:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            snprintf(tmp, sizeof(tmp), "%.2f", (double)pp[i].proc_cpu);
            strncat(result, tmp, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, "proc_mem:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            snprintf(tmp, sizeof(tmp), "%.2f", (double)pp[i].proc_mem);
            strncat(result, tmp, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, "proc_state:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            snprintf(tmp, sizeof(tmp), "%s", pp[i].proc_state);
            strncat(result, tmp, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, "proc_time:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            snprintf(tmp, sizeof(tmp), "%s", pp[i].proc_time);
            strncat(result, tmp, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, ", ", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            strncat(result, "proc_port:", sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            snprintf(tmp, sizeof(tmp), "%s", pp[i].proc_port);
            strncat(result, tmp, sizeof(result) - strnlen(result, STRNLEN_MAX) - 1);
            tmpres = realloc(res, (proc_num + 3) * sizeof(char *));
            if (!tmpres)
            {
                klog_err("内存申请失败:%s\n", strerror(errno));
                free(res);
                return NULL;
            }
            res = tmpres;
            res[counts] = malloc(115200 * sizeof(char) + 1);
            if (!res[counts])
            {
                free(tmpres);
                klog_err("内存申请失败:%s\n", strerror(errno));
                return NULL;
            }
            strncpy(res[counts], result, 115200);
            counts++;
        }
    }
    res[counts] = NULL;
    return res;
}

inline void kdk_proc_freeall(char **list)
{
    if (!list)
        return;
    size_t index = 0;
    while (list[index])
    {
        free(list[index]);
        index++;
    }
    free(list);
}

inline void kdk_proc_freeid(int *list)
{
    if (!list)
        return;
    free(list);
}

float kdk_get_process_kernel_modes_per(int pid)
{
    FILE *file = NULL;
    char path[128] = "\0";
    char buf[1024] = "\0";
    float ratio = 0.0;
    unsigned long long total_time; /* jiffies used by this process */
    unsigned long long utime;      // user time
    unsigned long long stime;      // kernel time

    // Read process stats
    snprintf(path, sizeof(path), "/proc/%d/stat", pid);
    file = fopen(path, "r");
    if (file == NULL)
    {
        return ratio;
    }
    if (fgets(buf, sizeof(buf) - 1, file) == NULL)
    {
        fclose(file);
        return ratio;
    }
    fclose(file);
    strstripspace(buf);

    // Parse the required fields
    sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*lu %*lu %*lu %*lu %*lu %llu %llu", &utime, &stime);
    total_time = utime + stime;
    ratio = (float)stime / total_time;
    return ratio;
}

float kdk_get_process_user_modes_per(int pid)
{
    FILE *file = NULL;
    char path[128] = "\0";
    char buf[1024] = "\0";
    float ratio = 0.0;
    unsigned long long total_time; /* jiffies used by this process */
    unsigned long long utime;      // user time
    unsigned long long stime;      // kernel time

    // Read process stats
    snprintf(path, sizeof(path), "/proc/%d/stat", pid);
    file = fopen(path, "r");
    if (file == NULL)
    {
        return ratio;
    }
    if (fgets(buf, sizeof(buf) - 1, file) == NULL)
    {
        fclose(file);
        return ratio;
    }
    fclose(file);
    strstripspace(buf);

    // Parse the required fields
    sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*lu %*lu %*lu %*lu %*lu %llu %llu", &utime, &stime);
    total_time = utime + stime;
    ratio = (float)utime / total_time;
    return ratio;
}

int extract_keyword_manual(const char *path, char *keyword, size_t size)
{
    const char *start = NULL;
    const char *end = NULL;
    const char *ptr = path;

    // 查找 "/opt/kare-applications/"
    const char *prefix = "/opt/kare-applications/";
    size_t prefix_len = strlen(prefix);

    start = strstr(ptr, prefix);
    if (!start)
    {
        return -1;
    }
    start += prefix_len;

    // 查找 "/merge" 或字符串结束
    const char *suffix = "/merge";
    end = strstr(start, suffix);
    if (!end)
    {
        // 如果没有找到 /merge，可能是路径结束或其他情况
        end = start + strlen(start);
    }

    // 提取关键字（直到遇到 '/' 或结束）
    const char *keyword_start = start;
    const char *keyword_end = end;

    // 可选：如果关键字中不应该包含 '/'
    const char *slash = strchr(start, '/');
    if (slash && slash < end)
    {
        keyword_end = slash;
    }

    size_t len = keyword_end - keyword_start;
    if (len >= size)
    {
        return -1; // 缓冲区太小
    }

    strncpy(keyword, keyword_start, len);
    keyword[len] = '\0';

    // 验证关键字不为空
    if (len == 0)
    {
        return -1;
    }

    return 0;
}

KdkRuntimeEnv kdk_get_process_runtime_env(int pid)
{
    KdkRuntimeEnv env = KDK_ENV_UNKNOWN;

    if (pid <= 0)
    {
        klog_err("无效的进程ID:%d\n", pid);
        return env;
    }

    env = _kdk_get_process_kare_env(pid);
    if (env != KDK_ENV_UNKNOWN)
    {
        return env;
    }
    env = _kdk_get_process_kaiming_env(pid);

    return env;
}

int kdk_open_process_debug_terminal(int pid)
{
    char deb_name[1024] = "\0";
    int ret = 0;

    if (pid <= 0)
    {
        klog_err("无效的进程ID:%d\n", pid);
        return -1;
    }

    int ppid = get_ppid(pid);
    if (ppid <= 0)
    {
        klog_err("获取父进程ID失败, pid:%d\n", pid);
        return -1;
    }

    KdkRuntimeEnv env = kdk_get_process_runtime_env(pid);

    switch (env)
    {
    case KDK_ENV_KAIMING:
    {
        // 使用 snprintf 防止格式化字符串溢出，添加输入验证
        char grep_cmd[512];
        snprintf(grep_cmd, sizeof(grep_cmd), "/usr/bin/kaiming ps | grep -i %d | awk '{print $1}'", ppid);

        FILE *fp = popen(grep_cmd, "r");
        if (!fp)
        {
            klog_err("执行命令失败: %s, errno:%d (%s)\n", grep_cmd, errno, strerror(errno));
            return -1;
        }

        if (fgets(deb_name, sizeof(deb_name), fp) == NULL)
        {
            klog_err("读取命令输出失败\n");
            pclose(fp);
            return -1;
        }
        pclose(fp);

        strstripspace(deb_name);

        // 验证 deb_name 是否为空
        if (strlen(deb_name) == 0)
        {
            klog_err("未获取到有效的容器名称\n");
            return -1;
        }
    }
    break;

    case KDK_ENV_KARE_SHADOW:
    case KDK_ENV_KARE_V10SP1:
    {
        char path[256], exec[256];
        memset(exec, 0, sizeof(exec));

        snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
        FILE *fp = fopen(path, "r");
        if (!fp)
        {
            klog_err("打开文件失败: %s, errno:%d (%s)\n", path, errno, strerror(errno));
            return -1;
        }

        // cmdline 使用 null 字节分隔参数，只读取第一个参数（可执行文件名）
        if (fgets(exec, sizeof(exec), fp) == NULL)
        {
            klog_err("读取 cmdline 失败\n");
            fclose(fp);
            return -1;
        }
        fclose(fp);

        // 验证 exec 是否为空
        if (strlen(exec) == 0)
        {
            klog_err("进程 cmdline 为空\n");
            return -1;
        }

        char *rets = NULL;
        extern char *const *environ;
        const char *kare_argv[] = {"/usr/bin/kare", "-S", exec, NULL};

        ret = _execve_cmd_pipe("/usr/bin/kare", kare_argv, environ, read_kare_deb_name, &rets);
        if (ret != 0)
        {
            klog_err("执行命令失败: %s, errno:%d (%s)\n", kare_argv[0], errno, strerror(errno));
            if (rets)
                free(rets);
            return -1;
        }

        if (!rets)
        {
            klog_err("命令执行成功但未获取到输出\n");
            return -1;
        }

        // klog_info("获取到的 deb_name: %s\n", rets);

        strncpy(deb_name, rets, sizeof(deb_name) - 1);
        deb_name[sizeof(deb_name) - 1] = '\0';
        free(rets);
        rets = NULL;

        strstripspace(deb_name);

        char *p = strstr(deb_name, ":");
        if (p != NULL)
        {
            *p = '\0';
        }
        else
        {
            klog_warning("未在 deb_name 中找到冒号分隔符: %s\n", deb_name);
        }

        // 验证 deb_name 是否为空
        if (strlen(deb_name) == 0)
        {
            klog_err("未获取到有效的调试会话名称\n");
            return -1;
        }
    }
    break;

    case KDK_ENV_HOST:
    default:
        klog_warning("不支持的运行时环境: %d, pid:%d\n", env, pid);
        return -1;
    }

    // 获取当前环境变量
    extern char *const *environ;

    // 子进程:执行命令
    const char *argv[6] = {"mate-terminal", "-x", NULL, NULL, NULL, NULL};
    if (env == KDK_ENV_KAIMING)
    {
        argv[2] = "kaiming";
        argv[3] = "enter";
        argv[4] = deb_name;
    }
    else
    {
        argv[2] = "kare";
        argv[3] = "inspect";
        argv[4] = deb_name;
    }

    _execve_cmd("/usr/bin/mate-terminal", argv, environ);

    return ret;
}
