This example should add an ‘inotify_add_watch’ functionality for a newly created subsequent directory within a given path (for example: /tmp), but does not add that watch function for the newly created directory (for example: /tmp/subdir1/subdir2).
Only for the root path directory (/tmp) level, given by argv[1], it is functional (for example: /tmp/subdir1). The returned watch descriptor (variable ‘watch_fd’) is increased.
For a directory created in a more distant tree position (/tmp/subdir1/subdir2) from root directory (/tmp), there’s that ‘no such file or directory’ error. The returned watch descriptor ‘watch_fd’ then is -1.
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#define EVENT_SIZE (sizeof(struct inotify_event))
#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
// Function to add inotify watch recursively up to a specified depth
void add_watch_recursive(int inotify_fd, const char *base_path, int depth, int current_depth) {
if (current_depth > depth) {
return;
}
printf("base_path %s t", base_path);
int watch_fd = inotify_add_watch(inotify_fd, base_path, IN_CREATE | IN_DELETE);
printf("watch_fd %d n", watch_fd);
if (watch_fd < 0) {
perror("inotify_add_watch");
printf("ttt 'inotify_add_watch: No such file or directory' watch_fd %dn", watch_fd);
return;
}
DIR *dir = opendir(base_path);
if (!dir) {
perror("opendir");
return;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
char path[PATH_MAX];
snprintf(path, PATH_MAX, "%s/%s", base_path, entry->d_name);
struct stat statbuf;
if (stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
add_watch_recursive(inotify_fd, path, depth, current_depth + 1);
}
}
closedir(dir);
}
int main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "Usage: %s <path> <depth>n", argv[0]);
return EXIT_FAILURE;
}
const char *path = argv[1];
int depth = atoi(argv[2]);
if (depth < 0) {
fprintf(stderr, "Error: Depth must be a non-negative integern");
return EXIT_FAILURE;
}
// Print the path to verify it
printf("Attempting to open directory: %sn", path);
// Check if the directory exists
struct stat statbuf;
if (stat(path, &statbuf) != 0) {
perror("stat");
return EXIT_FAILURE;
}
// Check if it is a directory
if (!S_ISDIR(statbuf.st_mode)) {
fprintf(stderr, "Error: %s is not a directoryn", path);
return EXIT_FAILURE;
}
// Initialize inotify
int inotify_fd = inotify_init();
if (inotify_fd < 0) {
perror("inotify_init");
return EXIT_FAILURE;
}
// Add watch on the specified directory and its subdirectories up to the specified depth
add_watch_recursive(inotify_fd, path, depth, 0);
printf("Watching directory: %s and its subdirectories up to depth: %dn", path, depth);
// Buffer to store inotify events
char buffer[EVENT_BUF_LEN];
// Event loop
while (1) {
int length = read(inotify_fd, buffer, EVENT_BUF_LEN);
if (length < 0) {
perror("read");
break;
}
int i = 0;
while (i < length) {
struct inotify_event *event = (struct inotify_event *) &buffer[i];
if (event->len) {
char event_path[PATH_MAX];
snprintf(event_path, PATH_MAX, "%s/%s", path, event->name);
if (event->mask & IN_CREATE) {
if (event->mask & IN_ISDIR) {
printf("Directory created: %sn", event_path);
// Add watch to the new directory if within the specified depth
add_watch_recursive(inotify_fd, event_path, depth, 1);
} else {
printf("File created: %sn", event_path);
}
} else if (event->mask & IN_DELETE) {
if (event->mask & IN_ISDIR) {
printf("Directory deleted: %sn", event_path);
} else {
printf("File deleted: %sn", event_path);
}
}
}
i += EVENT_SIZE + event->len;
}
}
// Clean up
close(inotify_fd);
return EXIT_SUCCESS;
}
This example code for a C program for Linux system is compiled with
gcc inotifyaddwatch_subdirs.c -o inotifyaddwatch_subdirs
and
started with
./inotifyaddwatch_subdirs /tmp 5
.
Only with restarting the program, a subsequent directory is added from startup, but not within the running program.
If it is a pointer error for a sub directory’s singular path reference within the line
int watch_fd = inotify_add_watch(inotify_fd, base_path, IN_CREATE | IN_DELETE);
for the variable ‘base_path’, then it would need an additional exception handling.
The man pages for ‘inotify_add_watch’ explains for this error return value
“ENOENT A directory component in pathname does not exist or is a dangling symbolic link.”,
but i did not succeed in adding that sub directory path (proved to exist and being recognized within that program) to that pathname pointer array.