pyinotify: fix directory monitoring on systems with native inotify other than Linux (gh-4250)

The parent directory watch was added with the mask containing IN_ISDIR,
which is an output-only flag (set by the kernel in events). Linux ignores
it, but FreeBSD 15+ (native kernel inotify) rejects the whole add_watch
with EINVAL, so the directory was not monitored at all:

  add_watch: cannot watch /var/log WD=-1, Errno=Invalid argument (EINVAL)

The file watch itself kept working, so new lines were found, but after a
log rotation (move + create) the new file was never noticed and the jail
silently stopped to find failures. This became visible with 1.1.1, since
pyinotify was unusable on python 3.12+ before (missing asyncore) and the
jails fell back to polling.

Additionally, the directory watch now includes IN_DELETE and IN_MOVED_FROM,
so removal of a watched log file is detected without relying on IN_IGNORED
for the file watch, which FreeBSD does not send in this case (test_del_file
failed there).

Verified on FreeBSD 15.1 (monitorfailures_FilterPyinotify passes, writes
after rotation detected) and on Linux.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
László Károlyi 2026-11-06 00:13:23 +01:00
parent fd09a9dcd2
commit da0fbbcd8b
No known key found for this signature in database
GPG key ID: 8EAA28E6FCF2F46C
2 changed files with 13 additions and 3 deletions

View file

@ -11,6 +11,10 @@ ver. 1.1.2-dev-1 (20??/??/??) - development nightly edition
-----------
### Fixes
* backend `pyinotify`: fixes monitoring on systems with native inotify other than Linux (e. g. FreeBSD 15+),
where the parent directory of the log could not be watched (`EINVAL` for output-only flag `IN_ISDIR` in the mask),
so log rotation was not detected and the jail silently stopped to find failures; also removal of a log file
is detected now without relying on `IN_IGNORED` (not sent there for a watched file) (gh-4250)
* `filter.d/postfix.conf` - monitor all Postfix instances in `system-postfix.slice` with the systemd backend (gh-4008)
* `filter.d/nginx-botsearch.conf` - error-log regex extended with support of journal format (gh-3732)
* `filter.d/apache-noscript.conf` - match a request for the `cgi-bin` directory itself (no script name after it),

View file

@ -243,10 +243,16 @@ class FilterPyinotify(FileFilter):
def _addDirWatcher(self, path_dir):
# Add watch for the directory:
if path_dir not in self.__watchDirs:
# note: IN_ISDIR is an output flag only (set in events by kernel), it must not be
# specified in the mask, since some systems reject it with EINVAL (e. g. FreeBSD 15+,
# with native inotify), so the directory would be not monitored at all (gh-4250);
# IN_ONLYDIR (input flag) to watch the path only if it is a directory;
# IN_DELETE and IN_MOVED_FROM to notice removal of watched files in the directory, since
# not all systems send IN_IGNORED for the watch of a removed file (e. g. FreeBSD):
self.__watchDirs.update(
self.__monitor.add_watch(path_dir, pyinotify.IN_CREATE |
pyinotify.IN_MOVED_TO | pyinotify.IN_MOVE_SELF |
pyinotify.IN_DELETE_SELF | pyinotify.IN_ISDIR))
self.__monitor.add_watch(path_dir, pyinotify.IN_CREATE |
pyinotify.IN_MOVED_TO | pyinotify.IN_DELETE | pyinotify.IN_MOVED_FROM |
pyinotify.IN_MOVE_SELF | pyinotify.IN_DELETE_SELF | pyinotify.IN_ONLYDIR))
logSys.debug("Added monitor for the parent directory %s", path_dir)
def _delDirWatcher(self, path_dir):