Skip to content

Commit 3a6bd70

Browse files
committed
Update NewListener API
- Update NewListener API - NewListener flags are set based on kernel version - Update README - Run Bug tests only when `sudo go test -v -bug` is passed
1 parent 83b7881 commit 3a6bd70

File tree

4 files changed

+160
-150
lines changed

4 files changed

+160
-150
lines changed

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func main() {
2727
os.Exit(1)
2828
}
2929
mountPoint := "/"
30-
listener, err := fanotify.NewListener(mountPoint, 4096, true)
30+
listener, err := fanotify.NewListener(mountPoint)
3131
if err != nil {
3232
fmt.Println(err)
3333
os.Exit(1)
@@ -77,3 +77,19 @@ Certain flag combinations / actions cause issues with event reporting.
7777
- Using `fanotify.FileOpened` with any of the actions containing `OrDirectory` (`unix.FAN_ONDIR`) causes an event flood for the directory and then stopping raising any events at all.
7878

7979
- `fanotifyFileOrDirectoryOpened` with any of the other actions causes an event flood for the directory and then stopping raising any events at all.
80+
81+
## Tests
82+
83+
Running tests require `CAP_SYS_ADM` privilege. To run the tests make sure to add `go` to the `sudo` PATH.
84+
85+
The command runs all the tests except the ones that test the flag bugs mentioned in the "Known Issues" section above -
86+
87+
```
88+
sudo go test -v
89+
```
90+
91+
To run the tests with flag issues -
92+
93+
```
94+
sudo go test -v -bug
95+
```

fanotify_api.go

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,27 +74,20 @@ type Listener struct {
7474
// `maxEvents` defines the length of the buffered channel which holds the notifications. The minimum length is 4096.
7575
// `withName` setting this to true populates the file name under the watched parent.
7676
//
77+
// For Linux kernel version 5.0 and earlier no additional information about the underlying filesystem object is available.
78+
// For Linux kernel versions 5.1 - 5.8 additional information about the underlying filesystem object is correlated to an event.
79+
// For Linux kernel version 5.9 or later the modified file name is made available in the event.
80+
//
7781
// NOTE that this call requires CAP_SYS_ADMIN privilege
78-
func NewListener(mountpointPath string, maxEvents uint, withName bool) (*Listener, error) {
82+
func NewListener(mountPoint string) (*Listener, error) {
7983
capSysAdmin, err := checkCapSysAdmin()
8084
if err != nil {
8185
return nil, err
8286
}
8387
if !capSysAdmin {
8488
return nil, ErrCapSysAdmin
8589
}
86-
if maxEvents < 4096 {
87-
maxEvents = 4096
88-
}
89-
var flags, eventFlags uint
90-
if withName {
91-
flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC | unix.FAN_REPORT_DIR_FID | unix.FAN_REPORT_NAME
92-
} else {
93-
flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC | unix.FAN_REPORT_FID
94-
}
95-
96-
eventFlags = unix.O_RDONLY | unix.O_LARGEFILE | unix.O_CLOEXEC
97-
return newListener(mountpointPath, flags, eventFlags, maxEvents)
90+
return newListener(mountPoint)
9891
}
9992

10093
// Start starts the listener and polls the fanotify event notification group for marked events.

fanotify_event.go

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,32 @@ func fanotifyEventOK(meta *unix.FanotifyEventMetadata, n int) bool {
191191
int(meta.Event_len) <= n)
192192
}
193193

194-
func newListener(mountpointPath string, flags, eventFlags, maxEvents uint) (*Listener, error) {
194+
func newListener(mountpointPath string) (*Listener, error) {
195+
196+
var flags, eventFlags uint
197+
195198
maj, min, _, err := kernelVersion()
196199
if err != nil {
197200
return nil, err
198201
}
202+
switch {
203+
case maj < 5:
204+
flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC
205+
case maj == 5:
206+
if min < 1 {
207+
flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC
208+
}
209+
if min >= 1 && min < 9 {
210+
flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC | unix.FAN_REPORT_FID
211+
}
212+
if min >= 9 {
213+
flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC | unix.FAN_REPORT_DIR_FID | unix.FAN_REPORT_NAME
214+
}
215+
case maj > 5:
216+
flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC | unix.FAN_REPORT_DIR_FID | unix.FAN_REPORT_NAME
217+
}
218+
eventFlags = unix.O_RDONLY | unix.O_LARGEFILE | unix.O_CLOEXEC
219+
199220
if err := flagsValid(flags); err != nil {
200221
return nil, fmt.Errorf("%w: %v", ErrInvalidFlagCombination, err)
201222
}
@@ -233,7 +254,7 @@ func newListener(mountpointPath string, flags, eventFlags, maxEvents uint) (*Lis
233254
r *os.File
234255
w *os.File
235256
}{r, w},
236-
Events: make(chan Event, maxEvents),
257+
Events: make(chan Event, 4096),
237258
}
238259
return listener, nil
239260
}
@@ -340,7 +361,7 @@ func (l *Listener) readEvents() error {
340361
panic("metadata structure from the kernel does not match the structure definition at compile time")
341362
}
342363
if metadata.Fd != unix.FAN_NOFD {
343-
// no fid
364+
// no fid (applicable to kernels 5.0 and earlier)
344365
procFdPath := fmt.Sprintf("/proc/self/fd/%d", metadata.Fd)
345366
n1, err := unix.Readlink(procFdPath, name[:])
346367
if err != nil {
@@ -360,9 +381,8 @@ func (l *Listener) readEvents() error {
360381
Pid: int(metadata.Pid),
361382
}
362383
l.Events <- event
363-
364384
} else {
365-
// fid
385+
// fid (applicable to kernels 5.1+)
366386
fid = (*fanotifyEventInfoFID)(unsafe.Pointer(&buf[i+int(metadata.Metadata_len)]))
367387
withName := false
368388
switch {

0 commit comments

Comments
 (0)