parsing/ proc / file是否安全?

我想parsing/proc/net/tcp/ ,但是安全吗?

我应该如何打开和从/proc/读取文件,而不是害怕,一些其他进程(或操作系统本身)将在同一时间改变它?

一般来说,没有。 (所以这里的大部分答案都是错误的。)这可能是安全的,取决于你想要的属性。 但是如果你对/proc文件的一致性假设过多,那么在你的代码中最后会出现bug。 例如,看到这个错误是由于/proc/mounts是一个一致的快照而产生的 。

例如:

  • /proc/uptime完全primefaces的 ,正如有人在另一个答案中提到的那样 – 但只是从Linux 2.6.30开始 ,这是不到两年的时间。 所以即使这个微小的文件也一直处于竞争状态,而且在大多数企业内核中依然存在。 请参阅fs/proc/uptime.c以获取当前源或提交primefaces的提交 。 在2.6.30内核之前,你可以open这个文件, read一下它,如果你以后回来read一遍,那么你得到的这个文件将与第一个文件不一致。 (我刚才展示了这个 – 试试吧,以获得乐趣。)

  • /proc/mounts单个read系统调用中的primefaces。 因此,如果您一次read整个文件,则会在系统上获得一个一致的安装点快照。 但是,如果您使用多个read系统调用 – 而且文件很大,那么如果您使用正常的I / O库并且不特别关注这个问题,就会发生这种情况 – 您将受到竞赛条件。 你不但不能得到一致的快照,而且在你开始之前存在的挂载点并且永远不会停止存在,在你看到的东西中可能会丢失。 要看到它是一个read()的primefaces,看看fs/namespace.c中的m_start() ,并看到它抓住一个信号量来保护挂载点列表,直到m_stop() read()完成了。 要看看会出现什么问题,请看看去年 (与上面链接的那个相同)的高级软件,它会轻易读取/proc/mounts

  • /proc/net/tcp ,这是你真正要问的,甚至不如此一致。 这只是在表格的每一行中primefaces 。 要看到这个,看看net/ipv4/tcp_ipv4.c中的listening_get_next()和正下方的established_get_next()在同一个文件中,依次查看它们在每个条目上取出的锁。 我没有repro代码方便地演示行与行之间缺乏一致性,但没有任何锁(或其他任何东西)会使其一致。 如果您考虑这一点,这是有道理的 – networking通常是系统中超级繁忙的部分,因此在诊断工具中呈现一致的视图是不值得的。

在每一行中保持/proc/net/tcpprimefaces的另一部分是seq_read()的缓冲,您可以在fs/seq_file.c读取fs/seq_file.c 。 这可以确保一旦read()一行的一部分,整行的文本就保存在一个缓冲区中,以便下一个read()会在启动一个新行之前得到该行的其余部分。 在/proc/mounts使用相同的机制来保持每行都是primefaces的,即使您执行了多个read()调用,也是新内核中的/proc/uptime保持primefaces性的机制。 该机制不会缓冲整个文件,因为内核对内存使用非常谨慎。

/proc大多数文件至less与/proc/net/tcp一致,每行在其提供的任何信息中都有一个一致的图片,因为它们大多数使用相同的seq_file抽象。 正如/proc/uptime例子所说明的,尽pipe如此,2009 seq_file一些文件仍然被迁移到使用seq_file ; 我敢打赌,还有一些使用旧的机制,甚至没有这样的primefaces水平。 这些警告很lesslogging。 对于一个给定的文件,你唯一的保证是读取源文件。

/proc/net/tcp的情况下,你可以阅读它并parsing每一行而不用担心。 但是,如果你试图从多行中得出任何结论,要小心,其他进程和内核正在改变它,而你可能正在创build一个bug。

尽pipe/proc的文件显示为用户空间中的常规文件,但它们不是真正的文件,而是支持用户空间( openreadclose )的标准文件操作的实体。 请注意,这与在内核中更改磁盘上的普通文件完全不同。

所有内核都使用类似sprintf的函数将其内部状态打印到自己的内存中,并且只要发出read(2)系统调用,该内存就被复制到用户空间中。

内核以与普通文件完全不同的方式处理这些调用,这可能意味着在open(2)它时,您将读取的数据的整个快照可以准备好,而内核则确保并发调用一致和primefaces。 我没有看到任何地方,但其他地方没有任何意义。

我的build议是看看在你的特定的Unix风格的proc文件的实现。 这实际上是一个实现问题(如输出的格式和内容),不受标准支配。

最简单的例子就是在Linux中执行uptime proc文件。 注意整个缓冲区是如何在提供给single_open的callback函数中产生的。

/ proc是一个虚拟文件系统:实际上,它只是给出了内核内部的一个方便的视图。 读它肯定是安全的(这就是为什么它在这里),但从长远来看这是有风险的,因为这些虚拟文件的内部可能随着更新版本的内核而发展。

