wolf/README.md
2024-07-31 11:27:02 +02:00

5.7 KiB

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:

  1. inotify is NOT recursive. Meaning that you cannot monitor subdirectories of a watched directory;
  2. inotify can only work within files for which you already have reading and writing permissions;
  3. inotify removes deleted files from the inotify_add_watch(2), meaning that a watchdog is automatically removed from a deleted file. To add it again, the program have to be restarted;
  4. inotify is quite verbose by design. For instance if you try to write to a non-empty watched file using the echo(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.

License

GPLv3