fanotify

package module
v0.4.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 2, 2023 License: MIT Imports: 11 Imported by: 3

README

Fanotify Library

Fanotify library provides a simple API to monitor filesystem for events.

The listener is initialized with flags automatically based on the kernel version. The mark flag features that specify the the events to monitor a file/directory are validated and checked for valid combinations and validated against the kernel version.

fanotify has features spanning different kernel versions -

  • For Linux kernel version 5.0 and earlier no additional information about the underlying filesystem object is available.
  • For Linux kernel versions 5.1 - 5.8 additional information about the underlying filesystem object is correlated to an event.
  • For Linux kernel version 5.9 or later the modified file name is made available in the event.

Examples

Example code for different use-cases can be found here https://github.com/opcoder0/fanotify-examples

Known Issues

Certain flag combinations / event types cause issues with event reporting.

  • fanotify.FileCreated cannot be or-ed / combined with fanotify.FileClosed. The fanotify event notification group does not generate any event for this combination.
  • Using fanotify.FileOpened with any of the event types containing OrDirectory causes numerous duplicate events for the path.
  • fanotifyFileOrDirectoryOpened with any of the other event types causes numerous duplicate events for the path.

Tests

Running tests require CAP_SYS_ADM privilege. To run the tests make sure to add go to the sudo PATH.

The command runs all the tests except the ones that test the flag bugs mentioned in the "Known Issues" section above -

sudo go test -v

To run the tests with flag issues -

sudo go test -v -bug

Documentation

Overview

Package fanotify library provides a simple API to monitor filesystem for notification and permission events.

The listener is initialized with flags automatically based on the kernel version. The mark flag features that specify the the events to monitor a file/directory are validated and checked for valid combinations and validated against the kernel version.

fanotify system has features spanning different kernel versions:

  • For Linux kernel version 5.0 and earlier no additional information about the underlying filesystem object is available.
  • For Linux kernel versions 5.1 to 5.8 additional information about the underlying filesystem object is correlated to an event.
  • For Linux kernel version 5.9 or later the modified file name is made available in the event.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrCapSysAdmin indicates caller is missing CAP_SYS_ADMIN permissions
	ErrCapSysAdmin = errors.New("require CAP_SYS_ADMIN capability")
	// ErrInvalidFlagCombination indicates the bit/combination of flags are invalid
	ErrInvalidFlagCombination = errors.New("invalid flag bitmask")
	// ErrUnsupportedOnKernelVersion indicates the feature/flag is unavailable for the current kernel version
	ErrUnsupportedOnKernelVersion = errors.New("feature unsupported on current kernel version")
	// ErrWatchPath indicates path needs to be specified for watching
	ErrWatchPath = errors.New("missing watch path")
)

Functions

This section is empty.

Types

type Event

type Event struct {
	// Fd is the open file descriptor for the file/directory being watched
	Fd int
	// Path holds the name of the parent directory
	Path string
	// FileName holds the name of the file under the watched parent. The value is only available
	// on kernels 5.1 or greater (that support the receipt of events which contain additional information
	// about the underlying filesystem object correlated to an event).
	FileName string
	// EventTypes holds bit mask representing the operations
	EventTypes EventType
	// Pid Process ID of the process that caused the event
	Pid int
}

Event represents a notification or a permission event from the kernel for the file, directory marked for watching. Notification events are merely informative and require no action to be taken by the receiving application with the exception being that the file descriptor provided within the event must be closed. Permission events are requests to the receiving application to decide whether permission for a file access shall be granted. For these events, the recipient must write a response which decides whether access is granted or not.

func (Event) String added in v0.2.0

func (e Event) String() string

type EventType added in v0.2.0

type EventType uint64

EventType represents an event / operation on a particular file/directory