编辑

在Linux内核文档中的proc文档中有更多的信息,第1.4章networking我找不到信息是如何随着时间的推移而发展的。 我以为这是公开的冻结,但不能有一个确定的答案。

EDIT2

根据Sco文档 (不是Linux,但我非常确定所有* nix的行为都是这样的)

尽pipe进程状态和/ proc文件的内容可以从瞬间变为瞬间,但是/ proc文件的单个读(2)保证返回一个“健全”的状态表示,也就是读进程状态的primefaces快照。 没有这样的保证适用于应用于正在运行的进程的/ proc文件的连续读取。 另外,对于应用于(地址空间)文件的任何I / O,primefaces性并不能保证; 任何进程的地址空间的内容都可能由该进程的LWP或系统中的任何其他进程同时修改。

Linux内核中的procfs API提供了一个接口来确保读取返回一致的数据。 阅读__proc_file_read的注释。 项目1)在大注释块中解释了这个接口。

这就是说,当然要执行一个特定的proc文件来正确地使用这个接口来确保它返回的数据是一致的。 所以,要回答你的问题:不,内核不能保证读取过程中proc文件的一致性,但它提供了实现这些文件的方法来提供一致性。

因为我在embedded式ARM目标上正在进行驱动程序开发,所以我有Linux 2.6.27.8的来源。

第934行的文件… linux-2.6.27.8-lpc32xx/net/ipv4/raw.c包含,例如

  seq_printf(seq, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", i, src, srcp, dest, destp, sp->sk_state, atomic_read(&sp->sk_wmem_alloc), atomic_read(&sp->sk_rmem_alloc), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops)); 

哪个输出

 [wally@zenetfedora ~]$ cat /proc/net/tcp sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode 0: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 15160 1 f552de00 299 1: 00000000:C775 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 13237 1 f552ca00 299 ... 

在函数raw_sock_seq_show() ,它是procfs处理函数层次结构的一部分。 直到由/proc/net/tcp文件发出read()请求才会生成文本,这是一个合理的机制,因为procfs读取肯定比更新信息less得多。

一些驱动程序(例如我的)使用一个sprintf()实现proc_read函数。 核心驱动程序实现中的额外复杂因素是处理潜在的非常长的输出,在单个读取期间可能不适合中间的内核空间缓冲区。

我用一个使用64K读取缓冲区的程序testing过,但是在我的系统中产生了一个3072字节的内核空间缓冲区,以便proc_read返回数据。 带前进指针的多个调用需要得到更多的文本返回。 我不知道什么是正确的方式来使返回的数据一致时,需要多个I / O。 当然/proc/net/tcp每个条目都是自我一致的。 在不同的时间,有可能并排的线是快照。

缺less未知错误, /proc中没有竞争条件,导致读取损坏的数据或新旧数据混合。 从这个意义上说,这是安全的。 但是仍然存在竞争条件:从/proc读取的大部分数据一旦生成就可能已经过时,甚至在读取/处理数据的时候也是如此。 例如,进程可以在任何时候死亡,一个新的进程可以被分配相同的PID; 你唯一可以在没有竞争条件的情况下使用的过程ID就是你自己的subprocess。 networking信息(开放端口等)和/proc大部分信息也是如此。 我认为依靠/proc任何数据是准确的,除了关于你自己的进程和潜在的subprocess的数据之外,这是一个糟糕而危险的做法。 当然,将/proc中的其他信息提供给用户/pipe理员以提供信息/logging等仍然是有用的。 目的。

当从/ proc文件中读取内核时,内核正在调用一个预先注册的函数,作为该proc文件的“读取”函数。 请参阅fs / proc / generic.c中的__proc_file_read函数。

因此,proc的读取安全性与内核调用的函数满足读取请求一样安全。 如果该function正确地locking了所有接触到的数据,并返回给你一个缓冲区,那么使用该function是完全安全的。 由于像proc / net / tcp这样的用于满足读取请求的proc文件已经存在了一段时间,并且经过了严格的审查,所以它们就像你所要求的那样安全。 事实上,许多常见的Linux实用程序都依赖于从proc文件系统读取数据,并以不同的方式格式化输出。 (关于我的头顶,我认为'ps'和'netstat'是这样做的)。

和往常一样,你不需要听我的话, 你可以看看来源来平息你的恐惧。 以下来自proc_net_tcp.txt的文档告诉你/ proc / net / tcp的“读取”function在哪里,所以你可以看看从proc文件读取时运行的实际代码,并确认没有locking危险。

本文档描述了interfaces / proc / net / tcp和/ proc / net / tcp6。
请注意,这些接口已弃用,以支持tcp_diag。 这些/ proc接口提供有关当前活动的TCP连接的信息,分别由net / ipv4 / tcp_ipv4.c中的tcp4_seq_show()和net / ipv6 / tcp_ipv6.c中的tcp6_seq_show()实现。