使用proc文件系统

news2024/11/16 3:44:38

使用proc文件系统


文章目录

  • 使用proc文件系统
  • 1.meminfo文件
  • 2. free命令
  • 3、创建 /proc 节点
  • 4、使用 file_operations 实现 proc 文件读写 导向内核信息
  • 5、使用 seq_file 实现 proc 文件的读取


在Linux系统中, “/proc”文件系统十分有用, 它被内核用于向用户导出信息。 “/proc”文件系统是一个虚拟文件系统, 通过它可以在Linux内核空间和用户空间之间进行通信。 在/proc文件系统中, 我们可以将对虚拟文件的读写作为与内核中实体进行通信的一种手段, 与普通文件不同的是, 这些虚拟文件的内容都是动态创建的。

“/proc”下的绝大多数文件是只读的, 以显示内核信息为主。 但是“/proc”下的文件也并不是完全只读的, 若节点可写, 还可用于一定的控制或配置目的, 例如前面介绍的写/proc/sys/kernel/printk可以改变printk() 的打印级别。

Linux系统的许多命令本身都是通过分析“/proc”下的文件来完成的, 如ps、 top、 uptime和free等。 例如, free命令通过分析/proc/meminfo文件得到可用内存信息, 下面显示了对应的meminfo文件和free命令的结果。

1.meminfo文件

在这里插入图片描述

2. free命令

在这里插入图片描述

3、创建 /proc 节点

  • struct proc_dir_entry
    内核使用
    proc_dir_entry 结构体来描述
    /proc 文件系统中的一个目录或者文件节点
/* 进程目录项结构体 /
struct proc_dir_entry {
    unsigned int low_ino; / 低位 inode 编号 /
    umode_t mode; / 文件访问权限 /
    nlink_t nlink; / 链接计数 /
    kuid_t uid; / 用户 ID /
    kgid_t gid; / 组 ID /
    loff_t size; / 文件大小 */
    const struct inode_operations proc_iops; / inode 操作函数集指针 */
    const struct file_operations proc_fops; / 文件操作函数集指针 */
    struct proc_dir_entry *next, *parent, subdir; / 目录项指针 */
    void data; / 自定义数据指针 /
    atomic_t count; / 使用计数 /
    atomic_t in_use; / 调用模块的进程数;负数表示正在卸载 */
    struct completion pde_unload_completion; / 卸载完成信号量指针 /
    struct list_head pde_openers; / 打开文件的进程链表头 /
    spinlock_t pde_unload_lock; / 卸载锁 /
    u8 namelen; / 名称长度 /
    char name[]; / 名称 */
};
  • proc_create
    内核提供了一套
    API用于在
    proc 文件系统中创建 文件节点
    /目录:
static struct proc_dir_entry *proc_create(  const char *name, umode_t mode,
                                            struct proc_dir_entry *parent, 
                const struct file_operations *proc_fops);    
                                            
@ name: 节点名
@ mode:    权限位
@ parent:父目录
@ proc_fops: 文件操作结构体

    struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent);

@ name: 目录名
@ parent:父目录
  • remove_proc_entry()
    内核提供
    remove_proc_entry 来移除
    proc 文件系统中的 文件
    /目录 项:
void remove_proc_entry(const char *name, struct proc_dir_entry *parent);

@ name: 文件/目录 名
@ parent:父目录

4、使用 file_operations 实现 proc 文件读写 导向内核信息

在调用 proc_create() 创建文件项时, 提供了一个 file_operations结构体, 实现里面的read, write方法即可实现proc 文件读写,demo 程序如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <asm/stat.h>
#include <linux/proc_fs.h>

MODULE_LICENSE("GPL");

#define LOG_TAG    "my_test1: "

static char my_buf[256];

//====================================================================================
static ssize_t my_proc_read(struct file *fp, char __user *buf, size_t size, loff_t *pos)
{
    int len = strlen(my_buf);

    pr_info(LOG_TAG "enter %s()\n", __func__);

    if( 0 == *pos )    {
        strncpy(buf, my_buf, sizeof(my_buf));
        *pos += len;
        return len;
    } else
        return 0;
}

