Linux描述符文件和示例

一次,在一次采访中,他们问我如果发现由于磁盘空间不足而无法使用的服务该怎么办?

当然,我回答说,我将看到这个地方被占用了,如果可能的话,我会清理这个地方。
然后,面试官问,该部分是否没有可用空间,但是您也看不到占据整个位置的文件?

为此,我说过,您始终可以例如使用lsof命令查看打开的文件描述符,并了解哪个应用程序占用了所有可用空间,然后可以根据情况进行操作,具体取决于是否需要数据。

面试官最后一句话打断了我,并补充了我的问题:“假设我们不需要数据,它只是调试日志,但是应用程序无法运行,因为它无法记录调试信息?”?

我回答说:“好的,我们可以在应用程序的配置中关闭调试并重新启动它。”
采访者反对:“不,我们无法重新启动应用程序,重要数据仍存储在我们的内存中,并且重要的客户端已连接到服务本身,因此我们不能强行重新连接”。

我说:“好吧,如果我们无法重新启动应用程序并且数据对我们来说并不重要,那么即使我们在文件系统上的ls命令中看不到它,也可以通过文件描述符简单地清除此打开的文件。”

面试官很高兴,但我不满意。

然后我想,为什么测试我的知识的人不更深入? 但是,如果数据仍然很重要怎么办? 如果我们无法重新启动该过程,并且与此过程同时在没有可用空间的部分中将其写入文件系统,该怎么办? 如果我们不仅不能丢失已经记录的数据,而且还可以丢失此过程写入或尝试记录的数据怎么办?

图兹克


在我职业生涯的开始,我试图创建一个小型应用程序,在其中必须存储有关用户的信息。 然后我想,如何将用户映射到他的数据。 例如,我有Ivan Ivanov Ivanich,他有一些数据,但是如何与他们交朋友呢? 我可以直接指出,名为“ Tuzik”的狗就属于这个伊凡。 但是,如果他更改了自己的名字而代替了伊凡,例如奥利亚,该怎么办? 事实证明,我们的Olya Ivanovna Ivanova将不再养狗,而我们的Tuzik仍属于不存在的Ivan。 该数据库得到一个数据库的帮助,该数据库为每个用户提供了一个唯一的标识符(ID),而我的Tuzik附加到该ID,实际上,这只是一个序数。 因此,tuzik的所有者的ID为2,并且在某个时间点Ivan处于该ID下,然后Olya成为相同的ID。 人畜问题已得到切实解决。

文件描述符


文件和使用此文件的程序的问题与我们的狗和人的问题大致相同。 假设我打开了一个名为ivan.txt的文件,并开始在其中写入单词tuzik,但是设法仅将第一个字母“ t”写入该文件,并且该文件被某人重命名,例如olya.txt。 但是文件保持不变,我仍然想在其中写入我的Ace。 每次使用任何编程语言通过开放系统调用打开文件时,我都会获得一个指向文件的唯一ID,该ID是文件描述符。 不管该文件的下一步操作是什么,他们都可以删除它,重命名它,更改所有者或删除读写权限,但我仍然可以访问它,因为在打开文件时我有权阅读和/或编写它,并且我设法开始与他合作,这意味着我必须继续这样做。

在Linux上,将为每个正在运行的应用程序(进程)3描述符文件打开libc库,编号为0,1,2。 您可以在链接man stdioman stdout上找到更多信息。

  • 文件描述符0称为STDIN,并且与从应用程序输入的数据相关联
  • 文件描述符1称为STDOUT,由应用程序用于输出数据,例如打印命令
  • 文件描述符2称为STDERR,应用程序使用它来输出错误报告数据。

如果在程序中打开文件进行读取或写入,则很可能会获得第一个免费ID,该ID为3。

如果知道描述符文件的PID,则可以从任何进程查看描述符文件的列表。

例如,使用bash打开一个控制台,然后查看我们进程的PID

[user@localhost ]$ echo $$ 15771 

