fanotify 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ecffc5a3eb865058ceb950305ba888e3734dc665e660d951304db99c49b3fd05
4
+ data.tar.gz: 07fe42885faa0a6f290013ab1be64dbed9b4ebf9a39bbcbb35ae60b1e20dbcc4
5
+ SHA512:
6
+ metadata.gz: 706d77daac3e9e4b96e85e41e006717b049b243d86641d73499baf883101644336a2df40c96ffc07b244e687f441a8781aaa96e5ffb50f70f5af7050cb6f2ee3
7
+ data.tar.gz: 3b1289e2e338479c385670b93a6740b77a61c4cf35c2752f79b7a170cb03a1492aaa73388283b500f75f3ebcd75cfe0dd33041eb933fffc854ea271d5e268fd8
data/.yardopts ADDED
@@ -0,0 +1,3 @@
1
+ --markup markdown
2
+ --readme README.md
3
+ lib/**/*.rb
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Yudai Takada
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # Fanotify
2
+
3
+ > [!WARNING]
4
+ > Permission events block the process that opened a file until userspace responds.
5
+ > A missing response or filesystem access from the handler can deadlock a process or
6
+ > the machine. `Fanotify::Notifier#each_event` fails open and closes event descriptors,
7
+ > but handlers must still follow the safety rules below.
8
+
9
+ Ruby 3.2+ C bindings for Linux `fanotify(7)`. The gem supports ordinary
10
+ notifications, permission decisions, FID/name records, PIDFD records, rename
11
+ records, filesystem errors, and queue-overflow detection.
12
+
13
+ ## Requirements
14
+
15
+ - Linux 5.1+ and a kernel built with `CONFIG_FANOTIFY`.
16
+ - `CAP_SYS_ADMIN` for mount/filesystem marks and all permission events.
17
+ - Linux 5.9+ for FID reporting, 5.13+ for unprivileged FID notification groups,
18
+ 5.15+ for PIDFD reports, 5.17+ for rename/target FID reports, and 6.14+ for
19
+ experimental pre-access events.
20
+ - A C compiler and Linux UAPI headers when installing the gem.
21
+
22
+ `Fanotify.supported?` checks whether the syscall exists. It does not prove that the
23
+ current process has permission for a particular class or mark.
24
+
25
+ ## Installation
26
+
27
+ ```ruby
28
+ gem "fanotify"
29
+ ```
30
+
31
+ Then run `bundle install`. The native extension is built during installation.
32
+
33
+ ## Notifications
34
+
35
+ The high-level API uses the unprivileged-compatible FID/name mode:
36
+
37
+ ```ruby
38
+ require "fanotify"
39
+
40
+ Fanotify.watch("/data", events: %i[create delete modify]) do |event|
41
+ puts "#{event.mask.inspect} #{event.name}"
42
+ end
43
+ ```
44
+
45
+ Use `Notifier` for explicit classes and marks:
46
+
47
+ ```ruby
48
+ Fanotify::Notifier.open(class: :notif, report: %i[fid dfid_name]) do |notifier|
49
+ notifier.mark(:add, "/data", events: %i[create delete event_on_child], only_dir: true)
50
+ notifier.each_event { |event| puts event.name }
51
+ end
52
+ ```
53
+
54
+ `Event#fid`, `#dfid`, `#old_dfid`, and `#new_dfid` are `Fanotify::FileHandle`
55
+ values. Handles are comparable and printable as hex, but v1 does not open them with
56
+ `open_by_handle_at(2)`.
57
+
58
+ Linux 6.14 pre-access events expose the requested byte range as
59
+ `Event#range_offset` and `Event#range_count`; see `examples/lazy_fetch.rb`.
60
+
61
+ ## Permission decisions
62
+
63
+ Permission marks require `CAP_SYS_ADMIN`:
64
+
65
+ ```ruby
66
+ Fanotify::Notifier.open(class: :content, response_timeout: 5.0) do |notifier|
67
+ notifier.exclude_self!
68
+ notifier.mark(:add, "/data", events: %i[open_perm event_on_child], only_dir: true)
69
+
70
+ notifier.each_event do |event|
71
+ event.deny! if event.path&.end_with?(".secret")
72
+ # No explicit decision means allow! when the block exits.
73
+ end
74
+ end
75
+ ```
76
+
77
+ The default behavior is fail-open:
78
+
79
+ - A permission event without `allow!` or `deny!` is allowed after the block.
80
+ - A handler exception allows the event before the same exception is raised again.
81
+ - `defer!` registers an asynchronous decision. The default watchdog allows it after
82
+ five seconds; `response_timeout: nil` disables the deadline, while GC fail-open
83
+ cleanup remains active.
84
+ - `pending_events` exposes live deferred events.
85
+ - `close` allows an unanswered event before closing its descriptors.
86
+ - If a response cannot be written, the notifier closes the whole group to release
87
+ every process still waiting on it.
88
+ - `close` interrupts threads blocked in `read_events` with `Fanotify::Error`.
89
+
90
+ `on_error: :deny` changes only the handler-exception decision. It is intentionally
91
+ opt-in because application bugs then deny access.
92
+
93
+ ### Handler safety
94
+
95
+ - Load code, resolve configuration, and open log destinations before adding a
96
+ permission mark. Do not call `require`, open logs, or lazily load files in a handler.
97
+ - `exclude_self!` filters self-generated events already read by the notifier. It cannot
98
+ rescue a handler that blocks itself while opening another marked file on the same
99
+ thread.
100
+ - Inspect `event.file`, which duplicates the kernel-opened descriptor and is closed
101
+ with the event. Do not reopen `event.path` for a security decision.
102
+ - `event.path` comes from `/proc/self/fd/N` and is informational. Reopening it has a
103
+ TOCTOU race. Deleted paths retain the kernel's `" (deleted)"` suffix.
104
+ - Keep handlers bounded. The kernel has no response timeout; the gem watchdog covers
105
+ only events explicitly deferred through this notifier.
106
+
107
+ ## Unsupported and restricted environments
108
+
109
+ - macOS, BSD, and Windows: `require "fanotify"` succeeds and `supported?` is false;
110
+ constructing a notifier raises `Fanotify::UnsupportedError`.
111
+ - Docker/Podman containers: permission events and mount/filesystem marks normally fail
112
+ without `CAP_SYS_ADMIN`; Docker Desktop also runs inside a Linux VM.
113
+ - GitHub-hosted runners: unit tests work normally, but system tests need the included
114
+ virtme-ng VM runner.
115
+ - WSL2: availability depends on its kernel configuration and the capabilities granted
116
+ to the process.
117
+ - Older Linux kernels accept only the flags available in that kernel; unsupported new
118
+ flag combinations fail with the kernel's `Errno::*` exception.
119
+
120
+ ## Development
121
+
122
+ ```sh
123
+ bundle install
124
+ bundle exec rake test:unit
125
+ bundle exec rake rbs
126
+ sudo bundle exec rake test:system # Linux with CAP_SYS_ADMIN
127
+ ```
128
+
129
+ The system suite has hard timeouts and covers notification, allow/deny, exception
130
+ fail-open, deferred timeout, FID names, unprivileged mode, queue overflow, and 10,000
131
+ permission events without fd growth.
132
+
133
+ Run the same suite in a kernel VM with:
134
+
135
+ ```sh
136
+ tools/vm/run.sh # Linux 6.12
137
+ KVER=6.1 tools/vm/run.sh
138
+ ```
139
+
140
+ `bundle exec rake gen:constants` regenerates the Ruby constant bindings. Values are
141
+ still resolved from the target system's UAPI headers at extension build time.
142
+
143
+ Reference throughput for 10,000 distinct `FAN_OPEN` FID events was 266,374 events/s
144
+ on Ruby 3.4.10, Linux 6.8 arm64 in a Docker Desktop VM. Run
145
+ `bundle exec ruby benchmark/events.rb` on the deployment host; handler work and event
146
+ shape dominate real throughput.
147
+
148
+ See `examples/` for audit logging, malware scanning, and experimental pre-access programs.
149
+
150
+ ## License
151
+
152
+ [MIT](LICENSE.txt)
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/extensiontask"
5
+ require "rbconfig"
6
+ require "rspec/core/rake_task"
7
+ require "yard"
8
+
9
+ Rake::ExtensionTask.new("fanotify") do |extension|
10
+ extension.lib_dir = "lib/fanotify"
11
+ end
12
+
13
+ RSpec::Core::RakeTask.new(:spec)
14
+ task spec: :compile
15
+ YARD::Rake::YardocTask.new
16
+
17
+ namespace :test do
18
+ RSpec::Core::RakeTask.new(:unit) do |task|
19
+ task.pattern = "spec/**/*_spec.rb"
20
+ task.exclude_pattern = "spec/system/**/*_spec.rb"
21
+ end
22
+
23
+ RSpec::Core::RakeTask.new(:system) do |task|
24
+ task.pattern = "spec/system/**/*_spec.rb"
25
+ end
26
+
27
+ task unit: :compile
28
+ task system: :compile
29
+ end
30
+
31
+ namespace :gen do
32
+ desc "Regenerate the C constant bindings"
33
+ task :constants do
34
+ sh RbConfig.ruby, "tools/generate_constants.rb"
35
+ end
36
+ end
37
+
38
+ desc "Validate RBS signatures"
39
+ task :rbs do
40
+ sh "bundle", "exec", "rbs", "-I", "sig", "validate"
41
+ end
42
+
43
+ task default: "test:unit"
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fanotify"
4
+ require "tmpdir"
5
+
6
+ count = Integer(ENV.fetch("EVENTS", "10000"))
7
+
8
+ Dir.mktmpdir("fanotify-benchmark-") do |directory|
9
+ paths = Array.new(count) do |index|
10
+ File.join(directory, index.to_s).tap { |path| File.write(path, "") }
11
+ end
12
+
13
+ Fanotify::Notifier.open(class: :notif, report: [:fid]) do |notifier|
14
+ notifier.mark(:add, directory, events: %i[open event_on_child], only_dir: true)
15
+ child = fork { paths.each { |path| File.open(path, &:read) } }
16
+ received = 0
17
+ started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
18
+ until received >= count
19
+ events = notifier.read_events
20
+ received += events.length
21
+ events.each(&:close)
22
+ end
23
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at
24
+ Process.wait(child)
25
+ puts format("%d events in %.3fs (%.0f events/s)", received, elapsed, received / elapsed)
26
+ end
27
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fanotify"
4
+
5
+ path = ARGV.fetch(0) { abort "usage: #{$PROGRAM_NAME} PATH [LOG]" }
6
+ log = File.open(ARGV[1] || "/dev/stdout", "a")
7
+ log.sync = true
8
+
9
+ Fanotify::Notifier.open(class: :notif, report: %i[fid dfid_name]) do |notifier|
10
+ notifier.mark(:add, path, events: %i[open create delete modify event_on_child], only_dir: true)
11
+ notifier.each_event do |event|
12
+ log.puts "pid=#{event.pid} events=#{event.mask.join(',')} name=#{event.name || '-'}"
13
+ end
14
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fanotify"
4
+
5
+ path = ARGV.fetch(0) { abort "usage: sudo #{$PROGRAM_NAME} FILE" }
6
+ payload = ENV.fetch("LAZY_PAYLOAD", "materialized by fanotify\n").b
7
+ abort "LAZY_PAYLOAD must not be empty" if payload.empty?
8
+
9
+ Fanotify::Notifier.open(
10
+ class: :pre_content,
11
+ event_flags: %i[rdwr largefile cloexec],
12
+ response_timeout: 5.0
13
+ ) do |notifier|
14
+ notifier.mark(:add, path, events: [:pre_access])
15
+ notifier.each_event do |event|
16
+ file = event.file
17
+ next unless file&.stat&.zero?
18
+
19
+ remaining = event.range_count || payload.bytesize
20
+ file.seek(event.range_offset || 0)
21
+ while remaining.positive?
22
+ chunk = payload.byteslice(0, [remaining, payload.bytesize].min)
23
+ file.write(chunk)
24
+ remaining -= chunk.bytesize
25
+ end
26
+ file.flush
27
+ event.allow!
28
+ end
29
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fanotify"
4
+
5
+ path = ARGV.fetch(0) { abort "usage: sudo #{$PROGRAM_NAME} PATH" }
6
+ signature = ENV.fetch("MALWARE_SIGNATURE", "EICAR-STANDARD-ANTIVIRUS-TEST-FILE").b
7
+ log = File.open("/dev/stderr", "w")
8
+ log.sync = true
9
+
10
+ Fanotify::Notifier.open(class: :content, response_timeout: 5.0) do |notifier|
11
+ notifier.exclude_self!
12
+ notifier.mark(:add, path, events: %i[open_perm event_on_child], only_dir: true)
13
+ notifier.each_event do |event|
14
+ sample = event.file&.read(1024 * 1024)
15
+ next unless sample&.include?(signature)
16
+
17
+ log.puts "denied pid=#{event.pid} path=#{event.path}"
18
+ event.deny!
19
+ end
20
+ end
@@ -0,0 +1,235 @@
1
+ #ifndef FANOTIFY_COMPAT_H
2
+ #define FANOTIFY_COMPAT_H
3
+
4
+ #include <fcntl.h>
5
+ #include <stdint.h>
6
+
7
+ #ifdef _WIN32
8
+ #include <io.h>
9
+ #define close _close
10
+ #define read _read
11
+ #define write _write
12
+ #endif
13
+
14
+ #ifndef O_LARGEFILE
15
+ #define O_LARGEFILE 0
16
+ #endif
17
+ #ifndef O_CLOEXEC
18
+ #define O_CLOEXEC 0
19
+ #endif
20
+ #ifndef O_NONBLOCK
21
+ #define O_NONBLOCK 0
22
+ #endif
23
+ #ifndef AT_FDCWD
24
+ #define AT_FDCWD -100
25
+ #endif
26
+
27
+ #ifdef __linux__
28
+ #include <linux/fanotify.h>
29
+ #include <sys/syscall.h>
30
+ #else
31
+ struct fanotify_event_metadata {
32
+ uint32_t event_len;
33
+ uint8_t vers;
34
+ uint8_t reserved;
35
+ uint16_t metadata_len;
36
+ uint64_t mask;
37
+ int32_t fd;
38
+ int32_t pid;
39
+ };
40
+ struct fanotify_response { int32_t fd; uint32_t response; };
41
+ #endif
42
+
43
+ #ifndef FAN_ACCESS
44
+ #define FAN_ACCESS 0x00000001
45
+ #endif
46
+ #ifndef FAN_MODIFY
47
+ #define FAN_MODIFY 0x00000002
48
+ #endif
49
+ #ifndef FAN_ATTRIB
50
+ #define FAN_ATTRIB 0x00000004
51
+ #endif
52
+ #ifndef FAN_CLOSE_WRITE
53
+ #define FAN_CLOSE_WRITE 0x00000008
54
+ #endif
55
+ #ifndef FAN_CLOSE_NOWRITE
56
+ #define FAN_CLOSE_NOWRITE 0x00000010
57
+ #endif
58
+ #ifndef FAN_OPEN
59
+ #define FAN_OPEN 0x00000020
60
+ #endif
61
+ #ifndef FAN_MOVED_FROM
62
+ #define FAN_MOVED_FROM 0x00000040
63
+ #endif
64
+ #ifndef FAN_MOVED_TO
65
+ #define FAN_MOVED_TO 0x00000080
66
+ #endif
67
+ #ifndef FAN_CREATE
68
+ #define FAN_CREATE 0x00000100
69
+ #endif
70
+ #ifndef FAN_DELETE
71
+ #define FAN_DELETE 0x00000200
72
+ #endif
73
+ #ifndef FAN_DELETE_SELF
74
+ #define FAN_DELETE_SELF 0x00000400
75
+ #endif
76
+ #ifndef FAN_MOVE_SELF
77
+ #define FAN_MOVE_SELF 0x00000800
78
+ #endif
79
+ #ifndef FAN_OPEN_EXEC
80
+ #define FAN_OPEN_EXEC 0x00001000
81
+ #endif
82
+ #ifndef FAN_Q_OVERFLOW
83
+ #define FAN_Q_OVERFLOW 0x00004000
84
+ #endif
85
+ #ifndef FAN_FS_ERROR
86
+ #define FAN_FS_ERROR 0x00008000
87
+ #endif
88
+ #ifndef FAN_OPEN_PERM
89
+ #define FAN_OPEN_PERM 0x00010000
90
+ #endif
91
+ #ifndef FAN_ACCESS_PERM
92
+ #define FAN_ACCESS_PERM 0x00020000
93
+ #endif
94
+ #ifndef FAN_OPEN_EXEC_PERM
95
+ #define FAN_OPEN_EXEC_PERM 0x00040000
96
+ #endif
97
+ #ifndef FAN_PRE_ACCESS
98
+ #define FAN_PRE_ACCESS 0x00100000
99
+ #endif
100
+ #ifndef FAN_EVENT_ON_CHILD
101
+ #define FAN_EVENT_ON_CHILD 0x08000000
102
+ #endif
103
+ #ifndef FAN_RENAME
104
+ #define FAN_RENAME 0x10000000
105
+ #endif
106
+ #ifndef FAN_ONDIR
107
+ #define FAN_ONDIR 0x40000000
108
+ #endif
109
+
110
+ #ifndef FAN_CLOEXEC
111
+ #define FAN_CLOEXEC 0x00000001
112
+ #endif
113
+ #ifndef FAN_NONBLOCK
114
+ #define FAN_NONBLOCK 0x00000002
115
+ #endif
116
+ #ifndef FAN_CLASS_NOTIF
117
+ #define FAN_CLASS_NOTIF 0x00000000
118
+ #endif
119
+ #ifndef FAN_CLASS_CONTENT
120
+ #define FAN_CLASS_CONTENT 0x00000004
121
+ #endif
122
+ #ifndef FAN_CLASS_PRE_CONTENT
123
+ #define FAN_CLASS_PRE_CONTENT 0x00000008
124
+ #endif
125
+ #ifndef FAN_UNLIMITED_QUEUE
126
+ #define FAN_UNLIMITED_QUEUE 0x00000010
127
+ #endif
128
+ #ifndef FAN_UNLIMITED_MARKS
129
+ #define FAN_UNLIMITED_MARKS 0x00000020
130
+ #endif
131
+ #ifndef FAN_ENABLE_AUDIT
132
+ #define FAN_ENABLE_AUDIT 0x00000040
133
+ #endif
134
+ #ifndef FAN_REPORT_PIDFD
135
+ #define FAN_REPORT_PIDFD 0x00000080
136
+ #endif
137
+ #ifndef FAN_REPORT_TID
138
+ #define FAN_REPORT_TID 0x00000100
139
+ #endif
140
+ #ifndef FAN_REPORT_FID
141
+ #define FAN_REPORT_FID 0x00000200
142
+ #endif
143
+ #ifndef FAN_REPORT_DIR_FID
144
+ #define FAN_REPORT_DIR_FID 0x00000400
145
+ #endif
146
+ #ifndef FAN_REPORT_NAME
147
+ #define FAN_REPORT_NAME 0x00000800
148
+ #endif
149
+ #ifndef FAN_REPORT_DFID_NAME
150
+ #define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME)
151
+ #endif
152
+ #ifndef FAN_REPORT_TARGET_FID
153
+ #define FAN_REPORT_TARGET_FID 0x00001000
154
+ #endif
155
+
156
+ #ifndef FAN_MARK_ADD
157
+ #define FAN_MARK_ADD 0x00000001
158
+ #endif
159
+ #ifndef FAN_MARK_REMOVE
160
+ #define FAN_MARK_REMOVE 0x00000002
161
+ #endif
162
+ #ifndef FAN_MARK_DONT_FOLLOW
163
+ #define FAN_MARK_DONT_FOLLOW 0x00000004
164
+ #endif
165
+ #ifndef FAN_MARK_ONLYDIR
166
+ #define FAN_MARK_ONLYDIR 0x00000008
167
+ #endif
168
+ #ifndef FAN_MARK_MOUNT
169
+ #define FAN_MARK_MOUNT 0x00000010
170
+ #endif
171
+ #ifndef FAN_MARK_IGNORED_MASK
172
+ #define FAN_MARK_IGNORED_MASK 0x00000020
173
+ #endif
174
+ #ifndef FAN_MARK_IGNORED_SURV_MODIFY
175
+ #define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040
176
+ #endif
177
+ #ifndef FAN_MARK_FLUSH
178
+ #define FAN_MARK_FLUSH 0x00000080
179
+ #endif
180
+ #ifndef FAN_MARK_FILESYSTEM
181
+ #define FAN_MARK_FILESYSTEM 0x00000100
182
+ #endif
183
+ #ifndef FAN_MARK_EVICTABLE
184
+ #define FAN_MARK_EVICTABLE 0x00000200
185
+ #endif
186
+ #ifndef FAN_MARK_IGNORE
187
+ #define FAN_MARK_IGNORE 0x00000400
188
+ #endif
189
+ #ifndef FAN_MARK_INODE
190
+ #define FAN_MARK_INODE 0x00000000
191
+ #endif
192
+
193
+ #ifndef FAN_ALLOW
194
+ #define FAN_ALLOW 0x01
195
+ #endif
196
+ #ifndef FAN_DENY
197
+ #define FAN_DENY 0x02
198
+ #endif
199
+ #ifndef FAN_AUDIT
200
+ #define FAN_AUDIT 0x10
201
+ #endif
202
+ #ifndef FANOTIFY_METADATA_VERSION
203
+ #define FANOTIFY_METADATA_VERSION 3
204
+ #endif
205
+ #ifndef FAN_NOFD
206
+ #define FAN_NOFD -1
207
+ #endif
208
+
209
+ #ifndef FAN_EVENT_INFO_TYPE_FID
210
+ #define FAN_EVENT_INFO_TYPE_FID 1
211
+ struct fanotify_event_info_header { uint8_t info_type; uint8_t pad; uint16_t len; };
212
+ #endif
213
+ #ifndef FAN_EVENT_INFO_TYPE_DFID_NAME
214
+ #define FAN_EVENT_INFO_TYPE_DFID_NAME 2
215
+ #endif
216
+ #ifndef FAN_EVENT_INFO_TYPE_DFID
217
+ #define FAN_EVENT_INFO_TYPE_DFID 3
218
+ #endif
219
+ #ifndef FAN_EVENT_INFO_TYPE_PIDFD
220
+ #define FAN_EVENT_INFO_TYPE_PIDFD 4
221
+ #endif
222
+ #ifndef FAN_EVENT_INFO_TYPE_ERROR
223
+ #define FAN_EVENT_INFO_TYPE_ERROR 5
224
+ #endif
225
+ #ifndef FAN_EVENT_INFO_TYPE_RANGE
226
+ #define FAN_EVENT_INFO_TYPE_RANGE 6
227
+ #endif
228
+ #ifndef FAN_EVENT_INFO_TYPE_OLD_DFID_NAME
229
+ #define FAN_EVENT_INFO_TYPE_OLD_DFID_NAME 10
230
+ #endif
231
+ #ifndef FAN_EVENT_INFO_TYPE_NEW_DFID_NAME
232
+ #define FAN_EVENT_INFO_TYPE_NEW_DFID_NAME 12
233
+ #endif
234
+
235
+ #endif
@@ -0,0 +1,12 @@
1
+ /* Generated by tools/generate_constants.rb. */
2
+ #include "ruby.h"
3
+ #include "compat.h"
4
+
5
+ void fanotify_define_constants(VALUE module)
6
+ {
7
+ #define X(name) rb_define_const(module, #name, ULL2NUM((unsigned long long)(name)));
8
+ #include "../../tools/constants.def"
9
+ #undef X
10
+ rb_define_const(module, "FAN_NOFD", INT2NUM(FAN_NOFD));
11
+ rb_define_const(module, "AT_FDCWD", INT2NUM(AT_FDCWD));
12
+ }
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+
5
+ have_header("linux/fanotify.h")
6
+ have_const("SYS_fanotify_init", "sys/syscall.h")
7
+ have_func("syscall", "unistd.h")
8
+ have_func("rb_thread_call_without_gvl", "ruby/thread.h")
9
+ create_header
10
+ create_makefile("fanotify/fanotify")