Linux中的/proc文件系统详解(C/C++代码实现)

news2024/11/25 18:50:23

Linux /proc这个特殊的目录包含有关Linux系统的所有详细信息,包括其内核、进程和配置参数。通过研究/proc目录,可以了解Linux命令的工作原理,甚至可以执行一些管理任务。

走进Linux的/proc目录

今天,我们将查看/proc目录并熟悉它。/proc目录存在于所有Linux系统上,无论其风格或体系结构如何。

/proc中的文件不是真正的文件,它们充当内核数据结构和进程信息的接口。由于它们不是真正的文件,文件大小等属性不适用于它们。


最有趣的部分是,/proc文件系统中几乎所有文件的大小都是0字节。让许多用户困惑的是,尽管它们的大小为0,但在查看时仍然包含数据。这怎么可能?

Linux能够处理许多不同类型的文件系统,因为它被称为VFS(虚拟文件系统)。/proc文件系统也由内核使用VFS访问。因此,当用户试图访问/proc文件系统中的文件时,proc文件系统会借助内核中的信息创建该文件的内容。这就是为什么在列出/proc目录时,大多数目录的大小显示为0字节,但在访问时会动态填充。

让我们实际检查并理解它。Linux中有一个名为file的命令。

file [ -bcnsvzL ] [ -f 命名文件 ] [ -m 幻数文件 ] file …


linux中的“file”命令用于通过检查文件的内容来确定文件的类型。如果文件为空,它将给出“文件为空”的输出。让我们尝试使用file命令检查任何/proc文件的文件类型。


输出表明文件为空。但是,让我们尝试使用vi、cat或更少的编辑器访问该文件。


因此,当您访问内容时,当前值将从内核填充。这就是为什么您可以从/proc中的文件获得系统的最新和准确状态的原因。

我们之前看到proc手册页将proc定义为“进程信息伪文件系统”。这是因为它包含所有当前正在运行的进程的详细信息。让我们看看/proc的目录列表


可以在上面显示的目录列表中看到,里面有很多编号的目录。这些目录用相应的PID编号。当进程开始和停止时,它们会动态地出现和消失。以各自PID命名的每个目录都包含进程当前状态的详细信息,我们随便进入一个PID看看里面的信息。

让我们看看/proc中PID目录的内容。下图显示了PID目录的内容。

Linux中 /proc/[pid] 目录各文件简析

在 /proc 目录里, 每个正在运行的进程都有一个以该进程 ID 命名的子目录, 其下包括如下的目录和伪文件

  • auxv

包含传递给进程的 ELF 解释器信息,格式是每一项都是一个 unsigned long长度的 ID 加上一个 unsigned long 长度的值。

  • cmdline

该文件保存了进程的完整命令行. 如果该进程已经 被交换出内存, 或者该进程已经僵死, 那么就没有 任何东西在该文件里,这时候对该文件的读操作将返回零 个字符. 该文件以空字符 null 而不是换行符作为结 束标志.

  • comm

comm 包含进程的命令名。

cwd

一个符号连接, 指向进程当前的工作目录. 例如, 要找出进程 20 的 cwd, 你可以:cd /proc/20/cwd;
/bin/pwd

environ

该文件保存进程的环境变量, 各项之间以空字符分隔, 结尾也可能是一个空字符. 因此, 如果要输出进程 1 的环境变量, 你应该: (cat /proc/1/environ; echo) | tr “;\000”; “;\n”;

exe

也是一个符号连接, 指向被执行的二进制代码

fd

进程所打开的每个文件都有一个符号连接在该子目 录里, 以文件描述符命名, 这个名字实际上是指向 真正的文件的符号连接,(和 exe记录一样). 例如, 0 是标准输入, 1是标准输出, 2 是标准错误, 等等

maps

该文件包含当前的映象内存区及他们的访问许可.

