【操作系统】实验八 proc文件系统

news2024/11/17 9:55:35

🕺作者: 主页

我的专栏
C语言从0到1
探秘C++
数据结构从0到1
探秘Linux

😘欢迎关注:👍点赞🙌收藏✍️留言

🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要,有问题可在评论区提出,感谢支持!!!

文章目录

  • 实验八
      • 实验目的
      • 实验准备
      • 编译内核模块
      • 加载内核模块
      • 查看和操作文件内容
      • 卸载内核模块

实验八

实验目的

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

  • 一个名叫proc_test的子目录。
  • 一个名叫current的文件,只读,读出的内容是读它的进程的情况。
  • 一个名叫current_too的链接,指向current。
  • 一个名叫hello的文件,可读可写。读出的内容是上次写的内容前面加两句话。

实验准备

  1. 复制文件到工作目录:
    • 使用将 proc_test.c 文件复制到工作目录。

  1. 进入工作目录:
    • 进入工作目录。

编译内核模块

  1. 编译 proc_test.c 模块:
    • 编写proc_test.c代码
#include <linux/sched.h>
#include <linux/init_task.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>

#define MAX_LENGTH 1024

static char hello_content[MAX_LENGTH] = "hello world\n";  // 初始化一个长度为 1024 的字符数组,并赋值 "hello world\n"


//用于处理对 /proc/proc_test/hello 文件的写操作。它从用户空间接收数据并将其复制到内核空间的 hello_content 数组中,偏移量为12。如果写入的字符数超过了数组长度,会返回错误。
static ssize_t hello_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) {
    if (count > MAX_LENGTH - 1)  // 如果写入的字符数大于 MAX_LENGTH - 1,则返回错误
        return -EINVAL;
    if (copy_from_user(hello_content + 12, buffer, count))  // 将用户空间的数据复制到内核空间的 hello_content 数组中,偏移量为 12
        return -EFAULT;
    hello_content[count + 12] = '\0';  // 在 hello_content 数组中写入字符串结束符'\0'
    return count;  // 返回成功写入的字符数
}
//用于处理对 /proc/proc_test/hello 文件的读操作。它将 hello_content 的内容输出到 seq_file 结构体中,从而在读取文件时显示出来。
static int hello_proc_show(struct seq_file *m, void *v) {
    seq_printf(m, "%s", hello_content);  // 将 hello_content 的内容输出到 seq_file 结构体 m 中
    return 0;
}
//用于打开 /proc/proc_test/hello 文件。它调用 single_open 函数来打开文件,并指定 hello_proc_show 函数来显示文件内容。
static int hello_proc_open(struct inode *inode, struct file *file) {
    return single_open(file, hello_proc_show, NULL);  // 打开 proc 文件,调用 hello_proc_show 函数来显示内容
}
//定义了对 /proc/proc_test/hello 文件的操作集合,包括打开、读取、写入、定位和释放文件。
static const struct proc_ops hello_proc_ops = {
    .proc_open = hello_proc_open,  // 打开文件操作
    .proc_read = seq_read,  // 读取文件操作
    .proc_write = hello_proc_write,  // 写文件操作
    .proc_lseek = seq_lseek,  // 文件定位操作
    .proc_release = single_release,  // 释放文件操作
};
//用于处理对 /proc/proc_test/current 文件的读操作。它输出当前进程的相关信息,如进程ID、优先级、进程名等。
static int current_proc_show(struct seq_file *m, void *v) {
    struct task_struct *cur = current;

    seq_printf(m, "进程ID: %d\n", cur->pid);  // 输出进程ID
    seq_printf(m, "优先级: %d\n", cur->prio);  // 输出进程优先级
    seq_printf(m, "静态优先级: %d\n", cur->static_prio);  // 输出静态优先级
    seq_printf(m, "正常优先级: %d\n", cur->normal_prio);  // 输出正常优先级
    seq_printf(m, "策略: %d\n", cur->policy);  // 输出进程调度策略
    seq_printf(m, "进程名: %s\n", cur->comm);  // 输出进程名

    return 0;
}
//用于打开 /proc/proc_test/current 文件。它调用 single_open 函数来打开文件,并指定 current_proc_show 函数来显示文件内容。
static int current_proc_open(struct inode *inode, struct file *file) {
    return single_open(file, current_proc_show, NULL);  // 打开 proc 文件,调用 current_proc_show 函数来显示内容
}
// 定义了对 /proc/proc_test/current 文件的操作集合,包括打开、读取、定位和释放文件。
static const struct proc_ops current_proc_ops = {
    .proc_open = current_proc_open,  // 打开文件操作
    .proc_read = seq_read,  // 读取文件操作
    .proc_lseek = seq_lseek,  // 文件定位操作
    .proc_release = single_release,  // 释放文件操作
};
//模块的初始化函数,它在内核加载模块时被调用。它创建了一个名为 /proc/proc_test 的目录,并在其中创建了文件 current、current_too 和 hello。
static int __init proc_test_init(void) {
    struct proc_dir_entry *test_dir;

    test_dir = proc_mkdir("proc_test", NULL);  // 创建一个目录 /proc/proc_test
    proc_create("current", 0, test_dir, &current_proc_ops);  // 在 /proc/proc_test 目录下创建一个名为 "current" 的文件
    proc_symlink("current_too", test_dir, "current");  // 在 /proc/proc_test 目录下创建一个名为 "current_too" 的符号链接,指向 "current"
    proc_create("hello", 0666, test_dir, &hello_proc_ops);  // 在 /proc/proc_test 目录下创建一个名为 "hello" 的文件,可读可写权限为 0666

    return 0;
}
//模块的退出函数,它在内核卸载模块时被调用。它移除了之前创建的 /proc/proc_test 目录及其下的文件。
static void __exit proc_test_exit(void) {
    remove_proc_entry("proc_test/current", NULL);  // 移除 /proc/proc_test 目录下的文件 "current"
    remove_proc_entry("proc_test/current_too", NULL);  // 移除 /proc/proc_test 目录下的文件 "current_too"
    remove_proc_entry("proc_test/hello", NULL);  // 移除 /proc/proc_test 目录下的文件 "hello"
    remove_proc_entry("proc_test", NULL);  // 移除 /proc/proc_test 目录
}

