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