fanotify.rb 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +10 -0
- data/LICENSE +21 -0
- data/README.md +205 -0
- data/ext/fanotify/constants.h +262 -0
- data/ext/fanotify/extconf.rb +10 -0
- data/ext/fanotify/fanotify.c +60 -0
- data/lib/fanotify/version.rb +5 -0
- data/lib/fanotify.rb +4 -0
- metadata +53 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 164eb7087ea0e3327407b27107999b32cb2e47c98021b13f16a4caebd088dc11
|
|
4
|
+
data.tar.gz: 6ddcc04fa61ce86bbce6f613cd5ab05b58769b99a0ff5b686ae316d1ba942be6
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 1aab4796ed440d07ff1945ed7ca1e89bfdc7c3a5fe860eeccc1299393551f9f0392eb0529e6a6469f2bdb919444c612fe8176ff24865d5f1d3585183d79bc554
|
|
7
|
+
data.tar.gz: 978b296931fcdf1098993658223129eb6c1c78eacf4f98c410e5664d60ca24f003d829c8f0846d5fadea665db24cd07e91adae07b1bbd1689cf196e42a62714a
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
Initial release.
|
|
6
|
+
|
|
7
|
+
- Native bindings for Linux `fanotify_init(2)` and `fanotify_mark(2)`.
|
|
8
|
+
- Linux fanotify constants, conditional on the build headers.
|
|
9
|
+
- Kernel errors exposed as Ruby `Errno::*` exceptions.
|
|
10
|
+
- Raw file descriptors for use with Ruby `IO`.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Matt Christen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# fanotify.rb
|
|
2
|
+
|
|
3
|
+
A thin, Linux-only Ruby gem for `fanotify_init(2)` and `fanotify_mark(2)`.
|
|
4
|
+
It exposes the syscalls and Linux constants. Use Ruby `IO` for `read(2)`,
|
|
5
|
+
`write(2)`, and `close(2)` on the returned descriptors.
|
|
6
|
+
|
|
7
|
+
## Build and install
|
|
8
|
+
|
|
9
|
+
Requires Ruby 3.1 or later, a C compiler, make, Ruby development headers,
|
|
10
|
+
and libc/Linux development headers providing `sys/fanotify.h` and both functions.
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
gem build fanotify.rb.gemspec
|
|
14
|
+
gem install ./fanotify.rb-0.1.0.gem
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
For Bundler, use `gem "fanotify.rb", require: "fanotify"`. The gem name is
|
|
18
|
+
`fanotify.rb`; the Ruby require path is `fanotify` and the module is `Fanotify`.
|
|
19
|
+
|
|
20
|
+
## API
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
require "fanotify"
|
|
24
|
+
|
|
25
|
+
fd = Fanotify.init(flags, event_f_flags)
|
|
26
|
+
result = Fanotify.mark(fd, flags, mask, dirfd, pathname)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`init` returns an integer file descriptor. `mark` returns `0` on success.
|
|
30
|
+
Arguments are required and follow the C API in the same order; flags and
|
|
31
|
+
the 64-bit event mask are integers. `pathname` accepts a String, an object
|
|
32
|
+
implementing `to_path`, or `nil` for a C `NULL` pointer. Relative paths are
|
|
33
|
+
resolved by the kernel against `dirfd`; `Fanotify::AT_FDCWD` uses the current
|
|
34
|
+
working directory. Embedded NUL bytes are rejected.
|
|
35
|
+
|
|
36
|
+
Syscall failures raise Ruby's corresponding `Errno::*` exception with the
|
|
37
|
+
kernel's errno. Flags, permissions, filesystem support, and kernel-version
|
|
38
|
+
restrictions are governed by Linux. In particular, many operations require
|
|
39
|
+
`CAP_SYS_ADMIN`; unprivileged groups have additional restrictions.
|
|
40
|
+
|
|
41
|
+
The `Fanotify` module exposes object-like `FAN_*` UAPI constants and
|
|
42
|
+
`FANOTIFY_METADATA_VERSION`, including event masks, initialization/mark flags,
|
|
43
|
+
permission responses, info-record types, and `FAN_EVENT_METADATA_LEN`.
|
|
44
|
+
Constants are conditional on the headers used to compile the extension;
|
|
45
|
+
their presence does not guarantee running-kernel support. Function-like C
|
|
46
|
+
macros are not Ruby methods.
|
|
47
|
+
|
|
48
|
+
There are no watchers, callbacks, recursive traversal, event parsing, or
|
|
49
|
+
automatic descriptor ownership. The caller reads the kernel event records,
|
|
50
|
+
writes responses, and closes the group descriptor and each event descriptor
|
|
51
|
+
(including any reported pidfds).
|
|
52
|
+
|
|
53
|
+
## Reading events
|
|
54
|
+
|
|
55
|
+
This example uses the default descriptor-based event format. It requires
|
|
56
|
+
permission to create this type of group. Pass an existing directory in `ARGV[0]`.
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
require "fanotify"
|
|
60
|
+
require "fcntl"
|
|
61
|
+
|
|
62
|
+
fd = Fanotify.init(Fanotify::FAN_CLOEXEC, Fcntl::O_RDONLY)
|
|
63
|
+
group = IO.for_fd(fd, "rb")
|
|
64
|
+
|
|
65
|
+
begin
|
|
66
|
+
Fanotify.mark(fd, Fanotify::FAN_MARK_ADD,
|
|
67
|
+
Fanotify::FAN_OPEN | Fanotify::FAN_EVENT_ON_CHILD,
|
|
68
|
+
Fanotify::AT_FDCWD, ARGV.fetch(0))
|
|
69
|
+
|
|
70
|
+
loop do
|
|
71
|
+
data = group.sysread(4096)
|
|
72
|
+
offset = 0
|
|
73
|
+
while offset < data.bytesize
|
|
74
|
+
event_len, version, _reserved, metadata_len, mask, event_fd, pid =
|
|
75
|
+
data.byteslice(offset, Fanotify::FAN_EVENT_METADATA_LEN).unpack("LCCSQl l")
|
|
76
|
+
|
|
77
|
+
begin
|
|
78
|
+
raise "unsupported metadata version" unless version == Fanotify::FANOTIFY_METADATA_VERSION
|
|
79
|
+
unless metadata_len >= Fanotify::FAN_EVENT_METADATA_LEN &&
|
|
80
|
+
event_len >= metadata_len && event_len <= data.bytesize - offset
|
|
81
|
+
raise "invalid event length"
|
|
82
|
+
end
|
|
83
|
+
puts "mask=#{mask} pid=#{pid} fd=#{event_fd}"
|
|
84
|
+
ensure
|
|
85
|
+
IO.for_fd(event_fd).close if event_fd >= 0
|
|
86
|
+
end
|
|
87
|
+
offset += event_len
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
ensure
|
|
91
|
+
group.close
|
|
92
|
+
end
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The unpack template uses native byte order and the Linux UAPI field widths.
|
|
96
|
+
Advance by `event_len`, since records may contain additional information
|
|
97
|
+
after the fixed metadata. `FAN_Q_OVERFLOW` reports lost events, and `FAN_NOFD`
|
|
98
|
+
is a sentinel rather than an open descriptor. Groups using `FAN_REPORT_*`
|
|
99
|
+
flags can return other record formats; consult the Linux API documentation.
|
|
100
|
+
|
|
101
|
+
For a permission event, the native `struct fanotify_response` can be written
|
|
102
|
+
with `group.syswrite([event_fd, Fanotify::FAN_ALLOW].pack("lL"))` (open `group`
|
|
103
|
+
in `"r+b"` mode). Respond before closing the event descriptor. `FAN_DENY`,
|
|
104
|
+
audit flags, and extra response records follow the kernel API.
|
|
105
|
+
|
|
106
|
+
See [fanotify(7)](https://man7.org/linux/man-pages/man7/fanotify.7.html),
|
|
107
|
+
[fanotify_init(2)](https://man7.org/linux/man-pages/man2/fanotify_init.2.html),
|
|
108
|
+
and [fanotify_mark(2)](https://man7.org/linux/man-pages/man2/fanotify_mark.2.html).
|
|
109
|
+
|
|
110
|
+
## Development
|
|
111
|
+
|
|
112
|
+
```sh
|
|
113
|
+
bundle install
|
|
114
|
+
bundle exec rake test
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The tests compile the extension and exercise constants, argument conversion,
|
|
118
|
+
and kernel errors. The event integration test skips when the kernel denies
|
|
119
|
+
creating a descriptor-based fanotify group; run it with `CAP_SYS_ADMIN` to
|
|
120
|
+
exercise event delivery, relative directory descriptors, removal, and flush.
|
|
121
|
+
|
|
122
|
+
To run the complete suite in a container, including the integration test:
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
sh script/test-container
|
|
126
|
+
# Optional: choose another Ruby image.
|
|
127
|
+
RUBY_IMAGE=ruby:3.1 sh script/test-container
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
This requires a rootful Docker daemon on Linux (or a Linux VM) whose kernel
|
|
131
|
+
supports fanotify. The script grants `SYS_ADMIN`, mounts the source read-only,
|
|
132
|
+
and builds and tests inside the container. It sets
|
|
133
|
+
`FANOTIFY_REQUIRE_INTEGRATION=1`, which turns an unavailable fanotify group
|
|
134
|
+
into a test failure instead of a skip. You can also set this variable when
|
|
135
|
+
running the suite directly.
|
|
136
|
+
|
|
137
|
+
The GitHub Actions workflow uses the same script on `ubuntu-24.04` VM runners
|
|
138
|
+
with Ruby 3.1 and 3.4 for pushes and pull requests. No repository secrets or
|
|
139
|
+
fully privileged container are needed. A container host with an additional
|
|
140
|
+
seccomp policy must allow `fanotify_init` and `fanotify_mark`; rootless Docker
|
|
141
|
+
and restricted container runners cannot supply the required host capability.
|
|
142
|
+
The container also builds the gem with strict validation, installs it into
|
|
143
|
+
an isolated gem directory, and verifies it loads outside the source checkout.
|
|
144
|
+
|
|
145
|
+
## Releasing
|
|
146
|
+
|
|
147
|
+
Releases use the manually dispatched `Release` workflow in `.github/workflows/release.yml`.
|
|
148
|
+
It runs the full CI matrix, checks that the tag matches `Fanotify::VERSION`,
|
|
149
|
+
builds and verifies the package, then uses `rubygems/release-gem` to authenticate
|
|
150
|
+
using RubyGems Trusted Publishing and run Bundler's `rake release` task.
|
|
151
|
+
No RubyGems API key secret is needed. The supplied tag must already exist
|
|
152
|
+
and point to the commit selected for the workflow run.
|
|
153
|
+
|
|
154
|
+
Before the first release, create a GitHub environment named `Release` under
|
|
155
|
+
the repository settings. On RubyGems.org, configure a
|
|
156
|
+
[pending trusted publisher](https://rubygems.org/profile/oidc/pending_trusted_publishers)
|
|
157
|
+
with these exact values:
|
|
158
|
+
|
|
159
|
+
| Setting | Value |
|
|
160
|
+
| --- | --- |
|
|
161
|
+
| Gem name | `fanotify.rb` |
|
|
162
|
+
| Repository owner | `mchristen` |
|
|
163
|
+
| Repository name | `fanotify.rb` |
|
|
164
|
+
| Workflow filename | `release.yml` |
|
|
165
|
+
| Environment | `Release` |
|
|
166
|
+
|
|
167
|
+
The workflow is defined directly in this repository; leave the optional
|
|
168
|
+
Workflow Repository Owner and Workflow Repository Name fields blank.
|
|
169
|
+
See the [RubyGems Trusted Publishing guide](https://guides.rubygems.org/trusted-publishing/).
|
|
170
|
+
|
|
171
|
+
For each release:
|
|
172
|
+
|
|
173
|
+
1. Set the version in `lib/fanotify/version.rb` and update `CHANGELOG.md`.
|
|
174
|
+
2. Commit the release changes and get passing GitHub Actions checks on that
|
|
175
|
+
commit for every Ruby version. Integration tests must run without skips,
|
|
176
|
+
and the packaged gem must install and load successfully.
|
|
177
|
+
3. Build the package from a clean checkout of that commit. For version 0.1.0:
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
gem build --strict fanotify.rb.gemspec
|
|
181
|
+
gem unpack ./fanotify.rb-0.1.0.gem --target /tmp/fanotify-release-review
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Review the unpacked files. The package should contain only the Ruby source,
|
|
185
|
+
native extension source, README, changelog, and license, with no compiled
|
|
186
|
+
objects or local configuration.
|
|
187
|
+
4. Tag the tested commit and push the tag:
|
|
188
|
+
|
|
189
|
+
```sh
|
|
190
|
+
git tag v0.1.0
|
|
191
|
+
git push origin v0.1.0
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
In GitHub Actions, open **Release**, select **Run workflow**, choose that
|
|
195
|
+
tag under **Use workflow from**, and enter the same tag in the `tag` input.
|
|
196
|
+
The tag must include the release workflow and Bundler release-task setup.
|
|
197
|
+
|
|
198
|
+
5. Verify `gem install fanotify.rb -v 0.1.0` on Linux and create GitHub release
|
|
199
|
+
notes from the changelog. Published versions cannot be overwritten; fixes
|
|
200
|
+
require a new version.
|
|
201
|
+
|
|
202
|
+
Branch pushes and pull requests only run tests. Publication requires a manual
|
|
203
|
+
workflow run and passing tests on both Ruby versions, including the required
|
|
204
|
+
integration test. A failed test, package check, tag/version mismatch, or tag
|
|
205
|
+
pointing to a different commit prevents publication.
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/* Linux UAPI constants; availability follows the build headers. */
|
|
2
|
+
#ifdef FAN_ACCESS
|
|
3
|
+
rb_define_const(mod, "FAN_ACCESS", ULL2NUM(FAN_ACCESS));
|
|
4
|
+
#endif
|
|
5
|
+
#ifdef FAN_MODIFY
|
|
6
|
+
rb_define_const(mod, "FAN_MODIFY", ULL2NUM(FAN_MODIFY));
|
|
7
|
+
#endif
|
|
8
|
+
#ifdef FAN_ATTRIB
|
|
9
|
+
rb_define_const(mod, "FAN_ATTRIB", ULL2NUM(FAN_ATTRIB));
|
|
10
|
+
#endif
|
|
11
|
+
#ifdef FAN_CLOSE_WRITE
|
|
12
|
+
rb_define_const(mod, "FAN_CLOSE_WRITE", ULL2NUM(FAN_CLOSE_WRITE));
|
|
13
|
+
#endif
|
|
14
|
+
#ifdef FAN_CLOSE_NOWRITE
|
|
15
|
+
rb_define_const(mod, "FAN_CLOSE_NOWRITE", ULL2NUM(FAN_CLOSE_NOWRITE));
|
|
16
|
+
#endif
|
|
17
|
+
#ifdef FAN_OPEN
|
|
18
|
+
rb_define_const(mod, "FAN_OPEN", ULL2NUM(FAN_OPEN));
|
|
19
|
+
#endif
|
|
20
|
+
#ifdef FAN_MOVED_FROM
|
|
21
|
+
rb_define_const(mod, "FAN_MOVED_FROM", ULL2NUM(FAN_MOVED_FROM));
|
|
22
|
+
#endif
|
|
23
|
+
#ifdef FAN_MOVED_TO
|
|
24
|
+
rb_define_const(mod, "FAN_MOVED_TO", ULL2NUM(FAN_MOVED_TO));
|
|
25
|
+
#endif
|
|
26
|
+
#ifdef FAN_CREATE
|
|
27
|
+
rb_define_const(mod, "FAN_CREATE", ULL2NUM(FAN_CREATE));
|
|
28
|
+
#endif
|
|
29
|
+
#ifdef FAN_DELETE
|
|
30
|
+
rb_define_const(mod, "FAN_DELETE", ULL2NUM(FAN_DELETE));
|
|
31
|
+
#endif
|
|
32
|
+
#ifdef FAN_DELETE_SELF
|
|
33
|
+
rb_define_const(mod, "FAN_DELETE_SELF", ULL2NUM(FAN_DELETE_SELF));
|
|
34
|
+
#endif
|
|
35
|
+
#ifdef FAN_MOVE_SELF
|
|
36
|
+
rb_define_const(mod, "FAN_MOVE_SELF", ULL2NUM(FAN_MOVE_SELF));
|
|
37
|
+
#endif
|
|
38
|
+
#ifdef FAN_OPEN_EXEC
|
|
39
|
+
rb_define_const(mod, "FAN_OPEN_EXEC", ULL2NUM(FAN_OPEN_EXEC));
|
|
40
|
+
#endif
|
|
41
|
+
#ifdef FAN_Q_OVERFLOW
|
|
42
|
+
rb_define_const(mod, "FAN_Q_OVERFLOW", ULL2NUM(FAN_Q_OVERFLOW));
|
|
43
|
+
#endif
|
|
44
|
+
#ifdef FAN_FS_ERROR
|
|
45
|
+
rb_define_const(mod, "FAN_FS_ERROR", ULL2NUM(FAN_FS_ERROR));
|
|
46
|
+
#endif
|
|
47
|
+
#ifdef FAN_OPEN_PERM
|
|
48
|
+
rb_define_const(mod, "FAN_OPEN_PERM", ULL2NUM(FAN_OPEN_PERM));
|
|
49
|
+
#endif
|
|
50
|
+
#ifdef FAN_ACCESS_PERM
|
|
51
|
+
rb_define_const(mod, "FAN_ACCESS_PERM", ULL2NUM(FAN_ACCESS_PERM));
|
|
52
|
+
#endif
|
|
53
|
+
#ifdef FAN_OPEN_EXEC_PERM
|
|
54
|
+
rb_define_const(mod, "FAN_OPEN_EXEC_PERM", ULL2NUM(FAN_OPEN_EXEC_PERM));
|
|
55
|
+
#endif
|
|
56
|
+
#ifdef FAN_PRE_ACCESS
|
|
57
|
+
rb_define_const(mod, "FAN_PRE_ACCESS", ULL2NUM(FAN_PRE_ACCESS));
|
|
58
|
+
#endif
|
|
59
|
+
#ifdef FAN_MNT_ATTACH
|
|
60
|
+
rb_define_const(mod, "FAN_MNT_ATTACH", ULL2NUM(FAN_MNT_ATTACH));
|
|
61
|
+
#endif
|
|
62
|
+
#ifdef FAN_MNT_DETACH
|
|
63
|
+
rb_define_const(mod, "FAN_MNT_DETACH", ULL2NUM(FAN_MNT_DETACH));
|
|
64
|
+
#endif
|
|
65
|
+
#ifdef FAN_EVENT_ON_CHILD
|
|
66
|
+
rb_define_const(mod, "FAN_EVENT_ON_CHILD", ULL2NUM(FAN_EVENT_ON_CHILD));
|
|
67
|
+
#endif
|
|
68
|
+
#ifdef FAN_RENAME
|
|
69
|
+
rb_define_const(mod, "FAN_RENAME", ULL2NUM(FAN_RENAME));
|
|
70
|
+
#endif
|
|
71
|
+
#ifdef FAN_ONDIR
|
|
72
|
+
rb_define_const(mod, "FAN_ONDIR", ULL2NUM(FAN_ONDIR));
|
|
73
|
+
#endif
|
|
74
|
+
#ifdef FAN_CLOSE
|
|
75
|
+
rb_define_const(mod, "FAN_CLOSE", ULL2NUM(FAN_CLOSE));
|
|
76
|
+
#endif
|
|
77
|
+
#ifdef FAN_MOVE
|
|
78
|
+
rb_define_const(mod, "FAN_MOVE", ULL2NUM(FAN_MOVE));
|
|
79
|
+
#endif
|
|
80
|
+
#ifdef FAN_CLOEXEC
|
|
81
|
+
rb_define_const(mod, "FAN_CLOEXEC", ULL2NUM(FAN_CLOEXEC));
|
|
82
|
+
#endif
|
|
83
|
+
#ifdef FAN_NONBLOCK
|
|
84
|
+
rb_define_const(mod, "FAN_NONBLOCK", ULL2NUM(FAN_NONBLOCK));
|
|
85
|
+
#endif
|
|
86
|
+
#ifdef FAN_CLASS_NOTIF
|
|
87
|
+
rb_define_const(mod, "FAN_CLASS_NOTIF", ULL2NUM(FAN_CLASS_NOTIF));
|
|
88
|
+
#endif
|
|
89
|
+
#ifdef FAN_CLASS_CONTENT
|
|
90
|
+
rb_define_const(mod, "FAN_CLASS_CONTENT", ULL2NUM(FAN_CLASS_CONTENT));
|
|
91
|
+
#endif
|
|
92
|
+
#ifdef FAN_CLASS_PRE_CONTENT
|
|
93
|
+
rb_define_const(mod, "FAN_CLASS_PRE_CONTENT", ULL2NUM(FAN_CLASS_PRE_CONTENT));
|
|
94
|
+
#endif
|
|
95
|
+
#ifdef FAN_ALL_CLASS_BITS
|
|
96
|
+
rb_define_const(mod, "FAN_ALL_CLASS_BITS", ULL2NUM(FAN_ALL_CLASS_BITS));
|
|
97
|
+
#endif
|
|
98
|
+
#ifdef FAN_UNLIMITED_QUEUE
|
|
99
|
+
rb_define_const(mod, "FAN_UNLIMITED_QUEUE", ULL2NUM(FAN_UNLIMITED_QUEUE));
|
|
100
|
+
#endif
|
|
101
|
+
#ifdef FAN_UNLIMITED_MARKS
|
|
102
|
+
rb_define_const(mod, "FAN_UNLIMITED_MARKS", ULL2NUM(FAN_UNLIMITED_MARKS));
|
|
103
|
+
#endif
|
|
104
|
+
#ifdef FAN_ENABLE_AUDIT
|
|
105
|
+
rb_define_const(mod, "FAN_ENABLE_AUDIT", ULL2NUM(FAN_ENABLE_AUDIT));
|
|
106
|
+
#endif
|
|
107
|
+
#ifdef FAN_REPORT_PIDFD
|
|
108
|
+
rb_define_const(mod, "FAN_REPORT_PIDFD", ULL2NUM(FAN_REPORT_PIDFD));
|
|
109
|
+
#endif
|
|
110
|
+
#ifdef FAN_REPORT_TID
|
|
111
|
+
rb_define_const(mod, "FAN_REPORT_TID", ULL2NUM(FAN_REPORT_TID));
|
|
112
|
+
#endif
|
|
113
|
+
#ifdef FAN_REPORT_FID
|
|
114
|
+
rb_define_const(mod, "FAN_REPORT_FID", ULL2NUM(FAN_REPORT_FID));
|
|
115
|
+
#endif
|
|
116
|
+
#ifdef FAN_REPORT_DIR_FID
|
|
117
|
+
rb_define_const(mod, "FAN_REPORT_DIR_FID", ULL2NUM(FAN_REPORT_DIR_FID));
|
|
118
|
+
#endif
|
|
119
|
+
#ifdef FAN_REPORT_NAME
|
|
120
|
+
rb_define_const(mod, "FAN_REPORT_NAME", ULL2NUM(FAN_REPORT_NAME));
|
|
121
|
+
#endif
|
|
122
|
+
#ifdef FAN_REPORT_TARGET_FID
|
|
123
|
+
rb_define_const(mod, "FAN_REPORT_TARGET_FID", ULL2NUM(FAN_REPORT_TARGET_FID));
|
|
124
|
+
#endif
|
|
125
|
+
#ifdef FAN_REPORT_FD_ERROR
|
|
126
|
+
rb_define_const(mod, "FAN_REPORT_FD_ERROR", ULL2NUM(FAN_REPORT_FD_ERROR));
|
|
127
|
+
#endif
|
|
128
|
+
#ifdef FAN_REPORT_MNT
|
|
129
|
+
rb_define_const(mod, "FAN_REPORT_MNT", ULL2NUM(FAN_REPORT_MNT));
|
|
130
|
+
#endif
|
|
131
|
+
#ifdef FAN_REPORT_DFID_NAME
|
|
132
|
+
rb_define_const(mod, "FAN_REPORT_DFID_NAME", ULL2NUM(FAN_REPORT_DFID_NAME));
|
|
133
|
+
#endif
|
|
134
|
+
#ifdef FAN_REPORT_DFID_NAME_TARGET
|
|
135
|
+
rb_define_const(mod, "FAN_REPORT_DFID_NAME_TARGET", ULL2NUM(FAN_REPORT_DFID_NAME_TARGET));
|
|
136
|
+
#endif
|
|
137
|
+
#ifdef FAN_ALL_INIT_FLAGS
|
|
138
|
+
rb_define_const(mod, "FAN_ALL_INIT_FLAGS", ULL2NUM(FAN_ALL_INIT_FLAGS));
|
|
139
|
+
#endif
|
|
140
|
+
#ifdef FAN_MARK_ADD
|
|
141
|
+
rb_define_const(mod, "FAN_MARK_ADD", ULL2NUM(FAN_MARK_ADD));
|
|
142
|
+
#endif
|
|
143
|
+
#ifdef FAN_MARK_REMOVE
|
|
144
|
+
rb_define_const(mod, "FAN_MARK_REMOVE", ULL2NUM(FAN_MARK_REMOVE));
|
|
145
|
+
#endif
|
|
146
|
+
#ifdef FAN_MARK_DONT_FOLLOW
|
|
147
|
+
rb_define_const(mod, "FAN_MARK_DONT_FOLLOW", ULL2NUM(FAN_MARK_DONT_FOLLOW));
|
|
148
|
+
#endif
|
|
149
|
+
#ifdef FAN_MARK_ONLYDIR
|
|
150
|
+
rb_define_const(mod, "FAN_MARK_ONLYDIR", ULL2NUM(FAN_MARK_ONLYDIR));
|
|
151
|
+
#endif
|
|
152
|
+
#ifdef FAN_MARK_IGNORED_MASK
|
|
153
|
+
rb_define_const(mod, "FAN_MARK_IGNORED_MASK", ULL2NUM(FAN_MARK_IGNORED_MASK));
|
|
154
|
+
#endif
|
|
155
|
+
#ifdef FAN_MARK_IGNORED_SURV_MODIFY
|
|
156
|
+
rb_define_const(mod, "FAN_MARK_IGNORED_SURV_MODIFY", ULL2NUM(FAN_MARK_IGNORED_SURV_MODIFY));
|
|
157
|
+
#endif
|
|
158
|
+
#ifdef FAN_MARK_FLUSH
|
|
159
|
+
rb_define_const(mod, "FAN_MARK_FLUSH", ULL2NUM(FAN_MARK_FLUSH));
|
|
160
|
+
#endif
|
|
161
|
+
#ifdef FAN_MARK_EVICTABLE
|
|
162
|
+
rb_define_const(mod, "FAN_MARK_EVICTABLE", ULL2NUM(FAN_MARK_EVICTABLE));
|
|
163
|
+
#endif
|
|
164
|
+
#ifdef FAN_MARK_IGNORE
|
|
165
|
+
rb_define_const(mod, "FAN_MARK_IGNORE", ULL2NUM(FAN_MARK_IGNORE));
|
|
166
|
+
#endif
|
|
167
|
+
#ifdef FAN_MARK_INODE
|
|
168
|
+
rb_define_const(mod, "FAN_MARK_INODE", ULL2NUM(FAN_MARK_INODE));
|
|
169
|
+
#endif
|
|
170
|
+
#ifdef FAN_MARK_MOUNT
|
|
171
|
+
rb_define_const(mod, "FAN_MARK_MOUNT", ULL2NUM(FAN_MARK_MOUNT));
|
|
172
|
+
#endif
|
|
173
|
+
#ifdef FAN_MARK_FILESYSTEM
|
|
174
|
+
rb_define_const(mod, "FAN_MARK_FILESYSTEM", ULL2NUM(FAN_MARK_FILESYSTEM));
|
|
175
|
+
#endif
|
|
176
|
+
#ifdef FAN_MARK_MNTNS
|
|
177
|
+
rb_define_const(mod, "FAN_MARK_MNTNS", ULL2NUM(FAN_MARK_MNTNS));
|
|
178
|
+
#endif
|
|
179
|
+
#ifdef FAN_MARK_IGNORE_SURV
|
|
180
|
+
rb_define_const(mod, "FAN_MARK_IGNORE_SURV", ULL2NUM(FAN_MARK_IGNORE_SURV));
|
|
181
|
+
#endif
|
|
182
|
+
#ifdef FAN_ALL_MARK_FLAGS
|
|
183
|
+
rb_define_const(mod, "FAN_ALL_MARK_FLAGS", ULL2NUM(FAN_ALL_MARK_FLAGS));
|
|
184
|
+
#endif
|
|
185
|
+
#ifdef FAN_ALL_EVENTS
|
|
186
|
+
rb_define_const(mod, "FAN_ALL_EVENTS", ULL2NUM(FAN_ALL_EVENTS));
|
|
187
|
+
#endif
|
|
188
|
+
#ifdef FAN_ALL_PERM_EVENTS
|
|
189
|
+
rb_define_const(mod, "FAN_ALL_PERM_EVENTS", ULL2NUM(FAN_ALL_PERM_EVENTS));
|
|
190
|
+
#endif
|
|
191
|
+
#ifdef FAN_ALL_OUTGOING_EVENTS
|
|
192
|
+
rb_define_const(mod, "FAN_ALL_OUTGOING_EVENTS", ULL2NUM(FAN_ALL_OUTGOING_EVENTS));
|
|
193
|
+
#endif
|
|
194
|
+
#ifdef FANOTIFY_METADATA_VERSION
|
|
195
|
+
rb_define_const(mod, "FANOTIFY_METADATA_VERSION", ULL2NUM(FANOTIFY_METADATA_VERSION));
|
|
196
|
+
#endif
|
|
197
|
+
#ifdef FAN_EVENT_INFO_TYPE_FID
|
|
198
|
+
rb_define_const(mod, "FAN_EVENT_INFO_TYPE_FID", ULL2NUM(FAN_EVENT_INFO_TYPE_FID));
|
|
199
|
+
#endif
|
|
200
|
+
#ifdef FAN_EVENT_INFO_TYPE_DFID_NAME
|
|
201
|
+
rb_define_const(mod, "FAN_EVENT_INFO_TYPE_DFID_NAME", ULL2NUM(FAN_EVENT_INFO_TYPE_DFID_NAME));
|
|
202
|
+
#endif
|
|
203
|
+
#ifdef FAN_EVENT_INFO_TYPE_DFID
|
|
204
|
+
rb_define_const(mod, "FAN_EVENT_INFO_TYPE_DFID", ULL2NUM(FAN_EVENT_INFO_TYPE_DFID));
|
|
205
|
+
#endif
|
|
206
|
+
#ifdef FAN_EVENT_INFO_TYPE_PIDFD
|
|
207
|
+
rb_define_const(mod, "FAN_EVENT_INFO_TYPE_PIDFD", ULL2NUM(FAN_EVENT_INFO_TYPE_PIDFD));
|
|
208
|
+
#endif
|
|
209
|
+
#ifdef FAN_EVENT_INFO_TYPE_ERROR
|
|
210
|
+
rb_define_const(mod, "FAN_EVENT_INFO_TYPE_ERROR", ULL2NUM(FAN_EVENT_INFO_TYPE_ERROR));
|
|
211
|
+
#endif
|
|
212
|
+
#ifdef FAN_EVENT_INFO_TYPE_RANGE
|
|
213
|
+
rb_define_const(mod, "FAN_EVENT_INFO_TYPE_RANGE", ULL2NUM(FAN_EVENT_INFO_TYPE_RANGE));
|
|
214
|
+
#endif
|
|
215
|
+
#ifdef FAN_EVENT_INFO_TYPE_MNT
|
|
216
|
+
rb_define_const(mod, "FAN_EVENT_INFO_TYPE_MNT", ULL2NUM(FAN_EVENT_INFO_TYPE_MNT));
|
|
217
|
+
#endif
|
|
218
|
+
#ifdef FAN_EVENT_INFO_TYPE_OLD_DFID_NAME
|
|
219
|
+
rb_define_const(mod, "FAN_EVENT_INFO_TYPE_OLD_DFID_NAME", ULL2NUM(FAN_EVENT_INFO_TYPE_OLD_DFID_NAME));
|
|
220
|
+
#endif
|
|
221
|
+
#ifdef FAN_EVENT_INFO_TYPE_NEW_DFID_NAME
|
|
222
|
+
rb_define_const(mod, "FAN_EVENT_INFO_TYPE_NEW_DFID_NAME", ULL2NUM(FAN_EVENT_INFO_TYPE_NEW_DFID_NAME));
|
|
223
|
+
#endif
|
|
224
|
+
#ifdef FAN_RESPONSE_INFO_NONE
|
|
225
|
+
rb_define_const(mod, "FAN_RESPONSE_INFO_NONE", ULL2NUM(FAN_RESPONSE_INFO_NONE));
|
|
226
|
+
#endif
|
|
227
|
+
#ifdef FAN_RESPONSE_INFO_AUDIT_RULE
|
|
228
|
+
rb_define_const(mod, "FAN_RESPONSE_INFO_AUDIT_RULE", ULL2NUM(FAN_RESPONSE_INFO_AUDIT_RULE));
|
|
229
|
+
#endif
|
|
230
|
+
#ifdef FAN_ALLOW
|
|
231
|
+
rb_define_const(mod, "FAN_ALLOW", ULL2NUM(FAN_ALLOW));
|
|
232
|
+
#endif
|
|
233
|
+
#ifdef FAN_DENY
|
|
234
|
+
rb_define_const(mod, "FAN_DENY", ULL2NUM(FAN_DENY));
|
|
235
|
+
#endif
|
|
236
|
+
#ifdef FAN_ERRNO_BITS
|
|
237
|
+
rb_define_const(mod, "FAN_ERRNO_BITS", ULL2NUM(FAN_ERRNO_BITS));
|
|
238
|
+
#endif
|
|
239
|
+
#ifdef FAN_ERRNO_SHIFT
|
|
240
|
+
rb_define_const(mod, "FAN_ERRNO_SHIFT", ULL2NUM(FAN_ERRNO_SHIFT));
|
|
241
|
+
#endif
|
|
242
|
+
#ifdef FAN_ERRNO_MASK
|
|
243
|
+
rb_define_const(mod, "FAN_ERRNO_MASK", ULL2NUM(FAN_ERRNO_MASK));
|
|
244
|
+
#endif
|
|
245
|
+
#ifdef FAN_AUDIT
|
|
246
|
+
rb_define_const(mod, "FAN_AUDIT", ULL2NUM(FAN_AUDIT));
|
|
247
|
+
#endif
|
|
248
|
+
#ifdef FAN_INFO
|
|
249
|
+
rb_define_const(mod, "FAN_INFO", ULL2NUM(FAN_INFO));
|
|
250
|
+
#endif
|
|
251
|
+
#ifdef FAN_NOFD
|
|
252
|
+
rb_define_const(mod, "FAN_NOFD", INT2NUM(FAN_NOFD));
|
|
253
|
+
#endif
|
|
254
|
+
#ifdef FAN_NOPIDFD
|
|
255
|
+
rb_define_const(mod, "FAN_NOPIDFD", INT2NUM(FAN_NOPIDFD));
|
|
256
|
+
#endif
|
|
257
|
+
#ifdef FAN_EPIDFD
|
|
258
|
+
rb_define_const(mod, "FAN_EPIDFD", INT2NUM(FAN_EPIDFD));
|
|
259
|
+
#endif
|
|
260
|
+
#ifdef FAN_EVENT_METADATA_LEN
|
|
261
|
+
rb_define_const(mod, "FAN_EVENT_METADATA_LEN", ULL2NUM(FAN_EVENT_METADATA_LEN));
|
|
262
|
+
#endif
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "mkmf"
|
|
4
|
+
|
|
5
|
+
abort "fanotify requires Linux" unless RUBY_PLATFORM.include?("linux")
|
|
6
|
+
abort "sys/fanotify.h is required" unless have_header("sys/fanotify.h")
|
|
7
|
+
abort "fanotify_init(2) is unavailable" unless have_func("fanotify_init", "sys/fanotify.h")
|
|
8
|
+
abort "fanotify_mark(2) is unavailable" unless have_func("fanotify_mark", "sys/fanotify.h")
|
|
9
|
+
|
|
10
|
+
create_makefile("fanotify/fanotify")
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#ifndef _GNU_SOURCE
|
|
2
|
+
#define _GNU_SOURCE 1
|
|
3
|
+
#endif
|
|
4
|
+
|
|
5
|
+
#include <ruby.h>
|
|
6
|
+
#include <fcntl.h>
|
|
7
|
+
#include <stdint.h>
|
|
8
|
+
#include <sys/fanotify.h>
|
|
9
|
+
|
|
10
|
+
/* Fanotify.init(flags, event_f_flags) -> Integer file descriptor */
|
|
11
|
+
static VALUE
|
|
12
|
+
fanotify_rb_init(VALUE self, VALUE flags, VALUE event_f_flags)
|
|
13
|
+
{
|
|
14
|
+
unsigned int c_flags = NUM2UINT(flags);
|
|
15
|
+
unsigned int c_event_f_flags = NUM2UINT(event_f_flags);
|
|
16
|
+
int fd = fanotify_init(c_flags, c_event_f_flags);
|
|
17
|
+
|
|
18
|
+
if (fd == -1)
|
|
19
|
+
rb_sys_fail("fanotify_init");
|
|
20
|
+
|
|
21
|
+
return INT2NUM(fd);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Fanotify.mark(fanotify_fd, flags, mask, dirfd, pathname) -> 0 */
|
|
25
|
+
static VALUE
|
|
26
|
+
fanotify_rb_mark(VALUE self, VALUE fanotify_fd, VALUE flags, VALUE mask,
|
|
27
|
+
VALUE dirfd, VALUE pathname)
|
|
28
|
+
{
|
|
29
|
+
int c_fd = NUM2INT(fanotify_fd);
|
|
30
|
+
unsigned int c_flags = NUM2UINT(flags);
|
|
31
|
+
uint64_t c_mask = NUM2ULL(mask);
|
|
32
|
+
int c_dirfd = NUM2INT(dirfd);
|
|
33
|
+
const char *c_path = NULL;
|
|
34
|
+
int result;
|
|
35
|
+
|
|
36
|
+
if (!NIL_P(pathname)) {
|
|
37
|
+
pathname = rb_get_path(pathname);
|
|
38
|
+
c_path = StringValueCStr(pathname);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
result = fanotify_mark(c_fd, c_flags, c_mask, c_dirfd, c_path);
|
|
42
|
+
RB_GC_GUARD(pathname);
|
|
43
|
+
|
|
44
|
+
if (result == -1)
|
|
45
|
+
rb_sys_fail("fanotify_mark");
|
|
46
|
+
|
|
47
|
+
return INT2NUM(result);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
RUBY_FUNC_EXPORTED void
|
|
51
|
+
Init_fanotify(void)
|
|
52
|
+
{
|
|
53
|
+
VALUE mod = rb_define_module("Fanotify");
|
|
54
|
+
|
|
55
|
+
rb_define_singleton_method(mod, "init", fanotify_rb_init, 2);
|
|
56
|
+
rb_define_singleton_method(mod, "mark", fanotify_rb_mark, 5);
|
|
57
|
+
|
|
58
|
+
rb_define_const(mod, "AT_FDCWD", INT2NUM(AT_FDCWD));
|
|
59
|
+
#include "constants.h"
|
|
60
|
+
}
|
data/lib/fanotify.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: fanotify.rb
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Matt Christen
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: Native bindings for fanotify_init(2) and fanotify_mark(2), with Linux
|
|
13
|
+
fanotify constants.
|
|
14
|
+
email:
|
|
15
|
+
- oss@christen.tech
|
|
16
|
+
executables: []
|
|
17
|
+
extensions:
|
|
18
|
+
- ext/fanotify/extconf.rb
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- CHANGELOG.md
|
|
22
|
+
- LICENSE
|
|
23
|
+
- README.md
|
|
24
|
+
- ext/fanotify/constants.h
|
|
25
|
+
- ext/fanotify/extconf.rb
|
|
26
|
+
- ext/fanotify/fanotify.c
|
|
27
|
+
- lib/fanotify.rb
|
|
28
|
+
- lib/fanotify/version.rb
|
|
29
|
+
homepage: https://github.com/mchristen/fanotify.rb
|
|
30
|
+
licenses:
|
|
31
|
+
- MIT
|
|
32
|
+
metadata:
|
|
33
|
+
source_code_uri: https://github.com/mchristen/fanotify.rb
|
|
34
|
+
bug_tracker_uri: https://github.com/mchristen/fanotify.rb/issues
|
|
35
|
+
changelog_uri: https://github.com/mchristen/fanotify.rb/blob/main/CHANGELOG.md
|
|
36
|
+
rdoc_options: []
|
|
37
|
+
require_paths:
|
|
38
|
+
- lib
|
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '3.1'
|
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0'
|
|
49
|
+
requirements: []
|
|
50
|
+
rubygems_version: 3.6.9
|
|
51
|
+
specification_version: 4
|
|
52
|
+
summary: Thin Ruby bindings for Linux fanotify syscalls
|
|
53
|
+
test_files: []
|