MODULE_LICENSE("GPL");  // 指定模块的许可证为 GPL
module_init(proc_test_init);  // 指定模块的初始化函数
module_exit(proc_test_exit);  // 指定模块的退出函数
  • 使用makefile文件编译内核模块。
obj-m:=proc_test.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD       := $(shell pwd)
default:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  • 使用make命令编译

make

加载内核模块

  1. 加载编译后的模块:
    • 使用insmod加载模块。

insmod proc_test.ko

  1. 检查是否加载成功:
  • 使用lsmod命令检查模块是否加载。

lsmod | grep proc_test

  1. 检查是否创建了 /proc/proc_test 目录:
    • 进入/proc目录查看。
cd /proc
ls

  1. 检查 /proc/proc_test 目录下是否创建了三个文件:
    • current、current_too 和 hello。
cd /proc/proc_test
ls

查看和操作文件内容

  1. 查看 current 文件的内容:
    • 使用more命令查看。

more current

  1. 查看 current_too 文件的内容:
    • 使用more命令查看。

more current_too

  1. 查看 hello 文件的内容:
    • 使用more命令查看。

more hello

  1. 写入 hello 文件:
    • 使用echo命令将数据输入到hello文件。

  1. 再次查看 hello 文件的内容:
    • 使用more命令查看。

more hello

卸载内核模块

  1. 卸载加载的内核模块:
    • 使用rmmod卸载模块。

rmmod proc_test

  1. 检查是否卸载成功:
    • 使用lsmod命令检查模块是否卸载。

lsmod | grep proc_test

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1410414.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

破解不了WIFI?也许你应该试试社工...

以下案例为虚拟环境,请勿模仿 做什么? 由于工作出差在该某某企业出差,手机和电脑都没办法用流量…流量包1G1块…太贵了…我勒个豆啊…发现WIFI密码难以破解&#xff08;小kali上过了&#xff09;。 出去逛逛吧…发现楼道有海康威视摄像头,学过交换机的一般都看得出来这个摄像…

jquery多选框

使用hbuilder <!DOCTYPE html> <html><head><meta charset"GBK"><title></title></head><body><table id"myTable"> <tr> <td>黄1</td> </tr> <tr> <td>…

C语言通过IXMLHttpRequest以get或post方式发送http请求获取服务器文本或xml数据

做过网页设计的人应该都知道ajax。 Ajax即Asynchronous Javascript And XML&#xff08;异步的JavaScript和XML&#xff09;。使用Ajax的最大优点&#xff0c;就是能在不更新整个页面的前提下维护数据。这使得Web应用程序更为迅捷地回应用户动作&#xff0c;并避免了在网络上发…

计算机网络——网络层(1)