格式如下:
   address           perms offset   dev   inode
   00000000-0002f000 r-x-- 00000400 03:03 1401
   0002f000-00032000 rwx-p 0002f400 03:03 1401
   00032000-0005b000 rwx-p 00000000 00:00 0
   60000000-60098000 rwx-p 00000400 03:03 215
   60098000-600c7000 rwx-p 00000000 00:00 0
   bfffa000-c0000000 rwx-p 00000000 00:00 0

address 是进程所占据的地址空间, perms 是权限集:
   r = read
   w = write
   x = execute
   s = shared
   p = private (copy on write)

offset 是文件或者别的什么的偏移量, dev 是设备号(主设 备号:从设备号), 而 inode 则是设备的节点号. 0 表明没有 节点与内存相对应, 就象 bss 的情形.

mem

该文件并不是 mem (1:1) 设备, 尽管它们有相同的设备号. /dev/mem 设备是做任何地址转换之前的物理内存, 而这里的 mem 文件是访问它的进程的内存.目前这个 mem 还不能 mmap(2) (内存映射)出去,而且可能一直要等到内核中增加了一个通用的mmap(2) 以后才能实现. (也许在你读本手册页时这一切已经发生了)

mmap

mmap(2) 做的 maps 映射目录,是和 exe, fd/* 等类似的符号连接. 请注意 maps 包含了比
/proc/*/mmap 更多的信息, 所以应该废弃 mmap.

root