static ssize_t my_proc_write(struct file *file,  const char __user *buf, size_t size, loff_t *pos)
{
    int len = size < sizeof(my_buf) ? size : sizeof(my_buf);

    pr_info(LOG_TAG "enter %s()\n", __func__);

    if( 0 == *pos)    {
        memset(my_buf, '\0', sizeof(my_buf));
        len = copy_from_user(my_buf, buf, len);
        *pos += len;
        my_buf[len - 1] = '\0';
        return size;
    }else 
        return 0;
}


static struct file_operations my_file_ops = {
    .owner     = THIS_MODULE,
    .read     = my_proc_read,
    .write     = my_proc_write,
};

//====================================================================================
static int __init my_module_init(void)
{
    struct proc_dir_entry * my_proc_node = NULL;

    pr_info(LOG_TAG "enter %s()\n", __func__);

    my_proc_node = proc_create("my_test1", S_IRUGO | S_IWUGO, NULL, &my_file_ops);
    if( NULL == my_proc_node )    {
        pr_err(LOG_TAG "creat /proc/my_test1 failed\n");
        remove_proc_entry("my_test1", NULL);
        return -1;
    }

    pr_info(LOG_TAG "creat /proc/my_test1 success\n");
    return 0;
}

static void __exit my_module_exit(void)
{
    pr_info(LOG_TAG "enter %s()\n", __func__);

    pr_info(LOG_TAG "remove /proc/my_test1\n");
    remove_proc_entry("my_test1", NULL);
}

module_init(my_module_init);
module_exit(my_module_exit);

5、使用 seq_file 实现 proc 文件的读取

seq_file只是在普通的文件read中加入了内核缓冲的功能,从而实现顺序多次遍历,读取大数据量的简单接口。内核使用 seq_file 结构体来描述seq_file:

/* 序列文件结构体 */
struct seq_file {
    char buf; / 缓冲区指针 /
    size_t size; / 缓冲区大小 /
    size_t from; / 开始位置 /
    size_t count; / 计数器 /
    loff_t index; / 索引 /
    loff_t read_pos; / 读取位置 /
    u64 version; / 版本号 /
    struct mutex lock; / 互斥锁 */
    const struct seq_operations op; / 序列操作函数集指针 /
    int poll_event; / poll() 事件 */
    #ifdef CONFIG_USER_NS
    struct user_namespace user_ns; / 用户命名空间 */
    #endifvoid private; / 私有数据指针 */
};

seq_file一般只提供只读接口,在使用seq_read时,主要靠下述四个操作来完成内核自定义缓冲区的遍历的输出操作,其中pos作为遍历的iterator,在seq_read函数中被多次使用,用以定位当前从内核自定义链表(不止是链表, 还可以是哈希表, 数组, 红黑树)中读取的当前位置,当多次读取时,pos非常重要,且pos总是遵循从0,1,2…end+1遍历的次序,其即必须作为遍历内核自定义链表的下标,也可以作为返回内容的标识。但是我在使用中仅仅将其作为返回内容的标示,并没有将其作为遍历链表的下标,从而导致返回数据量大时造成莫名奇妙的错误,注意:start返回的void*v如果非0,被show输出后,在作为参数传递给next函数,next可以对其修改,也可以忽略;当next或者start返回NULL时,在seq_open中控制路径到达seq_end。

struct seq_operations {
    void * (*start) (struct seq_file *m, loff_t *pos);
    void (*stop) (struct seq_file *m, void *v);
    void * (*next) (struct seq_file *m, void *v, loff_t *pos);
    int (*show) (struct seq_file *m, void *v);
};

