操作系统实验八

本文详细描述了如何通过编写C语言内核模块在Linux系统中创建proc文件,并实现文件的读写功能,涉及系统调用、模块加载及管理。实验内容包括创建目录、文件和链接,以及读写操作的处理函数。
摘要由CSDN通过智能技术生成

实验8 创建proc文件

一、实验目的

通过添加一个功能为创建proc文件的内核模块,进一步理解系统调用的相关知识。

二、实验内容

通过加载内核模块,为/proc文件路径下创建以下内容:

  • 一个名叫proc_test的子目录。一个名叫current的文件,只读,读出的内容是读它的进程的情况。

  • 一个名叫current_too的链接,指向current

  • 一个名叫hello的文件,读出加入其中的文件。

三、实验内容

编写相关内核模块的C语言代码如下

#define    __KERNEL__
#define MODULE

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
//以上几行是模块必须包含的头文件和宏,不需要深究

#define STRINGLEN      1024

char global_buffer[STRINGLEN];    //这里申请了一块大小为1024的内存
struct proc_dir_entry *example_dir, *hello_file, *current_file, *symlink;
struct proc_dir_entry *my_dir, *DXH_file, *
xxxxxxxx_file,*xxxxxxxxsym;

int proc_read_current(char *page, char **start, off_t off, int count, int *eof,
                      void *data) {    //当用户读取"current"文件的内容时,内核调用这个函数
    int len;
    MOD_INC_USE_COUNT;    //模块引用计数增加1,保证模块不会被卸载
    len = sprintf(page, "current process usages:\nname:%s\ngid:%d\npid:%d\n", current->comm, current->pgrp,
                  current->pid);
    //告诉用户,读出的文件内容是一行字符串,说明了当前进程的名字和pid等等。
    MOD_DEC_USE_COUNT;    //模块引用计数减1。
    return len;
}

int proc_read_hello(char *page, char **start, off_t off, int count, int *eof
                    , void *data) {    //当用户读取"hello"文件的内容时,内核调用这个函数
    int len;

    MOD_INC_USE_COUNT;
    len = sprintf(page, "hello message:\n%s write:%s\n", current->comm, global_buffer);
    //给global_buffer(前面申请的1024大小的内存)的前面加上两行文字,作为用户读出的内容
    MOD_DEC_USE_COUNT;

    return len;
}

static int proc_write_hello(struct file *file, const char *buffer, unsigned long count,
                            void *data) {    //当用户写"hello"文件的内容时,内核调用这个函数
    int len;

    MOD_INC_USE_COUNT;
    if (count > STRINGLEN)        //如果要写的内容多于1024个字符,就把多出来的部分截断
        len = STRINGLEN;
    else
        len = count;

    copy_from_user(global_buffer, buffer, len);    //从用户的缓冲区获得要写的数据,注意必须用copy_from_user
    global_buffer[len] = '\0';    //给字符串后面加一个0,表示字符串结束

    MOD_DEC_USE_COUNT;
    return len;
}

int proc_read_DXH(char *page, char **start, off_t off, int count, int *eof, void *data) {    //当用户读取"csy"文件的内容时,内核调用这个函数
    int len;
    MOD_INC_USE_COUNT;    //模块引用计数增加1,保证模块不会被卸载
    len = sprintf(page, "current process usages:\nname:%s\ngid:%d\npid:%d\n", current->comm, current->pgrp,
                  current->pid);
    //告诉用户,读出的文件内容是一行字符串,说明了当前进程的名字和pid等等。
    MOD_DEC_USE_COUNT;    //模块引用计数减1。
    return len;
}

int proc_read_xxxxxxxx(char *page, char **start, off_t off, int count, int *eof,
                       void *data) {    //当用户读取"f20182642"文件的内容时,内核调用这个函数
    int len;

    MOD_INC_USE_COUNT;
    len = sprintf(page, "hello message:csy write:hello!%s\n", global_buffer);
    //给global_buffer(前面申请的1024大小的内存)的前面加上两行文字,作为用户读出的内容
    MOD_DEC_USE_COUNT;

    return len;
}