依靠系统调用 chroot(2), unix 和 linux 可以让 每个进程有各自的文件系统根目录. 由 chroot(2) 系统调用设置. 根指向文件系统的根,性质就象 exe, fd/* 等一样.

stat

进程状态信息, 被命令 ps(1) 使用.


通过访问/proc中的文件来获取信息

cpuinfo

保存了CPU 以及体系架构依赖条目的列表. 对于不同的系 统架构有不同的列表, 共有的两项是 cpu 和 BogoMIPS, cpu 可能是当前在用的 CPU, 而 BogoMIPS 则是内核初始化时计算出的一个系统常数.

devices

主设备号及设备组的列表, 文本格式. MAKEDEV 脚本使用 该文件来维持内核的一致性.

dma

一个列表, 指出正在使用的ISA DMA (直接内存访问)通道.

filesystems

以文本格式列出了被编译进内核的文件系统. 当没有给 mount(1) 指明哪个文件系统的时候, mount(1) 就依靠该文件遍历不同的文件系统.

interrupts

该文件以 ASCII 格式记录了(至少是在 i386 体系上的)每次 IRQ 的中断数目.

ioports

该文件列出了当前在用的已注册 I/O 端口范围.

kcore

该伪文件以 core 文件格式给出了系统的物理内存映象, 再 利用未卸载的内核 (/usr/src/linux/tools/zSystem), 我 们就可以用 GDB 查探当前内核的任意数据结构.

kmsg

可以用该文件取代系统调用 syslog(2) 来记录内核信息. 但是读该文件需要超级用户权限, 并且一次只能有一个进 程可以读该文件,因而如果一个使用了 syslog(2)系统调用功能来记录内核信息的系统日志进程正在运行的话,别的进程就不能再去读该伪文件了.该文件的内容可以用 dmesg(8) 来察看.

ksyms

该文件保存了内核输出的符号定义, modules(X) 使用该文件 动态地连接和捆绑可装载的模块.

loadavg

平均负载数给出了在过去的 1, 5, 15 分钟里在运行队列里 的任务数, 与 uptime(1) 等命令的结果相同.

locks

这个文件显示当前文件锁.

malloc

只有在编译时定义了 CONFIGDEBUGMALLOC 才会有该文件.

meminfo

free(1) 利用该文件来给出系统总的空闲内存和已用内存 (包括物理内存和交换内存), 以及内核所使用的共享内存 和缓冲区.该文件与 free(1) 格式相同, 但是以字节为单位而不是 KB.

modules

列出了系统已载入的模块, 文本格式.

self

当某进程访问 /proc 目录时, 该目录就指向 /proc 下以该进 程 ID 命名的目录.

stat

内核及系统的统计数据.

uptime

该文件包含两个数: 系统正常运行时间和总的空闲时间, 都以秒为单位.

version

指明了当前正在运行的内核版本

获取当前进程的名称 C/C++代码实现
proc.h

...
struct proc {
	pid_t pid;
	pid_t ppid;
	pid_t tracer;
	unsigned long *auxvals;
	size_t nauxvals;
	char state;
	char *path;
	char *name;
	struct environ *environ;
	size_t nenviron;
	char **cmdline;
	size_t ncmdline;
	pid_t *threads;
	size_t nthreads;
};

struct module {
	void *base;
	size_t size;
	void *end;
	char *path;
	char *name;
};

struct page {
	void *base;
	size_t size;
	unsigned long offset;
	void *end;
	int prot;
	int flags;
};

int proc_enumpids(int(*callback)(pid_t pid, void *arg), void *arg);
int proc_checkpid(pid_t pid);
pid_t proc_getppid(pid_t pid);
pid_t proc_gettracer(pid_t pid);
int proc_enumauxvals(pid_t pid, int(*callback)(unsigned long type,
		     unsigned long val, void *arg), void *arg);
unsigned long proc_getauxval(pid_t pid, unsigned long type);
uid_t proc_getuid(pid_t pid);
uid_t proc_geteuid(pid_t pid);
gid_t proc_getgid(pid_t pid);
gid_t proc_getegid(pid_t pid);
char proc_getstate(pid_t pid);
unsigned long proc_getplatform(pid_t pid);
size_t proc_getpath(pid_t pid, char **ppathbuf, size_t maxlen);
size_t proc_getname(pid_t pid, char **pnamebuf, size_t maxlen);
int proc_enumenviron(pid_t pid,
		     int(*callback)(char *name, char *value, void *arg),
		     void *arg);
int proc_enumcmdline(pid_t pid, int(*callback)(char *cmdarg, void *arg),
		     void *arg);
size_t proc_getcmdline(pid_t pid, char **pcmdlinebuf, size_t maxlen);
int proc_enumthreads(pid_t pid, int(*callback)(pid_t tid, void *arg),
		     void *arg);
unsigned long proc_getentry(pid_t pid);
ssize_t proc_vmread(pid_t pid, off_t src, void *dst, size_t size);
ssize_t proc_vmwrite(pid_t pid, off_t dst, void *src, size_t size);
int proc_openproc(pid_t pid, struct proc *pproc);
void proc_closeproc(struct proc *pproc);

proc.c

...
int proc_openproc(pid_t pid, struct proc *pproc)
{
	int ret = -1;
	char *status_filebuf;
	char status_path[64] = { 0 };

	snprintf(status_path, sizeof(status_path) - 1, "/proc/%d/status", pid);
	status_filebuf = get_filebuf(status_path);
	if (!status_filebuf)
		goto EXIT;

	pproc->pid = pid;

	pproc->ppid = _proc_getppid(status_filebuf);
	if (pproc->ppid == (pid_t)-1)
		goto ERR_PPID;
	
	pproc->tracer = _proc_gettracer(status_filebuf);
	if (pproc->tracer == (pid_t)-1)
		goto ERR_TRACER;
	
	pproc->auxvals = (unsigned long *)NULL;
	pproc->nauxvals = 0;
	proc_enumauxvals(pproc->pid, _proc_openproc_callback_auxv,
			 (void *)pproc);
	if (!pproc->auxvals || !pproc->nauxvals)
		goto ERR_AUXVALS;
	
	pproc->state = _proc_getstate(status_filebuf);
	if (pproc->state == 0)
		goto ERR_STATE;
	
	if (!proc_getpath(pproc->pid, &pproc->path, 0))
		goto ERR_PATH;
	
	if (!_proc_getname(status_filebuf, &pproc->name, 0))
		goto ERR_NAME;
	
	pproc->environ = (struct environ *)NULL;
	pproc->nenviron = 0;
	if (proc_enumenviron(pproc->pid, _proc_openproc_callback_env, (void *)pproc))
		goto ERR_ENVIRON;
	
	pproc->cmdline = (char **)NULL;
	pproc->ncmdline = 0;
	if (proc_enumcmdline(pproc->pid, _proc_openproc_callback_cmd, (void *)pproc))
		goto ERR_CMDLINE;

	pproc->threads = (pid_t *)NULL;
	pproc->nthreads = 0;
	if (proc_enumthreads(pproc->pid, _proc_openproc_callback_tid, (void *)pproc))
		goto ERR_THREADS;

	ret = 0;
	goto EXIT; /* skip errors */