在读取 proc file 时:

  • 如果只有一条记录, 调用过程是:
    start->show->stop,
    start->stop.
  • 如果有多条记录并且能通过缓冲区一次传第完, 调用过程是,继续
    start->show->next->show->next-> … ->nex->show->stop,
    start->stop .
  • 如果有多条记录, 比且不能一次通过缓冲区传送完成, 调用过程是:
    start->show->next->show->…->show->stop,
    start->show->next->show->…->show->stop, … , start->stop.

seq_file 的缓冲区通常为1K, 但是会动态增长以便能容纳至少一条记录(当单条记录的大小大于1页的时候,这个就很有用), 通常, 应该在start中进行必要的加锁, 在stop中进行必要的解锁一边避免竟态。
当使用seq_read时, 需要实现seq_operations, 并且将file和seq_file关联起来(通常在open操作中进行), 同时, seq_file也提供了游离的 seq_lseek, seq_release用于支持llseek和release操作。
使用seq_file 的demo如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <asm/stat.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>

#define LOG_TAG    "my_test2: "

MODULE_LICENSE("GPL");

static char my_buf[][32] = {    {"i am the 0th record"},    //buf[0]
                {"i am the 1th record"},    //buf[1]
                {"i am the 2th record"},    //buf[2]
                {"i am the 3th record"},    //buf[3]
                {"i am the 4th record"},    //buf[4]
};

//==========================================================================
static void* my_seq_start (struct seq_file *m, loff_t *pos)
{
    pr_info(LOG_TAG "enter %s()\n", __func__);

    if( *pos < 0 || *pos > 4 /*my_buf[][32] index*/)    {
        pr_err(LOG_TAG "invalid pos %ld\n", (long)*pos);
        return NULL;
    }else    
        return my_buf[*pos];
}

static void my_seq_stop (struct seq_file *m, void *v)
{
    pr_info(LOG_TAG "enter %s()\n", __func__);
    pr_info(LOG_TAG "do nothing\n");
}

static void* my_seq_next (struct seq_file *m, void *v, loff_t *pos)
{
    pr_info(LOG_TAG "enter %s()\n", __func__);

    if( ++(*pos) < 0  || *pos > 4 /*my_buf[][32] index*/)    {
        pr_info(LOG_TAG "end\n");
        return NULL;
    }else
        return my_buf[*pos];
}

static int my_seq_show (struct seq_file *m, void *v)
{
    seq_printf(m, "%s\n", (char*)v);
    return 0;    
}

static struct seq_operations my_seq_ops = {
    .start    =    my_seq_start,
    .stop    =    my_seq_stop,
    .next    =    my_seq_next,
    .show    =    my_seq_show,
      };
//==========================================================================

static int my_proc_open(struct inode * inode , struct file * file) 
{ 
    return seq_open(file, &my_seq_ops ); 
}

static struct file_operations my_file_ops = {
    .owner      = THIS_MODULE,
    .open     = my_proc_open,
    .read      = seq_read,
    .llseek  = seq_lseek,
    .release = seq_release,
};

//==========================================================================
static int __init my_module_init(void)
{
    struct proc_dir_entry * my_proc_node = NULL;

    pr_info(LOG_TAG "enter %s()\n", __func__);

    my_proc_node = proc_create("my_test2", S_IRUGO, NULL, &my_file_ops);
    if( NULL == my_proc_node )    {
        pr_err(LOG_TAG "creat /proc/my_test2 failed\n");
        remove_proc_entry("my_test2", NULL);
        return -1;
    }

    pr_info(LOG_TAG "creat /proc/my_test2 success\n");
    return 0;
}

static void __exit my_module_exit(void)
{
    pr_info(LOG_TAG "enter %s()\n", __func__);

    pr_info(LOG_TAG "remove /proc/my_test2\n");
    remove_proc_entry("my_test2", NULL);
}

module_init(my_module_init);
module_exit(my_module_exit);    

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

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

相关文章

vue3学习四 watch