计算机网络——网络层(1&#xff09; 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU) 网络层&#xff1a;数据平面网络层概述核心功能协议总结 路由器工作原理路由器的工作步骤总结 网际协议IPv4主要特点不足IPv6主要特点现状 通用转发和SDN通用转发SDN&#xff08;软件…

《WebKit技术内幕》学习之十三(3):移动WebKit

3 其他机制 3.1 新渲染机制 为了移动领域更好的用户体验&#xff0c;渲染机制所做的改进主要是提升渲染性能来增加响应的速度&#xff0c;甚至不惜牺牲一些跟规范定义的行为不一致的地方。在这一小节中主要介绍三个方面的技术&#xff0c;其一是Tiled Backing Store&#x…

【LLM】FuseLLM:大模型融合trick-知识融合LLMs

前言 传统的模型融合方法分为集成的方法和权重合并的方法&#xff0c;这两种方法在以往的NLP的比赛中非常常见&#xff0c;是一种提分手段。然而&#xff0c;上述两种方法都需要预训练或者微调相应的模型。在大模型场景下&#xff0c;对每个源模型都进行初始化成本太高&#x…

是用原生js创建红包雨效果

需求: 创建红包雨 答案: // 红包雨代码 开始 // 添加遮罩层 const addOverlay () > {const overlay document.createElement(div);overlay.className overlay;overlay.style.position fixed;overlay.style.top 0;overlay.style.left 0;overlay.style.width 100%;o…

华为机考入门python3--(0)测试题1-句子平均重量

分类&#xff1a;字符串 知识点&#xff1a; 获取输入 input().strip().split(" ") 拼接列表 " ".join(list) 输出指定位数的浮点数 print("%.2f" % value) len() 函数对于很多内置的数据类型都适用&#xff0c;它返回对象的元素个数或长度。…

Qt6入门教程 11:父子对象关系

在上一篇中的纯手写部分&#xff0c;不管是创建菜单、工具栏还是状态栏&#xff0c;我们new完之后都未显式的调用delete进行销毁&#xff0c;这样难道不会有内存泄漏么&#xff1f; QMenuBar *menuBar new QMenuBar(this); QToolBar *toolBar new QToolBar(this); QStatusBa…

yolov8上使用gpu教程

yolov8上使用gpu教程 安装Cuda和Cudnnyolov8上使用gpu 安装Cuda和Cudnn 1.查看支持的cuda版本&#xff0c;并去官网下载。 nvidia-smi2.网址&#xff1a;https://developer.nvidia.com/cuda-toolkit-archive 3.安装细节 安装的前提基础是&#xff0c;有vs的C环境。我电脑有…

GBASE南大通用Connection 构造函数

GBASE南大通用分享  重载列表 1) 初始化一个新的 GBaseConnection 类实例。 GBaseConnection() 2) 当给定连接字符串的时候初始化一个新的 GBaseConnection 类实例。 GBaseConnection(string)  注释 当创建一个新的 GBaseConnection 实例的时候&#xff0c;其属性设…

DataStream API(源算子)

目录 源算子 1&#xff0c;从集合中读取数据 2&#xff0c;从文件读取数据 3&#xff0c;从 Socket 读取数据 4&#xff0c;从 Kafka 读取数据 5&#xff0c;自定义源算子 6&#xff0c;Flink 支持的数据类型 6.1 Flink 支持多种数据类型&#xff0c;包括但不限于&…

动态SQL:MyBatis强大的特性之一

一般来说&#xff0c;一个程序的服务器可以部署多个&#xff0c;但是数据库却只能有一个。这么多服务器&#xff0c;如果每天都要给数据库海量的操作数据&#xff0c;数据库的压力就会非常大。 所以为了减轻数据库的压力&#xff0c;我们可以把一些查询数据库的语句简化&#…

在Rust中编写自定义Error

前言 之前我们聊过&#xff0c;Result<T, E> 类型可以方便地用于错误传导&#xff0c;Result<T, E>是模板类型&#xff0c;实例化后可以是各种类型&#xff0c;但 Rust 要求传导的 Result 中的 E 是相同类型的&#xff0c;或者能够自动转化为相同类型。比如&#…

单例模式-C#实现

该实例基于WPF实现&#xff0c;直接上代码&#xff0c;下面为三层架构的代码。 一 Model using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace 设计模式练习.Model.单例模式 {//单例模式的实现in…

el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)

elementplus 的 el-checkbox 官方代码中的多选框组实例如下&#xff1a; 上方代码中选中哪个选项就会往 checkList 数组中加入选项的 label 值&#xff0c;如果需要实现展示的值与选中的值不一样要怎么实现呢&#xff1f; 解决方法 el-checkbox组件中存在插槽&#xff0c;只需…

【Linux】 开始使用 gcc 吧!!!

Linux 1 认识gcc2 背景知识3 gcc 怎样完成 &#xff1f;3.1 预处理预处理^条件编译 3.2 编译3.3 汇编3.4 链接 4 函数库5 gcc 基本选项Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读下一篇文章见&#xff01;&#xff01;&#xff01; 1 认识gcc 我们在windows环…

02.领域驱动设计:了解领域、子域、核心域、通用域、支撑域、通用语言和限界上下文

目录 概要 1、领域 2、子领域 建立领域模型步骤&#xff1a; 3、核心域 4、通用域 5、支撑域 6、思考题 7、通用语言 8、限界上下文 限界上下文和微服务的关系 9、总结 限界上下文在微服务设计中的作用和意义是什么 概要 领域驱动设计&#xff08;DDD&#xff09;…

Web09--jQuery基础

1、jQuery概述 1.1 什么是jQuery jQuery是一款优秀的JavaScript的轻量级框架之一&#xff0c;封装了DOM操作、事件绑定、ajax等功能。特别值得一提的是基于jQuery平台的插件非常丰富&#xff0c;大多数前端业务场景都有其封装好的工具可直接使用。 jQuery下载和版本介绍 官…

qml中访问控件内部的子项

如何访问Repeater类型内部的子项、Row等布局类型内部的子项以及ListView内部的子项等。。。 1、测试代码 import QtQuick 2.0 import QtQuick.Controls 2.12 import QtQuick.Window 2.12 import QtQuick.Layouts 1.3 import QtQml 2.12Window {id: windowobjectName: "m…