fsmon: one filesystem watcher for Linux, Android, macOS and iOS
Filesystem monitor tool for Linux/Android iOS/macOS
At a glance
- What is it?
- fsmon is a small C utility from NowSecure that reports filesystem events as they happen, picking the right kernel facility on each platform, inotify and fanotify on Linux, FSEvents, kqueue and kdebug on Apple systems. What makes it more than a tail command is the process level filtering, the JSON output for piping into other tools, and the fact that it is one binary rather than a per platform script.
- Who is it for?
- Adopt fsmon if you need to see which process touched which file, on any of the four operating systems it covers, and if you want the output in a form a pipeline can consume. Do not adopt it as an audit system with a durable trail, since the output is a stream, and do not rely on the backup option, which the tool itself marks experimental.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A low level monitor with a short feature list
The project is described as a low level, cross-platform filesystem monitor designed for developers, forensic analysts, and reverse engineers, and it works by hooking into the OS kernel's tracing facilities or file notification APIs.
The audience is spelled out in the README, and it is a wider list than a tail wrapper would have. It is designed for system administrators and incident responders, for security researchers and forensic analysts, for developers debugging I/O-heavy applications, and for reverse engineers interested in observing filesystem access behavior.
The last of those explains the design. A tool that only reports that a file changed is a monitoring tool. A tool that reports which process made the change is an investigative one, and that is the feature that distinguishes fsmon from the platform facilities it sits on.
It is written in portable C with no runtime dependencies beyond standard libraries, which is a genuine constraint rather than a boast, because the tool is expected to be dropped onto an Android device, an iOS device or a locked down Linux box and to run there without dragging a runtime along. The licence is MIT, the author is listed as pancake at NowSecure, and the contact address in the README belongs to Sergi Alvarez. The last push was on 2026-04-11, and the release tags are 1.8.4 from 2021, 1.8.6 from 2024-06-14 and 1.8.8 from 2025-05-06.
The repository is laid out the way a portable C tool usually is, with main.c, util.c and util.h at the top, a backend/ directory holding the per platform implementations, config.mk holding the shared build configuration, a man page in fsmon.1, a pkg.sh packaging script, an android-shell.sh helper, and entitlements.plist for the Apple side.
The backend is chosen for you, or forced with -B
The mechanism is a set of backends, one per kernel facility, and fsmon picks the best available one unless you tell it otherwise.
On Linux the options are inotify and fanotify. On Android the tool works via inotify, and the README notes that fanotify is not always supported there. On macOS it uses kdebug, FSEvents, kqueue and /dev/fsevents, and on iOS there is limited support through the FSEvent APIs. The list of backends in the code is named in the features section as inotify and fanotify on the Linux side, and fsevapi, kdebug, devfsev and kqueue for the iOS and macOS side.
Two things control the choice. The -L flag lists all filemonitor backends, which is the first thing to run on a new machine, because the answer decides whether you get the coverage you need. And the -B flag specifies an alternative backend by name, which is what you reach for when the automatic pick is not the one you want, for instance because you need a specific kernel facility for the events you care about.
The Makefile shows the same split at the build level, with the target triple from the compiler deciding which branch is compiled. The Linux branch defines HAVE_FANOTIFY and HAVE_SYS_FANOTIFY, and the Apple branch covers macOS, iOS and the watch, with a separate -arch armv7k target triple for the watch. The result is one source tree that produces a Linux binary, a macOS binary, an iOS binary and an Android binary, and the backends are compiled in or out depending on the platform.
Filtering by process, and the JSON output
The usage block is the full command line, and the flags fall into three groups.
$ ./fsmon -h
Usage: ./fsmon-macos [-Jjc] [-a sec] [-b dir] [-B name] [-p pid] [-P proc] [path]
-a [sec] stop monitoring after N seconds (alarm)
-b [dir] backup files to DIR folder (EXPERIMENTAL)
-B [name] specify an alternative backend
-c follow children of -p PID
-f show only filename (no path)
-h show this help
-j output in JSON format
-J output in JSON stream format
-n do not use colors
-L list all filemonitor backends
-p [pid] only show events from this pid
-P [proc] events only from process name
-v show version
[path] only get events from this pathThe process filtering is the group that matters for the forensic audience. -p restricts the output to one process id, -P restricts it to a process name, and -c extends the selection to the children of the process given with -p. The path argument restricts the events to one directory, and the tool recurses through the tree, adding new directories as they appear.
The output formats are the second group that matters, because they are what turns a monitoring tool into a pipeline component. -j produces JSON, -J produces a JSON stream, and the README gives the example fsmon -J / | jq -r .filename, which is how you would extract just the file names out of a busy system and feed them to something else. The features section names the tools this is aimed at, jq and ELK among them.
The presentation flags complete the set. -f strips the path and shows only the filename, -n turns off the colour, and the colours otherwise are applied based on event type, so a deletion and a modification are visually distinct without you having to read them. The event types the tool tracks include CREATE_FILE, DELETE, RENAME, OPEN, CLOSE, STAT_CHANGED, CHOWN, CHMOD, XATTR_MODIFIED, CONTENT_MODIFIED, EXCHANGE and FINDER_INFO_CHANGED.
Two behaviours are worth knowing before you point this at a machine. Timestamps are added to each event, which is what makes the output usable for forensic analysis, and the tool handles SIGINT, SIGTERM and SIGALRM for clean exits and timed monitoring sessions, which is what the -a sec alarm flag relies on.
The backup option is marked experimental
One flag deserves a separate mention because the README labels it EXPERIMENTAL in the help text itself, which is unusual and worth respecting.
The -b flag backs up files to a DIR folder, and the core capabilities section describes it as automatically copying affected files to a backup directory when changes are detected. In other words, the tool can take a copy of a file at the moment it is modified, which is a preservation feature rather than a monitoring one.
That is a genuinely useful capability for the incident responder audience, and it is also the kind of feature that has consequences. A tool that copies files on change writes to the filesystem it is monitoring, so the copies are themselves filesystem events, and the behaviour of the tool on a busy system depends on how the monitoring interacts with the writing. Nothing in the README describes how that self reference is handled, and that is exactly the kind of detail an experimental label is warning you about.
The right way to treat it is as a feature to evaluate rather than to rely on. If you need file preservation, test it on a copy of the data with the tool running, and check what it actually does when the file it is writing to is itself observed. If you only need the event stream, leave the flag off.
The same caution applies to the timestamps, in the opposite direction. They are what makes the output useful for analysis, and there is no indication in the README that the clock is synchronised or that the timestamps are monotonic, so a forensic workflow should not treat them as authoritative without checking.
Building it, and crosscompiling for Android and iOS
Installation on macOS goes through Homebrew, with a tap pointing at the repository:
brew tap nowsecure/fsmon https://github.com/nowsecure/fsmon
brew install nowsecure/fsmon/fsmonAlternatively you can just run make, or pick a build from the release page. The install target takes a prefix:
make
make install PREFIX=/usrThe build itself is deliberately plain. The Makefile includes config.mk for the shared configuration, adds -I. and -Wall to the compiler flags, and defines the version into the binary with -DFSMON_VERSION, so the -v flag can report it. The source list is main.c, util.c and everything under backend/, which is the whole program.
The portability is the interesting part. The tool works on iOS, OSX, Linux and Android, across the x86, arm, arm64 and mips architectures, and crosscompilation is a make target away:
$ make android NDK_ARCH=<ARCH> ANDROID_API=<API>There is a make ios target as well, and the Apple branch of the Makefile shows how much platform knowledge is baked in. The iOS build sets the architecture flags, uses the iPhoneOS sysroot from xcrun, and targets arm64-apple-ios10.0 with -miphoneos-version-min=10.0 and -O3. There is a separate path for on device compilation, where the sysroot is the running system and the compiler is the system clang, and another for the watch, with -arch armv7k and the watchOS sysroot.
The Makefile also handles the platform detection in a way that shows the author's experience with the boundaries between the systems. The target triple is taken from the compiler, and Darwin, Linux and Android are matched explicitly, with uname as the fallback, so an unusual host still gets a build rather than an error.
Editorial conclusion
Adopt fsmon if you need to see which process touched which file, on any of the four operating systems it covers, and if you want the output in a form a pipeline can consume. Do not adopt it as an audit system with a durable trail, since the output is a stream, and do not rely on the backup option, which the tool itself marks experimental. Verify first which backend your machine actually supports, since the README notes that fanotify is not always available on Android, that iOS support is limited through the FSEvent APIs, and that the backup flag is experimental.
Frequently asked questions
How do I install fsmon?
On macOS, tap the repository with brew tap nowsecure/fsmon https://github.com/nowsecure/fsmon and then brew install nowsecure/fsmon/fsmon. Otherwise run make, or take a build from the release page, and make install PREFIX=/usr to install it.
Which monitoring backends does fsmon use on each platform?
Linux uses inotify and fanotify, Android uses inotify with fanotify not always supported, macOS uses kdebug, FSEvents, kqueue and /dev/fsevents, and iOS has limited support through the FSEvent APIs. You can list the available backends with fsmon -L and force one with -B.
Can fsmon show which process caused a file event?
Yes. The tool associates file events with process names, PIDs and UIDs where possible, and you can restrict the output to a process id with -p, to a process name with -P, and to the children of a process with -c.
Is the fsmon backup option safe to rely on?
The help text labels it EXPERIMENTAL. The -b flag copies affected files to a backup directory when changes are detected, so the tool writes to the filesystem it is watching, and the README does not describe how that is handled.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nowsecure-fsmon)Was this useful?