在vue3中使用watch 来监听某个数据的变化&#xff0c; 因为我们定义数据的时候有 ref 和 reactive 两种方法&#xff0c; 所以watch 也会分出不同的五种情况 当使用 watch 来监听 ref 定义的数据时 <template><div> sum: {{sum}}</div><button click&qu…

java非静态代码块和静态代码块介绍

代码块 SE.10.0…02.28 非静态普通代码块&#xff1a;定义在方法内部的代码块&#xff0c;不用任何关键字修饰&#xff0c;又名构造代码块、实例代码块 静态代码块&#xff1a;用static修饰的代码块 非静态代码块 public class Test {public static void main(String[] args…

【EKF】卡尔曼滤波的一维应用实例

前言 推导了卡尔曼滤波的原理之后&#xff0c;使用一个简单的一维应用实例来训练一下&#xff0c;加深印象。使用一个温度测量的实例来说明&#xff0c;系统的状态方程为&#xff1a; X(k) A*X(k-1) B*u(k-1) w(k-1) Z(k) H*X(k) v(k) 其中 w 为过程噪声&#xff0c;方…

方言翻译APP小程序开发具备哪些功能?

我国语言文华博大精深&#xff0c;很多地方都有着民族特色方言&#xff0c;在当地很盛行但是外地人听不懂也不会说&#xff0c;这就給沟通造成了一定的困扰。方言翻译APP软件是专门针对地方性方言开发的一款系统软件&#xff0c;提供全国各地方言翻译功能&#xff0c;一键在线就…

Android中如何使用GPS

目录 GPS简介 GPS的常用API locationProvider 使用GPS获取位置信息 室内WIFI定位 近距离警报 GPS简介 Gobal Positioning System&#xff0c;全球定位系统&#xff0c;是美国在20世纪70年代研制的一种以人造地球卫星为基础的高精度无线电导航的定位系统&#xff0c;它在全…

【手机摄影】--全集

算了&#xff0c;摄像机太贵了&#xff0c;玩不起&#xff0c;还是看看手机摄影吧。 学习链接 &#xff1a;https://www.bilibili.com/video/BV14e411T7md 1. 认识手机摄影 1.1 局限性 手机的摄像头能够满足大部分场景&#xff0c;但以下场景会受到掣肘&#xff0c;最好还是用…

面试这么简单,阿里原来这么容易就能进去…...

最近和阿里的一个老朋友闲聊&#xff0c;感触颇深&#xff0c;据他说公司近期招聘的测试工程师&#xff0c;大多数候选人都有一个“通病”&#xff1a;在工作2-3年的时候遇到瓶颈&#xff0c;而且是一道很难跨越的坎。 为什么会遇到这种情况&#xff1f;因为大部分测试工程师在…

项目管理基础(第五版)读书笔记

项目管理基础&#xff08;第五版&#xff09;读书笔记 章节概要前言第一章&#xff1a;项目管理概述 日期&#xff1a;2023年3月23日 章节概要 前言 项目管理协会 Project Management Institute。简称PMI。项目管理知识体系指南 Project Management Body Of Knowledge。简称P…

4.QT应用程序主窗口

本章代码见文末链接 主窗口框架 新建Qt Wisgets项目mymainwindow&#xff0c;类名默认MainWindow&#xff0c;基类默认QMainWindow 更改文字如图&#xff0c;如果中文无法直接输入&#xff0c;可以试试复制粘贴 “动作编辑器”中&#xff08;默认在右下角&#xff09;&…

关于IRIG-B码对时的理解和分析

一、IRIG-B是什么&#xff1f; IRIG-B&#xff08;简称B码&#xff09;是一种应用于靶场的串行时间交换码。由美国靶场司令部委员会下属“靶场仪器组”提出的一种时间信息编码标准&#xff08;IRIG是英文InterRange Instrumentation Group的缩写。它是美国靶场司令委员会的下属…

一百零八、Kettle采集Kafka数据到HDFS(踩坑,亲测有效)