const (
	// FileAccessed event when a file is accessed
	FileAccessed EventType = unix.FAN_ACCESS

	// FileOrDirectoryAccessed event when a file or directory is accessed
	FileOrDirectoryAccessed EventType = unix.FAN_ACCESS | unix.FAN_ONDIR

	// FileModified event when a file is modified
	FileModified EventType = unix.FAN_MODIFY

	// FileClosedAfterWrite event when a file is closed
	FileClosedAfterWrite EventType = unix.FAN_CLOSE_WRITE

	// FileClosedWithNoWrite event when a file is closed without writing
	FileClosedWithNoWrite EventType = unix.FAN_CLOSE_NOWRITE

	// FileClosed event when a file is closed after write or no write
	FileClosed EventType = unix.FAN_CLOSE_WRITE | unix.FAN_CLOSE_NOWRITE

	// FileOpened event when a file is opened
	FileOpened EventType = unix.FAN_OPEN

	// FileOrDirectoryOpened event when a file or directory is opened
	FileOrDirectoryOpened EventType = unix.FAN_OPEN | unix.FAN_ONDIR

	// FileOpenedForExec event when a file is opened with the intent to be executed.
	// Requires Linux kernel 5.0 or later
	FileOpenedForExec EventType = unix.FAN_OPEN_EXEC

	// FileAttribChanged event when a file attribute has changed
	// Requires Linux kernel 5.1 or later (requires FID)
	FileAttribChanged EventType = unix.FAN_ATTRIB

	// FileOrDirectoryAttribChanged event when a file or directory attribute has changed
	// Requires Linux kernel 5.1 or later (requires FID)
	FileOrDirectoryAttribChanged EventType = unix.FAN_ATTRIB | unix.FAN_ONDIR

	// FileCreated event when file a has been created
	// Requires Linux kernel 5.1 or later (requires FID)
	// BUG FileCreated does not work with FileClosed, FileClosedAfterWrite or FileClosedWithNoWrite
	FileCreated EventType = unix.FAN_CREATE

	// FileOrDirectoryCreated event when a file or directory has been created
	// Requires Linux kernel 5.1 or later (requires FID)
	FileOrDirectoryCreated EventType = unix.FAN_CREATE | unix.FAN_ONDIR

	// FileDeleted event when file a has been deleted
	// Requires Linux kernel 5.1 or later (requires FID)
	FileDeleted EventType = unix.FAN_DELETE

	// FileOrDirectoryDeleted event when a file or directory has been deleted
	// Requires Linux kernel 5.1 or later (requires FID)
	FileOrDirectoryDeleted EventType = unix.FAN_DELETE | unix.FAN_ONDIR

	// WatchedFileDeleted event when a watched file has been deleted
	// Requires Linux kernel 5.1 or later (requires FID)
	WatchedFileDeleted EventType = unix.FAN_DELETE_SELF

	// WatchedFileOrDirectoryDeleted event when a watched file or directory has been deleted
	// Requires Linux kernel 5.1 or later (requires FID)
	WatchedFileOrDirectoryDeleted EventType = unix.FAN_DELETE_SELF | unix.FAN_ONDIR

	// FileMovedFrom event when a file has been moved from the watched directory
	// Requires Linux kernel 5.1 or later (requires FID)
	FileMovedFrom EventType = unix.FAN_MOVED_FROM

	// FileOrDirectoryMovedFrom event when a file or directory has been moved from the watched directory
	// Requires Linux kernel 5.1 or later (requires FID)
	FileOrDirectoryMovedFrom EventType = unix.FAN_MOVED_FROM | unix.FAN_ONDIR

	// FileMovedTo event when a file has been moved to the watched directory
	// Requires Linux kernel 5.1 or later (requires FID)
	FileMovedTo EventType = unix.FAN_MOVED_TO

	// FileOrDirectoryMovedTo event when a file or directory has been moved to the watched directory
	// Requires Linux kernel 5.1 or later (requires FID)
	FileOrDirectoryMovedTo EventType = unix.FAN_MOVED_TO | unix.FAN_ONDIR

	// WatchedFileMoved event when a watched file has moved
	// Requires Linux kernel 5.1 or later (requires FID)
	WatchedFileMoved EventType = unix.FAN_MOVE_SELF

	// WatchedFileOrDirectoryMoved event when a watched file or directory has moved
	// Requires Linux kernel 5.1 or later (requires FID)
	WatchedFileOrDirectoryMoved EventType = unix.FAN_MOVE_SELF | unix.FAN_ONDIR

	// FileOpenPermission event when a permission to open a file or directory is requested
	FileOpenPermission EventType = unix.FAN_OPEN_PERM

	// FileOpenToExecutePermission event when a permission to open a file for
	// execution is requested
	FileOpenToExecutePermission EventType = unix.FAN_OPEN_EXEC_PERM

	// FileAccessPermission event when a permission to read a file or directory is requested
	FileAccessPermission EventType = unix.FAN_ACCESS_PERM
)

