dtrace:如何从文件中获取符号链接目标

Posted

技术标签:

【中文标题】dtrace:如何从文件中获取符号链接目标【英文标题】:dtrace: How to get symlink target from file 【发布时间】:2013-11-18 16:33:44 【问题描述】:

我正在使用 dtrace 记录所有被删除的文件。

是否有可能找出符号链接目标是什么(如果它是符号链接)?我想输出符号链接文件名和目标文件名以备日后需要恢复链接。

我想出的一个解决方案是使用 dtrace "system" 函数来调用我自己的程序,该程序将打印出符号链接目标: system("myprogram %s") 其中 %s 是我要为其打印目标的符号链接的全名。

这工作正常(它是一个非常短的 C 程序并且可以完成这项工作) - 但是有没有办法直接通过 dtrace 获取信息,因为我们正在处理文件,所以我们应该能够查找符号链接目标?

我查看了 fileinfo_t 结构,但它没有符号链接目标: http://docs.oracle.com/cd/E18752_01/html/817-6223/chp-io-args.html#chp-io-fileinfo

到目前为止,这是我的脚本: 这是在 Solaris 10 中。(这是探测 fop_remove 而不是 syscall::unlink 并且其原因是能够在用户没有在调用 rm 时指定目录的情况下获取符号链接目录)。

    #!/usr/sbin/dtrace -s

    #pragma D option quiet

    fbt::fop_remove:entry
    
           self->dir = stringof(args[0]->v_path);
           self->file = stringof(args[1]);
    

    fbt::fop_remove:return
    /self->file != NULL/
    
           printf("%s/%s\n", self->dir, self->file);
           self->file = 0;
           self->dir = 0;
    

谢谢!

【问题讨论】:

【参考方案1】:

在 Solaris VFS 级别(又名vnode_t 结构)上,符号链接目标附加到符号链接本身的节点。这是一个文件系统实现细节。

对于 UFS 文件系统,如果链接目标的路径名短于 48 字节(UFS 称之为“快速符号链接”),它将与 inode_t 结构内联记录,您可以通过 DTrace 打印该值:

vnode = args[0];
inode = (inode_t*)vnode->v_data;

printf("symlink tgt: %47s\n",
    vnode->v_type != VLNK ||
    vnode->v_op != ufs_vnodeops ||
    inode->i_flags & I_FASTSYMLINK == 0 ?
        "[unresolved]" :
        (char *)inode->i_db);

对于其他文件系统 / 在一般情况下,您必须使用 fsinfo::readlink:return(或 fop::fop_readlink:return)探测点来获取目标 - 在访问时,也就是说,它不会(通常)可检索直接来自vnode_t

【讨论】:

谢谢弗兰克 - 这是 FreeBSD 的吗?我收到 ufs_vnodeopsi_db 的编译错误,它们不是已知的变量或 i_node 的成员。 不——那是 Solaris。我不知道 FreeBSD 的 UFS 是否具有 Solaris UFS 所具有的“快速符号链接”机制(如果合适,直接块指针被重新用于保存符号链接目标路径名)。 碰巧我正在处理的链接比 48 字节长得多。但感谢您澄清这一点。我不确定是否有任何方法可以直接使用文件本身访问目标。【参考方案2】:

我有以下可能的解决方案 - 像你说的那样访问:

syscall::open:entry /strstr(stringof(copyinstr(arg0)), "mydirectory")!=NULL/ 
    self->file=copyinstr(arg0);


syscall::open:return /self->file != "" && strstr(stringof(fds[arg0].fi_pathname),   "mydirectory")!=NULL / 
    printf("%s %s\n", self-> file, fds[arg0].fi_pathname);
    self -> file=0;


syscall::open:return 
    self -> file=0;

(我在这里将跟踪限制在 mydirectory)。

因此,这利用了这样一个事实,即在进入时,arg0 是符号链接名称,而在返回时,文件描述符可用于获取路径名,即实际文件的路径名。所以这将是符号链接的目标。 在删除时完成跟踪实际上并不重要,只是记录了符号链接 -> 目标。

【讨论】:

以上是关于dtrace:如何从文件中获取符号链接目标的主要内容,如果未能解决你的问题,请参考以下文章

Bash 脚本实例:获取符号链接的目标位置

获取符号链接目标的卷名的最佳方法 [NTFS]

如何使用 .Net 获取符号链接(或重解析点)的目标?

如何在 Node.js 中读取符号链接

gcc 链接器如何获取函数的大小?

如何将符号链接视为Mercurial中的目录?