如何使用 LKM 在 C 程序中创建 Linux Proc 文件
【摘要】 Proc 文件系统反映了 Linux 内核的当前状态。
内核的当前状态可以代表各种信息,例如在其上运行的进程、硬件信息、网络信息等。因此,该系统的设计方式使所有这些信息都可以很容易地被用户级进程访问。
Proc 文件系统反映了 Linux 内核的当前状态。
内核的当前状态可以代表各种信息,例如在其上运行的进程、硬件信息、网络信息等。因此,该系统的设计方式使所有这些信息都可以很容易地被用户级进程访问。
我们也说 proc 文件系统是一个伪文件系统。这是因为,当访问这些文件时,此文件系统中的文件会加载信息,并且此文件系统中的文件通常显示大小为零的原因。
在您的系统上执行 ls /proc ,您会注意到类似于以下内容:
$ ls /proc
1 15 1681 1719 35 60 713 878 cgroups 文件系统 kpageflags pagetypeinfo sysrq-trigger ....
所以我们看到这个文件系统包含文件和目录。文件或目录的名称是字母或数字。数字文件或目录名称大多对应于系统上运行的进程,数字代表进程的进程ID。因此,通过使用进程 ID 并打开相应的文件,可以很容易地了解任何进程的内核级信息。
创建过程文件
在关于Linux 内核模块的文章中,我们讨论了如何创建、加载和卸载 LKM。这是在运行时向 linux 内核添加更多功能的基本概念。Proc 文件的工作原理相同。每个 proc 文件都以 LKM 的形式创建、加载和卸载。
在下面的代码中,我们尝试创建一个 proc 文件并定义它的读写能力。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#define MAX_LEN 4096
int read_info( char *page, char **start, off_t off,int count, int *eof, void *data );
ssize_t write_info( struct file *filp, const char __user *buff,unsigned long len, void *data );
static struct proc_dir_entry *proc_entry;
static char *info;
static int write_index;
static int read_index;
int init_module( void )
{
int ret = 0;
info = (char *)vmalloc( MAX_LEN );
memset( info, 0, MAX_LEN );
proc_entry = create_proc_entry( "procEntry123", 0644, NULL );
if (proc_entry == NULL)
{
ret = -1;
vfree(info);
printk(KERN_INFO "procEntry123 could not be created\n");
}
else
{
write_index = 0;
read_index = 0;
proc_entry->read_proc = read_info;
proc_entry->write_proc = write_info;
printk(KERN_INFO "procEntry123 created.\n");
}
return ret;
}
void cleanup_module( void )
{
remove_proc_entry("procEntry123", proc_entry);
printk(KERN_INFO "procEntry123 unloaded.\n");
vfree(info);
}
ssize_t write_info( struct file *filp, const char __user *buff, unsigned long len, void *data )
{
int capacity = (MAX_LEN-write_index)+1;
if (len > capacity)
{
printk(KERN_INFO "No space to write in procEntry123!\n");
return -1;
}
if (copy_from_user( &info[write_index], buff, len ))
{
return -2;
}
write_index += len;
info[write_index-1] = 0;
return len;
}
int read_info( char *page, char **start, off_t off, int count, int *eof, void *data )
{
int len;
if (off > 0)
{
*eof = 1;
return 0;
}
if (read_index >= write_index)
read_index = 0;
len = sprintf(page, "%s\n", &info[read_index]);
read_index += len;
return len;
}
在上面的代码中:
- 在 init_module 函数中,我们使用“create_proc_entry”函数创建了一个名为“procEntry123”的 proc 文件
- 该文件是使用 create_proc_entry 函数的第二个参数所描述的适当权限创建的。
- 读写proc文件时使用了两个函数read_info和write_info。
- 这两个函数的地址分配给 proc_dir_entry 结构的成员。
- 完成上述步骤是为了让代码知道在读取和写入 proc 文件时要调用哪个函数。
- 在 write_info 函数中,如果缓冲区有写入容量,则使用函数 copy_from_user 将字符串从用户空间复制到内核模块分配的内存缓冲区。
- 在函数 read_info 中,缓冲区中存在的信息被发送回用户空间。
上述代码的 Makefile 如下所示:
$ cat Makefile
obj-m += proc.o
all:
sudo make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
sudo make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
现在,当编译上面的代码时,我们看到:
$ make
sudo make -C /lib/modules/2.6.32-21-generic/build M=/home/himanshu modules
make: Entering directory `/usr/src/linux-headers-2.6.32-21-generic'
CC [M] /home/himanshu/proc.o
/home/himanshu/proc.c: In function ‘init_module’:
/home/himanshu/proc.c:33: warning: assignment from incompatible pointer type
Building modules, stage 2.
MODPOST 1 modules
LD [M] /home/himanshu/proc.ko
make: Leaving directory `/usr/src/linux-headers-2.6.32-21-generic'
代码编译成功后,通过以下命令插入并加载模块:
$ sudo insmod proc.ko
插入后,如果我们看到 proc 目录,我们会找到一个条目 'procEntry123'
$ ls /proc/procEntry123
/proc/procEntry123
现在,如果我们尝试读写它:
$ echo "TGS" > /proc/procEntry123
$ cat /proc/procEntry123
TGS
所以我们看到我们能够读取和写入 proc 文件。以同样的方式实现所有标准 proc 文件。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)