func (EventType) Has added in v0.2.0

func (e EventType) Has(et EventType) bool

Has returns true if event types (e) contains the passed in event type (et).

func (EventType) Or added in v0.2.0

func (e EventType) Or(et EventType) EventType

Or appends the specified event types to the set of event types to watch for

func (EventType) String added in v0.2.0

func (e EventType) String() string

String prints event types

type Listener

type Listener struct {

	// Events holds either notification events for the watched file/directory.
	Events chan Event
	// PermissionEvents holds permission request events for the watched file/directory.
	PermissionEvents chan Event
	// contains filtered or unexported fields
}

Listener represents a generic notification group that holds a list of files, directories or a mountpoint for which notification or permission events shall be created.

func NewListener

func NewListener(mountPoint string, entireMount bool, permType PermissionType) (*Listener, error)

NewListener returns a fanotify listener from which filesystem notification events can be read. Each listener supports listening to events under a single mount point. For cases where multiple mount points need to be monitored multiple listener instances need to be used.

Notification events are merely informative and require no action to be taken by the receiving application with the exception being that the file descriptor provided within the event must be closed.

Permission events are requests to the receiving application to decide whether permission for a file access shall be granted. For these events, the recipient must write a response which decides whether access is granted or not.

  • mountPoint can be any file/directory under the mount point being watched.
  • entireMount initializes the listener to monitor either the the entire mount point (when true) or allows adding files or directories to the listener's watch list (when false).
  • permType initializes the listener either notification events or both notification and permission events. Passing PreContent value allows the receipt of events notifying that a file has been accessed and events for permission decisions if a file may be accessed. It is intended for event listeners that need to access files before they contain their final data. Passing PostContent is intended for event listeners that need to access files when they already contain their final content.

The function returns a new instance of the listener. The fanotify flags are set based on the running kernel version. ErrCapSysAdmin is returned if the process does not have CAP_SYS_ADM capability.

  • For Linux kernel version 5.0 and earlier no additional information about the underlying filesystem object is available.
  • For Linux kernel versions 5.1 till 5.8 (inclusive) additional information about the underlying filesystem object is correlated to an event.
  • For Linux kernel version 5.9 or later the modified file name is made available in the event.
Example
package main

import (
	"log"

	"github.com/opcoder0/fanotify"
)

func main() {
	if _, err := fanotify.NewListener("/", true, fanotify.PostContent); err != nil {
		log.Fatal("Cannot create listener for mount /", err)
	}
}
Output:

func (*Listener) AddWatch

func (l *Listener) AddWatch(path string, eventTypes EventType) error

AddWatch adds or modifies the fanotify mark for the specified path. The events are only raised for the specified directory and does raise events for subdirectories. Calling AddWatch to mark the entire mountpoint results in os.ErrInvalid. To watch the entire mount point use [WatchMount] method. Certain flag combinations are known to cause issues.

  • FileCreated cannot be or-ed / combined with FileClosed. The fanotify system does not generate any event for this combination.
  • FileOpened with any of the event types containing OrDirectory causes an event flood for the directory and then stopping raising any events at all.
  • FileOrDirectoryOpened with any of the other event types causes an event flood for the directory and then stopping raising any events at all.
Example
package main

import (
	"log"

	"github.com/opcoder0/fanotify"
)

