文章

LINUX下一切皆文件

为什么说LINUX下一切皆文件

在Linux系统中,”一切皆文件”是一个基本的设计理念。这是因为Linux系统中的大多数事物,包括硬件设备、目录、网络套接字等,都被表示为文件。这种设计使得用户和程序可以使用统一且一致的接口(即文件系统API)来交互和操作系统中的各种资源。

硬件设备(如硬盘、鼠标、键盘等)在Linux中都有对应的设备文件,通常位于/dev目录下,比如可以通过。网络套接字和进程间通信管道也可以通过文件描述符来操作。此外,Linux系统的配置信息也通常存储在文件中,例如/etc目录下的各种配置文件。甚至是/proc/下的进程都可以以文件的方式进行查看,cat /proc/cpuinfo就可以看到cpu的信息

因此,当我们说”Linux下一切皆文件”时,意思是在Linux系统中,几乎所有的资源都可以通过文件的方式来访问和管理。

开始实验

开始实验之前,推荐大家先看看这个问题:Linux 系统误将 chmod 权限改成 了 000,如何恢复?

这种情况下,chmod命令我们是不能用的,那么我们该如何去使用chmod命令呢?

这种情况下就可以通过编写代码直接运行usr/bin/chmod文件进行权限的修改修复死局,下面将通过一个简单的实验讲解一下内核文件管理的实现:

首先实验环境为VMware Ubuntu 20.04.5 LTS

内核版本为 5.15.0-101-generic

在搞之前 记得切换到管理员状态:

1
su root

至于原因,只有系统管理员才有power去insmod 模块

然后实验需要的材料是一个[文件系统实验(proc_fs)2024_.rar]

外校的同学可以直接联系我,我邮箱发一份文件 cuvo@foxmail.com

把这个文件丢进Ubuntu里面然后解压

1
unrar x 文件系统实验(proc_fs)2024_.rar

如果提示没有unrar,记得下载

1
sudo apt-get install unrar

然后切目录

1
cd /文件系统实验(proc_fs)2024/proc2019@fc14/

进到代码目录后,可以自行跑一下make看看有没有错误,如果使用Ubuntu肯定会提醒相应的模块或者库函数没了 这是原先的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * main.c -- the bare scull char module
 *
 * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
 * Copyright (C) 2001 O'Reilly & Associates
 *
 * The source code in this file can be freely used, adapted,
 * and redistributed in source or binary form, so long as an
 * acknowledgment appears in derived source files.  The citation
 * should list that the code comes from the book "Linux Device
 * Drivers" by Alessandro Rubini and Jonathan Corbet, published
 * by O'Reilly & Associates.   No warranty is attached;
 * we cannot take responsibility for errors or fitness for use.
 *
 */

//#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/kernel.h>	/* printk() */
#include <linux/slab.h>		/* kmalloc() */
#include <linux/fs.h>		/* everything... */
#include <linux/errno.h>	/* error codes */
#include <linux/types.h>	/* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h>	/* O_ACCMODE */
#include <linux/seq_file.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <asm/system.h>		/* cli(), *_flags */
#include <asm/uaccess.h>	/* copy_*_user */

#include "scull.h"		/* local definitions */

MODULE_AUTHOR("Alessandro Rubini, Jonathan Corbet");
MODULE_LICENSE("Dual BSD/GPL");

/*
 * The proc filesystem: function to read and entry
 */

int scull_read_procmem(char *buf, char **start, off_t offset,
                   int count, int *eof, void *data)
{
  //      printk("<0> hello i'm a proc file builded by you\n");
//        printk("<0> hello i'm %d \n",current->pid);
        int len = sprintf(buf,"%s\n","hello world"); 
	return len;
}


/*
 * Now to implement the /proc file we need only make an open
 * method which sets up the sequence operators.

static int scull_proc_open(struct inode *inode, struct file *file)
{
	return 0;
}
 */
/*
 * Create a set of file operations for our proc file.
 
static struct file_operations scull_proc_ops = {
	.owner   = THIS_MODULE,
	.open    = scull_proc_open,
	.read    = scull_read_procmem,
	.llseek  = seq_lseek,
	.release = seq_release
};


 * Actually create (and remove) the /proc file(s).
 */