ERR_THREADS:
	{
		size_t i;

		for (i = 0; i < pproc->ncmdline; ++i)
			free(pproc->cmdline[i]);
		
		free(pproc->cmdline);
	}
ERR_CMDLINE:
	{
		size_t i;

		for (i = 0; i < pproc->nenviron; ++i) {
			free(pproc->environ[i].name);
			free(pproc->environ[i].value);
		}

		free(pproc->environ);
	}
ERR_ENVIRON:
	free(pproc->name);
ERR_NAME:
	free(pproc->path);
ERR_PATH:
ERR_STATE:
	free(pproc->auxvals);
ERR_AUXVALS:
ERR_TRACER:
ERR_PPID:
	free(status_filebuf);
EXIT:
	return ret;
}
...

main.c

int main(int argc, char **argv)
{
...

	pid = getpid();
	if (proc_openproc(pid, &proc)) {
		printf("[!] Unable to open process\n");
		return -1;
	}

	printf("[*] PID: %d\n", proc.pid);
	printf("[*] PPID: %d\n", proc.ppid);
	printf("[*] Tracer: %d\n", proc.tracer);
	printf("[*] UID: %d\n", (uid_t)proc.auxvals[AT_UID]);
	printf("[*] EUID: %d\n", (uid_t)proc.auxvals[AT_EUID]);
	printf("[*] GID: %d\n", (gid_t)proc.auxvals[AT_GID]);
	printf("[*] EGID: %d\n", (gid_t)proc.auxvals[AT_EGID]);
	printf("[*] Entry: %p\n", (void *)proc.auxvals[AT_ENTRY]);
	printf("[*] State: %c\n", proc.state);
	printf("[*] Path: %s\n", proc.path);
	printf("[*] Name: %s\n", proc.name);
	printf("[*] Environment Variables: \n");
	{
		size_t i;
		
		for (i = 0; i < proc.nenviron; ++i) {
			printf("\t%s=%s\n", proc.environ[i].name,
			       proc.environ[i].value);
		}
	}
	printf("[*] Command Line: ");
	{
		size_t i;

		for (i = 0; i < proc.ncmdline; ++i) {
			printf("%s ", proc.cmdline[i]);
		}
	}
	printf("\n");
	printf("[*] Threads: { ");
	{
		size_t i;
		
		for (i = 0; i < proc.nthreads; ++i) {
			printf("%d ", proc.threads[i]);
		}
	}
	printf("}\n");

	printf("===================\n");

	proc_closeproc(&proc);

	printf("Press ENTER to exit...");
	getchar();

	return 0;
}

编译运行

在这里插入图片描述proc获取当前进程的名称,其中包含有关进程的宝贵信息,如命令行、绝对路径、ppid、跟踪程序pid、状态、环境变量等。

If you need the complete source code of proc, add your WeChat number (c17865354792)

总结

proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。

系统中当前运行的每一个进程都有对应的一个目录在 proc 下,以进程的 PID 号为目录名,它们是读取进程信息的接口。

Welcome to follow WeChat official account【程序猿编码

参考:https://man7.org/linux/man-pages/man5/proc.5.html

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

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

相关文章

最新版 苹果 IOS AppStore证书申请全流程 包括p12文件

第一步 登陆开发者网站并进入证书管理页。 辅助工具网站地址&#xff1a;http://www.applicationloader.net/ 第二步 添加【Certificates】证书。在这里插入图片描述 第三步 进入添加页后&#xff0c;根据需求选择。 第四步 选择好环境之后&#xff0c;这里需要选择一个…

