I'm not going for complicated tools like AppArmor complain mode, I need easy tools to tell me which files are accessed by a specific program.
3 Answers
Per Chris Down, you can use strace -p
to examine an already running process, to see what files it opens from now until the time you terminate strace or the process itself finishes.
If you want to see files opened for the entire duration of a process, right from the start, use strace
with the executable name. Adding -f
ensures that any forked sub-processes also get reported. Example
# strace -e open -f /bin/id
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/proc/thread-self/attr/current", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/proc/self/task/1581/attr/current", O_RDONLY|O_CLOEXEC) = 3
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
open("/usr/share/locale/en_US.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3
open("/etc/group", O_RDONLY|O_CLOEXEC) = 3
open("/etc/group", O_RDONLY|O_CLOEXEC) = 3
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
+++ exited with 0 +++
#
Using lsof
to see what files a process currently has open
# lsof -p $(pidof NetworkManager)
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
NetworkMa 722 root cwd DIR 253,0 224 64 /
NetworkMa 722 root rtd DIR 253,0 224 64 /
NetworkMa 722 root txt REG 253,0 2618520 288243 /usr/sbin/NetworkManager
NetworkMa 722 root mem REG 253,0 27776 34560 /usr/lib64/libnss_dns-2.17.so
[...]
#
If you have SystemTap, you can monitor the entire host for files being opened.
[root@localhost tmp]# cat mon
#!/usr/bin/env stap
probe syscall.open { printf ("pid %d program %s opened %s\n", pid(), execname(), filename) }
# ./mon
pid 14813 program touch opened "/etc/ld.so.cache"
pid 14813 program touch opened "/lib64/libc.so.6"
pid 14813 program touch opened 0x7f7a8c6ec8d0
pid 14813 program touch opened "foo2"
[...]
#

- 21,892
-
2
open
isn't the only relevant system call. For example it is possible to pass file descriptors between processes over a unix socket, and there is theopenat
system call which can also open a file. – kasperd Jan 27 '18 at 17:47 -
---- SIGUSR1 {si_signo=SIGUSR1, si_code=SI_TKILL, si_pid=6026, si_uid=1002} ---- whats that – Boll19 Jan 28 '18 at 06:55
-
kaspers, do I only need to search for 'openat' at the strace output command? – Boll19 Jan 29 '18 at 05:33
-
Trying open a file (but the file may not be exist) is displayed in the 'strace' outputs too? – Boll19 Jan 29 '18 at 05:41
-
Boll19, files that fail to open due to them not existing are happily reported within
strace
, see the ENOENT lines in the example. – steve Feb 03 '18 at 13:44
You can use opensnoop
from BCC, which uses eBPF under the hood:
# ./opensnoop -p 1576
PID COMM FD ERR PATH
1576 snmpd 11 0 /proc/sys/net/ipv6/conf/lo/forwarding
1576 snmpd 11 0 /proc/sys/net/ipv6/neigh/lo/base_reachable_time_ms
1576 snmpd 9 0 /proc/diskstats
1576 snmpd 9 0 /proc/stat
1576 snmpd 9 0 /proc/vmstat
[...]
This is quite performant since it uses kprobes instead of having to restart syscalls, like strace
does.
You can also do this with strace
(potentially with -f
to follow the traced process' children), but its way of operating, involving restarting syscalls as part of ptrace will slow down your application somewhat:
# strace -e open -p 15735
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/gconv/gconv-modules", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/python2.7/site-packages", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 4
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/etc/localtime", O_RDONLY|O_CLOEXEC) = 8
[...]
You can also start your application this way if desired, using strace [executable]
, or strace -f [executable]
.

- 125,559
- 25
- 270
- 266
My favorite tool for monitoring which files an application opens is the powerful monitoring framework sysdig
.
For monitoring all the open files opened by a program named exe_file
:
sudo sysdig -p "proc.name=exe_file %12user.name %6proc.pid %12proc.name %3fd.num %fd.typechar %fd.name" evt.type=open
Monitoring all the files opened in the server:
sudo sysdig -p "%12user.name %6proc.pid %12proc.name %3fd.num %fd.typechar %fd.name" evt.type=open
Creating a trace file that will only contain writing events in home directories (which we can inspect later with sysdig -r writetrace.scap.gz
):
sudo sysdig -p "%user.name %proc.name %fd.name" "evt.type=write and fd.name contains /home/" -z -w writetrace.scap.gz
Seeing everything at syscall level a process named exe_file
does:
sudo sysdig proc.name=exe_file
Sysdig has many chisels, see for more interesting things it can do:
You also have got dtrace
that is not much used in Linux, but is still use a lot with *BSD operating systems:
# Files opened by process,
dtrace -n 'syscall::open*:entry { printf("%s %s",execname,copyinstr(arg0)); }'
Besides sysdig
, strace
and dtrace
, you also have got ltrace
, which records/intercepts signals/dynamic libraries/system calls which are called/received by a process:
ltrace
is a program that simply runs the specified command until it exits. It intercepts and records the dynamic library calls which are called by the executed process and the signals which are received by that process. It can also intercept and print the system calls executed by the program.
$ltrace exe_file
_libc_start_main(0x400624, 1, 0x7ffcb7b6d7c8, 0x400710 <unfinished ...>
time(0) = 1508018406
srand(0x59e288e6, 0x7ffcb7b6d7c8, 0x7ffcb7b6d7d8, 0) = 0
sprintf("mkdir -p -- '/opt/sms/AU/mo'", "mkdir -p -- '%s'", "/opt/sms/AU/mo") = 28
system("mkdir -p -- '/opt/sms/AU/mo'" <no return ...>
--- SIGCHLD (Child exited) ---
<... system resumed> ) = 0
rand(2, 0x7ffcb7b6d480, 0, 0x7f9d6d4622b0) = 0x2d8ddbe1
sprintf("/opt/sms/AU/mo/tmp.XXXXXX", "%s/tmp.XXXXXX", "/opt/sms/AU/mo") = 29
mkstemp(0x7ffcb7b6d5c0, 0x40080b, 0x40081a, 0x7ffffff1) = 3
sprintf("/opt/sms/AU/mo/tmp.XXXXXX", "%s/tmp.XXXXXX", "/opt/sms/AU/mo") = 29
mkstemp(0x7ffcb7b6d5c0, 0x40080b, 0x40081a, 0x7ffffff1) = 4
+++ exited (status 0) +++
If the program is small, you might also consider disassembling it with objdump -d exe_file
or disassembling/decompiling it with Hopper
, to see all the files it deals with.
For more details see: Understanding what a Linux binary is doing
As a first approach, I would also do:
strings exe_file
It is a low cost approach, and with luck some of the files names might just be present in ASCII mode in the binary file with luck.
See also related answer Why are true and false so large?
If binaries/files that come with the distribution you can also fetch the sources from the sources repositories of the distribution, or the official repositories of the actual utility.
As a last resource, you can always use tools like gdb or rr to debug the binary in real time.

- 349

- 56,709
- 26
- 150
- 232
-
aaa43bb66:~ # sudo proc.name=exe_file sysdig -p "%12user.name %6proc.pid %12proc.name %3fd.num %fd.typechar %fd.name" evt.type=open Unable to load the driver error opening device /dev/sysdig0. Make sure you have root credentials and that the sysdig-probe module is loaded. – Boll19 Jan 29 '18 at 05:45
-
/
aaa43bb66:~ # sudo proc.name=exe_file sysdig -p "%12user.name %6proc.pid %12proc.name %3fd.num %fd.typechar %fd.name" evt.type=open Unable to load the driver error opening device /dev/sysdig0. Make sure you have root credentials and that the sysdig-probe module is loaded.
/ – Boll19 Jan 29 '18 at 05:53 -
@Boll19 Got an error there, corrected it. That message seems about a
sysdig
bug (are you using ARM?), please post a new question for it. – Rui F Ribeiro Jan 29 '18 at 09:51
fstat()
orlstat()
info, etc. – Sergiy Kolodyazhnyy Jan 27 '18 at 20:56