I'm trying to port a Linux bash script to FreeBSD. The script needs to check if a file is open (for writing) before deciding whether or not to take some action.
On Linux, this was easy using the fuser
command:
if [[ ! `/usr/bin/fuser "$FILE"` ]]
then
...
fi
However, on FreeBSD the fuser
command seems totally broken (borne out by this) and doesn't return any proper exit codes or indeed any useful output to stdout. For example, on a file which is actively being written to:
# fuser file
file:
Edit:
Vladimir Botka's comment:
"Simple test in FreeBSD 12.0 shows":
# tail -f /scratch/test-file`
# fuser /scratch/test-file
/scratch/test-file: 45042
# echo $?
0
# ps ax | grep 45042
45042 0 I+ 0:00.00 tail -f /scratch/test-file
45232 1 R+ 0:00.00 grep 45042
On my FreeBSD box (also FreeBSD 12), the same test yields the following:
# tail -f /scratch/test-file
# fuser /scratch/test-file
/scratch/test-file:
# echo $?
0
Vladimir Botka's comment:
Let's try and test the writing to a file with a simple C program which opens the file, waits for an input and writes the input to the file.
Here is my test on the compiled C code:
# ./a.out
Enter num:
# fuser /scratch/test-file
/scratch/test-file:
# echo $?
0
Therefore, fuser
does seem to be broken. However, it only seems broken on my system, not on Vladimir Botka's system, which is strange as they're both FreeBSD 12.
It seems I could use lsof
or fstat
to get this information but not without some complex parsing of the output which is going to make my script more complicated. I wondered if anyone can point me towards a simple 'yes/no' command to determine whether a file is in use like fuser
that will work on FreeBSD?
I conclude that fuser
is broken in FreeBSD. In the end I went with a parse of the fstat
output to solve the problem. fstat
produces the following output on a file which is being actively written (and there is also another process reading it, hence the two lines):
# fstat file
USER CMD PID FD MOUNT INUM MODE SZ|DV R/W NAME
root smbd 36299 41 /data 1282756 -rwxr--r-- 7407140864 rw file
root smbd 36295 30 /data 1282756 -rwxr--r-- 7407140864 r file
The following bash code tests the file using fstat
, removes the header line (sed
), then uses awk
to grab the 9th column, that which is concerned with whether the file is open for reading or writing. A grep
then follows to look for the w
write flag in any of the lines. If it finds one, it will return true. The whole condition is negated (!
) to ensure that the action is only carried out if the file is NOT in use:
if [[ ! `/usr/bin/fstat "$FILE" | sed 1d | awk '{print $9}' | grep "w"` ]]
then
... do something ...
fi