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

1.5k Views Asked by At

fuser can show you ONLY if original file is in use.

fuser DOESN'T SHOW YOU IF SYMLINK IS IN USE which calls original file. That's the issue. You don't know if symlink unused and can be removed.

I have started two processes (24261 opened original file and 24262 opened symlink) :

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 #

In both cases fuser tells that symlink and original file is in use (there are two processes for each command):

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 #

But we know that symlink was not used for the first process. It can be even removed and will not affect first process.

Let's say I want to remove 'gcc' package if the package is not in use.

Original file comes from 'libgcc' package.

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

Symlink comes from 'gcc' package:

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

If I will remove 'gcc' package which contains only symlink, I will affect second process! How I can see if symlink is unused?

In my case 'ps -ef' shows that I used command:

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

So ps cannot even tell you that symlink was used.

Any Linux guru?

EDITED: There is partial solution checking cwd - current working directory:

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 #

So from here you see the path "/usr/lib/gcc/x86_64-redhat-linux/4.4.4" and you can get file name from ps.

This doesn't work if you do:

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

It shows cwd for /root, but symlink is inside the script/program. So then you need to check 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 #

This is very confusing when you want to automate package removal (if the package is not in use).

It will be great if someone can see simpler way of this. Also if someone can confirm the accuracy of using cwd and ps child processes for symlink in use detection.

What will happen if script.sh would be binary file? Will I still able to see full symlink path in 'ps' or cwd?

4

There are 4 best solutions below

0
On BEST ANSWER

Unfortunately, Linux kernel is designed to assign original file from the symlink in the start up phase. So when the process is running there is no possibility to check if file called directly or through symlink.

All you can do is to check what was current working directory ls -l /proc/<process_id>/cwd, command line arguments strings /proc/<process_id>/cmdline, what user started the process ps -ef | grep <process_id> then you can check user startup scripts and $PATH, ldd can show you which libraries are called from particular library. If you want to restart the process to see if symlink called then strace is your friend.

0
On

Symlinks are not usual files: they cannot be opened with open() like regular files or directories. Symlink actually is just a constant string, which is automatically interpreted internally during path resolution.

Because of that symlinks are not "used" in the sence of utilities like fuser. When you call fuser for symlink, it actually shows info about file pointed by the link.

1
On

If by "in use" you mean "one or more programs is using the link as its path name for the file", then there is no way to tell. It could have been used yesterday, and it might be used tomorrow. Unix is designed so that, unless you are specifically using tools designed for that specific purpose, a symlink looks just like the file it points to. Programs like fuser or lsof will just go right through the links without even telling you it's a link.

If by "in use" you mean "points to a valid file", then there are ways to tell. The simplest being 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
0
On

The premise of this question (identifying unused packages with fuser / lsof) is fundamentally flawed:

Not every file your system needs to work properly will referenced by an open file descriptor at any random time.

For example, you would have a bad time if you removed /bin/systemctl (since things like /sbin/shutdown are symlinks to it), but lsof shows nothing using it.

It's easy to come up with many more examples, like /bin/grep on my system. It's used all over the place in shell scripts, but I don't happen to have any long-running instances of it.