Fixed child process bug and updated documentation

This commit is contained in:
2025-07-21 16:08:49 +02:00
parent f83f8f034e
commit 19a6deac95
4 changed files with 45 additions and 20 deletions

14
.github/workflows/wolf.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
name: wolf
on:
push:
branches: [master]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Wolf
run: |
make clean build

View File

@@ -8,7 +8,7 @@ DEBUG_CFLAGS = -Wall -Wextra -Werror -pedantic-errors -fstack-protector-strong \
-Wwrite-strings -std=c99 -g
CFLAGS = -Wall -Wextra -Werror -pedantic-errors -Wwrite-strings -std=c99 -O3
BUILD_FLAGS = -DVERSION=\"0.0.2\"
BUILD_FLAGS = -DVERSION=\"0.0.3\"
build: $(TARGET)
debug: $(DEBUG_TARGET)

View File

@@ -1,4 +1,4 @@
# Wolf 🐺
# Wolf 🐺 [![](https://github.com/ceticamarco/wolf/actions/workflows/wolf.yml/badge.svg)](https://github.com/ceticamarco/wolf/actions/workflows/wolf.yml)
**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
@@ -34,7 +34,7 @@ options:
-v, --version | Show program version
-h, --help | Show this helper
General help with the software: https://git.marcocetica.com/marco/wolf
Project homepage: https://github.com/ceticamarco/wolf
Report bugs to: Marco Cetica(<email@marcocetica.com>)
```
@@ -103,7 +103,8 @@ P '/home/marco/wolf/a.out' (file)
W '/home/marco/wolf/a.out' (file)
```
Additionally, if you want to execute a custom command every time a watchdog detects a change, you can do so by
using the `-e,--exec` option. For instance, suppose that you have a Python file(`foo.py`) with the following content:
using the `-e,--exec` option. For instance, suppose that you have a Python file(`foo.py`) on the current directory
with the following content:
```py
def square(x):
@@ -116,14 +117,14 @@ and you want to continously evaluate it as soon as you save it to the disk. To d
below:
```sh
$> ./wolf -w --exec 'python foo.py'
$> ./wolf -w --exec 'python foo.py' .
```
Each time a write event is detected by the watchdog, the supplied command will be issued, causing the program
to be automatically evaluated, that is:
```sh
$> ./wolf -w --exec 'python foo.py'
$> ./wolf -w --exec 'python foo.py' .
[2024-08-20 16:24:43] W 'foo.py' (file)
10^2 = 100
[2024-08-20 16:24:55] W 'foo.py' (file)
@@ -143,11 +144,9 @@ Below there is a brief list of the things you should be aware of when using **Wo
- The `-e,--exec` option works by spawning a child process using the `fork(2)` system call; thus, the command is being executed
in a new process;
- The `-e,--exec` option is a **NON-BLOCKING** feature, meaning that the parent process will continue to log new changes while the
child process execute the supplied command; therefore the parent process will **NOT** wait for the child(s) process to terminate;
- Since the parent process does not await for the child process to complete it will also not handle its return code, thus the exit
status of any supplied command is ignored.
- Any `SIGCHLD` signal generated by a child process is ignored, therefore the reaping of any child process is delegated to the kernel;
- The `-e,--exec` option is a **BLOCKING** feature, meaning that the parent process waits for the child process to terminate
before logging new changes;
- The child's return code will be printed to standard output only if it is non-zero or if the child was terminated by a signal;
- `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 the `inotify_add_watch(2)`, meaning that, after a file is being deleted, the watchdog associated with it

30
wolf.c
View File

@@ -61,13 +61,13 @@ void helper(const char *name) {
"--no-timestamp | Disable timestamp from watchdog output\n"
"-v, --version | Show program version\n"
"-h, --help | Show this helper\n\n"
"General help with the software: https://git.marcocetica.com/marco/wolf\n"
"Project homepage: https://github.com/ceticamarco/wolf\n"
"Report bugs to: Marco Cetica(<email@marcocetica.com>)\n", name);
}
void version() {
printf("Wolf (v%s) - Configurable file watchdog for Linux platform.\n"
"Copyright (c) 2024 Marco Cetica\n"
"Copyright (c) 2024, 2025 Marco Cetica\n"
"License GPLv3+: GNU GPL version 3 or later\n\n"
"Project homepage: <https://git.marcocetica.com/marco/wolf>.\n"
"Email bug reports to: <email@marcocetica.com>.\n", VERSION);
@@ -300,13 +300,6 @@ static void get_timestamp(uint8_t *timestamp, const ssize_t timestamp_len) {
}
static void exec_command(const char *cmd) {
// Ignore SIGCHLD signals.
// This allows us to avoid blocking the parent process until the child completes
// its execution; furthermore, it allows us to prevent the creation of zombie processes
// by delegating the cleanup process to the kernel. By doing so, we lose the ability
// to check the return status of the child process.
signal(SIGCHLD, SIG_IGN);
// Execute command in a new process
pid_t pid = fork();
@@ -333,6 +326,25 @@ static void exec_command(const char *cmd) {
}
free(argv);
exit(EXIT_FAILURE);
} else { // Parent process
// Block until child exits
int status;
pid_t wpid = waitpid(pid, &status, 0);
if (wpid == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
// Log when child process exited(normally) with an error
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
printf("[Wolf] - Child process exited with status %d\n", WEXITSTATUS(status));
}
// Log when child process was terminated by a signal
if (WIFSIGNALED(status)) {
printf("[Wolf] - Child process wass terminated by signal %d\n", WTERMSIG(status));
}
}
}