static void scull_create_proc(void)
{
	
	create_proc_read_entry("shou", 0 /* default mode */,
			NULL /* parent dir */, scull_read_procmem,
			NULL /* client data */);
	
}

static void scull_remove_proc(void)
{
	/* no problem if it was not registered */
	remove_proc_entry("shou", NULL /* parent dir */);
//	remove_proc_entry("scullseq", NULL);
}


void scull_cleanup_module(void)
{

	scull_remove_proc();

}

这个代码是给fc14编写的,他的内核版本为2.6

这时候肯定需要修改main.c文件了,这样才能在较新的内核上跑起来,首先还得了解一下之前模块是干什么的,之前的模块创建了一个名为”shou”的proc文件。当你读取这个文件时,它会显示”Hello, world! [当前进程的PID]”。根据之前的内容和功能,我们对此进行修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/*
 * main.c -- the bare scull char module
 *
 * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
 * Copyright (C) 2001 O'Reilly & Associates
 *
 * The source code in this file can be freely used, adapted,
 * and redistributed in source or binary form, so long as an
 * acknowledgment appears in derived source files.  The citation
 * should list that the code comes from the book "Linux Device
 * Drivers" by Alessandro Rubini and Jonathan Corbet, published
 * by O'Reilly & Associates.   No warranty is attached;
 * we cannot take responsibility for errors or fitness for use.
 *
 */

//#include <linux/config.h>
#include <linux/module.h>  // 包含了Linux内核模块需要的函数和符号
#include <linux/init.h>  // 包含了模块初始化和清理函数的宏
#include <linux/proc_fs.h>  // 包含了创建和删除proc文件的函数
#include <linux/seq_file.h>  // 包含了顺序文件接口的函数
#include <linux/sched.h>  // 包含了获取当前进程信息的函数
#include "scull.h"  // 包含了本地定义

// 模块的作者和许可证信息
MODULE_AUTHOR("Alessandro Rubini, Jonathan Corbet");
MODULE_LICENSE("Dual BSD/GPL");

// 当读取proc文件时,这个函数会被调用
static int scull_proc_show(struct seq_file *m, void *v) {
    seq_printf(m, "Hello, world! Current PID: %d\n", current->pid);  // 打印当前进程的PID
    return 0;
}

// 当打开proc文件时,这个函数会被调用
static int scull_proc_open(struct inode *inode, struct file *file) {
    return single_open(file, scull_proc_show, NULL);  // 使用单一打开,scull_proc_show作为显示函数
}

// 定义proc文件的操作
static const struct proc_ops scull_proc_fops = {
    .proc_open = scull_proc_open,  // 打开文件时的操作
    .proc_read = seq_read,  // 读取文件时的操作
    .proc_lseek = seq_lseek,  // 定位文件时的操作
    .proc_release = single_release,  // 释放文件时的操作
};

// 创建proc文件
static void scull_create_proc(void)
{
    proc_create("shou", 0, NULL, &scull_proc_fops);  // 创建名为"shou"的proc文件,使用scull_proc_fops作为文件操作
}

// 删除proc文件
static void scull_remove_proc(void)
{
    remove_proc_entry("shou", NULL);  // 删除名为"shou"的proc文件
}

// 模块清理函数
void scull_cleanup_module(void)
{
    scull_remove_proc();  // 删除proc文件
}

// 模块初始化函数
int scull_init_module(void)
{
    scull_create_proc();  // 创建proc文件
    return 0;
}

// 注册模块初始化和清理函数
module_init(scull_init_module);
module_exit(scull_cleanup_module);

修改完main.c文件后可以开始编译

1
make

然后insmod

1
insmod scull.ko

然后可以去proc里面看有没有shou文件了

1
ls /proc/

如果有: 那就可以

1
cat /proc/shou

那就会出现这样的内容 此时我们再把模块卸载掉看看

1
2
rmmod scull.ko
ls /proc/

就可以发现之前的shou文件没了 至此实验结束

整个实验流程图如下

graph LR
A[开始]--> B[加载模块]
B --> C{创建进程文件 shou}
C --> D{注册文件shou}
D --> E[前往查看/proc/shou内的文件]
E --> F{卸载模块}
F --> G{移除进程文件 shou}
G --> H[结束,清除编译结果]
本文由作者按照 CC BY 4.0 进行授权