static int proc_write_xxxxxxxx(struct file *file, const char *buffer, unsigned long count,
                               void *data) {    //当用户写"hello"文件的内容时,内核调用这个函数
    int len;
    MOD_INC_USE_COUNT;
    if (count > STRINGLEN)        //如果要写的内容多于1024个字符,就把多出来的部分截断
        len = STRINGLEN;
    else
        len = count;

    copy_from_user(global_buffer, buffer, len);    //从用户的缓冲区获得要写的数据,注意必须用copy_from_user
    global_buffer[len] = '\0';    //给字符串后面加一个0,表示字符串结束

    MOD_DEC_USE_COUNT;
    return len;
}

int init_module() {    //这是我们熟悉的init_module函数,将会在加载模块的时候被调用,我们需要在加载模块的时候创建proc文件
    example_dir = proc_mkdir("proc_test", NULL);
    example_dir->owner = THIS_MODULE;    //创建目录(相当于Windows的文件夹) /proc/proc_test
    xxxxxxxx_dir = proc_mkdir("xxxxxxxx", example_dir);
    xxxxxxxx_dir->owner = THIS_MODULE;

    current_file = create_proc_read_entry("current", 0666, example_dir, proc_read_current, NULL);
    current_file->owner = THIS_MODULE;    //创建只读文件  /proc/proc_test/current

    hello_file = create_proc_entry("hello", 0644, example_dir);
    strcpy(global_buffer, "hello");
    hello_file->read_proc = proc_read_hello;
    hello_file->write_proc = proc_write_hello;
    hello_file->owner = THIS_MODULE;    //创建一个可以读写的文件 /proc/proc_test/hello
    symlink = proc_symlink("current_too", example_dir, "current");
    symlink->owner = THIS_MODULE;    //创建一个链接(相当于Windows的快捷方式)/proc/proc_test/current_too,指向current

    csy_file = create_proc_read_entry("DXH", 0666, xxxxxxxx_dir, proc_read_csy, NULL);
    csy_file->owner = THIS_MODULE;
    xxxxxxxx_file = create_proc_entry("xxxxxxxx", 0644, xxxxxxxx_dir);
    strcpy(global_buffer, "xxxxxxxx");
    xxxxxxxx_file- > read_proc = proc_read_f20182642;
    xxxxxxxx_file- > write_proc = proc_write_f20182642;
    xxxxxxxx_file- > owner = THIS_MODULE;
    xxxxxxxxsym = proc_symlink("xxxxxxxx_too", xxxxxxxx_dir, "xxxxxxxx_too");
    xxxxxxxxsym->owner = THIS_MODULE;
    return 0;
}

void cleanup_module() {    //要卸载模块了,因此需要把创建的目录和文件都清除掉。
    remove_proc_entry("current_too", example_dir);
    remove_proc_entry("hello", example_dir);
    remove_proc_entry("current", example_dir);
    remove_proc_entry("proc_test", NULL);

    remove_proc_entry("xxxxxxxx_too", xxxxxxxx_dir);
    remove_proc_entry("xxxxxxxx", xxxxxxxx_dir);
    remove_proc_entry("xxxxxxxx", xxxxxxxx_dir);
    remove_proc_entry("xxxxxxxx", NULL);
}

编译程序

gcc -c -I/usr/src/linux-2.4.20-8/include  proc_test.c

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

查看所有已添加的系统调用

lsmod

可见名为proc_test的模块已经被加入

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

进入相应目录,可以看到文件已经创建

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

四、实验结果

使用命令在对应目录下读取文件

more hello

可以看到代码中的文字输出在控制台中,这是由于该模块将前文C程序代码中的字符串写入了对应文件夹的对应位置,因此能够被读取文件的命令顺利读取出来.

hello文件

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其他文件

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

五、实验心得

本次实验实现了编写内核模块,并利用它实现增加文件、写入信息的功能。完成本次实验需要有一定的C语言功底,并且需要对Linux下的函数和功能实现有一定了解。

本次实验仅仅是在模板代码的基础上实现了一些最基本的功能,要完整的理解岁所有的代码,编写出更复杂的系统模块,还需要付出更多的时间来进行Linux系统以及C语言编程的学习和实践。

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值