有一次做研发的一位同事,因为系统根目录空间不足,想释放磁盘空间,结果使

用find命令找到了单个文件大于1GB的文件,发现/var/log/messages和

/var/log/warn文件每个都是1.3GB。他的系统根目录空间只有50GB的容量,结果

把/var/log/messages日志文件及/var/log/warn日志文给删除了。删除之后,却

没有达到的目的,磁盘使用空间依然是100%。


殊不知,当进程打开了某个文件时,只要该进程保持打开该文件,即使将其删除,

它依然存在于磁盘中。这意味着,进程并不知道文件已经被删除,它仍然可以向

打开该文件时提供给它的文件描述符进行读取和写入。除了该进程之外,这个文

件是不可见的,因为已经删除了其相应的目录条目。


拿/var/log/messages文件为例,看看如何在故意删除后如何找回来。我们先看一

下/var/log/messages文件是什么进程打开的。

1
2
3
4
5
\begin{verbatim}
[root@iLiuc ~]# lsof /var/log/messages 
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
syslog-ng 1493 root   10w   REG    8,2 57599903 3080573 /var/log/messages
\end{verbatim}


该命令的输出表明,/var/log/messages文件由syslog-ng进程打开,当前的进程

号为1493,用户身份是root,打开的文件描述符为10且该文件处于只写模式,对

应的TYPE(类型)为REG(常规)文件、磁盘位置、文件大小(以字节为单位)、

索引节点。下面一一验证:

1
2
3
4
5
6
7
8
9
10
11
\begin{verbatim}
[root@iLiuc ~]# stat /var/log/messages 
  File: `/var/log/messages'
  Size: 57603503   Blocks: 112632     IO Block: 4096   regular file
Device: 802h/2050d Inode: 3080573     Links: 1
Access: (0640/-rw-r-----)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2015-03-12 15:33:28.000000000 +0800
Modify: 2015-03-12 16:02:01.000000000 +0800
Change: 2015-03-12 16:02:01.000000000 +0800
 Birth: -
\end{verbatim}


现在,我们可以删除该文件以模拟误删除,

1
2
3
4
5
\begin{verbatim}
[root@iLiuc ~]# rm -f /var/log/messages
[root@iLiuc ~]# lsof -n |grep '(deleted)'
syslog-ng 1493  root 10w  REG  8,2 57605375   3080573 /var/log/messages (deleted)
\end{verbatim}


文件已被删除,看怎么恢复吧!从上面的输出信息可以看出之前打开该文件的进

程号及文件描述符,有了这两个信息就足够了。接下来,我们去cat一下/proc目

录中相应的目录中的文件描述符,

1
2
3
4
5
6
7
8
9
10
11
12
13
\begin{verbatim}
[root@iLiuc ~]# cat /proc/1493/fd/10 |head
Oct  9 03:55:32 linux syslog-ng[5747]: syslog-ng starting up; version='2.0.9'
Oct  9 03:55:32 linux syslog-ng[5747]: syslog-ng starting up; version='2.0.9'
Oct  9 03:55:32 linux syslog-ng[5747]: syslog-ng starting up; version='2.0.9'
Oct  9 03:55:32 linux syslog-ng[5747]: syslog-ng starting up; version='2.0.9'
Oct  9 03:55:32 linux syslog-ng[5747]: syslog-ng starting up; version='2.0.9'
Oct  9 03:55:32 linux syslog-ng[5747]: syslog-ng starting up; version='2.0.9'
Oct  9 03:55:32 linux syslog-ng[5747]: syslog-ng starting up; version='2.0.9'
Oct  9 03:55:32 linux syslog-ng[5747]: syslog-ng starting up; version='2.0.9'
Oct  9 03:55:32 linux syslog-ng[5747]: syslog-ng starting up; version='2.0.9'
Oct  9 03:55:32 linux syslog-ng[5747]: syslog-ng starting up; version='2.0.9'
\end{verbatim}


通过文件描述符查看了相应的数据,那么就可以使用I/O重定向将其复制到文件中,

如cat /proc/1493/fd/10 > /tmp/messages。此时,可以中止该守护进程(这将

删除 FD,从而删除相应的文件),将这个临时文件复制到所需的位置,然后重

新启动该守护进程。

1
2
3
4
5
6
7
8
9
10
11
12
\begin{verbatim}
[root@iLiuc ~]# cat /proc/1493/fd/10 > /tmp/messages
[root@iLiuc ~]# /etc/init.d/syslog stop
[root@iLiuc ~]# cp /tmp/messages /var/log/messages
[root@iLiuc ~]# /etc/init.d/syslog start
[root@iLiuc ~]# wc -l /var/log/messages 
452113 /var/log/messages
 
[root@iLiuc ~]# lsof /var/log/messages 
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
syslog-ng 3819 root    4w   REG    8,2 57608271 3080449 /var/log/messages
\end{verbatim}


我们可以看到,已删除的/var/log/messages文件已回来了!对于许多应用程序,

尤其是日志文件和数据库,这种恢复删除文件的方法非常有用。