如何检查 Linux 符号链接是否正在使用? (删除未使用的符号链接)

how to check if Linux symlink is in use? (removing unused symlink)

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

如果正在使用调用原始文件的符号链接,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,但符号链接在 script/program 内。那么你需要检查 ps chill process for /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so.

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 中看到完整的符号链接路径吗?

如果"in use"是指"one or more programs is using the link as its path name for the file",那就没法说了。昨天还可以用,明天就可以用了。 Unix 的设计是这样的,除非您专门使用为该特定目的设计的工具,否则 symlink 看起来就像它指向的文件一样。 fuserlsof 之类的程序将直接通过 link 甚至不会告诉您它是 link.

如果 "in use" 你的意思是 "points to a valid file",那么有很多方法可以分辨。最简单的是 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

Symlinks 不是普通文件:它们无法像普通文件一样用open()打开或目录。 Symlink实际上只是一个常量字符串,在路径解析过程中会在内部自动解释。

因为 symlink 在 fuser 等实用程序的意义上不是 "used"。当您为 symlink 调用 fuser 时,它实际上显示有关 link.

指向的文件的信息

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

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

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

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

例如,如果您删除 /bin/systemctl(因为 /sbin/shutdown 之类的东西是它的符号链接),您会很不开心,但是 lsof 没有显示任何使用它的信息。

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