• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.gitignoreH A D19-Oct-201526 43

LICENSEH A D19-Oct-2015730 1411

MakefileH A D19-Oct-20151.6 KiB6428

README.mdH A D19-Oct-20155 KiB12794

TODOH A D19-Oct-2015216 54

filewatcherd.8H A D19-Oct-20151.6 KiB5049

filewatcherd.cH A D19-Oct-20157.3 KiB320219

log.cH A D19-Oct-20157.6 KiB312186

log.hH A D19-Oct-20154.8 KiB17773

run.cH A D19-Oct-20152.3 KiB9355

run.hH A D19-Oct-20151 KiB317

watchtab.5H A D19-Oct-20153.2 KiB105104

watchtab.cH A D19-Oct-201515.3 KiB672460

watchtab.hH A D03-May-20223.5 KiB11855

README.md

1# Overview
2
3`filewatcherd` is a daemon inspired by cron, that run commands based on
4file changes instead of time.
5
6In principle it is similar to `incron`, but it's simpler, more limited,
7and does not depend on anything outside of FreeBSD base.
8
9# Watchtab
10
11Usage of `filewatcherd` is quite straightforward: the daemon has a few
12basic command-line options, and takes a _watchtab_ file as main input.
13
14The watchtab is heavily inspired from `crontab`. Blank lines are ignored,
15leading and trailing blanks in line are ignored, line starting with a
16hash sign (`#`) are ignored as comments.
17
18Environment lines are defined as having an equal sign (`=`) before any
19backslash (`\\`) or tabulation character. They represent environment
20variables available for commands, and only affect the entries below them.
21
22Entry lines consist of 3 to 6 tabulation-separated fields. A complete line
23contains the following fields in respective order:
24
251. Path of the file to watch
262. Event set to consider
273. Delay between the first triggering event and command run
284. User, and optionally group, to set for the command
295. `chroot` to set for the command
306. The command itself
31
32When only 5 fields are present, `chroot` is skipped. When there are only
334 fields, user is also skipped. When there are only 3 field, delay is
34considered 0.
35
36In path, `chroot` and command fields, backslashes (`\\`) act as an escape
37character, allowing to embed tabulations, backslashes and/or equal signs
38in those fields without misinterpretation.
39
40The event set can be a single star sign (`*`) to mean all available events,
41or a list of any number of event names separated by a single non-letter
42byte. The available events are `delete`, `write`, `extend`, `attrib`,
43`link`, `rename` and `revoke`, with semantics matching those of
44similar-named `fflags` for vnode filter.
45
46The delay is given in seconds and can be fractional, up to the nanosecond
47(though most system probably do not have such a resolution in
48`nanosleep(3)`).
49
50The user can be a login string or a numeric id, and is optionally followed
51by a group string or numeric id after a colon (`:`). When specified, those
52must exist and have a matching `passwd` or `group` entry.
53
54The command is run in a clean environment, containing only variables
55explicitly declared in the watchtab file, and `SHELL`, `PATH`, `HOME`,
56`TRIGGER`, `USER`, `LOGNAME`.
57
58  * `SHELL` and `PATH` default respectively to `/bin/sh` and
59`/usr/bin:/bin`, but they can be overwritten in the watchtab.
60  * `HOME` default to the home directory of the user running the command,
61but can be overwritten in the watchtab.
62  * `USER` and `LOGNAME` are both forced to the login name of the user
63running the command, and values provided in the watchtab are ignored.
64  * `TRIGGER` is forced to the path of the file triggering the event
65(seen from outside the `chroot`), ignoring any value provided in the
66watchtab.
67
68The watchtab is automatically watched by `filewatcherd` itself, and is
69automatically reloaded when it changes.
70
71# Internals
72
73## Source organization
74
75`filewatcherd` is split between 4 `.c` modules:
76
77  * `log.c` implements logging functions, which means all user-facing
78output
79  * `watchtab.c` implements watchtab parsing and upkeep of structures
80related to watchtab entries
81  * `run.c` implements actual execution of a watchtab entry
82  * `filewatcherd.c` implements the event loop directly in `main()`
83function
84
85## Event loop overview
86
87### Watchtab entries
88
89Watchtab entries oscillate between two states:
90
91  * waiting for an `EVFILT_VNODE` event described in the watchtab,
92which triggers execution of the associated command
93  * waiting for an `EVFILT_PROC` event that signals the end of the command
94to switch back to `EVFILT_VNODE` wait.
95
96Events are not reused, at each step of cycle a new one is added to the
97kernel queue with `EV_ONESHOT` flag.
98
99This architecture guarantees that there cannot be more than one file
100descriptor per watchtab entry or more than one process started per watchtab
101entry. System resources consumed by `filewatcherd` are therefore bounded
102by the watchtab length.
103
104Whenever an error happens, e.g. when spawning the command or opening the
105watched path, the cycle is broken and the watchtab entry becomes inactive
106until the watchtab is reloaded.
107
108There is currently no way to re-enable a single inactive watchtab entry.
109
110### Watchtab watcher
111
112The watchtab file itself is also watched by `filewatcherd`, in a process
113similar to a watchtab entry except that `EVFILT_VNODE` events trigger an
114`EVFILT_TIMER` addition before reloading the file.
115
116Errors are handled so that this cycle can only be broken by a failure to
117insert an event in the queue:
118
119  * When the watchtab file cannot be opened, the timer event is left in the
120kernel queue to trigger another attempt after the delay. To prevent log
121spamming, only the first failure is logged, even though subsequent failures
122might have other causes.
123  * When the watchtab file is opened, the timer event is removed and an
124`EVFILT_VNODE` filter is added to track watchtab changes. Should a parse
125error occurs, the old watchtab is used instead, and a subsequent change in
126the watchtab file will trigger a reload.
127