因为项目中一个小需求要从一个文件描述符中获取出文件描述符所指向的文件名
本来可以在接口中把文件描述符和文件名一起封装成一个结构来返回
但因为在别的地方也会这种应用,所以就想单独把从文件描述符获取文件名做成一个能用接口来使用
本接口只能在linux系统下使用,因为linux系统下所有的东西都可以当成文件来使用
主要使用了lsof指令来实现
lsof常用参数
lsof 常见的用法是查找应用程序打开的文件的名称和数目。可用于查找出某个特定应用程序将日志数据记录到何处,或者正在跟踪
某个问题。例如,linux限制了进程能够打开文件的数目。通常这个数值很大,所以不会产生问题,并且在需要时,应用程序可以请
求更大的值(直到某个上限)。如果你怀疑应用程序耗尽了文件描述符,那么可以使用 lsof 统计打开的文件数目,以进行验证。
lsof语法格式是:
lsof [options] filename
常用的参数列表:
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 -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指令输出格式如下:COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
init 1 root cwd DIR 3,3 4096 2 /
init 1 root rtd DIR 3,3 4096 2 /
init 1 root txt REG 3,3 34352 13959233 /sbin/init
init 1 root mem REG 3,3 126648 9831535 /lib/ld-2.3.5.so
init 1 root mem REG 3,3 1489572 9831536 /lib/libc-2.3.5.so
init 1 root mem REG 3,3 81284 9830507 /lib/libsepol.so.1
init 1 root mem REG 3,3 68864 9831549 /lib/libselinux.so.1
init 1 root mem REG 0,0 0 [heap] (stat: No such file or directory)
init 1 root 10u FIFO 0,13 1887 /dev/initctl
syslogd 1584 root 2w REG 3,3 438824 1574198 /var/log/messages
syslogd 1584 root 3w REG 3,3 1581 1574338 /var/log/secure
syslogd 1584 root 4w REG 3,3 1678 1574346 /var/log/maillog
syslogd 1584 root 5w REG 3,3 10907 1574315 /var/log/cron
syslogd 1584 root 6w REG 3,3 0 1574365 /var/log/spooler
syslogd 1584 root 7w REG 3,3 0 1574363 /var/log/boot.log
syslogd 1584 root 8w REG 3,3 0 1606423 /var/log/news/news.crit
syslogd 1584 root 9w REG 3,3 0 1606424 /var/log/news/news.err
每行显示一个打开的文件,若不指定条件默认将显示所有进程打开的所有文件。lsof输出各列信息的意义如下: COMMAND:进程的名
称
PID:进程标识符
USER:进程所有者
FD:文件描述符,应用程序通过文件描述符识别该文件。如cwd、txt等
TYPE:文件类型,如DIR、REG等
DEVICE:指定磁盘的名称
SIZE:文件的大小
NODE:索引节点(文件在磁盘上的标识)
NAME:打开文件的确切名称
我们所关注的主要就是 FD列和NAME列
可以用 lsof -d 8
有如下结果
syslogd 1584 root 8w REG 3,3 0 1606423 /var/log/news/news.crit
可以看到文件描述符8对应的文件为 /var/log/news/news.crit
在代码中,我们可以用popen来把这个指令的结果存到一个FILE的文件中
然后按照一般文件操作方法来进行处理
先用fgets 来读出一整行数据
再用strtok 来把各个列的数据给读出来,直到取到NAME列数据
这就是我们需要的数据了
以上只是本人提供的一个思路,希望能对读到此文的朋友有点帮助
char s[100] = { 0 };
snprintf(s, 100, "/proc/%d/fd/%d", getpid(), fd);
char name[100] = { 0 };
nRet = readlink(s, name, sizeof(name));
这样也不错
On certain systems (see below) you can count them in /proc/[pid]/fd. If not on one of those, see below for:wallyk's answer.
In c, you can list the dir and count the total, or list the dir contents:
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int
main (void)
{
DIR *dp;
struct dirent *ep;
dp = opendir ("/proc/MYPID/fd/");
if (dp != NULL)
{
while (ep = readdir (dp))
puts (ep->d_name);
(void) closedir (dp);
}
else
perror ("Couldn't open the directory");
return 0;
}
In bash, something like:
ls -l /proc/[pid]/fd/ | wc -l
Operating systems that support the proc filesystem include, but are not limited to:
Solaris
IRIX
Tru64 UNIX
BSD
Linux (which extends it to non-process-related data)
IBM AIX (which bases its implementation on Linux to improve compatibility)
QNX
Plan 9 from Bell Labs
现工作中,有这么个需求:当处理一个文件结束后,如果该文件大小不合要求(有可能大小为0),就得将该文件删除,可是在文件处理过程中,只知道文件描述符,于是,就想通过一个已打开的文件描述符得到该描述符对应的文件名。经过查询,得知在系统在/proc/pid/fd下为我们记录了已打开文件的一个符号链接,如是想利用readlink通过这个链接得到对应的文件名,如是有了下面的例子:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(){
FILE *fd=fopen("test.txt","w+");
char s[100]={0};
char name[100]={0};
snprintf(s, 100, "/proc/%d/fd/%d", getpid(), fileno(fd) );
printf("sizeof(name)=%d\n",sizeof(name));
int nRet=readlink(s, name, sizeof(name));
printf("s=%s,name=%s\n",s,name);
fclose(fd);
while(1){};
}
可是结果不是我所希望的,readlink竟然返回-1,errno置22(EINVAL 参数bufsiz 为负数)了。这里很是不解,我所传递的参数sizeof(name)明明是100.可是………………望哪位知晓的指点一二,谢谢!!