在第二个控制台中,运行

 [user@localhost ]$ ls -lah /proc/15771/fd/ total 0 dr-x------ 2 user user 0 Oct 7 15:42 . dr-xr-xr-x 9 user user 0 Oct 7 15:42 .. lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21 

您可以放心地忽略本文框架中的文件描述符编号255;它是由bash本身(而不是由链接库)根据需要打开的。

现在,所有3个描述符文件都与伪终端设备/ dev / pts关联,但是我们仍然可以操纵它们,例如,在第二个控制台中运行

 [user@localhost ]$ echo "hello world" > /proc/15771/fd/0 

在第一个控制台中,我们将看到

 [user@localhost ]$ hello world 

重定向和管道


您可以在任何进程中轻松覆盖这3个描述符文件,包括在bash中,例如,通过连接两个进程的管道,请参见

 [user@localhost ]$ cat /dev/zero | sleep 10000 

您可以使用strace -f自己运行此命令,并查看内部发生的情况,但我将简要介绍一下。

我们带有PID 15771的父进程bash解析我们的命令,并确切地了解我们要运行多少个命令,在我们的例子中,有两个命令:cat和sleep。 Bash知道他需要创建两个子进程,并将它们与一个管道结合在一起。 总共bash需要2个子进程和1个管道。

在创建子进程之前,bash启动管道系统调用并接收临时管道缓冲区的新文件描述符,但是该缓冲区尚未绑定我们的两个子进程。

对于父进程,看起来管道已经存在,并且还没有子进程:

 PID command 15771 bash lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 3 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:42 4 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21 

然后,使用系统调用, clone bash创建两个子进程,我们的三个进程如下所示:

 PID command 15771 bash lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 3 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:42 4 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21 PID command 9004 bash lrwx------ 1 user user 64 Oct 7 15:57 0 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 3 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:57 4 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:57 255 -> /dev/pts/21 PID command 9005 bash lrwx------ 1 user user 64 Oct 7 15:57 0 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 3 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:57 4 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:57 255 -> /dev/pts/21 

不要忘记克隆会与所有文件描述符一起克隆该进程,因此它们在父进程和子进程中将是相同的。 具有PID 15771的父进程的任务是监视子进程,因此它仅等待子进程的响应。

因此,他不需要管道,并且用数字3和4关闭文件描述符。

在具有PID 9004的第一个bash子进程中, dup2系统调用将我们的STDOUT文件描述符编号1更改为指向管道的文件描述符,在本例中为3。因此,具有PID 9004的第一个子进程将写入STDOUT的所有内容将自动落入管道缓冲区。

在使用PID 9005的第二个子进程中,bash使用dup2更改了描述符STDIN的编号为0,现在,我们使用PID 9005的第二bash读取的所有内容将从管道中读取。

此后,数字3和4的描述符也将在子进程中关闭,因为不再使用它们。

我故意忽略文件描述符255,它使用bash满足内部需要,并且也会在子进程中关闭。

此外,在具有PID 9004的第一个子进程中,bash使用系统调用exec启动在命令行上指定的可执行文件,在本例中为/ usr / bin / cat。

在PID 9005的第二个子进程中,bash启动我们指定的第二个可执行文件,在本例中为/ usr / bin / sleep。

如果在打开调用期间未使用O_CLOEXEC标志打开文件描述符,则exec系统调用不会关闭文件描述符。 在我们的情况下,运行可执行文件后,将保存所有当前文件描述符。

