How to find the pid of the process which has deleted a file?
I am working on a project related to VM migration. Sometimes the VM image will disappear and I just want to know who the culprit is. I tried strace on suspicious processes but to no avail.
Finally I found the answer here.
The Linux Audit daemon will do the trick.
sudo auditctl -w /path/to/somefile -p wra
and then
ausearch -f /path/to/somefile -i
You can find out the PID of a process, which has some file open using lsof
.
Once file is closed and deleted, you cannot get that information.
BTW. Keep in mind, that deleting a file is operation on directory it's in, not on a file itself.
Let me suggest an alternative with sysdig as the answers above are aging. Let display the pid
and name
of the processes that delete the file /tmp/test
. First we create the file with touch /tmp/test
. Then we start sysdig
with the following filter:
$ sudo sysdig -p'%proc.pid,%proc.name' '(evt.type=unlinkat and (evt.arg.name=test or evt.arg.name=/tmp/test)) or (evt.type=unlink and evt.arg.path=/tmp/test)'
unlinkat(2)
requires an or
filter if the path (e.g. evt.arg.name
) may be relative. To handle both unlink
(which calls unlink(2)
) and rm
(which calls unlinkat(2)
in its GNU version), the filter should match both syscalls.
sysdig
should be running when a process deletes the file. Then when we execute such commands:
$ unlink /tmp/test
$ touch /tmp/test
$ rm /tmp/test
$ cd /tmp; touch test; rm test
It will displays such an output:
11380,unlink
11407,rm
11662,rm
Please refer to the sysdig user guide for an explanation about filtering and output.
As the filter is pretty long, I found it convenient to write a chisel. It is a lua script that is associated with a sysdig
command:
description = "displays processes that delete a file"
short_description = "spy file deletion"
category = "files"
args =
{
{
name = "path",
description = "the path of the file to monitor",
argtype = "string"
},
}
function on_set_arg(name, val)
path = val
return true
end
function on_init()
local filename = path
for i in string.gmatch(path, "[^/]+") do
filename = i
end
chisel.set_event_formatter("%proc.pid\t%proc.name")
chisel.set_filter(
"(evt.type=unlinkat and (evt.arg.name=" .. path .. " or \
evt.arg.name=" .. filename .. ")) or \
(evt.type=unlink and evt.arg.path=" .. path .. ")")
return true
end
Feel free to comment and improve it. You can put the lua script in a spy_deletes.lua
file inside a directory and execute sysdig
in this directory to make the chisel available. When typing sudo sysdig -cl
you will see it as:
Category: files
---------------
spy_deletes spy file deletion
Now you can call it:
$ sudo sysdig -c spy_deletes /tmp/test
And in another terminal type:
$ touch test; unlink test
$ touch test; unlink /tmp/test
$ touch test; rm test
$ touch test; rm /tmp/test
It will output:
16025 unlink
16033 unlink
16041 rm
16049 rm
The unlinkat
filter would deserve to be more accurate and only match the absolute path. This would require to retrieve the fd of the directory passed to unlinkat(2)
.