Lsof是遵从Unix哲学的典范,它只做一件事情,并且做的相当完美。以列出某个进程打开的所有文件信息。打开的文件可能是普通的文件,目录,NFS文件,块文件,字符文件,共享库,常规管道,符号链接,Socket流,网络Socket,UNIX域Socket,以及其它。
在UNIX环境中,文件无处不在,这便产生了一句格言:“任何事物都是文件”。通过文件不仅仅可以访问常规数据,通常还可以访问网络连接和硬件。在有些情况下,当您使用ls 请求目录清单时,将出现相应的条目。在其他情况下,如传输控制协议 (TCP) 和用户数据报协议 (UDP) 套接字,不存在相应的目录清单。但是在后台为该应用程序分配了一个文件描述符,无论这个文件的本质如何,该文件描述符为应用程序与基础操作系统之间的交互提供了通用接口。
因为应用程序打开文件的描述符列表提供了大量关于这个应用程序本身的信息,所以能够查看这个列表将是很有帮助的。完成这项任务的实用程序称为lsof,它对应于“list open files”(列出打开的文件)。几乎在每个 UNIX 版本中都有这个实用程序,但奇怪的是,大多数供应商并没有将其包含在操作系统的初始安装中。要获取更多关于lsof 的信息,请参见参考资料部分。
参考资料:
http://www.ibm.com/developerworks/cn/aix/library/au-lsof.html#listing2
安装lsof:
许多Unix系统都内置了lsof,如果你的系统没有安装,你可以从这里直接下载源代码。
BSD系统有一个类似的工具可以做同样的事情,叫做fstat。
lsof
需要访问核心内存和各种文件,所以必须以 root 用户的身份运行它才能够充分地发挥其功能。
[oracle@xml-ora1 ~]$ lsof -h
lsof 4.78
latest revision:ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/
latest FAQ:ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ
latest man page:ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/lsof_man
usage: [-?abhlnNoOPRstUvVX] [+|-c c] [+|-d s][+D D] [+|-f]
[-F[f]] [-g [s]] [-i [i]] [+|-L [l]] [+m [m]] [+|-M] [-o [o]]
[-ps] [+|-r [t]] [-S [t]] [-T [t]] [-u s] [+|-w] [-x [fl]] [-Z [Z]] [--] [names]
Defaults in parentheses; comma-separatedset (s) items; dash-separated ranges.
-?|-h list help -a AND selections (OR) -b avoid kernel blocks
-cc cmd c, /c/[bix] +c w COMMAND width (9)
+ds dir s files -d s select by FD set +D D dir D tree *SLOW?*
-i select IPv[46]files -l list UID numbers
-nno host names -N select NFSfiles -o list file offset
-Oavoid overhead *RISK -P no portnames -R list paRent PID
-slist file size -t terselisting -T disable TCP/TPI info
-Uselect Unix socket -v list versioninfo -V verbose search
+|-w Warnings (+) -X skip TCP&UDP files -Z Z context [Z]
--end option scan
+f|-f +filesystem or -filenames
-F[f] select fields; -F? for help
+|-L [l] list (+) suppress (-) link counts < l (0 = all; default = 0)
+m [m]use|create mount supplement
+|-M portMap registration(-) -o o o 0t offset digits (8)
-ps exclude(^)|select PIDs -S [t] t second stat timeout (15)
-Tqs TCP/TPI Q,St (s) info
-g[s] exclude(^)|select and print process group IDs
-ii select by IPv[46] address:[46][proto][@host|addr][:svc_list|port_list]
+|-r [t] repeat every t seconds (15); + until no files, - forever
-us exclude(^)|select login|UID set s
-x[fl] cross over +d|+D File systems or symbolic Links
names select named files or fileson named file systems
Anyone can list all files; /dev warningsdisabled; kernel ID check disabled.
常用参数解释:
lsof filename 显示打开指定文件的所有进程
lsof -a 表示两个参数都必须满足时才显示结果
lsof -c string 显示COMMAND列中包含指定字符的进程所有打开的文件
lsof -u username 显示所属user进程打开的文件,逗号分隔指定多个用户
lsof -g gid 显示归属gid的进程情况
lsof +d /DIR/ 显示目录下被进程打开的文件
lsof +D /DIR/ 同上,但是会搜索目录下的所有目录,时间相对较长
lsof -d FD 显示指定文件描述符的进程
lsof -n 不将IP转换为hostname,缺省是不加上-n参数
lsof -L, 作用: 列出打开文件的连接数
lsof -i 用以显示符合条件的进程情况
lsof -i[46][protocol][@hostname|hostaddr][:service|port]
46 –> IPv4 or IPv6
protocol –> TCP or UDP
hostname –> Internet host name
hostaddr –> IPv4地址
service –> /etc/service中的 servicename (可以不只一个)
port –> 端口号 (可以不只一个)
组合用法:
[oracle@xml-ora1~]$ lsof -u oracle -cmysql
由用户oracle打开的进程的文件,或者由mysql进程打开的文件。注意这里是或者
[oracle@xml-ora1 ~]$ lsof -a -u oracle -c mysql
由用户oracle打开的进程的文件同时又是有进程mysql打开的文件。这里是并且的关系。
[oracle@xml-ora1 ~]$ lsof | head
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
Init 1 root cwd unknown /proc/1/cwd (readlink: Permission denied)
Init 1 root rtd unknown /proc/1/root (readlink: Permissiondenied)
Java 337 oracle txt REG 8,3 50794 1046664 /usr/local/jdk1.6.0_31/bin/java
Java 3337 oracle mem REG 8,3 139416 2485804 /lib64/ld-2.5.so
oracle 28448 oracle 0u CHR 1,3 3776 /dev/null
oracle 20991 oracle 12uWREG 8,8 56962 105186 /u01/app/oradata/system01.dbf
注意:普通用户可以使用/usr/sbin/lsof命令,但是访问某些UNIX/LINUX内核文件的时候出现系统限制权限(readlink: Permission denied)提示。
lsof输出各列信息的意义如下:
COMMAND:进程的名称
PID:进程标识符
USER:进程所有者
FD:文件描述符,应用程序通过文件描述符识别该文件。如cwd、txt等
TYPE:文件类型,如DIR、REG等
DEVICE:指定磁盘的名称
SIZE:文件的大小,单位byte
NODE:索引节点(文件在磁盘上的标识)
NAME:打开文件的确切名称
FD 文件描述符:
cwd 值表示应用程序的当前工作目录,这是该应用程序启动的目录,除非它本身对这个目录进行更改。
txt 类型的文件是程序代码,如应用程序二进制文件本身或共享库,如上列表中显示的/usr/local/jdk1.6.0_31/bin/java程序。
12uW 其中数值12表示应用程序的文件描述符,这是打开该文件时返回的一个整数。如上的最后一行文件/u01/app/oradata/system01.dbf,其文件描述符为 12。u 表示该文件被打开并处于读取/写入模式,而不是只读(r
)或只写 (w) 模式。同时还有大写 的W 表示该应用程序具有对整个文件的写锁。该文件描述符用于确保每次只能打开一个应用程序实例。
初始打开每个应用程序时,都具有三个文件描述符,从 0 到 2,分别表示标准输入、输出和错误流。所以大多数应用程序所打开的文件的 FD 都是从 3 开始。
Type文件类型:
文件和目录分别称为 REG 和 DIR。
CHR 和 BLK,分别表示字符和块设备。
UNIX、FIFO 和 IPv4,分别表示 UNIX 域套接字、先进先出(FIFO) 队列和网际协议 (IP) 套接字。
尽管与使用 lsof 没有什么直接的关系,但对/proc 目录进行简要的介绍是有必要的。/proc 是一个目录,其中包含了反映内核和进程树的各种文件。这些文件和目录并不存在于磁盘中,因此当您对这些文件进行读取和写入时,实际上是在从操作系统本身获取相关信息。大多数与lsof 相关的信息都存储于以进程的 PID 命名的目录中,所以 /proc/1234 中包含的是 PID 为 1234 的进程的信息。
在 /proc 目录的每个进程目录中存在着各种文件,它们可以使得应用程序简单地了解进程的内存空间、文件描述符列表、指向磁盘上的文件的符号链接和其他系统信息。lsof 实用程序使用该信息和其他关于内核内部状态的信息来产生其输出。稍后将看到把lsof 的输出与 /proc 目录中的信息联系起来。
[root@xml-ora1 ~]# cat /proc/25348/
attr/ coredump_filter environ io maps mountstats oom_score smaps status
auxv cpuset exe limits mem numa_maps root/ stat task/
cmdline cwd/ fd/ loginuid mounts oom_adj schedstat statm wchan
[root@xml-ora1 ~]# cat /proc/25348/fd/
0 10 12 14 16 18 2 21 23 25 27 29 30 32 34 36 38 4 41 43 45 5 7 9
1 11 13 15 17 19 20 22 24 26 28 3 31 33 35 37 39 40 42 44 46 6 8
lsof 常见的用法是查找应用程序打开的文件的名称和数目。您可能想尝试找出某个特定应用程序将日志数据记录到何处,或者正在跟踪某个问题。
例如,UNIX 限制了进程能够打开文件的数目。通常这个数值很大,所以不会产生问题,并且在需要时,应用程序可以请求更大的值(直到某个上限)。如果您怀疑应用程序耗尽了文件描述符,那么可以使用lsof 统计打开的文件数目,以进行验证。
要指定单个进程,可以使用 -p 参数,后面加上该进程的PID。因为这样做不仅会返回该应用程序所打开的文件,还会返回共享库和代码,所以通常需要对输出进行筛选。要完成此任务,可以使用-d 标志根据FD 列进行筛选,使用-a 标志表示两个参数都必须满足 (AND)。如果没有-a 标志,缺省的情况是显示匹配任何一个参数 (OR) 的文件。显示了sendmail 进程打开的文件,并使用 txt 对这些文件进行筛选。
查看oracle监听进程:
[root@xml-ora1 ~]# ps -ef | grep lsnr | grep -v grep
oracle 6462 1 0Aug01 ? 00:00:04/u01/app/oracle/product/10.2/db_1/bin/tnslsnr LISTENER –inherit
带有 PID 筛选器并进行 txt 文件描述符筛选的 lsof 输出
[root@xml-ora1 ~]# lsof -a -p 6462 -d ^txt
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
tnslsnr 6462oracle cwd DIR 8,6 4096 195841 /home/oracle
tnslsnr 6462oracle rtd DIR 8,3 4096 2 /
tnslsnr 6462oracle mem REG 8,3 139416 2485804 /lib64/ld-2.5.so
tnslsnr 6462oracle mem REG 8,3 114352 2485695 /lib64/libnsl-2.5.so
tnslsnr 6462oracle 0u CHR 1,3 3776 /dev/null
tnslsnr 6462oracle 1u CHR 1,3 3776 /dev/null
tnslsnr 6462oracle 2u CHR 1,3 3776 /dev/null
tnslsnr 6462 oracle 3w REG 8,8 305574 1052527 /u01/app/oracle/db_1/network/log/listener.log
tnslsnr 6462oracle 4r FIFO 0,6 18543 pipe
tnslsnr 6462oracle 7w FIFO 0,6 18544 pipe
tnslsnr 6462oracle 8u IPv4 18547 TCP *:ncube-lm (LISTEN)
tnslsnr 6462oracle 12u unix 0xffff810475438e80 18552 /var/tmp/.oracle/s#6462.2
tnslsnr 6462 oracle13u IPv4 3661562 TCPxml-ora1:ncube-lm->xml-ora1:45221 (ESTABLISHED)
lsof指定了三个参数:
第一个是 -a,它表示当所有的参数都为真时,才显示这个文件。
第二个参数是 -p 605,它限制仅输出 PID 为 605 的进程,通过 ps 命令获取PID。\
最后一个参数 -d ^txt,它表示筛选出其中 txt类型的记录(脱字符号 [^] 表示排除)。
输出提供了关于进程行为的信息。cwd 行所示,该应用程序的工作目录为 /home/oracle。文件描述符 0、1 和 2 分配给了/dev/null(大量使用符号链接,所以显示相应的伪设备)。
文件描述符 3是只写的,并且指向/u01/app/oracle/db_1/network/log/listener.log,写入监听日志。
文件描述符 8 和 13 可以告诉您,该应用程序正以IPv4 模式监听1521端口,并以 IPv4 模式建立连接。
有一个文件或目录,并且需要知道哪个应用程序控制了该文件(打开了该文件)。例如我想知道/u01/app/oracle/db_1/network/log/listener.log这个日志文件被那个oracle监听打开和使用着。
[root@xml-ora1 ~]# lsof/u01/app/oracle/product/10.2/db_1/network/log/listener.log
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
tnslsnr 6462 oracle 3w REG 8,8 7305704 105251527/u01/app/oracle/product/10.2/db_1/network/log/listener.log
正如输出所示,进程 tnslsnr(PID 为 6462)控制了文件 /u01/app/oracle/product/10.2/db_1/network/log/listener.log,并且只进行写入操作。如果出于某种原因,您需要删除这个文件,那么正确的做法是中止该进程,而不是直接删除这个文件。否则,这个守护进程下次可能无法正常启动,或者可能稍后会启动另一个实例,从而导致争用。
有时您只知道在文件系统的某处打开了文件。在卸载文件系统时,如果该文件系统中有任何打开的文件,那么操作将会失败。通过指定装入点的名称,您可以使用lsof 显示一个文件系统中所有打开的文件。
使用 lsof 找出谁在使用文件系统:
[oracle@xml-ora1 ~]$ lsof /home/oracle/ COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME tnslsnr 6462 oracle cwd DIR 8,6 4096 195841 /home/oracle/ bash 23896 oracle cwd DIR 8,6 4096 195841 /home/oracle/ sftp-serv 26499 oracle cwd DIR 8,6 4096 195841 /home/oracle/ sftp-serv 29054 oracle cwd DIR 8,6 4096 195841 /home/oracle/ bash 31185 oracle cwd DIR 8,6 4096 195841 /home/oracle/ lsof 31213 oracle cwd DIR 8,6 4096 195841 /home/oracle/ |
/tmp目录被垃圾文件塞满了,用ls 又看不到太大文件, 谁干的?
[oracle@xml-ora1 ~]$ lsof /tmp
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
java 3337 oracle mem REG 8,2 32768 3342343/tmp/hsperfdata_oracle/3337
java 3404 oracle mem REG 8,2 32768 3342344/tmp/hsperfdata_oracle/3404
列出所有NFS(网络文件系统)文件:[oracle@xml-ora1 ~]$ lsof -N
寻找本地断开(无效)的打开文件:[oracle@xml-ora1~]$lsof +L1
用户 oracle正在其 home 目录中进行一些操作。有两个 bash(一种 Shell)实例正在运行,并且当前目录设置为oracle 的 home 目录。还有一个名为sftp-serv的应用程序正运行于相同的目录。
潜在的问题:lsof /export/home 与 lsof/export/home/(请注意尾部的斜杠)有所区别。第一种方式可以正常工作,因为它指向了装入点。第二种方式不会生成任何输出,因为它指向了目录。如果您在 Shell 中使用 Tab 键自动完成命令,那么可能碰到这个问题,其中会帮助您添加结尾的斜杠。在这种情况下,您可以删除这个斜杠或者使用+D 指定目录。前者是首选的方法,因为与指定任意的目录相比,其执行速度更快。
参数D可以递归查找某个目录中所有打开的文件:
[oracle@xml-ora1 ~]$ lsof +D /home/oracle
加上+D参数,lsof会对指定目录进行递归查找,注意这个参数要比grep版本慢
[oracle@xml-ora1 ~]$ lsof |grep /home/oracle
之所以慢是因为+D首先查找所有的文件,然后一次性输出。
当 UNIX 计算机受到入侵时,常见的情况是日志文件被删除,以掩盖攻击者的踪迹。管理错误也可能导致意外删除重要的文件,比如在清理旧日志时,意外地删除了数据库的活动事务日志。有时可以恢复这些文件,并且lsof 可以为您提供帮助。
当进程打开了某个文件时,只要该进程保持打开该文件,即使将其删除,它依然存在于磁盘中。这意味着,进程并不知道文件已经被删除,它仍然可以向打开该文件时提供给它的文件描述符进行读取和写入。除了该进程之外,这个文件是不可见的,因为已经删除了其相应的目录条目。
在/proc目录部分中说过,通过在适当的目录中进行查找,您可以访问进程的文件描述符。lsof 可以显示进程的文件描述符和相关的文件名。当向lsof 传递文件名时,比如在lsof /file/I/deleted 中,它首先使用 stat() 系统调用获得有关该文件的信息,不幸的是,这个文件已经被删除。在不同的操作系统中,lsof 可能可以从核心内存中捕获该文件的名称。
显示了一个 Linux 系统,其中意外地删除了 oracle数据库的监听日志,我正使用grep 工具查找是否有人打开了该文件。
[oracle@xml-ora1 ~]$ lsof | grep listener.log tnslsnr 6462 oracle 3w REG 8,8 7307132 105251527 /u01/app/oracle/product/10.2/db_1/network/log/listener.log (deleted) |
在这个示例中,您可以看到 PID 6462打开文件的文件描述符为 2,在 /proc/6426/fd/3中查看相应的信息:
[oracle@xml-ora1 ~]$ ll /proc/6462/fd/3
l-wx------ 1 oracle oinstall 64 Sep 1814:18 /proc/6462/fd/3 ->/u01/app/oracle/product/10.2/db_1/network/log/listener.log (deleted)
通过/proc 查找删除的文件内容:
[oracle@xml-ora1 ~]$ tail /proc/6462/fd/3
20-SEP-2012 13:49:36 * service_update *xmlgis * 0
20-SEP-2012 13:59:39 * service_update *xmlgis * 0
20-SEP-2012 14:09:42 * service_update *xmlgis * 0
20-SEP-2012 14:11:24 * service_update *xmlgis * 0
20-SEP-2012 14:21:27 * service_update *xmlgis * 0
20-SEP-2012 14:31:30 * service_update *xmlgis * 0
20-SEP-2012 14:41:33 * service_update *xmlgis * 0
20-SEP-2012 14:51:36 * service_update *xmlgis * 0
20-SEP-2012 15:01:39 * service_update *xmlgis * 0
20-SEP-2012 15:11:42 * service_update *xmlgis * 0
Linux 的优点在于,它保存了文件的名称,甚至可以告诉我们它已经被删除。在遭到破坏的系统中查找相关内容时,这是非常有用的内容,因为攻击者通常会删除日志以隐藏他们的踪迹。我们知道lsnr 进程使用了listener.log文件,所以可以使用ps 命令找到这个 PID,然后可以查看这个进程打开的所有文件。
在REDHAT中查找删除的文件
[oracle@xml-ora1 ~]$ lsof | grep deleted
[oracle@xml-ora1 ~]$ lsof +L1
COMMAND PID USER FD TYPE DEVICE SIZE NLINK NODE NAME
oracle 25342 oracle 7u REG 8,8 0 0 104793747/u01/app/oracle/product/10.2/db_1/dbs/lkinstxmlgis(deleted)
oracle 25344 oracle 7u REG 8,8 0 0 104793747 /u01/app/oracle/product/10.2/db_1/dbs/lkinstxmlgis (deleted)
如果可以通过文件描述符查看相应的数据,那么您就可以使用 I/O 重定向将其复制到文件中:
[oracle@xml-ora1~]$cat /proc/6462/fd/3 > /u01/app/oracle/product/10.2/db_1/network/log/listener.log
此时,您可以中止该守护进程(这将删除 FD,从而删除相应的文件),将这个临时文件复制到所需的位置,然后重新启动该守护进程。
[oracle@xml-ora1 ~]$ lsnrctl stop
[oracle@xml-ora1 ~]$ lsnrctl start
[oracle@xml-ora1 ~]$ lsof | grep listener.log
tnslsnr 6882 oracle 3w REG 8,8 7308113 13565953 /u01/app/oracle/product/10.2/db_1/network/log/listener.log
对于许多应用程序,尤其是日志文件和数据库,这种恢复删除文件的方法非常有用。正如您所看到的,有些操作系统(以及不同版本的lsof)比其他的系统更容易查找相应的数据。
网络连接也是文件,这意味着可以使用 lsof获得关于它们的信息。只知道相应的端口,那么可以使用-i 参数利用套接字信息进行搜索。
查找监听端口1521 的进程:
[oracle@xml-ora1 ~]$ lsof -i :1521
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
java 3337 oracle 34u IPv6 8215146 TCPxml-ora1:61437->xml-ora1:ncube-lm (ESTABLISHED)
java 3337 oracle 35u IPv6 8215147 TCPxml-ora1:61438->xml-ora1:ncube-lm (ESTABLISHED)
oracle 24636 oracle 14u IPv4 8384208 TCP xml-ora1:ncube-lm->xml-ora1:45193(ESTABLISHED)
需要以 protocol:@ip:port的形式向 lsof 实用程序传递相关信息,其中的 protocol 为 TCP 或 UDP(可以使用 4 或 6 作为前缀,表示 IP 的版本),IP 为可解析的名称或 IP 地址,而 port 为数字或表示该服务的名称(来自 /etc/services)。需要一个或多个元素(端口、IP、协议)。
列出所有网络连接:[oracle@xml-ora1~]$ lsof -i
列出所有TCP网络连接:[oracle@xml-ora1 ~]$ lsof -i udp
列出所有UDP网络连接:[oracle@xml-ora1 ~]$ lsof -i tcp
列出所有IP4网络连接:[oracle@xml-ora1 ~]$ lsof -i4 *
列出固定IP网络连接:[oracle@xml-ora1 ~]$lsof -i @222.76.206.226
[oracle@xml-ora1 ~]$ uname -a
Linux xml-ora1 2.6.18-194.el5 #1 SMP TueMar 16 21:52:39 EDT 2010 x86_64 x86_64 x86_64 GNU/Linux
[oracle@xml-ora1 ~]$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 5.5(Tikanga)
[oracle@xml-ora1 ~]$ ps -ef | grep ora_
oracle 23923 23896 0 09:43 pts/3 00:00:00 grep ora_
oracle 25342 1 0 Aug06 ? 00:00:52 ora_pmon_xmlgis
oracle 25344 1 0 Aug06 ? 00:00:00 ora_psp0_xmlgis
oracle 25346 1 0 Aug06 ? 00:00:00 ora_mman_xmlgis
oracle 25348 1 0Aug06 ? 00:00:13 ora_dbw0_xmlgis
创建表空间、表、数据以及数据文件:
SQL> create tablespace test_del datafile '/u01/app/oracle/oradata/xmlgis/test_del.dbf'size 50m;
Tablespace created.
SQL> select file_name from dba_data_files where file_name like'%del%';
FILE_NAME
--------------------------------------------------------------------------------
/u01/app/oracle/oradata/xmlgis/test_del.dbf
SQL> select name from v$datafile where name like '%del%';
NAME
--------------------------------------------------------------------------------
/u01/app/oracle/oradata/xmlgis/test_del.dbf
SQL> create table test_del tablespace test_del as select * from dba_objects;
Table created.
SQL> commit;
Commit complete.
SQL> alter system checkpoint;
System altered.
SQL> select count(*) from test_del;
COUNT(*)
----------
51459
SQL>select OWNER,OBJECT_NAME from test_del WHERE OWNER<>'SYS' AND ROWNUM<3;
OWNER OBJECT_NAME
--------------------------------------------------------------------------------
PUBLIC DUAL
PUBLIC SYSTEM_PRIVILEGE_MAP
[oracle@xml-ora1 ~]$ strings/u01/app/oracle/oradata/xmlgis/test_del.dbf | grep"SYSTEM_PRIVILEGE_MAP"
SYSTEM_PRIVILEGE_MAP
I_SYSTEM_PRIVILEGE_MAP
SYSTEM_PRIVILEGE_MAP
[oracle@xml-ora1 ~]$ lsof -a -p 25348 -d ^txt | egrep"COMMAND|dbf"
Output information may be incomplete.
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
oracle 25348 oracle 18uW REG 8,8 566239232 105186656 /u01/app/oracle/oradata/xmlgis/system01.dbf
…..省略其它文件…..
oracle 25348 oracle 48uW REG 8,8 52436992 21364739 /u01/app/oracle/oradata/xmlgis/test_del.dbf
SQL> !
[oracle@xml-ora1 ~]$ ll/u01/app/oracle/oradata/xmlgis/test_del.dbf
-rw-r----- 1 oracle oinstall 52436992 Sep20 14:17 /u01/app/oracle/oradata/xmlgis/test_del.dbf
[oracle@xml-ora1 ~]$ rm/u01/app/oracle/oradata/xmlgis/test_del.dbf
[oracle@xml-ora1 ~]$ ll/u01/app/oracle/oradata/xmlgis/test_del.dbf
ls:/u01/app/oracle/oradata/xmlgis/test_del.dbf: No such file or directory
[oracle@xml-ora1 ~]$ exit
Exit
SQL> select file_name from dba_data_files where file_name like'%del%';
FILE_NAME
--------------------------------------------------------------------------------
/u01/app/oracle/oradata/xmlgis/test_del.dbf
SQL> select name from v$datafile where name like '%del%';
NAME
--------------------------------------------------------------------------------
/u01/app/oracle/oradata/xmlgis/test_del.dbf
SQL> insert into test_del select * from dba_objects;
51459 rows created.
SQL> commit;
Commit complete.
SQL> select count(*) from test_del;
COUNT(*)
----------
102918
SQL> alter system checkpoint;
System altered.
SQL> create table test_del_new tablespace test_del as select * from dba_objects;
Table created.
操作正常,说明数据文件虽然被删除,但是可以继续写入,说明可以恢复。但是注意,不能关掉DBWR0进行,重新启动后将丢失文件描述符,则无法恢复。
[oracle@xml-ora1 ~]$ lsof | grep test_del
oracle 25348 oracle 48uW REG 8,8 52436992 21364739 /u01/app/oracle/oradata/xmlgis/test_del.dbf (deleted)
oracle 25350 oracle 30u REG 8,8 52436992 21364739 /u01/app/oracle/oradata/xmlgis/test_del.dbf (deleted)
oracle 25356 oracle 45u REG 8,8 52436992 21364739 /u01/app/oracle/oradata/xmlgis/test_del.dbf (deleted)
oracle 25358 oracle 44u REG 8,8 52436992 21364739 /u01/app/oracle/oradata/xmlgis/test_del.dbf (deleted)
oracle 32244 oracle 15u REG 8,8 52436992 21364739 /u01/app/oracle/oradata/xmlgis/test_del.dbf (deleted)
oracle 32244 oracle 19u REG 8,8 52436992 21364739 /u01/app/oracle/oradata/xmlgis/test_del.dbf (deleted)
注意:/u01/app/oracle/oradata/xmlgis/test_delete.dbf(deleted)说明该数据库文件被删除了,但是却出现了这么多是描述符号。仔细看了下其中的信息,发现PID为25348的才是DBWR0进行写入的文件,同时48uW也说明了是原来删除的文件,那其它信息呢,根据PID去查找进程。得到如下信息
[oracle@xml-ora1 ~]$ ps -ef | egrep"25348|25350|25356|25358|32244" | grep -v egrep
oracle 25348 1 0Aug06 ? 00:00:13 ora_dbw0_xmlgis
oracle 25350 1 0 Aug06 ? 00:00:22 ora_dbw1_xmlgis
oracle 25356 1 0 Aug06 ? 00:02:29 ora_ckpt_xmlgis
oracle 25358 1 0 Aug06 ? 00:01:33 ora_smon_xmlgis
oracle 32244 32243 0 12:58 ? 00:00:03 oraclexmlgis(DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
原来除了DBWR0对该进程进行读写,还包括DBWR1,CKPT,SMON以及我当前连接的session进行读写。哪个才是要恢复的文件呢?
Cd /proc/819/fd/ 就可以得到所要查找的数据
[oracle@xml-ora1 ~]$ ll /proc/25348/fd/* | grep test_del
lrwx------ 1 oracle oinstall 64 Sep 2014:15 /proc/25348/fd/48-> /u01/app/oracle/oradata/xmlgis/test_del.dbf (deleted)
看来他们都是对同一个文件进行打开,只是返回的值不同而且,而真正打开该文件的是DBWR0,恢复该文件即可。
验证文件内容:
[oracle@xml-ora1 ~]$ strings /proc/25348/fd/48 | grep"TEST_DEL"
TEST_DEL
TEST_DEL
TEST_DEL
TEST_DEL_NEW
TEST_DEL
[oracle@xml-ora1 ~]$ cat /proc/25348/fd/48>/u01/app/oracle/oradata/xmlgis/test_del.dbf
[oracle@xml-ora1 ~]$ ll/u01/app/oracle/oradata/xmlgis/test_del.dbf
-rw-r--r-- 1 oracle oinstall 52436992 Sep20 14:45 /u01/app/oracle/oradata/xmlgis/test_del.dbf
新建表在此表空间:
SQL> create table test_del_recover tablespace test_del as select * from dba_objects;
Table created.
SQL> alter system checkpoint;
System altered.
SQL> !
[oracle@xml-ora1 ~]$ ll/u01/app/oracle/oradata/xmlgis/test_del.dbf
-rw-r--r-- 1 oracle oinstall 52436992 Sep20 14:45 /u01/app/oracle/oradata/xmlgis/test_del.dbf
[oracle@xml-ora1 ~]$ strings /proc/25348/fd/48 | grep"TEST_DEL"
TEST_DEL
TEST_DEL
TEST_DEL
TEST_DEL_NEW
TEST_DEL
TEST_DEL_RECOVER
TEST_DEL_NEW
TEST_DEL