检入控制台:

 [user@localhost ]$ pgrep -P 15771 9004 9005 [user@localhost ]$ ls -lah /proc/15771/fd/ total 0 dr-x------ 2 user user 0 Oct 7 15:42 . dr-xr-xr-x 9 user user 0 Oct 7 15:42 .. lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21 [user@localhost ]$ ls -lah /proc/9004/fd total 0 dr-x------ 2 user user 0 Oct 7 15:57 . dr-xr-xr-x 9 user user 0 Oct 7 15:57 .. lrwx------ 1 user user 64 Oct 7 15:57 0 -> /dev/pts/21 l-wx------ 1 user user 64 Oct 7 15:57 1 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21 lr-x------ 1 user user 64 Oct 7 15:57 3 -> /dev/zero [user@localhost ]$ ls -lah /proc/9005/fd total 0 dr-x------ 2 user user 0 Oct 7 15:57 . dr-xr-xr-x 9 user user 0 Oct 7 15:57 .. lr-x------ 1 user user 64 Oct 7 15:57 0 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:57 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21 [user@localhost ]$ ps -up 9004 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND user 9004 0.0 0.0 107972 620 pts/21 S+ 15:57 0:00 cat /dev/zero [user@localhost ]$ ps -up 9005 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND user 9005 0.0 0.0 107952 360 pts/21 S+ 15:57 0:00 sleep 10000 

如您所见,我们的管道的唯一编号在两个过程中都相同。 因此,我们在一个父级的两个不同进程之间建立了联系。

对于那些不熟悉bash使用的系统调用的人,我强烈建议您通过strace运行命令并查看内部发生了什么,例如:

 strace -s 1024 -f bash -c "ls | grep hello" 

让我们回到磁盘空间不足并尝试在不重新启动进程的情况下保存数据的问题。 让我们编写一个小程序,该程序每秒将大约1兆字节写入磁盘。 此外,如果由于某种原因我们无法将数据写入磁盘,我们将简单地将其忽略,然后尝试在一秒钟后再次写入数据。 在我使用Python的示例中,您可以使用任何其他编程语言。

 [user@localhost ]$ cat openforwrite.py import datetime import time mystr="a"*1024*1024+"\n" with open("123.txt", "w") as f: while True: try: f.write(str(datetime.datetime.now())) f.write(mystr) f.flush() time.sleep(1) except: pass 

运行程序并查看文件描述符

 [user@localhost ]$ python openforwrite.py & [1] 3762 [user@localhost ]$ ps axuf | grep [o]penforwrite user 3762 0.0 0.0 128600 5744 pts/22 S+ 16:28 0:00 | \_ python openforwrite.py [user@localhost ]$ ls -la /proc/3762/fd total 0 dr-x------ 2 user user 0 Oct 7 16:29 . dr-xr-xr-x 9 user user 0 Oct 7 16:29 .. lrwx------ 1 user user 64 Oct 7 16:29 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 7 16:29 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 7 16:29 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 7 16:29 3 -> /home/user/123.txt 

如您所见,我们有3个标准文件描述符和另一个打开的文件描述符。 检查文件大小:

 [user@localhost ]$ ls -lah 123.txt -rw-rw-r-- 1 user user 117M Oct 7 16:30 123.txt 

正在写入数据,请尝试更改文件权限:

 [user@localhost ]$ sudo chown root: 123.txt [user@localhost ]$ ls -lah 123.txt -rw-rw-r-- 1 root root 168M Oct 7 16:31 123.txt [user@localhost ]$ ls -lah 123.txt -rw-rw-r-- 1 root root 172M Oct 7 16:31 123.txt 

尽管我们的用户无权写入文件,但我们仍看到数据仍在写入中。 让我们尝试将其删除:

 [user@localhost ]$ sudo rm 123.txt [user@localhost ]$ ls 123.txt ls: cannot access 123.txt: No such file or directory 

数据写在哪里? 而且它们是全部写的吗? 我们检查:

 [user@localhost ]$ ls -la /proc/3762/fd total 0 dr-x------ 2 user user 0 Oct 7 16:29 . dr-xr-xr-x 9 user user 0 Oct 7 16:29 .. lrwx------ 1 user user 64 Oct 7 16:29 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 7 16:29 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 7 16:29 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 7 16:29 3 -> /home/user/123.txt (deleted) 

是的,我们的描述符文件仍然存在,我们可以像使用旧文件一样使用此描述符文件,我们可以读取,清理和复制它。

