17

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.

1
  • I was hoping to find a way to trace unlink system call on every process instead of just one but I guess there is no easy way to do this...
    – Mohammad
    Jun 15, 2011 at 12:28

3 Answers 3

19

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
3
1

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.

2
  • Unfortunately there is no need to open a file to delete it. At least for example "strace rm some-file" output doesn't show that rm command first open the file and then delete it. So I guess lsof is not helpful.
    – Mohammad
    Jun 15, 2011 at 12:35
  • Read the last sentence of my answer
    – vartec
    Jun 15, 2011 at 13:29
1

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).

2
  • I have no output with your command.
    – A.B.
    Aug 7, 2015 at 18:07
  • I was typing rm /tmp/test in another terminal. I edited my answer to make it clearer. Aug 8, 2015 at 20:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .