目录
1 proc文件系统简介
/proc
文件系统,也称为进程信息文件系统(Process Information file system),是一种在 Linux 和其他类 Unix 系统中存在的虚拟文件系统。它被设计用来提供一种机制,允许用户空间访问内核空间的数据结构和信息。
但是与普通文件不同的是, proc 文件系统是动态创建的,文件本身并不存在于磁盘当中、 只存在于内存当中,与 devfs 一样,都被称为虚拟文件系统。
proc 文件系统挂载在系统的/proc 目录下, 对于内核开发者(譬如驱动开发工程师)来说, proc 文件系统给了开发者一种调试内核的方法:通过查看/proc/xxx 文件来获取到内核特定数据结构的值。
可以看到/proc 目录下有很多以数字命名的文件夹,譬如 1、 138、 1833,这些数字对应的其实就是一个一个的进程 PID 号,每一个进程在内核中都会存在一个编号,通过此编号来区分不同的进程,这个编号就是 PID 号。
所以这些以数字命名的文件夹中记录了这些进程相关的信息,不同的信息通过不同的虚拟文件呈现出来。
/proc 目录下除了文件夹之外,还有很多的虚拟文件,譬如 buddyinfo、 cgroups、 cmdline、version 等等,不同的文件记录了不同信息, 关于这些文件记录的信息和意思如下:
- cmdline: 内核启动参数;
- cpuinfo: CPU 相关信息;
- iomem: IO 设备的内存使用情况;
- interrupts:显示被占用的中断号和占用者相关的信息;
- ioports: IO 端口的使用情况;
- kcore:系统物理内存映像,不可读取;
- loadavg:系统平均负载;
- meminfo:物理内存和交换分区使用情况;
- modules:加载的模块列表;
- mounts:挂载的文件系统列表;
- partitions:系统识别的分区表;
- swaps:交换分区的利用情况;
- version:内核版本信息;
- uptime:系统运行时间;
2 proc 文件系统的使用
proc 文件系统的使用就是去读取/proc 目录下的这些文件,获取文件中记录的信息,可以直接使用 cat 命令读取,也可以在应用程序中调用 open()打开、然后再使用 read()函数读取。
2.1 使用 cat 命令读取
读取特定进程的命令行参数:pid
应该替换为目标进程的进程ID,如下命令显示了启动该进程的完整命令行。
cat /proc/pid/cmdline
查看当前进程的环境变量:/proc/self
是一个特殊的目录,它总是指向当前正在执行的进程。
cat /proc/self/environ
获取系统内存使用情况:/proc/meminfo 文件提供了系统的内存使用统计,包括总内存、空闲内存、缓冲区内存等。
cat /proc/meminfo
查看当前进程的文件描述符:/proc/self/fd/将列出当前进程打开的所有文件描述符,每个文件描述符都是一个指向实际文件的符号链接。
cat /proc/self/fd/
获取当前进程的CPU使用情况:如下命令将从 stat
文件中提取出CPU使用情况的部分。
cat /proc/stat | grep '^cpu '
查看当前进程的状态:/proc/self/status文件包含了当前进程的多种状态信息,如线程数、内存使用、用户和组ID等。
cat /proc/self/status
获取内核版本信息:/proc/version文件显示了Linux内核的版本信息。
cat /proc/version
2.2 使用 read()函数读取
在用户空间程序中使用 read()
系统调用来读取 /proc
文件系统的内容是一种常见的做法,如下程序示例使用 read()
读取内核版本信息、当前进程的文件描述符、CPU 使用情况。
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 1024
int main()
{
char buffer[BUFFER_SIZE];
ssize_t bytesRead;
int fd;
// 读取内核版本信息
fd = open("/proc/version", O_RDONLY);
if (fd == -1) {
perror("open /proc/version failed");
return 1;
}
bytesRead = read(fd, buffer, BUFFER_SIZE - 1);
if (bytesRead == -1) {
perror("read /proc/version failed");
close(fd);
return 1;
}
buffer[bytesRead] = '\0'; // 确保字符串以空字符结尾
printf("Kernel version: %s\n", buffer);
close(fd);
// 读取当前进程的文件描述符
fd = open("/proc/self/fd", O_RDONLY | O_DIRECTORY);
if (fd == -1) {
perror("open /proc/self/fd failed");
return 1;
}
// 这里我们只读取目录的第一个文件描述符作为示例
bytesRead = readlinkat(fd, "0", buffer, BUFFER_SIZE - 1);
if (bytesRead == -1) {
perror("readlinkat failed");
close(fd);
return 1;
}
buffer[bytesRead] = '\0';
printf("First file descriptor: %s\n", buffer);
close(fd);
// 读取CPU使用情况
fd = open("/proc/stat", O_RDONLY);
if (fd == -1) {
perror("open /proc/stat failed");
return 1;
}
bytesRead = read(fd, buffer, BUFFER_SIZE - 1);
if (bytesRead == -1) {
perror("read /proc/stat failed");
close(fd);
return 1;
}
buffer[bytesRead] = '\0';
// 打印整个CPU使用情况可能很长,这里只打印前几行
printf("CPU usage information:\n%.*s\n", (int)bytesRead, buffer);
close(fd);
return 0;
}
运行结果如下: