đ Select Language | éæŠč¯č¨
Features
- Real-time Monitoring: Captures 14 fanotify events (default: 8 core change events,
--all-eventsfor all 14) - Process Attribution: Tracks PID, command name, and user for every file change â even short-lived processes like
touch,rm,mv - Recursive Monitoring: Watch entire directory trees with automatic tracking of newly created subdirectories
- Complete Deletion Capture: Captures every file deleted during
rm -rfvia persistent directory handle cache - High Performance: Rust + Tokio, <5MB memory footprint, zero-copy FID event parsing, binary-search log querying
- Flexible Filtering: Filter by time, size, process, user, event type, and exclude patterns (wildcards)
- Multiple Formats: Human-readable, JSON, and CSV output
- TOML Configuration: Persistent config at
~/.fsmon/config.tomlor/etc/fsmon/config.toml - Log Management: Time-based and size-based log rotation with dry-run preview
- Systemd Service: Install as systemd service with configurable security hardening
Why fsmon
Ever needed to answer "Who modified this file?" on a Linux server? That's exactly what fsmon is for.
Traditional file monitoring tools give you events without context â fsmon bridges that gap by attributing every file change to its responsible process. Whether it's a rogue script, an automated deployment, or a misconfigured service, you'll know exactly what happened, when, and who (or what) caused it.
Quick Start
Prerequisites
- OS: Linux 5.9+ (requires fanotify FID mode)
- Tested Filesystems: ext4, XFS, btrfs (Note: Linux 6.18+ recommended for full recursive operation support of btrfs)
- Build: Rust toolchain (
cargo)
# Verify kernel version
# Install Rust if needed
|
Installation
# Build from source
# Or install from crates.io
Important: Fanotify requires root privileges
# Method 1: Copy to /usr/local/bin (recommended)
# Method 2: Use full path directly
Basic Usage
# Monitor a directory
# Monitor with recursive watching
# Exclude patterns
# Install as systemd service for long-term auditing
# Query historical events
# Clean old logs (dry-run preview)
# Check service status
Examples
Investigate Configuration Changes
# Monitor /etc for modifications
# In another terminal, make a change
|
# Query the results
Track Large File Creation
# Watch for files larger than 50MB
# Trigger
Audit Deletion Operations
# Capture complete recursive deletion
# Trigger
# Output shows every file deleted (even in subdirectories)
)
)
Filter with Combined Criteria
# Query nginx operations in last hour, sorted by file size
# Monitor only CREATE and DELETE events, exclude temp files
Command Reference
Configuration
fsmon supports TOML configuration files at ~/.fsmon/config.toml or /etc/fsmon/config.toml:
[]
= ["/var/log", "/tmp"]
= "100MB"
= "MODIFY,CREATE"
= "*.tmp"
= true
= "/var/log/fsmon.log"
= "json"
= true
= 65536
[]
= "/var/log/fsmon.log"
= "1h"
= "json"
= "size"
[]
= 7
= "500MB"
[]
= "false"
= "false"
= ["/var/log", "/tmp"]
= "no"
CLI flags override config file values.
Technical Architecture
Modules
| Module | Description |
|---|---|
main.rs |
CLI entry point with clap derive, FileEvent struct, log cleaning engine |
monitor.rs |
Core fanotify monitoring loop, scope filtering, file size tracking (LRU) |
fid_parser.rs |
Low-level FID mode event parsing, two-pass path recovery |
dir_cache.rs |
Directory handle caching via name_to_handle_at for deleted file path resolution |
proc_cache.rs |
Netlink proc connector listener â captures short-lived process info at exec() |
query.rs |
Log file querying with binary search optimization and combined filters |
config.rs |
TOML-based persistent configuration |
systemd.rs |
Systemd service lifecycle (install, uninstall, status, start, stop) |
output.rs |
Event output formatting (human, JSON, CSV) |
utils.rs |
Size/time parsing, process info helpers, UID lookup |
help.rs |
Centralized help text for all commands |
Data Flow
Linux Kernel (fanotify)
â FID events pushed to queue
â tokio::select reads events asynchronously
â fid_parser parses FID records (two-pass: resolve + cache recover)
â Monitor filters (type, size, exclude, scope)
â output formats (human/json/csv) â stdout + optional file
- fanotify (FID mode + FAN_REPORT_NAME): Kernel pushes file events with directory file handles and filenames. No polling â events delivered immediately via non-blocking read.
- Proc Connector: Background thread subscribes to netlink
PROC_EVENT_EXECnotifications, caching every process's(pid, cmd, user)at the instant it execs. This ensures short-lived processes (touch,rm,mv) are attributable even after they exit. - FID Parser + Dir Cache: Two-pass event processing: (1) resolve file handles via
open_by_handle_at, (2) use persistent directory handle cache to recover paths for events where the parent directory was already deleted. Handles multi-level nestedrm -rfscenarios. - Binary Search Query:
fsmon queryuses binary search on approximately time-sorted log files, narrowing the scan range to O(log N) seek operations. Combined withexpand_offset_backwardto catch minor out-of-order entries. - Rust + Tokio: Single-threaded async loop (
tokio::selectbetween fanotify fd and Ctrl+C signal). Background thread for proc connector. No complex concurrency â high efficiency instead.
Event Mask Strategy
fsmon uses a two-tier marking strategy:
- FAN_MARK_FILESYSTEM (preferred): Marks the entire mount point covering the target path â no race window for newly created files. Falls back if
EXDEV(btrfs subvolumes). - Inode mark fallback: Marks individual directories one by one, with recursive traversal for
--recursivemode. Dynamically marks newly created directories in real-time.
Event Types
Default captures 8 core events. Use --all-events for all 14.
Default Events (8):
| Event | Description |
|---|---|
| CLOSE_WRITE | File closed after write (best "modified" signal) |
| ATTRIB | Metadata changed (permissions, timestamps, owner) |
| CREATE | File/directory created |
| DELETE | File/directory deleted |
| DELETE_SELF | The monitored file/directory itself was deleted |
| MOVED_FROM | File moved out of monitored directory |
| MOVED_TO | File moved into monitored directory |
| MOVE_SELF | The monitored file/directory itself was moved |
Additional Events (6, via --all-events):
| Event | Description |
|---|---|
| ACCESS | File read |
| MODIFY | File content written (very noisy) |
| OPEN | File/directory opened |
| OPEN_EXEC | File opened for execution |
| CLOSE_NOWRITE | Read-only file closed |
| FS_ERROR | Filesystem error (Linux 5.16+) |