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 +7 -0
- data/.yardopts +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +152 -0
- data/Rakefile +43 -0
- data/benchmark/events.rb +27 -0
- data/examples/audit_logger.rb +14 -0
- data/examples/lazy_fetch.rb +29 -0
- data/examples/malware_scan.rb +20 -0
- data/ext/fanotify/compat.h +235 -0
- data/ext/fanotify/constants.c +12 -0
- data/ext/fanotify/extconf.rb +10 -0
- data/ext/fanotify/fanotify.c +481 -0
- data/lib/fanotify/event.rb +215 -0
- data/lib/fanotify/file_handle.rb +12 -0
- data/lib/fanotify/mark.rb +6 -0
- data/lib/fanotify/notifier.rb +458 -0
- data/lib/fanotify/version.rb +5 -0
- data/lib/fanotify.rb +38 -0
- data/sig/fanotify.rbs +93 -0
- data/tools/constants.def +59 -0
- data/tools/dump_constants.c +12 -0
- data/tools/generate_constants.rb +18 -0
- data/tools/vm/Makefile +5 -0
- data/tools/vm/config-fragment +3 -0
- data/tools/vm/run.sh +14 -0
- metadata +70 -0
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
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"
|
data/benchmark/events.rb
ADDED
|
@@ -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")
|