我们看一下文件大小:

 [user@localhost ]$ lsof | grep 123.txt python 31083 user 3w REG 8,5 19923457 2621522 /home/user/123.txt 

文件大小19923457。尝试清除文件:

 [user@localhost ]$ truncate -s 0 /proc/31083/fd/3 [user@localhost ]$ lsof | grep 123.txt python 31083 user 3w REG 8,5 136318390 2621522 /home/user/123.txt 

如您所见,文件大小仅在增加,而我们的trankate无效。 有关开放系统调用,请参考文档。 如果在打开文件时使用O_APPEND标志,则每次操作系统检查文件大小并将数据写入文件的最后时,它都会自动执行此操作。 这允许多个线程或进程写入同一文件。 但是在我们的代码中,我们不使用此标志。 仅在打开文件进行其他记录时,我们才能在lsof中看到不同的文件大小,这意味着,而不是在我们的代码中

 with open("123.txt", "w") as f: 

我们必须把

 with open("123.txt", "a") as f: 

用“ w”标志检查

 [user@localhost ]$ strace -e trace=open python openforwrite.py 2>&1| grep 123.txt open("123.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 

并带有“ a”标志

 [user@localhost ]$ strace -e trace=open python openforwrite.py 2>&1| grep 123.txt open("123.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3 

对已经运行的进程进行编程


在创建和测试程序时,程序员经常在应用程序中使用调试器(例如GDB)或各种级别的日志记录。 Linux提供了实际编写和更改已经运行的程序的功能,例如,更改变量的值,设置断点等。

返回到磁盘空间不足以写入文件的原始问题,我们将尝试模拟该问题。

为分区创建一个文件,该文件将作为单独的磁盘装入:

 [user@localhost ~]$ dd if=/dev/zero of=~/tempfile_for_article.dd bs=1M count=10 10+0 records in 10+0 records out 10485760 bytes (10 MB) copied, 0.00525929 s, 2.0 GB/s [user@localhost ~]$ 

创建一个文件系统:

 [user@localhost ~]$ mkfs.ext4 ~/tempfile_for_article.dd mke2fs 1.42.9 (28-Dec-2013) /home/user/tempfile_for_article.dd is not a block special device. Proceed anyway? (y,n) y ... Writing superblocks and filesystem accounting information: done [user@localhost ~]$ 

挂载文件系统:

 [user@localhost ~]$ sudo mount ~/tempfile_for_article.dd /mnt/ [sudo] password for user: [user@localhost ~]$ df -h | grep mnt /dev/loop0 8.7M 172K 7.9M 3% /mnt 

与我们的所有者创建目录:

 [user@localhost ~]$ sudo mkdir /mnt/logs [user@localhost ~]$ sudo chown user: /mnt/logs 

我们打开文件以仅在程序中写入:

 with open("/mnt/logs/123.txt", "w") as f: 

我们启动

 [user@localhost ]$ python openforwrite.py 

等待几秒钟

 [user@localhost ~]$ df -h | grep mnt /dev/loop0 8.7M 8.0M 0 100% /mnt 

因此,我们得到了本文开头所述的问题。 可用空间为0,已占用100%。

我们记住,根据任务的条件,我们正在尝试记录非常重要的数据,这些数据不会丢失。 同时,我们需要在不重新启动过程的情况下修复服务。

假设我们仍然有磁盘空间,但是在另一个分区中,例如/ home。

让我们尝试“即时编程”我们的代码。

我们看一下进程的PID,它占用了所有磁盘空间:

 [user@localhost ~]$ ps axuf | grep [o]penfor user 10078 27.2 0.0 128600 5744 pts/22 R+ 11:06 0:02 | \_ python openforwrite.py 

我们通过gdb连接到进程

 [user@localhost ~]$ gdb -p 10078 ... (gdb) 

我们看一下打开的文件描述符:

 (gdb) shell ls -lah /proc/10078/fd/ total 0 dr-x------ 2 user user 0 Oct 8 11:06 . dr-xr-xr-x 9 user user 0 Oct 8 11:06 .. lrwx------ 1 user user 64 Oct 8 11:09 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:09 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:06 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:09 3 -> /mnt/logs/123.txt 

我们查看编号3的文件描述符信息,这对我们很感兴趣

 (gdb) shell cat /proc/10078/fdinfo/3 pos: 8189952 flags: 0100001 mnt_id: 482 

记住Python做什么样的系统调用(请参见上文,我们在其中运行strace并找到了open调用),处理代码以打开文件,我们以自己的名义执行相同的操作,但是我们需要O_WRONLY | O_CREAT | O_TRUNC位用数值代替。 为此,请在此处打开内核源代码,例如,查看哪些标志负责什么。

#定义O_WRONLY 00000001
#定义O_CREAT 00000100
#定义O_TRUNC 00001000

我们将所有值合为一,得到00001101

从gdb运行我们的电话

 (gdb) call open("/home/user/123.txt", 00001101,0666) $1 = 4 

因此,我们得到了一个编号为4的新描述符文件,另一部分为一个新的打开文件,请检查:

 (gdb) shell ls -lah /proc/10078/fd/ total 0 dr-x------ 2 user user 0 Oct 8 11:06 . dr-xr-xr-x 9 user user 0 Oct 8 11:06 .. lrwx------ 1 user user 64 Oct 8 11:09 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:09 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:06 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:09 3 -> /mnt/logs/123.txt l-wx------ 1 user user 64 Oct 8 11:15 4 -> /home/user/123.txt 

我们记得管道示例-bash如何更改文件描述符,并且已经学习了dup2系统调用。

我们尝试将一个文件描述符替换为另一个文件描述符

 (gdb) call dup2(4,3) $2 = 3 

我们检查:

 (gdb) shell ls -lah /proc/10078/fd/ total 0 dr-x------ 2 user user 0 Oct 8 11:06 . dr-xr-xr-x 9 user user 0 Oct 8 11:06 .. lrwx------ 1 user user 64 Oct 8 11:09 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:09 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:06 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:09 3 -> /home/user/123.txt l-wx------ 1 user user 64 Oct 8 11:15 4 -> /home/user/123.txt 

我们关闭文件描述符4,因为我们不需要它:

 (gdb) call close (4) $1 = 0 

并退出gdb

 (gdb) quit A debugging session is active. Inferior 1 [process 10078] will be detached. Quit anyway? (y or n) y Detaching from program: /usr/bin/python2.7, process 10078 

检查新文件:

 [user@localhost ~]$ ls -lah /home/user/123.txt -rw-rw-r-- 1 user user 5.1M Oct 8 11:18 /home/user/123.txt [user@localhost ~]$ ls -lah /home/user/123.txt -rw-rw-r-- 1 user user 7.1M Oct 8 11:18 /home/user/123.txt 

如您所见,数据已写入一个新文件,请检查旧文件:

 [user@localhost ~]$ ls -lah /mnt/logs/123.txt -rw-rw-r-- 1 user user 7.9M Oct 8 11:08 /mnt/logs/123.txt 

数据不会丢失,应用程序将运行,日志将被写入新位置。

让我们把任务复杂一点


想象一下数据对我们很重要,但是任何部分都没有磁盘空间,因此我们无法连接磁盘。

我们可以做的是将数据重定向到某个地方,例如到管道,然后来自管道的数据又通过某些程序(例如netcat)重定向到网络。
我们可以使用mkfifo命令创建一个命名管道。 即使文件系统上没有可用空间,它也会在文件系统上创建一个伪文件。

我们重新启动应用程序,并检查:

 [user@localhost ]$ python openforwrite.py [user@localhost ~]$ ps axuf | grep [o]pen user 5946 72.9 0.0 128600 5744 pts/22 R+ 11:27 0:20 | \_ python openforwrite.py [user@localhost ~]$ ls -lah /proc/5946/fd total 0 dr-x------ 2 user user 0 Oct 8 11:27 . dr-xr-xr-x 9 user user 0 Oct 8 11:27 .. lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/123.txt [user@localhost ~]$ df -h | grep mnt /dev/loop0 8.7M 8.0M 0 100% /mnt 

没有磁盘空间,但是我们在此处成功创建了一个命名管道:

 [user@localhost ~]$ mkfifo /mnt/logs/megapipe [user@localhost ~]$ ls -lah /mnt/logs/megapipe prw-rw-r-- 1 user user 0 Oct 8 11:28 /mnt/logs/megapipe 

现在,我们需要以某种方式将进入该管道的所有数据通过网络包装到另一台服务器,为此,所有相同的netcat都会这样做。

在remote-server.example.com服务器上,运行

 [user@localhost ~]$ nc -l 7777 > 123.txt 

在我们的问题服务器上,在单独的终端上运行

 [user@localhost ~]$ nc remote-server.example.com 7777 < /mnt/logs/megapipe 

现在,进入管道的所有数据将自动转到netcat中的stdin,它将通过端口7777发送到网络。

我们要做的就是开始将数据写入此命名管道。

我们已经有一个正在运行的应用程序:

 [user@localhost ~]$ ps axuf | grep [o]pen user 5946 99.8 0.0 128600 5744 pts/22 R+ 11:27 169:27 | \_ python openforwrite.py [user@localhost ~]$ ls -lah /proc/5946/fd total 0 dr-x------ 2 user user 0 Oct 8 11:27 . dr-xr-xr-x 9 user user 0 Oct 8 11:27 .. lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/123.txt 

在所有标志中,我们只需要O_WRONLY,因为该文件已经存在并且我们不需要清除它

 [user@localhost ~]$ gdb -p 5946 ... (gdb) call open("/mnt/logs/megapipe", 00000001,0666) $1 = 4 (gdb) shell ls -lah /proc/5946/fd total 0 dr-x------ 2 user user 0 Oct 8 11:27 . dr-xr-xr-x 9 user user 0 Oct 8 11:27 .. lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/123.txt l-wx------ 1 user user 64 Oct 8 14:20 4 -> /mnt/logs/megapipe (gdb) call dup2(4,3) $2 = 3 (gdb) shell ls -lah /proc/5946/fd total 0 dr-x------ 2 user user 0 Oct 8 11:27 . dr-xr-xr-x 9 user user 0 Oct 8 11:27 .. lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/megapipe l-wx------ 1 user user 64 Oct 8 14:20 4 -> /mnt/logs/megapipe (gdb) call close(4) $3 = 0 (gdb) shell ls -lah /proc/5946/fd total 0 dr-x------ 2 user user 0 Oct 8 11:27 . dr-xr-xr-x 9 user user 0 Oct 8 11:27 .. lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/megapipe (gdb) quit A debugging session is active. Inferior 1 [process 5946] will be detached. Quit anyway? (y or n) y Detaching from program: /usr/bin/python2.7, process 5946 

检查远程服务器remote-server.example.com

 [user@localhost ~]$ ls -lah 123.txt -rw-rw-r-- 1 user user 38M Oct 8 14:21 123.txt 

数据走了,我们检查问题服务器

 [user@localhost ~]$ ls -lah /mnt/logs/ total 7.9M drwxr-xr-x 2 user user 1.0K Oct 8 11:28 . drwxr-xr-x 4 root root 1.0K Oct 8 10:55 .. -rw-rw-r-- 1 user user 7.9M Oct 8 14:17 123.txt prw-rw-r-- 1 user user 0 Oct 8 14:22 megapipe 

数据已保存,问题已解决。

我借此机会向Degiro的同事们表达我的问候。
收听Radio T播客。

对所有人都好。

作为一项家庭作业,我建议考虑一下如果运行以下命令,cat and sleep进程的文件描述符中将包含什么内容:

 [user@localhost ~]$ cat /dev/zero 2>/dev/null| sleep 10000 

Source: https://habr.com/ru/post/zh-CN471038/


All Articles