GitHub上传本地程序操作的问题解决汇总

1、新建远程仓库 2、提交本地程序到GitHub 完整命令汇总&#xff0c;这些命令的顺序已解决目前Git提交所遇到的下面问题 存在的问题展示部分没贴出来&#xff0c;可以先按命令顺序走一遍流程。 git init //把这个目录变成Git可以管理的仓库git checkout -b main //切换至main默…

如何零基础自学 Python ?听我娓娓道来

如何零基础自学 Python &#xff1f; 前言 今天这篇文章是对初学者的一篇学习资料分享与总结&#xff01; 简单介绍下笔者的自学之路 起初学习 Python 是在 2020 年&#xff0c;那时临近毕业&#xff0c;由于面临着找工作的不确定性&#xff0c;便学习了相关的网络安全知识&…

计组作业笔记【 总线 】

系统总线按传输内容不同分为数据总线&#xff0c;地址总线&#xff0c;控制总线。 片内总线与系统总线是并列关系&#xff0c;与通信总线一同作为总线按功能的分类。 所以选B 总线复用是指一种信号线在不同时间传输不同的信息。 所以该题选A。 当某设备正获得了总线控制权时…

系统安装技能测试

系统安装技能测试 目录 系统安装技能测试 一、制作PE U盘 安装完成之后查看U盘是否有PE 使用制作好的U盘进入PE界面 二、使用虚拟机进入PE界面 虚拟机成功进入PE主界面 三、PE界面进行分区操作 在PE模式下&#xff0c;使用ISO进行系统安装 四、PE系统备份 五、使用PXE进行网克…

Springboot毕业设计毕设作品,微信校园疫情防控小程序设计与实现

功能清单 【后台管理员功能】 关于我们设置&#xff1a;设置学校简介、联系我们、加入我们、法律声明、学校详情 广告管理&#xff1a;设置小程序首页轮播图广告和链接 留言列表&#xff1a;所有用户留言信息列表&#xff0c;支持删除 会员列表&#xff1a;查看所有注册会员信…

基于51单片机GPS定位系统设LCD12864显示(程序+原理图+PCB+论文)

资料编号&#xff1a;202 功能介绍&#xff1a; (1).定位功能 GPS通过接收卫星信号&#xff0c;可以准确地定出其所在的位置&#xff0c;位置误差小于10米。利用GPS&#xff0c;在12864上面显示当前位置。 (2).查询时间功能 GPS还可以接收卫星发下来的时间信息&#xff0c;…

【openEuler系列】配置本地yum源

个人名片&#xff1a; 对人间的热爱与歌颂&#xff0c;可抵岁月冗长&#x1f31e; Github&#x1f468;&#x1f3fb;‍&#x1f4bb;&#xff1a;念舒_C.ying CSDN主页✏️&#xff1a;念舒_C.ying 个人博客&#x1f30f; &#xff1a;念舒_C.ying 【openEuler系列】配置本地y…

漏洞深度分析|Apache Fineract 远程代码执行漏洞

项目介绍 Apache Fineract 是一个开源的系统&#xff0c;用于核心银行系统平台化建设。为创业者、金融机构和服务提供商提供了一个可靠、健壮的、可负担得起的金融服务解决方案。 项目地址 https://github.com/apache/fineract 漏洞概述 Apache Fineract 在 1.8.1 之前的版…

NR DCI Format介绍

NR DCI(下行控制信息)与LTE中的DCI类似&#xff0c;均是承载上/下行数据信道的调度信息&#xff08;如PDSCH/PUSCH&#xff09;。 如下表&#xff0c;摘自38212 7.3.1节。其中0-0/0-1承载上行数据信道PUSCH的调度信息。1-0/1-1承载下行数据信道PDSCH的调度信息&#xff0c;加扰…

QT断点调试[通俗易懂]

