Tuesday, September 16, 2008

Using fuser to Identify Users and Processes

Using fuser to Identify Users and Processes
UNIX IN THE ENTERPRISE --- 07/20/2006

Sandra Henry-Stocker

The fuser (pronounced "ef-user") command is a very handy command for determining who is currently using a particular file or directory. If one user can't access a file because another user has it locked in some way, the fuser command can help you determine who that user is so that you can decide how to resolve the apparent conflict.

Who is Using My File?

When you ask fuser about a file, it can tell you both who is using it and how the particular file is being used. For example, if we were to ask fuser who is using the file /var/log/syslog, we would get response like this:

% fuser -u /var/log/syslog
/var/log/syslog: 247o(root)

That string, "247o(root)", in fuser's response tells us that root is using the file, what the particular root process ID happens to be (247) and that this process has the file open (o).

Without the -u (show user) option, the fuser command would not have added "(root)" to this output.

If we track down the process using ps or ptree (i.e., ptree 247), we aren't likely to be startled. The process is the syslog daemon, syslogd, Syslogd opens /var/log/syslog so that it can append system messages. The ptree command identifies the process easily:

$ ptree 247
247 /usr/sbin/syslogd

Further, if we are inclined to verify that syslogd has the syslog file open, we can display the inode for the /var/log/syslog file and then (as root) find it in the open files (pfiles) listing for the process:

# ls -i /var/log/syslog
102337 /var/log/syslog

# pfiles 102337
... 7: S_IFREG mode:0644 dev:102,3 ino:102337 uid:0 gid:1 size:807186 O_WRONLY|O_APPEND|O_LARGEFILE ...

So, if one of your users complains that a file is busy, you can use the fuser command to see who has the file tied up like this:

# fuser -u /data/src/project1/myfile
/data/src/project1/myfile: 10336o(shs)

If the best course of action is to terminate the process that is using the file, you can use the fuser command for that, too, using the -k option:

# fuser -k /data/src/project1/myfile

In fact, you could terminate the process without first looking to see who owns it and what they are doing, but that generally isn't a good idea.

Who is Using this File System?

If you were trying to unmount a file system and found it busy, fuser would be a useful tool for determining why you are unable to unmount it. Let's say you wanted to unmount /data and saw this:

# umount /data
umount: /data busy # fuser -u /data /data: 24271c(shs)

This time, we notice that the character following the process ID is a "c". What can this mean?

Well, there are a number of reasons why a file system might be considered busy. As we have seen, a file system is considered busy if a program has a file open. A file system is also busy if it's shared. In addition, a file system is busy if someone has issued a cd command and moved into one of its directories. The "c" in the output above means that /data is shs's current working directory.

When you see a "c" in the fuser output, you can change the file system's busy status by getting the user to cd to a directory in some other file system or log off. If necessary, you can kill the user process that is keeping the file system busy, though its always better to give the user some warning if you can.

If the file system is busy because it is being shared, you can un-share the file system and then unmount it.

The various file system uses that fuser reports about include a process that is:

using the file as its current directory -- c
mapping the file with mmap -- m having the file open (i.e., for reading or writing) -- o using the file as its root directory -- r using the file as its text file -- t using the file as it controlling terminal -- y

There is one complication, however, to "fuser -u". You might try to find out why you cannot unmount a file system, like /data, and get a response from "fuser -u" that is not entirely satisfactory. For example, let's say you get this output:

# umount /data
umount: /data busy # fuser -u /data /data:

What's going on here? Basically, fuser isn't telling us anything about why /data is busy because /data is not itself the directory that is in use. Just as "fuser -u /var/log" would not have told us that the /var/log/syslog file was open, "fuser -u /data" won't tell use if someone has moved into some directory further down in the /data file system, like /data/src or /data/project/accts. Another fuser option than comes in handy in situations like this is -c. Let's see what it will show us.

# fuser -cu /data
/data: 24271c(shs)

NOTE: The -c option only works with mount points.

With the -c option, fuser reports the process and the user occupying the /data directory even though the /data isn't the user's current directory. The "c" at the end of the string "24271c" tells us that the file system is busy because of a current working directory issue. It just doesn't tell us which directory is in use. If, for some reason, you need to know this, you could check every directory within the file system using as many "fuser -c" commands as it took. But, since the user could be currently located in any subdirectory and might move while you are checking, this process could be both slow and problematical.

You might try looping through all the subdirectories in the file system using a loop and an embedded find command like that shown below, but you would soon discover that the find command, in accessing each subdirectory, also ends up "using" it and, therefore, reporting itself in the process. In fact, every directory would be listed in the output of this command.

for dir in `find /data -type d -print`
do fuser -u $dir done

If you wanted to ignore the effect of fuser's accessing the directories, you could elect to only look at directories with more than one reported use or you could create a directory list using find and then separately run fuser against each directory (after find has finished using the directories) as this script does:

#!/bin/bash

if [ $# == 0 ]; then
echo "Usage: $0 start-location" exit 1 else START=$1 fi

TEMP=/tmp/findbusy$$

# make a list of directories in the file system
find $START -type d -exec fuser -u {} \; 2>$TEMP 1>&2

# ------------------------------------------
# Begin awk script to print busy directories # ------------------------------------------ awk '

{ if (NF > 2) {
print $0 } } END { print "done" }

' "$TEMP"
# --------------- # End awk script. # ---------------

rm $TEMP

If you don't care which directory the user happens to be using, you can simply ask that the user log off or kill the user's login process. While I don't advocate tossing users off systems without due courtesy, I have often found that users who are keeping a file system busy have been idle for hours. Interestingly, editing a file does not, by itself, keep a file system busy.

The -k option doesn't work on a mount point. In other words, you can't type "fuser -k /data" and kill the processes keeping /data busy. Once you identify a process that is using a particular directory or file, you can terminate the process using the kill command. Alternately, if you identify the particular file or directory that is being used, you can use fuser's -k command to kill it.

If a file system is busy because of user activity, the most expedient way to make the file system non-busy is to list the processes keeping it busy and terminate each process with a kill -9. In the commands below, I have verified that the user is not actively working before terminating his or her process, but you will have to weigh the interests of your users' processing needs against your need to unmount the file system.

boson:/ # fuser -cu /data
/data: 10149co(shs) 10140c(shs) boson:/ # finger -i Login TTY When Idle shs pts/1 Sun Jul 16 14:55 15 hours 2 minutes root pts/4 Sun Jul 16 14:07 boson:/ # kill -9 10149 10140

Where will you find the fuser command?

Linux systems also include the fuser command, but with different options than Solaris. If you are administering Linux systems, you should

No comments: