文章目录
二、实验
1.内容
Proc文件系统实践
2.过程
(1)编写内核模块.c文件
mkdir project && cd project
gedit catkinModule.c
#include <linux/init.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/module.h> // 模块
#include <linux/fs.h> // 文件系统
#include <linux/proc_fs.h> // proc_fs定义
#include <linux/seq_file.h> // seq_file接口
#include <linux/uaccess.h> // copy_to_user() & copy_from_user
// DataType结构体类型,
typedef struct
{
int data1;
int data2;
} DataType;
// my_data结构体类型
struct my_data
{
int len;
char str[128];
};
// my_data型的mdata变量
static struct my_data mdata = {
0,
};
// DataType型的data变量
static DataType data[2];
// proc的结点
static struct proc_dir_entry *procdir;
static int test_proc_show(struct seq_file *m, void *v)
{
DataType *pData = (DataType *)m->private;
if (pData != NULL)
{
// 打印DataType类型的两个值
seq_printf(m, "%d----%d\n", pData->data1, pData->data2);
if (mdata.len > 0)
{
seq_printf(m, "%s\n", mdata.str);
}
}
return 0;
}
static int test_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, test_proc_show, PDE(inode)->data);
}
static ssize_t test_proc_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
{
if (count < 128)
{
copy_from_user(mdata.str, buf, count);
mdata.len = count;
return count;
}
else
{
copy_from_user(mdata.str, buf, 127);
mdata.len = 127;
return 127;
}
}
// file_operations结构体函数
static const struct file_operations dl_file_ops = {
.owner = THIS_MODULE,
.open = test_proc_open,
.write = test_proc_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
// module_init()内的初始化函数。
static int __init test_module_init(void)
{
printk("[test]: module init\n");
// 创建文件目录 /proc/test
procdir = proc_mkdir("test", NULL);
// 创建失败
if (!procdir)
{
printk("create directory error!\n");
return 0;
}
data[0].data1 = 1;
data[0].data2 = 2;
// 在/proc/test目录下创建proc_test1节点
proc_create_data("proc_test1", 0644, procdir, &dl_file_ops, &data[0]);
data[1].data1 = 3;
data[1].data2 = 4;
// 在/proc/test目录下创建proc_test2节点
proc_create_data("proc_test2", 0644, procdir, &dl_file_ops, &data[1]);
return 0;
}
// module_exit()内的退出函数。
static void __exit test_module_exit(void)
{
/* 先删结点,删完后成空目录再删目录 */
// 删除/proc/test下的文件结点proc_test1
remove_proc_entry("proc_test1", procdir);
// 删除/proc/test下的文件结点proc_test2
remove_proc_entry("proc_test2", procdir);
// 删除/proc下的目录test
remove_proc_entry("test", NULL);
printk("[test]: module exit\n");
}
module_init(test_module_init);
module_exit(test_module_exit);
// 内核模块描述
MODULE_DESCRIPTION("a simple driver module");
// GPL协议证书
MODULE_LICENSE("GPL");
(2)编写Makefile文件
gedit Makefile
obj-m := catkinModule.o
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order Module.symvers
(3)编译
make
PS:
如果重新编译的话,要把之前残留的垃圾删除(试过不管这些垃圾也能编译成功,但编辑结果还是原来的就很气)
# 清理垃圾
make clean
# 编译
make
(4)安装模块:
先清理一下缓存,不然一会就可能输出一大堆多余东西,影响到我们想要看到的输出东西
sudo dmesg -c
安装
sudo insmod catkinModule.ko
查看printk
的输出在缓冲区的信息:
sudo dmesg
(5)交互proc文件
储存字符串的数组是共享的,所以一变都变。
cd /proc
cd test
echo "hello" > proc_test1
cat proc_test1
cat proc_test2
echo "world" > proc_test2
cat proc_test1
cat proc_test2
(6)卸载模块:
sudo rmmod catkinModule
(7)清除printk
输出在缓存区的信息:
sudo dmesg -c