LICENSE | ||
Makefile | ||
README.md | ||
wolf.c |
Wolf 🐺
Wolf is a configurable file watchdog for Linux platform written in C. Wolf monitors
a set of files or directories and prints out a log event each time the watched resources changes. The watchdog
can be configured to watch for any kind of event, that includes file creation and deletion, file moving, I/O and
permission changing. Wolf relies on the inotify(7)
system call, therefore it is only compatible with Linux-based systems.
Building
The single source file(wolf.c
) of the watchdog can be compiled using any C99 compiler. To build it, issue the following command:
$> make clean all
This command will produce a statically compiled binary called wolf.
Usage
Wolf - Configurable file watchdog for Linux platform.
Syntax: './wolf [-c|-d|-m|-r|-w|-p|-f] <PATH ...>'
options:
-c, --create | Add a watchdog for file creation
-d, --delete | Add a watchdog for file deletion
-m, --move | Add a watchdog for file movements or file renaming
-r, --read | Add a watchdog for reading events
-w, --write | Add a watchdog for writing events
-p, --permission | Add a watchdog for permissions changes
-f, --full | Enable all the previous options
--no-timestamp | Disable timestamp from watchdog output
-v, --version | Show program version
-h, --help | Show this helper
General help with the software: https://git.marcocetica.com/marco/wolf
Report bugs to: Marco Cetica(<email@marcocetica.com>)
Wolf is pretty straightforward to use. It requires at least one watchdog option and at least
one file/directory to watch as command line arguments. For example, to watch the local files foo
, bar
and
the directory src/
for reading, writing and deletion events, issue the following command:
$> ./wolf -rwd foo bar src
The watchdog will start polling the resources for the specified events and will log on the standard output using the following pattern:
[<timestamp>] <event> '<path>' (<filetype>)
Where <timestamp>
is the timestamp of the event, <event>
is the event type, <path>
is the filename of
the watched resource and <filetype>
is the type of the resource in the watchlist.
The <event>
field is any of the following token: C, D, M, R, W, P.
For instance, if you try to read one of the files of the previous example(cat foo
), wolf would produce the following
output:
[2024-07-29 20:24:52] R 'foo' (file)
A write syscall to the src/test
file would instead produce the following log:
[2024-07-29 20:26:20] W 'src/test' (file)
You can also choose to watch a directory by specifying its path:
$> ./wolf -rwd $PWD
This command will add a watchdog to the current directory for events of the type "read", "write" and "delete" generated for any file or directory on the current path. Do note that this command is NOT recursive(see the caveats section for more information).
Additionally, you can also tell wolf to add a watchdog to any kind of event by using the -f, --full
option:
%> ./wolf --full $PWD
Which is equivalent to ./wolf -cdmrwp $PWD
. Finally, you can also force wolf to disable the timestamp output by using the --no-timestamp
option:
%> ./wolf -f --no-timestamp $PWD
This would produce the following output:
R '/home/marco/wolf' (dir)
R '/home/marco/wolf/foo' (file)
D '/home/marco/wolf/src' (dir)
R '/home/marco/wolf' (dir)
P '/home/marco/wolf/a.out' (file)
W '/home/marco/wolf/a.out' (file)
Caveats
Wolf relies on the Linux inotify(7)
system call to implement the file tracking mechanism. Before using this
tool you should be aware of the following idiosyncrasies related to the way this system interface works:
inotify
is NOT recursive. Meaning that you cannot monitor subdirectories of a watched directory;inotify
can only work within files for which you already have reading and writing permissions;inotify
removes deleted files from theinotify_add_watch(2)
, meaning that a watchdog is automatically removed from a deleted file. To add it again, the program have to be restarted;inotify
is quite verbose by design. For instance if you try to write to a non-empty watched file using theecho(1)
command along with a redirection(i.e.,echo 'hello world' > foo
), the watchdog will log two events:
W '/home/marco/wolf/foo' (file)
W '/home/marco/wolf/foo' (file)
This is because the previous command makes two system calls: one to truncate(1)
the file at zero length and
the other to write(1)
the content into the file. The former is issued by the shell itself while the latter is
performed by the echo(1)
command. You can detect these syscalls by using the strace(1)
command:
$> strace sh -c 'echo "hello world" > foo'
execve("/usr/bin/sh", ["sh", "-c", "echo \"hello world\" > foo"], 0xffffd10381d0 /* 23 vars */) = 0
# Suppressed output
openat(AT_FDCWD, "foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 # <-- Truncate system call(first event)
fcntl(1, F_DUPFD, 10) = 10
close(1) = 0
fcntl(10, F_SETFD, FD_CLOEXEC) = 0
dup3(3, 1, 0) = 1
close(3) = 0
write(1, "hello world\n", 12) = 12 # <-- Write system call(second event)
dup3(10, 1, 0) = 1
close(10) = 0
exit_group(0) = ?
+++ exited with 0 +++
Since inotify(1)
intercepts both, wolf will also log twice the same operation.