{"id":20942221,"url":"https://github.com/tinkershack/fluffy","last_synced_at":"2026-03-15T23:17:28.019Z","repository":{"id":91068267,"uuid":"122762066","full_name":"tinkershack/fluffy","owner":"tinkershack","description":"Fluffy watches, reports Linux on-disk filesystem events faithfully. Comes with a CLI framework/tool for convenience. The library, libfluffy, can be independently used in other projects.","archived":false,"fork":false,"pushed_at":"2018-10-08T19:02:17.000Z","size":115,"stargazers_count":32,"open_issues_count":4,"forks_count":9,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-02T10:06:51.631Z","etag":null,"topics":["cli","filesystem-events","freedom","inotify","inotify-library","linux","notification-library","watch","wip"],"latest_commit_sha":null,"homepage":"http://tinkershack.in","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tinkershack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-02-24T17:20:01.000Z","updated_at":"2025-01-27T15:36:36.000Z","dependencies_parsed_at":"2024-04-21T16:36:53.137Z","dependency_job_id":null,"html_url":"https://github.com/tinkershack/fluffy","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinkershack%2Ffluffy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinkershack%2Ffluffy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinkershack%2Ffluffy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinkershack%2Ffluffy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tinkershack","download_url":"https://codeload.github.com/tinkershack/fluffy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254043218,"owners_count":22004912,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","filesystem-events","freedom","inotify","inotify-library","linux","notification-library","watch","wip"],"created_at":"2024-11-18T23:24:39.350Z","updated_at":"2026-03-15T23:17:28.007Z","avatar_url":"https://github.com/tinkershack.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"In the spirit of true freedom, Fluffy is [Unlicensed][]. Free as in *do \nwhat ever pleases you* sort of freedom and free beer as well! Fluffy \nbelieves that a piece of software is free(freedom?) only when it has \nsevered ties with licenses, copyrights, intellectual property rights and \nother crap of similar kind. Attribution is a kind gesture, Fluffy \nappreciates it but doesn't fret if you fail to say \"[good dog][]!\"\n\n\n*Fluffy reports on-disk filesystem events faithfully and celebrates \ncraftsmanship.*\n\n# Fluffy - A 'free' watchdog for Linux on-disk filesystems [WIP]\n\n__Fluffy__ is a convenient CLI tool, __libfluffy__ is what you \nwill find under the hood. libfluffy uses the inotify kernel subsystem.\n\nThere are challenges in using the native [inotify][] library \neffectively; [Michael Kerrisk][] provides a lucid description. Fluffy's \nmagic cuts through all the challenges cleanly.\n\n### Why Fluffy?\n\nThere are other implementations of filesystem watchers already, why \nFluffy?\n\n - Linux specific; Fluffy is not cross platform, but loyal to Linux.  \n   Linux has its tricks, \\*BSD has its, so does Solaris. It only makes\n   sense to have separate implementations for each of it to fully \n   utilize the exclusive features which aren't available across all\n   platforms. If the features aren't very diverse, then it's only a \n   matter of porting; though it may be painful it's relatively less \n   painful than an all-in-one model. Besides, a platform specific \n   library helps keep the code base clean and lean. It's simpler. If you \n   are thinking POSIX, please think again why many of the popular \n   operating systems aren't POSIX/SUS compliant.\n\n - Reports events faithfully.  \n   There are popular libraries/tools built already that do a poor job \n   at reporting the events - wrong event path, erroneous event handling, \n   erroneous event reporting, oblivious to filesystem \n   structure/hierarchy changes(dir moves especially), can't add watches \n   on the fly without re-executing(reinitiating) the program(library).\n   After considering various aspects of the process, building from \n   scratch seemed better than fixing the broken ones. \n\n - Add/remove watch paths on the fly.\n\n - A fully functional library that utilizes the native inotify kernel \n   subsystem properly. This means, unlike few tools, the events are not \n   limited to just file 'modifications'. Every possible event action \n   like 'open', 'access', 'close', 'no write', 'delete', 'move' is \n   caught. User has the flexibility(control?) to discard/process select \n   events. \n\n - Freedom. NO GPL shit.  \n   Fluffy has three heads. It likes to flip the middle one to licensing.\n\n\n### Contents\n - [libfluffy](#libfluffy)\n\n   - [A simple example program using \n     `libfluffy`](#a-simple-example-program-using-libfluffy)\n\n - [Dependencies](#dependencies)\n\n - [Don't mind getting your hands \n   dirty?](#dont-mind-getting-your-hands-dirty)\n\n - [CLI invocations](#cli-invocations)\n\n   - [fluffy usage](#fluffy-usage)\n\n   - [fluffyctl usage](#fluffyctl-usage)\n\n   - [Fluffy event log snippet](#fluffy-event-log-snippet)\n\n   - [Perform actions on events from \n     CLI](#perform-actions-on-events-from-cli)\n\n - [TODO: Fluffy is a WIP](#todo-fluffy-is-a-wip)\n\n\n### [libfluffy](#contents)\n\n_libfluffy_ is a better choice if you are planning to use it in \nproduction. [fluffy.h][] has the interface description and callables.  \n[example.c][] provides a sample.\n\nlibfluffy code is fairly documented. [fluffy.h][] would be good place to \nstart the trail. From there, jump to the corresponding function \ndefinition in `fluffy.c` and follow the calls thereafter. Should you \nfeel that it's a bit confusing, head to the [example.c][] to get a sense \nof the flow.\n\n#### API list\n\nPlease look at [fluffy.h][] for description. This is just a list of \nfunction calls available.\n\n__Primary functions__\n\n```c\nint fluffy_init(int (*user_event_fn) (\n    const struct fluffy_event_info *eventinfo,\n    void *user_data), void *user_data);\n\nint fluffy_add_watch_path(int fluffy_handle, const char *pathtoadd);\n\nint fluffy_remove_watch_path(int fluffy_handle, const char *pathtoremove);\n\nint fluffy_wait_until_done(int fluffy_handle);\n\nint fluffy_no_wait(int fluffy_handle);\n\nint fluffy_destroy(int fluffy_handle);\n```\n\n__Helper functions__\n\n```c\nint fluffy_print_event(const struct fluffy_event_info *eventinfo,\n    void *user_data);\n\nint fluffy_reinitiate_context(int fluffy_handle);\n\nint fluffy_reinitiate_all_contexts();\n\nint fluffy_set_max_queued_events(const char *max_size);\n\nint fluffy_set_max_user_instances(const char *max_size);\n\nint fluffy_set_max_user_watches(const char *max_size);\n```\n\n#### [A simple example program using `libfluffy`](#contents)\n\n```c\n/*\n * example.c\n */\n#include \u003cpthread.h\u003e\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n#include \u003cunistd.h\u003e\n\n#include \u003cfluffy.h\u003e\n\nint\nmain(int argc, char *argv[])\n{\n\tint ret = 0;\n\tint flhandle = 0;       /* Fluffy handle */\n\tint rc = EXIT_SUCCESS;\t/* Return code */\n\n\tif (argc \u003c 2) {\n\t\tfprintf(stderr, \"Atleast a path required.\\n\");\n\t\texit(EXIT_FAILURE);\n\t}\n\n        /* /proc/sys/fs/inotify/max_user_watches */\n\tret = fluffy_set_max_user_watches(\"524288\");\n\tif (ret != 0) {\n\t\tfprintf(stderr, \"fluffy_set_max_user_watches fail\\n\");\n\t}\n\n        /* /proc/sys/fs/inotify/max_queued_events */\n\tret = fluffy_set_max_queued_events(\"524288\");\n\tif (ret != 0) {\n\t\tfprintf(stderr, \"fluffy_set_max_queued_events fail\\n\");\n\t}\n\n        /*\n\t * Initiate fluffy and print events on the standard out with the help\n\t * of libfluffy's print event helper function.\n\t *\n\t * Look at fluffy.h for help with plugfing your custom event handler\n\t */\n\tflhandle = fluffy_init(fluffy_print_event, (void *)\u0026flhandle);\n\tif (flhandle \u003c 1) {\n\t\tfprintf(stderr, \"fluffy_init fail\\n\");\n\t\texit(EXIT_FAILURE);\n\t}\n\n\tdo {\n\t\t/* Watch argv[1] */\n\t\tret = fluffy_add_watch_path(flhandle, argv[1]);\n\t\tif (ret != 0) {\n\t\t\tfprintf(stderr, \"fluffy_add_watch_path %s fail\\n\", argv[1]);\n\t\t\trc = EXIT_FAILURE;\n\t\t\tbreak;\n\t\t}\n\n\t\t/* Let us not exit until Fluffy exits/returns */\n\t\tret = fluffy_wait_until_done(flhandle);\n\t\tif (ret != 0) {\n\t\t\tfprintf(stderr, \"fluffy_wait_until_done fail\\n\");\n\t\t\trc = EXIT_FAILURE;\n\t\t\tbreak;\n\t\t}\n\t} while(0);\n\n\tif (rc != EXIT_SUCCESS) {\n\t\tret = fluffy_destroy(flhandle);\t/* Destroy Fluffy context */\n\t}\n\n\texit(rc);\n}\n\n```\n\nThe above code block is available as `example.c` in \n`./fluffy/libfluffy/`, run `make example` from within the libfluffy \ndirectory to compile the example program.\n\nUntil the documentation is completed, these Stack Overflow answers may \nbe of some reference.\n\n[Inotify: Odd behavior with directory \ncreations](https://stackoverflow.com/questions/47648301/inotify-odd-behavior-with-directory-creations/49347059#49347059)\n\n[Inotify linux watching \nsubdirectories](https://stackoverflow.com/questions/47673447/inotify-linux-watching-subdirectories/49345762#49345762)\n\n[How to use inotifywait to watch files within folder instead of \nfolder](https://stackoverflow.com/questions/47225008/how-to-use-inotifywait-to-watch-files-within-folder-instead-of-folder/49349226#49349226)\n\n\n### [Dependencies](#contents)\n\n - Linux kernel \u003e 2.6\n\n - `gcc`\n\n - `pkg-config`\n\n - `make`\n\n - `glib-2.0`\n\n - glib-2.0 devel package (`glib2-devel` for CentOS or RPM based \n   distros, `libglib2.0-dev` for Debian)\n\n### [Don't mind getting your hands dirty?](#contents)\n\n```bash\n# Fork and clone this repo\n# Ensure glib-2.0 has been installed\n# cd to fluffy dir\nmake            # `make clean` to cleanup\n\n# If you see errors, please consider creating an issue here.\n# No erros? Cool, let's proceed.\nmake install    # `make uninstall` to uninstall\n\n# The framework, along with the library, has been installed.\n\n# Run help\nfluffyctl --help-all\n\nfluffy --help\n\n# Try\n# Execute fluffy first\nfluffy\n\n# Open a new terminal to execute fluffyctl\n# Let's watch /var/log \u0026 /tmp\nfluffyctl -w /var/log -w /tmp\n\n# You must see some action at the terminal where fluffy is run.\n# Nothing yet?\nls -l /var/log  # Still nothing? We may have a problem!\n\n# Let's ignore /tmp, not interested watching anymore.\nfluffyctl -I /tmp\n\n# More? Let's quit fluffy so that you can start over \u0026 explore.\nfluffy exit\n\n# If you are interested only in the library, you can choose to compile \n# just the library.\ncd ./libfluffy\nmake\n\n# There will now be a libfluffy.a archive file(static library), you can\n# link against it in your projects.\n\n# example.c shows a simple usage of the library\nmake example\n./fluffy-example\n\n# Modify example.c to play around. Run `make example` when you wish\n# to compile the modified example.c for testing.\n\n```\n\n### [CLI invocations](#contents)\n\n#### fluffy usage\n\n```bash\nroot@six-k:~# fluffy -h\nUsage:\n  fluffy [OPTION...] [exit]\n\nHelp Options:\n  -h, --help                     Show help options\n\nApplication Options:\n  -O, --outfile=./out.fluffy     File to print output [default:stdout] Ensure that it's NOT located within the watch path to prevent a recurring feedback loop!\n  -E, --errfile=./err.fluffy     File to print errors [default:stderr] Ensure that it's NOT located within the watch path to prevent a recurring feedback loop!\n\n```\n\n#### fluffyctl usage\n\n```bash\nroot@six-k:~# fluffyctl --help-all\nUsage:\n  fluffyctl [OPTION...] [\"/path/to/hogwarts/kitchen\"]\n\n'fluffyctl' controls 'fluffy' program.\nfluffy must be invoked before adding/removing watches.  By default all \nfile system events are watched and reported. --help-events will show the \noptions to modify this behaviour\n\nHelp Options:\n  -h, --help                                      Show help options\n  --help-all                                      Show all help options\n  --help-events                                   File system events to report\n\nWhen an option or more from 'events' group is passed, only those events \nwill be reported. When a new invocation of fluffyctl sets any 'events' \noption, previously set events choice is discarded; overrides.\n\n  --all                                           Watch all possible events [default]\n  --access                                        Watch file access\n  --modify                                        Watch file modifications\n  --attrib                                        Watch metadata change\n  --close-write                                   Watch closing of file opened for writing\n  --close-nowrite                                 Watch closing of file/dir not opened for writing\n  --open                                          Watch opening of file/dir\n  --moved-from                                    Watch renames/moves: reports old file/dir name\n  --moved-to                                      Watch renames/moves: reports new file/dir name\n  --create                                        Watch creation of files/dirs\n  --delete                                        Watch deletion of files/dirs\n  --root-delete                                   Watch root path deletions\n  --root-move                                     Watch root path moves/renames\n  --isdir                                         Watch for events that occur against a directory\n  --unmount                                       Watch for unmount of the backing filesystem ['isdir' not raised]\n  --queue-overflow                                Watch for event queue overflows ['isdir' not raised]\n  --ignored                                       Watch for paths ignored by Fluffy(not watched) ['isdir' not raised]\n  --root-ignored                                  Watch for root paths ignored(not watched) ['isdir' not raised]\n  --watch-empty                                   Watch whether all Fluffy watches are removed ['isdir' not raised]\n\nApplication Options:\n  -w, --watch=/grimmauld/place/12                 Paths to watch recursively. Repeat flag for multiple paths.\n  -W, --watch-glob                                Paths to watch recursively: supports wildcards. Any non-option argument passed will be considered as paths. [/hogwarts/*/towers]\n  -i, --ignore=/knockturn/alley/borgin/brukes     Paths to ignore recursively. Repeat flag for multiple paths.\n  -I, --ignore-glob                               Paths to ignore recursively: supports wildcards. Any non-option argument passed will be considered as paths. [/hogwarts/*/dungeons]\n  -U, --max-user-watches=524288                   Upper limit on the number of watches per uid [fluffy defaults 524288]\n  -Q, --max-queued-events=524288                  Upper limit on the number of events [fluffy defaults 524288]\n  -z, --reinit                                    Reinitiate watch on all root paths. [Avoid unless necessary]\n\n```\n\n#### Fluffy event log snippet\n\n```bash\nMODIFY, /var/log/daemon.log\nMODIFY, /var/log/syslog\nMODIFY, /var/log/kern.log\nMODIFY, /var/log/messages\nGNORED, /var/log/apache2\nIGNORED,        /var/log/tor\nIGNORED,        /var/log/vmware\nCREATE,ISDIR,   /tmp/test\nACCESS,ISDIR,   /tmp/test\nACCESS,ISDIR,   /tmp/test\nCLOSE_NOWRITE,ISDIR,    /tmp/test\nCREATE, /tmp/test/f1\nOPEN,   /tmp/test/f1\nATTRIB, /tmp/test/f1\nCLOSE_WRITE,    /tmp/test/f1\nOPEN,   /tmp/test/f1\nMODIFY, /tmp/test/f1\nMODIFY, /tmp/test/f1\nMODIFY, /tmp/test/f1\nCLOSE_WRITE,    /tmp/test/f1\nIGNORED,ROOT_IGNORED,WATCH_EMPTY,       /tmp\n```\n\n\n#### Perform actions on events from CLI\n\n**CAUTION** It's recommended that you use `libfluffy` to perform \nsophisticated actions on events rather than scripting with CLI usage. \n\nLet's consider a trivial action: `ls -l` the path on a MODIFY event\n\nAt terminal:1\n\n```bash\nroot@six-k:/home/lab/fluffy# fluffy | \\\nwhile read events path; do \\\n    if echo $events | grep -qie \"MODIFY\"; then \\\n        ls -l $path; \\\n    fi \\\ndone\n```\n\nAt terminal:2\n\n```bash\nroot@six-k:/opt/test2# fluffyctl -w ./\nroot@six-k:/opt/test2# touch f1\nroot@six-k:/opt/test2# ls -l\ntotal 0\n-rw-r--r-- 1 root root 0 Mar 18 19:38 f1\nroot@six-k:/opt/test2# echo \"this is a MODIFY\" | cat \u003e\u003e f1\nroot@six-k:/opt/test2# echo \"this is another MODIFY\" | cat \u003e\u003e f1\nroot@six-k:/opt/test2# fluffy exit\n```\n\nOutput from terminal:1: [cont.]\n\n```bash\nroot@six-k:/home/lab/fluffy# fluffy | \\\n\u003e while read events path; do \\\n\u003e     if echo $events | grep -qie \"MODIFY\"; then \\\n\u003e         ls -l $path; \\\n\u003e     fi \\\n\u003e done\n-rw-r--r-- 1 root root 17 Mar 18 19:38 /opt/test2/f1\n-rw-r--r-- 1 root root 40 Mar 18 19:38 /opt/test2/f1\nroot@six-k:/home/lab/fluffy# \n```\n\n\n### [TODO: Fluffy is a WIP](#contents)\n\nThere's still quite a few more to be done but these are the primary ones\n\n - Documentation _WIP_\n - Proper error reporting. For now, most error returns have been set -1 \n   deliberately without any error string or value.\n - Valgrind\n - Test cases\n\n - Other helper functions\n   - Destroy all contexts\n   - Emit internal events(eg. watches set, file info) for analytics\n   - Get the list of root watch paths\n - Option to terminate context thread when watch list becomes empty\n - Ability to modify callback function pointer\n\n\n[fluffy.h]:     libfluffy/fluffy.h\n[example.c]:    libfluffy/example.c\n\n[Unlicensed]:   https://unlicense.org/\n[good dog]:     http://harrypotter.wikia.com/wiki/Fluffy\n[inotify]:      http://man7.org/linux/man-pages/man7/inotify.7.html\n[Michael Kerrisk]:      https://lwn.net/Articles/605128/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinkershack%2Ffluffy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftinkershack%2Ffluffy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinkershack%2Ffluffy/lists"}