wolf/README.md

143 lines
5.7 KiB
Markdown
Raw Normal View History

2024-07-31 11:22:30 +02:00
# 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:
```sh
$> 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:
```sh
$> ./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:
```sh
$> ./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:
```sh
%> ./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:
```sh
%> ./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:
```sh
$> 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](https://choosealicense.com/licenses/gpl-3.0/)