Home
TR

Watching

How the index keeps up: why inotify is not used, why fanotify asks for root once, and what happens without the mark.

A search tool’s index is only right if it changes when the filesystem does. Linux offers two ways to hear about that; Scour uses one, and why it does not use the other is not a detail.

inotify — and why not

inotify wants a separate watch for every directory. One example: a development machine had 609,322 folders, and the kernel hands out 524,288 watches per session. That machine could not be watched with inotify at all — not even if Scour swallowed the whole budget by itself.

And the budget is shared. Your editor, your IDE, your file manager and every npm run dev draw from the same pool. When one program exhausts it, the failure appears not in that program but in the next one to start — and it never says “out of watches”. Each watch holds about a kilobyte of unswappable kernel memory.

So there is no inotify in Scour — not even as a fallback. It was one for a release, and it did exactly this to a machine: a development tool would not open. Breaking somebody else’s program is not its job.

fanotify — one mark per volume

fanotify marks the filesystem itself rather than the directories in it. Two volumes watched means two marks; the number of folders does not enter into it. A million folders is still two marks.

Measured cost while idle, with two volumes watched and nobody looking: 0.8% of one core. The index commits every second while a face is open and every fifteen seconds when none is; that, not the watcher, is how long a change takes to appear.

Why root, once

Listening to a whole filesystem means, by definition, seeing outside your own files. The kernel puts that behind CAP_SYS_ADMIN — a reasonable place for it.

Scour does not hold that privilege. It borrows it for a moment and gives it back.

scour-watch is a separate program that depends on no part of Scour and does only this, in order: it opens the fanotify descriptor, places the marks, resolves them, drops the privilege and execs scourd. The service spends the rest of its life unprivileged.

The handover was measured rather than assumed: the process that comes out reports CapEff=0, and both attempts to escalate return EPERM. scour-watch installs nothing — no setcap, no persistent mount, no service of its own.

Why not a passwordless sudo rule

The thing people reach for instead is a NOPASSWD line in sudoers. Here that is worse: every binary in the chain lives under the user’s home, so a passwordless rule pointing at one of them is passwordless root for anything that can write that directory — which is the user’s own account.

The system unit grants the privilege only at start, and only to scour-watch.

Installing it

systemctl --user disable --now scourd.service   # if the user unit is on
sudo bash packaging/install-service.sh           # [--user NAME] [ROOT...]
systemctl start scour.service

The installer puts the helper under root-owned /usr/local/libexec/scour and writes the system unit and the polkit rule for your account — the user from whoever ran sudo, the roots from its arguments (default /home). Do not skip the first line. Two services running at once both race for the index lock; the loser exits saying the index is busy, and systemd starts it again, and again.

Read the unit file before running it: it says what the privilege is for and where it is dropped.

If you do not install it

Scour still works — but it does not fall back to inotify; that road is gone. When a volume’s write counter moves it reconciles by walking: nothing is missed, changes take a little longer to appear. On a small home directory you will not notice. Network and FUSE mounts have no counter, are walked once and never reconciled again; they need the mark.

To see where you stand:

scour status

The watching line says how many sources are being watched live.