赞
踩
编写一个内核模块,打印系统中各进程的PID和进程名字,同时统计系统中进程个数。
tip:需要用上list_for_each()和list_entry()内核函数
下面这篇文章也可以进行参考
Linux内核模块编程(列出系统中所有内核线程的程序名、PID 号、进程状态及进程优先级、父进程的PID)-CSDN博客
list_for_each() 和 list_entry() 是 Linux 内核中用于遍历和访问链表的常用函数。
list_for_each() 函数是一个宏定义,它使用 C 语言中的 for 循环来遍历链表中的每个节点。该宏的参数包括当前节点指针以及链表头指针
- struct list_head *pos;
- list_for_each(pos, &my_list)
- {
- // 对当前节点进行操作
- }
在每次循环迭代时,pos 指针会自动从链表头开始向后移动,直到遍历完整个链表。你可以使用 list_entry() 函数来获取当前节点的数据结构指针
- struct my_data *data;
- list_for_each(pos, &my_list)
- {
- data = list_entry(pos, struct my_data, list);
- // 使用 data 进行操作
- }
在上面的示例中,list_entry() 函数会将 pos 转换为一个指向 struct my_data 数据结构的指针,并返回该指针。其中,struct my_data 是链表中每个节点所包含的数据结构类型,list 则是该数据结构中用于嵌入链表的字段名。
需要注意的是,在使用 list_for_each() 和 list_entry() 函数遍历和访问链表时,必须确保链表头节点不包含任何数据,仅作为链表起点使用。另外,链表的节点结构需要包含一个 list_head 类型的字段,以便在链表中链接不同的节点。
num.c
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/sched.h>
- #include <linux/init_task.h>
- #include <linux/list.h>
-
- int hello_init(void)
- {
- struct task_struct *task;
- int num_process = 0;
-
- printk(KERN_INFO "Printing process information:\n");
- list_for_each_entry(task, &init_task.tasks, tasks)
- {
- printk(KERN_INFO "PID: %d, Name: %s\n", task->pid, task->comm);
- num_process++;//进程计数器
- }
-
- printk(KERN_INFO "Total number of processes: %d\n", num_process);
-
- return 0;
- }
-
- void hello_exit(void)
- {
- printk(KERN_INFO "Exiting module.\n");
- }
-
- module_init(hello_init);
- module_exit(hello_exit);
-
- MODULE_LICENSE("GPL");
- MODULE_DESCRIPTION("Print process information module");
Makefile
- obj-m:=num.o
- CURRENT_PATH := $(shell pwd)
- LINUX_KERNEL := $(shell uname -r)
- LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)
-
- all:
- make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
- clean:
- make -C $(LINUX_KERNEL_PATH) M=$ (CURRENT_PATH) clean
sudo insmod num.ko
dmesg
打印输出了进程号,以及进程名字,最后一次次遍历,统计进程数量
make的时候出现,
make: Nothing to be done for `all'.
在网上找到的资料都显示是重复编译等问题,但其实还有可能用gpt写Makefile文件的时候,因为没有正确缩进,所以显示错误。和这个错误的原因可能是一样的Makefile:18: *** missing separator. Stop.
第二个问题是
Invalid module format,也就是显示无效的模块格式,以下是几种原因
模块版本不匹配:模块的编译版本与当前运行的内核版本不兼容。请确保你正在使用的模块是针对当前内核版本编译的。尝试重新编译模块并确保编译过程中没有出现任何错误。
模块依赖关系问题:模块可能依赖于其他模块或库文件,而这些依赖关系可能出现问题。请检查模块的依赖关系,并确保所有依赖项都已正确安装和配置。
模块文件损坏:模块文件本身可能已损坏。尝试重新下载或获取正确的模块文件,并再次尝试加载。
内核配置不正确:内核可能未正确配置以支持加载该模块。请确保你的内核配置包括相关功能和选项,以便正确加载模块。
但我检查了很多遍,模块版本是能对上的,可能就只是我的模块内核损坏了?就重新去make其他的文件,发现也是这个错误。。。后面用的是14.04版本的虚拟机。
sy.c
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/init_task.h>
- // 初始化函数
- static int hello_init(void)
- {
- struct task_struct *task;
- int num_process=0;//统计进程数量
- printk(KERN_ALERT"名称\t进程号\t状态\t优先级\t父进程号\t");
-
- for_each_process(task)
- {
- if (task->mm == NULL)
- {
- printk(KERN_INFO "%s\t%d\t%d\t%d\t%d\n", task->comm, task->pid, task->prio, task->normal_prio, task->parent->pid);
- num_process++;
-
- }
- }
- printk("%d\n",num_process);
-
-
- return 0;
- }
- // 清理函数
- static void hello_exit(void)
- {
- printk(KERN_ALERT"goodbye!\n");
- }
-
- // 函数注册
- module_init(hello_init);
- module_exit(hello_exit);
-
- // 模块许可申明
- MODULE_LICENSE("GPL");
Makefile
- obj-m += sy.o
-
- all:
- make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
-
- clean:
- make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
这两段代码也可以进行进程的输出,但是没有用上对应的内核函数
这两段代码就是参考的最最最前面的文章的,就只是加了一个进程计数器
但存在一个问题,两个程序显示的进程数量不一样
pgrep -l . | wc -l //列出所有进程的信息
ps aux | grep -v "^USER" | wc -l //
grep -v "^USER"
用于过滤掉ps
命令输出中的表头信息ps aux | wc -l
这三个命令都可以来统计并输出进程数量,wc -I 用来统计行数
所以还是前面的靠谱一点,毕竟数量匹配更相近
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。