Fixed child process bug and updated documentation
This commit is contained in:
14
.github/workflows/wolf.yml
vendored
Normal file
14
.github/workflows/wolf.yml
vendored
Normal 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
|
||||||
2
Makefile
2
Makefile
@@ -8,7 +8,7 @@ DEBUG_CFLAGS = -Wall -Wextra -Werror -pedantic-errors -fstack-protector-strong \
|
|||||||
-Wwrite-strings -std=c99 -g
|
-Wwrite-strings -std=c99 -g
|
||||||
CFLAGS = -Wall -Wextra -Werror -pedantic-errors -Wwrite-strings -std=c99 -O3
|
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)
|
build: $(TARGET)
|
||||||
debug: $(DEBUG_TARGET)
|
debug: $(DEBUG_TARGET)
|
||||||
|
|||||||
19
README.md
19
README.md
@@ -1,4 +1,4 @@
|
|||||||
# Wolf 🐺
|
# Wolf 🐺 [](https://github.com/ceticamarco/wolf/actions/workflows/wolf.yml)
|
||||||
|
|
||||||
**Wolf** is a configurable file watchdog for Linux platform written in C. **Wolf** monitors
|
**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
|
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
|
-v, --version | Show program version
|
||||||
-h, --help | Show this helper
|
-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>)
|
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)
|
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
|
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
|
```py
|
||||||
def square(x):
|
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:
|
below:
|
||||||
|
|
||||||
```sh
|
```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
|
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:
|
to be automatically evaluated, that is:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$> ./wolf -w --exec 'python foo.py'
|
$> ./wolf -w --exec 'python foo.py' .
|
||||||
[2024-08-20 16:24:43] W 'foo.py' (file)
|
[2024-08-20 16:24:43] W 'foo.py' (file)
|
||||||
10^2 = 100
|
10^2 = 100
|
||||||
[2024-08-20 16:24:55] W 'foo.py' (file)
|
[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
|
- 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;
|
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
|
- The `-e,--exec` option is a **BLOCKING** feature, meaning that the parent process waits for the child process to terminate
|
||||||
child process execute the supplied command; therefore the parent process will **NOT** wait for the child(s) process to terminate;
|
before logging new changes;
|
||||||
- Since the parent process does not await for the child process to complete it will also not handle its return code, thus the exit
|
- 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;
|
||||||
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;
|
|
||||||
- `inotify` is **NOT** recursive. Meaning that you cannot monitor subdirectories of a watched directory;
|
- `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` 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
|
- `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
30
wolf.c
@@ -61,13 +61,13 @@ void helper(const char *name) {
|
|||||||
"--no-timestamp | Disable timestamp from watchdog output\n"
|
"--no-timestamp | Disable timestamp from watchdog output\n"
|
||||||
"-v, --version | Show program version\n"
|
"-v, --version | Show program version\n"
|
||||||
"-h, --help | Show this helper\n\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);
|
"Report bugs to: Marco Cetica(<email@marcocetica.com>)\n", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void version() {
|
void version() {
|
||||||
printf("Wolf (v%s) - Configurable file watchdog for Linux platform.\n"
|
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"
|
"License GPLv3+: GNU GPL version 3 or later\n\n"
|
||||||
"Project homepage: <https://git.marcocetica.com/marco/wolf>.\n"
|
"Project homepage: <https://git.marcocetica.com/marco/wolf>.\n"
|
||||||
"Email bug reports to: <email@marcocetica.com>.\n", VERSION);
|
"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) {
|
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
|
// Execute command in a new process
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
|
||||||
@@ -333,6 +326,25 @@ static void exec_command(const char *cmd) {
|
|||||||
}
|
}
|
||||||
free(argv);
|
free(argv);
|
||||||
exit(EXIT_FAILURE);
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user