【问题标题】:how to check if Linux symlink is in use? (removing unused symlink)如何检查 Linux 符号链接是否正在使用? (删除未使用的符号链接)
【发布时间】:2016-06-20 13:18:31
【问题描述】:

仅当原始文件正在使用中时,fuser 才能向您显示。

如果调用原始文件的 SYMLINK 正在使用中,fuser 不会向您显示。这就是问题所在。您不知道符号链接是否未使用并且可以删除。

我已经启动了两个进程(24261 打开原始文件和 24262 打开符号链接):

root@server DEV # ls -l /lib64/libgcc_s-4.4.7-20120601.so.1
-rwxr-xr-x 1 root root 93320 Sep  1  2014 /lib64/libgcc_s-4.4.7-20120601.so.1
root@server DEV # ls -l /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so
lrwxrwxrwx. 1 root root 20 Oct 19  2015 /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so -> /lib64/libgcc_s.so.1
root@server DEV #
root@server DEV # tail -f /lib64/libgcc_s.so.1 &
[1] 24261
root@server DEV #
root@server DEV # cd /usr/lib/gcc/x86_64-redhat-linux/4.4.4
root@server DEV # tail -f libgcc_s.so &
[2] 24262
root@server DEV #
root@server DEV # ps -ef | grep tail
root     24261  3265  0 13:39 pts/1    00:00:00 tail -f /lib64/libgcc_s.so.1
root     24262  3265  0 13:39 pts/1    00:00:00 tail -f libgcc_s.so
root     24492  3265  0 13:40 pts/1    00:00:00 grep tail
root@server DEV #

在这两种情况下,fuser 都会告诉符号链接和原始文件正在使用中(每个命令有两个进程):

root@server DEV # fuser /lib64/libgcc_s.so.1
/lib64/libgcc_s.so.1: 24261 24262
root@server DEV # fuser /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so
/usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so: 24261 24262
root@server DEV #

但我们知道符号链接没有用于第一个进程。它甚至可以被删除,并且不会影响第一个进程。

假设我想删除'gcc'包,如果包没有被使用。

原始文件来自“libgcc”包。

root@server DEV # rpm -qf /lib64/libgcc_s.so.1
libgcc-4.4.7-11.el6.x86_64

符号链接来自 'gcc' 包:

root@server DEV # rpm -qf /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so
gcc-4.4.7-11.el6.x86_64

如果我要删除只包含符号链接的“gcc”包,我会影响第二个进程!如何查看符号链接是否未使用?

在我的例子中,'ps -ef' 表明我使用了命令:

root     24262  3265  0 13:39 pts/1    00:00:00 tail -f libgcc_s.so

所以 ps 甚至不能告诉你使用了符号链接。

任何 Linux 大师?

编辑: 有部分解决方案检查 cwd - 当前工作目录:

root@server DEV # ls -l /proc/24262/cwd
lrwxrwxrwx 1 root root 0 Jun 20 13:57 /proc/24262/cwd -> /usr/lib/gcc/x86_64-redhat-linux/4.4.4
root@server DEV #

所以从这里你可以看到路径“/usr/lib/gcc/x86_64-redhat-linux/4.4.4”,你可以从ps获取文件名。

如果你这样做,这不起作用:

root@server DEV # cd /root
root@server DEV # cat script.sh
/usr/bin/tail -f /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so
root@server DEV #
root@server DEV # nohup ./script.sh &
[2] 26713
root@server DEV #
root@server DEV # ls -l /proc/26713/cwd
lrwxrwxrwx 1 root root 0 Jun 20 14:32 /proc/26713/cwd -> /root

它显示 /root 的 cwd,但符号链接在脚本/程序内。那么你需要检查 /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so 的 ps chill 进程。

root@server DEV # ps -ef | grep 26713
root     26713  3265  0 14:32 pts/1    00:00:00 /bin/sh ./script.sh
root     26714 26713  0 14:32 pts/1    00:00:00 /usr/bin/tail -f /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so
root     26780  3265  0 14:38 pts/1    00:00:00 grep 26713
root@server DEV #

当您想要自动删除软件包时(如果软件包未在使用中),这非常令人困惑。

如果有人能看到更简单的方法,那就太好了。此外,如果有人可以确认使用 cwd 和 ps 子进程进行符号链接检测的准确性。

如果 script.sh 是二进制文件会发生什么?我还能在“ps”或 cwd 中看到完整的符号链接路径吗?

【问题讨论】:

  • 为什么需要删除未使用的符号链接?
  • 我需要删除未使用的编译器(例如 gcc)。这是出于安全目的。
  • “未使用的编译器”和符号链接有什么关系?
  • 这些在同一个包中。例如:root@server DEV # rpm -ql gcc | grep -e '/usr/bin/gcc' -e '/usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so' /usr/bin/gcc /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so
  • 所以现在我很困惑。你担心,如果你删除 gcc 包,那么没有人可以使用它吗?

标签: linux kernel ps lsof fuser


【解决方案1】:

符号链接不是普通文件:它们不能用open() 打开,就像普通文件或目录一样。符号链接实际上只是一个常量字符串,在路径解析期间会在内部自动解释。

因为符号链接在fuser 等实用程序的意义上没有“使用”。当您为符号链接调用 fuser 时,它实际上会显示有关链接指向的文件的信息。

【讨论】:

    【解决方案2】:

    如果“使用中”是指“一个或多个程序正在使用该链接作为文件的路径名”,那么就无法判断。昨天可以用,明天就可以用了。 Unix 的设计是这样的,除非您专门使用为特定目的设计的工具,否则符号链接看起来就像它指向的文件。像fuserlsof 这样的程序会直接通过链接,甚至不会告诉你这是一个链接。

    如果“使用中”是指“指向有效文件”,那么可以通过一些方法来判断。最简单的是ls -L

    $ ls -l foo
    /bin/ls: cannot access foo: No such file or directory
    $ ls -l g
    lrwxrwxrwx 1 hymie users 3 2016-06-20 10:09 g -> foo
    $ ls -lL g
    /bin/ls: cannot access g: No such file or directory
    

    【讨论】:

    • 这是 Unix/Linux 无法轻易告诉您有关符号链接的问题,如果它正在使用中的话。如果该进程昨天运行或短暂运行等,则有一个解决方案“auditd”工具。
    【解决方案3】:

    不幸的是,Linux 内核被设计为在启动阶段从符号链接分配原始文件。因此,当进程运行时,无法检查文件是直接调用还是通过符号链接调用。

    你所能做的就是检查当前工作目录ls -l /proc/<process_id>/cwd,命令行参数strings /proc/<process_id>/cmdline,用户启动进程ps -ef | grep <process_id>然后你可以检查用户启动脚本和$PATHldd可以向您展示从特定库中调用了哪些库。如果您想重新启动该过程以查看是否调用了符号链接,则 strace 是您的朋友。

    【讨论】:

      【解决方案4】:

      这个问题的前提(用fuser/lsof标识未使用的包)存在根本缺陷:

      并非您的系统需要正常工作的每个文件都会在任何随机时间被打开的文件描述符引用。

      例如,如果您删除了 /bin/systemctl(因为 /sbin/shutdown 之类的东西是指向它的符号链接),您会遇到麻烦,但 lsof 没有显示任何使用它的信息。

      很容易想出更多示例,例如我系统上的/bin/grep。它在 shell 脚本中随处可见,但我碰巧没有任何长期运行的实例。

      【讨论】:

        猜你喜欢
        • 2011-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-08
        • 1970-01-01
        • 2020-07-18
        • 1970-01-01
        相关资源
        最近更新 更多