Kafka到HDFS&#xff0c;除了用Kafka API和flume之外&#xff0c;还可以用kettle&#xff0c;最大优点是不用写代码&#xff01; 版本&#xff1a;Kettle版本&#xff1a;8.2、Hadoop版本&#xff1a;3.1.3 前提&#xff1a; 详情请看鄙人的一百零一、Kettle8.2.0连接Hive…

pip安装配置清华镜像源scrapy框架,并进行框架的案例演示

文章目录 运行cmd终端后直接输入安装成功scrapy框架安装成功 为什么使用此命令安装scrapy框架成功后创建scrapy项目建议在pycharm终端创建项目打开项目 用scrapy框架实现案例——从新浪网爬取热点并把数据输入到excel表中编辑setting.py文件创建脚本、写入脚本在终端运行脚本文…

长三角生物医药产业加速跑,飞桨螺旋桨为创新药企、医药技术伙伴装上AI大模型引擎...

生物医药是国家“十四五”规划中明确的战略性新兴产业之一。长三角地区是中国生物医药产业的排头兵&#xff0c;也是《“十四五”生物经济发展规划》的“生物经济先导区”之一。据《上海市生物医药产业投资指南》显示&#xff0c;2022 年上海市生物医药产业在 I 类国产创新药数…

新手如何学习挖漏洞?【网络安全】

新手如何学习挖漏洞&#xff1f;看这篇就够了 前言 有不少阅读过我文章的伙伴都知道&#xff0c;我从事网络安全行业已经好几年&#xff0c;积累了丰富的经验和技能。在这段时间里&#xff0c;我参与了多个实际项目的规划和实施&#xff0c;成功防范了各种网络攻击和漏洞利用&…

Cron表达式X分钟执行一次的设计缺陷。SQL JOIN的设计缺陷。在线Cron表达式网站的缺陷。Spring 定时任务的年问题。

Cron Cron表达式 定时任务计划任务 Chronological英 /ˌkrɒnəˈlɒdʒɪk(ə)l/adj. 按发生时间顺序排列的&#xff1b;&#xff08;年龄&#xff09;按时间计算的1. 月 周设计精妙吗&#xff1f; 学习 0/5 * * * * ? * 秒 分 时 日 月 周 年1. 年一般省略。为&#xf…

Live800:服务经济时代,企业如何满足客户需求?

在互联网与市场经济的催化下&#xff0c;我们正在从产品经济时代过渡到服务经济时代。在产品经济时代&#xff0c;企业关注的核心是质量和成本&#xff1b;而在服务经济时代&#xff0c;如何面向客户&#xff0c;满足客户需求则成为企业建立核心竞争力的关键。 具体来说&#x…

【精选】关于洪涝灾害智慧水利和人工智能大模型的解决方案2023版

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除 智慧水利平台 实现“全局一盘棋”的智慧水利综合管理&#xff0c;通过“一图、一库、一平台”结合水利大数据、数字孪生与人工智能&#xff0c;为水利工作提供有力的管理抓手&…

SingleR --细胞注释

文章目录 briefExample使用内置的 references使用其他注释好的数据集作为 reference singleR还提供了注释诊断的方法 brief Example The celldex package provides access to several reference datasets (mostly derived from bulk RNA-seq or microarray data)。 The Human…

《狂飙》原著来了,邀你重新见证

2023年的开篇十分精彩且丰富&#xff0c;经历过生活的不幸&#xff0c;新的一年万物复兴&#xff0c;每个人心底那颗躁动的心又重新释放&#xff0c;希望新的开始不负所望&#xff0c;年末复盘时所得皆所愿&#xff01; 开篇 开年影视第一炮&#xff0c;炸出了所有人被压抑的内…

AIGC技术发展和应用方向

AIGC&#xff08;Artificial Intelligence Generated Content&#xff09;是指通过人工智能技术生成的各种文本、图像、音频和视频等多媒体内容。AIGC技术是机器学习和自然语言处理等技术的结合&#xff0c;通过对海量数据的学习和分析&#xff0c;可以让计算机模拟人类的创造力…