From 19a6deac9554ccfecc656bbce2974b810a9f9a38 Mon Sep 17 00:00:00 2001 From: Marco Cetica Date: Mon, 21 Jul 2025 16:08:49 +0200 Subject: [PATCH] Fixed child process bug and updated documentation --- .github/workflows/wolf.yml | 14 ++++++++++++++ Makefile | 2 +- README.md | 19 +++++++++---------- wolf.c | 30 +++++++++++++++++++++--------- 4 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 .github/workflows/wolf.yml diff --git a/.github/workflows/wolf.yml b/.github/workflows/wolf.yml new file mode 100644 index 0000000..970f55a --- /dev/null +++ b/.github/workflows/wolf.yml @@ -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 diff --git a/Makefile b/Makefile index d82d706..c26d1bc 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/README.md b/README.md index cd0d004..ea7021a 100644 --- a/README.md +++ b/README.md @@ -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() ``` @@ -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 diff --git a/wolf.c b/wolf.c index ce34614..5a643b2 100644 --- a/wolf.c +++ b/wolf.c @@ -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()\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: .\n" "Email bug reports to: .\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)); + } } }