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/tcp
primefaces的另一部分是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
的文件显示为用户空间中的常规文件,但它们不是真正的文件,而是支持用户空间( open
, read
, close
)的标准文件操作的实体。 请注意,这与在内核中更改磁盘上的普通文件完全不同。
所有内核都使用类似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()实现。