proc文件系统:3.single_xxxx接口


二、实验

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
发布了461 篇原创文章 · 获赞 183 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/sandalphon4869/article/details/104782496