1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
use crate::FanotifyPath;
use libc::{__s32, __u16, __u32, __u64, __u8};
use std::io::Error;
use std::mem;
use std::os::unix::ffi::OsStrExt;
use std::slice;
#[doc(hidden)]
/// Re-export relevant libc constants
pub use libc::{O_RDONLY, O_WRONLY, O_RDWR, O_LARGEFILE, O_CLOEXEC, O_APPEND, O_DSYNC, O_NOATIME, O_NONBLOCK, O_SYNC};
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct FanotifyEventMetadata {
/// This is the length of the data for the current event and the
/// offset to the next event in the buffer. Without
/// `FAN_REPORT_FID`, the value of event_len is always
/// FAN_EVENT_METADATA_LEN. With `FAN_REPORT_FID`, event_len also
/// includes the variable length file identifier.
pub event_len: __u32,
/// This field holds a version number for the structure. It must
/// be compared to FANOTIFY_METADATA_VERSION to verify that the
/// structures returned at run time match the structures defined
/// at compile time. In case of a mismatch, the application
/// should abandon trying to use the fanotify file descriptor.
pub vers: __u8,
/// This field is not used.
pub reserved: __u8,
/// This is the length of the structure. The field was introduced
/// to facilitate the implementation of optional headers per event
/// type. No such optional headers exist in the current implemen‐
/// tation.
pub metadata_len: __u16,
/// This is a bit mask describing the event (see below).
pub mask: __u64,
/// This is an open file descriptor for the object being accessed,or FAN_NOFD if a queue overflow occurred.
/// If the fanotify file descriptor has been initialized using `FAN_REPORT_FID`,
/// applications should expect this value to be set to FAN_NOFDfor each event that is received. The file descriptor can be
/// used to access the contents of the monitored file or directory. The reading application is responsible for closing this file descriptor.
/// When calling fanotify_init(2), the caller may specify (via the event_f_flags argument) various file status flags that are to
/// be set on the open file description that corresponds to this file descriptor. In addition, the (kernel-internal) FMODE_NONOTIFY file status flag is set on the open file description.
/// This flag suppresses fanotify event generation. Hence, when the receiver of the fanotify event accesses the notified file or directory using this file descriptor, noadditional events will be created.
pub fd: __s32,
/// If flag FAN_REPORT_TID was set in fanotify_init(2), this is
/// the TID of the thread that caused the event. Otherwise, this
/// the PID of the process that caused the event.
pub pid: __s32,
}
#[derive(Debug)]
#[repr(C)]
/// It is used to control file access.
pub struct FanotifyResponse {
pub fd: __s32,
pub response: __u32,
}
/// Current platform sizeof of `FanotifyEventMetadata`.
const FAN_EVENT_METADATA_LEN: usize = mem::size_of::<FanotifyEventMetadata>();
/// This const is used to be compared to vers field of `FanotifyEventMetadata` to verify that the structures returned at run time match the structures defined at compile time.
///
///
/// In case of a mismatch, the application should abandon trying to use the fanotify file descriptor.
pub const FANOTIFY_METADATA_VERSION: u8 = 3;
/// Allow the file operation.
pub const FAN_ALLOW: u32 = 0x01;
/// Deny the file operation.
pub const FAN_DENY: u32 = 0x02;
/// bit mask to create audit record for result
pub const FAN_AUDIT: u32 = 0x10;
/// Indicates a queue overflow.
pub const FAN_NOFD: i32 = -1;
/// The event queue exceeded the limit of 16384 entries.
///
///
/// This limit can be overridden by specifying the `FAN_UNLIMITED_QUEUE` flag when calling `fanotify_init(2)`.
pub const FAN_Q_OVERFLOW: u64 = 0x0000_4000;
/// Set the close-on-exec flag `(FD_CLOEXEC) `on the new file descriptor.
///
/// See the description of the `O_CLOEXEC flag` in `open(2)`.
pub const FAN_CLOEXEC: u32 = 0x0000_0001;
/// Enable the nonblocking flag `(O_NONBLOCK)` for the file descriptor.
///
///
/// Reading from the file descriptor will not block. <br/>
/// Instead, if no data is available, `read(2)` fails with the error `EAGAIN`
pub const FAN_NONBLOCK: u32 = 0x0000_0002;
/// This is the default value. It does not need to be specified.
///
///
/// This value only allows the receipt of events notifying that a file has been accessed. <br/>
/// Permission decisions before the file is accessed are not possible.
pub const FAN_CLASS_NOTIF: u32 = 0x0000_0000;
/// This 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 when they already contain their final content. <br/>
/// This notification class might be used by malware detection programs, for example.
pub const FAN_CLASS_CONTENT: u32 = 0x0000_0004;
/// This value allows the receipt of events notifying that a file has been accessed and events for permission decisions if a file may be accessed. <br/>
/// It is intended for event listeners that need to access files before they contain their final data.<br/>
/// This notification class might be used by hierarchical storage managers, for example.
pub const FAN_CLASS_PRE_CONTENT: u32 = 0x0000_0008;
/// Remove the limit of 16384 events for the event queue. <br/>
/// Use of this flag requires the `CAP_SYS_ADMIN` capability.
pub const FAN_UNLIMITED_QUEUE: u32 = 0x0000_0010;
/// Remove the limit of 8192 marks. <br/>
/// Use of this flag requires the `CAP_SYS_ADMIN` capability.
pub const FAN_UNLIMITED_MARKS: u32 = 0x0000_0020;
/// `CONFIG_AUDIT_SYSCALL`
pub const FAN_ENABLE_AUDIT: u32 = 0x0000_0040;
/// Flags to determine fanotify event format
/// event->pid is thread id
pub const FAN_REPORT_TID: u32 = 0x0000_0100;
/// Flags to determine fanotify event format
/// report unique file id
pub const FAN_REPORT_FID: u32 = 0x0000_0200;
/// Flags to determine fanotify event format
/// report unique directory id
pub const FAN_REPORT_DIR_FID: u32 = 0x0000_0400;
/// Flags to determine fanotify event format
/// report events with name
pub const FAN_REPORT_NAME: u32 = 0x0000_0800;
/// Create an event when a file or directory is accessed (read).
pub const FAN_ACCESS: u64 = 0x0000_0001;
/// Create an event when a file is modified (write).
pub const FAN_MODIFY: u64 = 0x0000_0002;
/// Create an event when a metadata changed.
pub const FAN_ATTRIB: u64 = 0x0000_0004;
/// Create an event when a writable file is closed.
pub const FAN_CLOSE_WRITE: u64 = 0x0000_0008;
/// Create an event when a read-only file or directory is closed.
pub const FAN_CLOSE_NOWRITE: u64 = 0x0000_0010;
/// Create an event when a file or directory is opened.
pub const FAN_OPEN: u64 = 0x0000_0020;
/// Create an event when a file was moved from X
pub const FAN_MOVED_FROM: u64 = 0x0000_0040;
/// Create an event when a file was moved to Y
pub const FAN_MOVED_TO: u64 = 0x0000_0080;
/// Create an event when a file was moved
pub const FAN_MOVE: u64 = FAN_MOVED_TO | FAN_MOVED_FROM;
/// Create an event when a file created
pub const FAN_CREATE: u64 = 0x0000_0100;
/// Create an event when a file deleted
pub const FAN_DELETE: u64 = 0x0000_0200;
/// Create an event when a self was deleted
pub const FAN_DELETE_SELF: u64 = 0x0000_0400;
/// Create an event when self was moved
pub const FAN_MOVE_SELF: u64 = 0x0000_0800;
/// Create an event when file was opened for exec
pub const FAN_OPEN_EXEC: u64 = 0x0000_1000;
/// Create an event when a permission to open a file or directory is requested. <br/>
/// An fanotify file descriptor created with `FAN_CLASS_PRE_CONTENT` or `FAN_CLASS_CONTENT` is required.
pub const FAN_OPEN_PERM: u64 = 0x0001_0000;
/// Create an event when a permission to read a file or directoryis requested. <br/>
/// An fanotify file descriptor created with `FAN_CLASS_PRE_CONTENT` or `FAN_CLASS_CONTENT` is required.
pub const FAN_ACCESS_PERM: u64 = 0x0002_0000;
/// Create an event when a permission to open a file for exec is requested. <br/>
/// An fanotify file descriptor created with `FAN_CLASS_PRE_CONTENT` or `FAN_CLASS_CONTENT` is required.
pub const FAN_OPEN_EXEC_PERM: u64 = 0x0004_0000;
/// Create events for directories—for example, when `opendir(3)`, `readdir(3)` (but see BUGS), and `closedir(3)` are called. <br/>
/// Without this flag, events are created only for files. <br/>
/// In the context of directory entry events, such as `FAN_CREATE,FAN_DELETE`, `FAN_MOVED_FROM`, and `FAN_MOVED_TO`, specifying the flag `FAN_ONDIR` is required in order to create events when subdirectory entries are modified (i.e., `mkdir(2)`/`rmdir(2)`).
pub const FAN_ONDIR: u64 = 0x4000_0000;
/// Events for the immediate children of marked directories shall be created.
///
///
/// The flag has no effect when marking mounts and filesystems. <br/>
/// Note that events are not generated for children of the subdirectories of marked directories. <br/>
/// More specifically, the directory entry modification events `FAN_CREATE`, `FAN_DELETE`, `FAN_MOVED_FROM`, and `FAN_MOVED_TO` arenot generated for any entry modifications performed inside subdirectories of marked directories. <br/>
/// Note that the events `FAN_DELETE_SELF` and `FAN_MOVE_SELF` are not generated for children of marked directories. <br/>
/// To monitor complete directory trees it is necessary to mark the relevant mount or filesystem. <br/>
pub const FAN_EVENT_ON_CHILD: u64 = 0x0800_0000;
/// A file is closed `(FAN_CLOSE_WRITE|FAN_CLOSE_NOWRITE)`. <br/>
pub const FAN_CLOSE: u64 = FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE;
/// The events in mask will be added to the mark mask (or to the ignore mask). mask must be nonempty or the error `EINVAL` will occur.
pub const FAN_MARK_ADD: u32 = 0x0000_0001;
/// The events in argument mask will be removed from the mark mask (or from the ignore mask). mask must be nonempty or the error `EINVAL` will occur.
pub const FAN_MARK_REMOVE: u32 = 0x0000_0002;
/// Remove either all marks for filesystems, all marks for mounts,or all marks for directories and files from the fanotify group. <br/>
/// If flags contains `FAN_MARK_MOUNT`, all marks for mounts are removed from the group. <br/>
/// If flags contains `FAN_MARK_FILESYSTEM`, all marks for filesystems are removed from the group. <br/>
/// Otherwise, all marks for directories and files are removed. <br/>
/// No flag other than and at most one of the flags `FAN_MARK_MOUNT` or `FAN_MARK_FILESYSTEM` can be used in conjunction with `FAN_MARK_FLUSH`. mask is ignored.
pub const FAN_MARK_FLUSH: u32 = 0x0000_0080;
/// If pathname is a symbolic link, mark the link itself, rather than the file to which it refers. <br/>
/// (By default,`fanotify_mark()` dereferences pathname if it is a symbolic link.)
pub const FAN_MARK_DONT_FOLLOW: u32 = 0x0000_0004;
/// If the filesystem object to be marked is not a directory, the error `ENOTDIR` shall be raised.
pub const FAN_MARK_ONLYDIR: u32 = 0x0000_0008;
/// Mark the inode specified by pathname.<br/>
/// It is default way to mark.
pub const FAN_MARK_INODE: u32 = 0x0000_0000;
/// Mark the mount point specified by pathname. If pathname is not itself a mount point, the mount point containing pathname will be marked. <br/>
/// All directories, subdirectories, and the contained files of the mount point will be monitored. <br/>
/// The events which require the `fanotify_fd` file descriptor to have been initialized with the flag `FAN_REPORT_FID`, such as `FAN_CREATE`, `FAN_ATTRIB`, `FAN_MOVE`, and `FAN_DELETE_SELF`, cannot be provided as a mask when flags contains `FAN_MARK_MOUNT`.<br/>
/// Attempting to do so will result in the error `EINVAL` being returned.
pub const FAN_MARK_MOUNT: u32 = 0x0000_0010;
/// Mark the filesystem specified by pathname. <br/>
/// The filesystem containing pathname will be marked. <br/>
/// All the contained files and directories of the filesystem from any mount point will be monitored.
pub const FAN_MARK_FILESYSTEM: u32 = 0x0000_0100;
/// The events in mask shall be added to or removed from the ignore mask.
pub const FAN_MARK_IGNORED_MASK: u32 = 0x0000_0020;
/// The ignore mask shall survive modify events. <br/>
/// If this flag is not set, the ignore mask is cleared when a modify event occurs for the ignored file or directory.
pub const FAN_MARK_IGNORED_SURV_MODIFY: u32 = 0x0000_0040;
pub const AT_FDCWD: i32 = -100;
pub const AT_SYMLINK_NOFOLLOW: i32 = 0x100;
pub const AT_REMOVEDIR: i32 = 0x200;
pub const AT_SYMLINK_FOLLOW: i32 = 0x400;
pub const AT_NO_AUTOMOUNT: i32 = 0x800;
pub const AT_EMPTY_PATH: i32 = 0x1000;
/// Initializes a new fanotify group and returns a file descriptor for the event queue associated with the group.<br/>
///
/// The file descriptor is used in calls to `fanotify_mark(2)` to specify the files, directories, mounts or filesystems for which fanotify events shall be created.
/// These events are received by reading from the file descriptor. <br/>
/// Some events are only informative, indicating that a file has been accessed.
/// Other events can be used to determine whether another application is permitted to access a file or directory.
/// Permission to access filesystem objects is granted by writing to the file descriptor.
/// Multiple programs may be using the fanotify interface at the same time to monitor the same files.<br/>
/// In the current implementation, the number of fanotify groups per user is limited to 128. This limit cannot be overridden.
/// Calling `fanotify_init()` requires the `CAP_SYS_ADMIN` capability.
/// This constraint might be relaxed in future versions of the API. <br/>
/// Therefore, certain additional capability checks have been implemented as indicated below.<br/>
/// The `flags` argument contains a multi-bit field defining the notification class of the listening application and further single bit fields specifying the behavior of the file descriptor.<br/>
/// If multiple listeners for permission events exist, the notification class is used to establish the sequence in which the listeners receive the events.<br/>
///
/// Only one of the following notification classes may be specified in `flags`:<br/>
/// * `FAN_CLASS_PRE_CONTENT`
/// * `FAN_CLASS_CONTENT`
/// * `FAN_CLASS_NOTIF`
///
/// Listeners with different notification classes will receive events in the order `FAN_CLASS_PRE_CONTENT`, `FAN_CLASS_CONTENT`, `FAN_CLASS_NOTIF`.
/// The order of notification for listeners in the same notification class is undefined.<br/>
/// The following bits can additionally be set in flags:<br/>
/// * `FAN_CLOEXEC`
/// * `FAN_NONBLOCK`
/// * `FAN_UNLIMITED_QUEUE`
/// * `FAN_UNLIMITED_MARKS`
/// * `FAN_REPORT_TID` (since Linux 4.20)
/// * `FAN_REPORT_FID` (since Linux 5.1)
///
/// The `event_f_flags` argument defines the file status flags that will be set on the open file descriptions that are created for fanotify events. <br/>
/// For details of these flags, see the description of the flags values in `open(2)`. `event_f_flags` includes a multi-bit field for the access mode. <br/>
/// This field can take the following values:
/// * `O_RDONLY`
/// * `O_WRONLY`
/// * `O_RDWR`
///
/// Additional bits can be set in `event_f_flags`. The most useful values are:
/// * `O_LARGEFILE`
/// * `O_CLOEXEC` (since Linux 3.18)
///
/// The following are also allowable: `O_APPEND`, `O_DSYNC`, `O_NOATIME`,`O_NONBLOCK`, and `O_SYNC`. Specifying any other flag in `event_f_flags` yields the error `EINVAL`.
/// # Examples
/// ```
/// use fanotify::low_level::*;
/// let fd = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY as u32).unwrap();
/// assert!(fd > 0)
/// ```
pub fn fanotify_init(flags: u32, event_f_flags: u32) -> Result<i32, Error> {
unsafe {
match libc::fanotify_init(flags, event_f_flags) {
-1 => {
Err(Error::last_os_error())
}
fd => {
Ok(fd)
}
}
}
}
/// Adds, removes, or modifies an fanotify mark on a filesystem object.
// The caller must have read permission on the filesystem object that is to be marked.
///
/// The `fanotify_fd` argument is a file descriptor returned by `fanotify_init()`.
///
/// `flags` is a bit mask describing the modification to perform. It must include exactly one of the following values:
/// * `FAN_MARK_ADD`
/// * `FAN_MARK_REMOVE`
/// * `FAN_MARK_FLUSH`
///
/// If none of the values above is specified, or more than one is specified, the call fails with the error `EINVAL`.
///
/// In addition, zero or more of the following values may be `ORed` into `flags`:
/// * `FAN_MARK_DONT_FOLLOW`
/// * `FAN_MARK_ONLYDIR`
/// * `FAN_MARK_MOUNT`
/// * `FAN_MARK_FILESYSTEM` (since Linux 4.20)
/// * `FAN_MARK_IGNORED_MASK`
/// * `FAN_MARK_IGNORED_SURV_MODIFY`
///
///
/// `mask` defines which events shall be listened for (or which shall be ignored). It is a bit mask composed of the following values:
/// * `FAN_ACCESS`
/// * `FAN_MODIFY`
/// * `FAN_CLOSE_WRITE`
/// * `FAN_CLOSE_NOWRITE`
/// * `FAN_OPEN`
/// * `FAN_OPEN_EXEC` (since Linux 5.0)
/// * `FAN_ATTRIB` (since Linux 5.1)
/// * `FAN_CREATE` (since Linux 5.1)
/// * `FAN_DELETE` (since Linux 5.1)
/// * `FAN_DELETE_SELF` (since Linux 5.1)
/// * `FAN_MOVED_FROM` (since Linux 5.1)
/// * `FAN_MOVED_TO` (since Linux 5.1)
/// * `FAN_MOVE_SELF` (since Linux 5.1)
/// * `FAN_OPEN_PERM`
/// * `FAN_OPEN_EXEC_PERM` (since Linux 5.0)
/// * `FAN_ACCESS_PERM`
/// * `FAN_ONDIR`
/// * `FAN_EVENT_ON_CHILD`
///
/// The following composed values are defined:
/// * `FAN_CLOSE`
/// * `FAN_MOVE` (since Linux 5.1)
///
///
/// The filesystem object to be marked is determined by the file descriptor `dirfd` and the pathname specified in pathname:
/// * If pathname is `NULL`, `dirfd` defines the filesystem object to be marked.
/// * If pathname is `NULL`, and `dirfd` takes the special value `AT_FDCWD`,the current working directory is to be marked.
/// * If pathname is absolute, it defines the filesystem object to be marked, and `dirfd` is ignored.
/// * If pathname is relative, and `dirfd` does not have the value `AT_FDCWD`, then the filesystem object to be marked is determined by interpreting pathname relative the directory referred to by `dirfd.`
/// * If pathname is relative, and `dirfd` has the value `AT_FDCWD`, then the filesystem object to be marked is determined by interpreting pathname relative the current working directory.
/// # Examples
/// ```
/// use fanotify::low_level::*;
/// let fd = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY as u32).unwrap();
/// fanotify_mark(fd, FAN_MARK_ADD, FAN_OPEN | FAN_CLOSE, AT_FDCWD, "./").unwrap();
/// ```
pub fn fanotify_mark<P: ?Sized + FanotifyPath>(
fanotify_fd: i32,
flags: u32,
mask: u64,
dirfd: i32,
path: &P,
) -> Result<(), Error> {
unsafe {
let mut raw_path = path.as_os_str().as_bytes().to_vec();
raw_path.push(0u8); // data must be null terminated
//make sure path is null terminated
match libc::fanotify_mark(
fanotify_fd,
flags,
mask,
dirfd,
raw_path.as_ptr().cast(),
) {
0 => {
Ok(())
}
_ => {
Err(Error::last_os_error())
}
}
}
}
pub fn fanotify_read(fanotify_fd: i32) -> Vec<FanotifyEventMetadata> {
let mut vec = Vec::new();
let mut buffer = Box::new([0u8;FAN_EVENT_METADATA_LEN * 200]);
unsafe {
// Allocate a buffer to store up to 200 events
let sizeof = libc::read(fanotify_fd, buffer.as_mut_ptr() as _, FAN_EVENT_METADATA_LEN * 200);
if sizeof != libc::EAGAIN as isize && sizeof > 0 {
let src = slice::from_raw_parts(
buffer.as_ptr().cast::<FanotifyEventMetadata>(),
sizeof as usize / FAN_EVENT_METADATA_LEN,
);
vec.extend_from_slice(src);
}
}
vec
}
pub fn close_fd(fd: i32) {
unsafe {
libc::close(fd);
}
}