QT设置断点调试&#xff1a; 1、知道哪里可能出问题2、完全不清楚自己程序bug在哪3、跳过肯定不会出错的地方 前言&#xff1a; 这个东西难道大家不都应该会吗??? 本人用Qt Creator编写Qt的&#xff0c;~ 当然是有大佬用记事本写Qt的hhhh&#xff0c;每个人用IDE或者编辑器…

Python中__init__.py的作用介绍

一、文件__init__.py作用&#xff1a;package / module 的标志 下图的serrors包含这个文件时候&#xff0c;Python会将其当做一个模块&#xff08;module&#xff09;来处理&#xff0c;进而可以使用from serrors import xx方式导入serrors包中的文件或模块。 如图所示&#x…

Linux的IO(初阶)

Linux的IO(初阶) 文章目录Linux的IO(初阶)1.C语言文件IO1.1 C语言文件的(复习)1.2 相对路径与绝对路径(复习)1.3 C语言中文件操作函数(复习)1.4 C语言文件写入方式(复习)1.5 三个默认打开的流1.6 FILE类型的理解2.Linux系统文件IO2.1 打开文件的系统接口函数&#xff1a;open2.…

2023年,学测试还有前途吗?

最近因为疫情等各种原因&#xff0c;大厂裁员&#xff0c;失业等等频频受到关注。 不解释&#xff0c;确实存在&#xff0c;各行各业都很难&#xff0c;但是&#xff0c;说软件测试行业没有前途&#xff0c;我还真不认同&#xff08;不是为培训机构说好话&#xff0c;大环境不…

面向对象编程 上 (1)

目录 学习面向对象内容的三条主线 面向过程与面向对象 面向过程(POP) 与 面向对象(OOP) 面向对象的三大特征 例子&#xff1a;人把大象装进冰箱 面向对象的思想概述 类和对象 面向对象的思想概述 Java类及类的成员 类的语法格式 创建Java自定义类 对象的创建和使用 类…

2022最新的护眼灯怎么选?护眼台灯到底有用吗

众所周知&#xff0c;人眼能看到各种事物&#xff0c;都是由于光线照射到物体身上&#xff0c;然后反射进入人眼成像&#xff0c;但是如果光线不合理或者不合适&#xff0c;那么进入人眼的光线就会对造成巨大的伤害。所以护眼灯到底有没有用&#xff0c;就在于其发出的光线能不…

【python与数据分析】实验十三 北京市空气质量

目录 一、实验内容 二、完成情况 三、数据分析 1.问题描述 2.编程思路 3.程序代码 4.程序运行结果 &#xff08;1&#xff09;2014年-2019年AQI时间序列折线图 &#xff08;2&#xff09;各年AQI折线图、AQI直方图、PM2.5与AQI散点图、空气质量整体情况的饼图 ​&am…

关于虚数与复数

关于虚数与复数1 数的分类1.1 实数域1.2 虚数与复数2 复数的性质及其运算2.1 复平面、大小及辐角2.2 复数四则运算2.3 共轭复数2.4 复数的极坐标表示3 欧拉公式3.1 欧拉公式证明3.2 利用欧拉公式表示极坐标3.3 欧拉公式推导三角函数加法定理4 复数的性质、乘法和除法运算和极坐…

catia基本操作

1.2CATIA的基本操作_哔哩哔哩_bilibili ctrl鼠标中键 视图放大缩小 alt鼠标中键 视图平移 Alt Enter 性质 4、中键可以平移图形 中键和左键&#xff08;或右键&#xff09;可以实现旋转 按下中键&#xff0c;再按右键&#xff0c;放开右键&#xff0c;拖动鼠标&#xff…

【阿里云】阿里云跨账号内网互通

阿里云VPC对等连接提供连通两个VPC的网络连接&#xff0c;您可以使用私有IP地址直接通信&#xff0c;两个VPC就像在同一个网络中一样。您可以与自己同地域或者跨地域其他VPC之间创建对等连接&#xff0c;也可以与其他账号的同地域或者跨地域VPC之间建立对等连接&#xff0c;同地…