func main() {
	var listener *fanotify.Listener
	listener, err := fanotify.NewListener("/", false, fanotify.PermissionNone)
	if err != nil {
		log.Fatal("Cannot create listener for mount /", err)
	}
	listener.AddWatch("/home/user", fanotify.FileModified)
}
Output:

Example (All)
package main

import (
	"log"

	"github.com/opcoder0/fanotify"
)

func main() {
	var listener *fanotify.Listener
	var eventTypes fanotify.EventType

	listener, err := fanotify.NewListener("/", false, fanotify.PermissionNone)
	if err != nil {
		log.Fatal("Cannot create listener for path /", err)
	}
	eventTypes = fanotify.FileAccessed |
		fanotify.FileOrDirectoryAccessed |
		fanotify.FileModified |
		fanotify.FileOpenedForExec |
		fanotify.FileAttribChanged |
		fanotify.FileOrDirectoryAttribChanged |
		fanotify.FileCreated |
		fanotify.FileOrDirectoryCreated |
		fanotify.FileDeleted |
		fanotify.FileOrDirectoryDeleted |
		fanotify.WatchedFileDeleted |
		fanotify.WatchedFileOrDirectoryDeleted |
		fanotify.FileMovedFrom |
		fanotify.FileOrDirectoryMovedFrom |
		fanotify.FileMovedTo |
		fanotify.FileOrDirectoryMovedTo |
		fanotify.WatchedFileMoved |
		fanotify.WatchedFileOrDirectoryMoved
	listener.AddWatch("/home/user", eventTypes)
}
Output:

func (*Listener) Allow added in v0.4.0

func (l *Listener) Allow(e Event)

Allow sends an "allowed" response to the permission request event.

func (*Listener) ClearWatch

func (l *Listener) ClearWatch() error

ClearWatch stops watching for all event types

func (*Listener) DeleteWatch

func (l *Listener) DeleteWatch(parentDir string, eventTypes EventType) error

DeleteWatch removes/unmarks the fanotify mark for the specified path. Calling DeleteWatch on the listener initialized to monitor the entire mount point results in os.ErrInvalid. Use [UnwatchMount] for deleting marks on the mount point.

func (*Listener) Deny added in v0.4.0

func (l *Listener) Deny(e Event)

Deny sends an "denied" response to the permission request event.

func (*Listener) Start

func (l *Listener) Start()

Start starts the listener and polls the fanotify event notification group for marked events. The events are pushed into the Listener's Events channel.

func (*Listener) Stop

func (l *Listener) Stop()

Stop stops the listener and closes the notification group and the events channel

func (*Listener) UnwatchMount added in v0.4.0

func (l *Listener) UnwatchMount(eventTypes EventType) error

UnwatchMount removes the notification marks for the entire mount point. This method returns an ErrWatchPath if the listener was not initialized to monitor the entire mount point. To unmark specific files or directories use [DeleteWatch] method.

func (*Listener) WatchMount added in v0.4.0

func (l *Listener) WatchMount(eventTypes EventType) error

WatchMount adds or modifies the notification marks for the entire mount point. This method returns an ErrWatchPath if the listener was not initialized to monitor the entire mount point. To mark specific files or directories use [AddWatch] method. The following event types are considered invalid and WatchMount returns ErrInvalidFlagCombination for - FileCreated, FileAttribChanged, FileMovedTo, FileMovedFrom, WatchedFileDeleted, WatchedFileOrDirectoryDeleted, FileDeleted, FileOrDirectoryDeleted

type PermissionType added in v0.4.0

type PermissionType int

PermissionType represents value indicating when the permission event must be requested.

const (
	// PermissionNone is used to indicate the listener is for notification events only.
	PermissionNone PermissionType = 0
	// PreContent is intended for event listeners that
	// need to access files before they contain their final data.
	PreContent PermissionType = 1
	// PostContent is intended for event listeners that
	// need to access files when they already contain their final content.
	PostContent PermissionType = 2
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL