1.demo.c
#include <stdlib.h> #include <stdio.h> #include <unistd.h> int main(void) { int cnt = 0; int fd = 0; char name[64]; while (1) { snprintf(name, sizeof(name),"%d.txt", cnt); fd = creat(name, 644); sleep(10); ++cnt; } return 0; }
运行程序:
fgao@fgao chapter1]#./hold_file & [1] 3000
通过lsof定位问题:
[fgao@fgao chapter1]#lsof -p 3000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME a.out 3000 fgao cwd DIR 253,2 4096 1321995 /home/fgao/works/my_git_codes/my_books/understanding_apue/sample_codes/chapter1 a.out 3000 fgao rtd DIR 253,1 4096 2 / a.out 3000 fgao txt REG 253,2 6115 1308841 /home/fgao/works/my_git_codes/my_books/understanding_apue/sample_codes/chapter1/a.out a.out 3000 fgao mem REG 253,1 157200 1443950 /lib/ld-2.14.90.so a.out 3000 fgao mem REG 253,1 2012656 1443951 /lib/libc-2.14.90.so a.out 3000 fgao 0u CHR 136,3 0t0 6 /dev/pts/3 a.out 3000 fgao 1u CHR 136,3 0t0 6 /dev/pts/3 a.out 3000 fgao 2u CHR 136,3 0t0 6 /dev/pts/3 a.out 3000 fgao 3w REG 253,2 0 1309088 /home/fgao/works/my_git_codes/ my_books/understanding_apue/sample_codes/chapter1/0.txt a.out 3000 fgao 4w REG 253,2 0 1312921 /home/fgao/works/my_git_codes/my_books/understanding_apue/sample_codes/chapter1/1.txt a.out 3000 fgao 5w REG 253,2 0 1327890 /home/fgao/works/my_git_codes/my_books/understanding_apue/sample_codes/chapter1/2.txt a.out 3000 fgao 6w REG 253,2 0 1327891 /home/fgao/works/my_git_codes/my_books/understanding_apue/sample_codes/chapter1/3.txt a.out 3000 fgao 7w REG 253,2 0 1327892 /home/fgao/works/my_git_codes/my_books/understanding_apue/sample_codes/chapter1/4.txt a.out 3000 fgao 8w REG 253,2 0 1327893 /home/fgao/works/my_git_codes/my_books/understanding_apue/sample_codes/chapter1/5.txt a.out 3000 fgao 9w REG 253,2 0 1327894 /home/fgao/works/my_git_codes/my_books/understanding_apue/sample_codes/chapter1/6.txt
lsof输出各列信息的意义如下:
COMMAND:进程的名称
PID:进程的id
USER:进程所有者
FD:文件描述符,应用程序通过文件描述符识别该文件。如cwd、txt等
TYPE:文件类型,如DIR、REG等
DEVICE:指定磁盘的名称
SIZE:文件的大小
NODE:索引节点(文件在磁盘上的标识)
NAME:打开文件的确切名称
FD列中的文件描述符cwd值表示应用程序的当前工作目录,默认是该应用程序启动的目录,除非它本身对这个目录进行更改。
FD是txt的文件是程序代码,如应用程序二进制文件本身或共享库,如上列表中显示的 /sbin/init 程序。
其次数值表示应用程序的文件描述符,这是打开该文件时返回的一个整数。如上的最后一行文件/dev/null,其文件描述符为2u,u表示该文件被打开并处于读取/写入模式,而不是只读 ® 或只写 (w) 模式。
同时还有大写的W表示该应用程序具有对整个文件的写锁。该文件描述符用于确保每次只能打开一个应用程序实例。初始打开每个应用程序时,都具有三个文件描述符,从 0 到 2,分别表示标准输入、输出和错误流。所以大多数应用程序所打开的文件的 FD 都是从 3 开始。
与 FD 列相比,Type 列则比较直观。文件和目录分别为REG和DIR。而CHR和BLK,分别表示字符和块设备,或者UNIX、FIFO 和 IPv4,分别表示 UNIX 域套接字、先进先出 (FIFO) 队列和网际协议 (IP) 套接字。
2.lsof语法
lsof命令的语法格式为: lsof [options] filename lsof常用形式为: lsof test.txt 显示开启文件test.txt的进程 lsof -c abc 显示abc进程现在打开的文件 lsof -cp 1234 列出进程号为1234的进程所打开的文件 lsof -g gid 显示归属gid的进程情况 lsof +d /usr/local/ 显示/usr/local/目录下被进程开启的文件 lsof +D /usr/local/ 同上,但是会搜索目录下的目录(即递归搜索),时间较长 lsof -d 4 显示fd为4的进程 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中的 service name (可以不止一个) port --> 端口号 (可以不止一个) lsof `which httpd` //查看哪个进程在使用apache的可执行文件 lsof /etc/passwd //查看哪个进程在占用/etc/passwd lsof /dev/hda6 //查看哪个进程在占用hda6 lsof /dev/cdrom //查看哪个进程在占用光驱 lsof -c sendmail //查看sendmail进程现在打开的文件 lsof -c courier -u ^zahn //显示出哪些文件被以courier打头的进程打开,但是并不属于用户zahn lsof -p 30297 //列出进程id为30297的进程所打开的文件 lsof -D /tmp //显示所有在/tmp目录下打开文件的进程 lsof -u1000 //查看uid是1000的用户的进程的文件使用情况 lsof -utony //查看用户tony的进程的文件使用情况 lsof -u^tony //查看不是用户tony的进程的文件使用情况(^是取反的意思) lsof -i //显示所有已经打开的端口 lsof -i:80 //查看80端口被哪个进程占用 lsof -i -U //显示所有打开的端口和UNIX domain文件 lsof -i UDP@[url]www.akadia.com:123 //显示哪些进程打开了到www.akadia.com的UDP的123(ntp)端口的链接 lsof -i tcp@ohaha.ks.edu.tw:ftp -r //不断查看目前ftp连接的情况(-r,lsof会永远不断的执行,直到收到中断信号,+r,lsof会一直执行,直到没有档案被显示,缺省是15s刷新) lsof -i tcp@ohaha.ks.edu.tw:ftp -n //lsof -n 不将IP转换为hostname,缺省是不加上-n参数
3.使用实例
3.1 查找谁在使用文件系统
在卸载文件系统时,如果该文件系统中有任何已经打开的文件,操作通常将会失败。那么通过lsof可以找出哪些进程在使用当前要卸载的文件系统,如下:
lsof /GTES11/ COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME bash 4208 root cwd DIR 3,1 4096 2 /GTES11/ vim 4230 root cwd DIR 3,1 4096 2 /GTES11/
在这个示例中,用户root正在其/GTES11目录中进行一些操作,一个bash实例正在运行,并且它当前的目录为/GTES11;另一个则显示的是vim正在编辑/GTES11下的文件。想要成功地卸载/GTES11,应该在通知用户以确保情况正常之后,中止这些进程。 这个示例说明了应用程序的当前工作目录非常重要,因为它仍保持着文件资源,并且可以防止文件系统被卸载。这就是为什么大部分守护进程(后台进程)将它们的目录更改为根目录或服务特定的目录(如 sendmail 示例中的 /var/spool/mqueue)的原因,以避免该守护进程阻止卸载不相关的文件系统。
原创文章,作者:506227337,如若转载,请注明出处:https://blog.ytso.com/268075.html