Structure and macros for filesystem events
#include <sys/fs_events.h> typedef struct fse_event_s { uint32_t signature; /* Version and fixed identifier */ uint16_t length; /* Type and length of the event data */ uint16_t command; /* Command / request information */ uint32_t properties; /* Classification of the event */ uint32_t reserved; /* Reserved for future use (zero) */ uint32_t identity; /* Locale and ID of the event */ } fsev_t;
The <sys/fs_events.h> header file includes everything necessary to read and process events from the filesystem event manager, fsevmgr.
The fsev_t structure is a header that describes a filesystem event, including its origin, locale, and identity. It's followed by any data associated with the event. Generally the data is a path string, but depends on the type of event.
Events are organized into tuples that have a common header, a description of the event, and length of that event. The length field represents the entire length from the starting address of the tuple.
You read an event from the event manager into an array of bytes, but there's no guarantee of alignment, so you should use the FSE_READ_EVENT_S() macro—which is a cover for the memcpy() function—to copy the data into an fsev_t structure:
#define FSE_READ_EVENT_S(pev, pdata)
where pev is a pointer to a fsev_t structure, and pdata is a pointer to the array of bytes.
To access a tuple, use the following FSE_*() macros, which take as an argument a pointer to an fsev_t structure:
Properties
Properties are boolean attributes of an event that help to describe its purpose, data, and/or impact to the system. An event can have multiple properties ORed together.
To assist in the filtering of events, properties are organized into a few groups: types, class, and data. FSE_TYPE_* properties indicate the purpose of an event; FSE_CLASS_* properties indicate the impact an event might have on a system; FSE_DATA_* properties describe attributes of the data attached to the event.
Properties of events aren't exclusive; some events may have two class properties.
Locales
Locales indicate the source of the event. An event can have only a single locale. In general, event client handlers filter out those events that don't match the locale that they're monitoring.
Event IDs
Event IDs indicate the cause of the event and the data associated with it. If the event data includes any strings, they're null-terminated.
ID | Properties | Description |
---|---|---|
FSE_ID_CHECK | Used internally for testing. | |
FSE_ID_CHMOD | FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING | Sent upon successful recording of a file's read, write, and execute modes.
This event indicates only that a file mode bits might have changed.
Mode information isn't available.
The data consists of:
|
FSE_ID_CHOWN | FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING | Sent on the successful recording of a file's ownership.
Note this event indicates that the ownership information might have changed.
Ownership information isn't available.
The data consists of:
|
FSE_ID_CLOSE_OTHER | Reserved for future use. | |
FSE_ID_CLOSE_UPDATE | FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING | The last close of a file handle that has write access to the inode generates this event.
Note that this may not be the same file name that was reported in an earlier
FSE_OPEN_UPDATE event.
The data consists of:
|
FSE_ID_CREATE | Reserved for future use. | |
FSE_ID_DEVCTL | Reserved for future use. | |
FSE_ID_FDINFO | Reserved for future use. | |
FSE_ID_FREE_SPACE | FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING | The block I/O system attempts to estimate disk space usage based on IO_WRITE and
IO_SPACE messages; when it estimates that a certain threshold has been crossed,
it queries the filesystem for the real change.
Once the real change is confirmed to be above a certain threshold, a FSE_ID_FREE_SPACE
event is emitted.
The data consists of:
|
FSE_ID_LINK | FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING | The link field indicates a filename has successfully been created and associated with an inode.
The target file name is unknown.
The data consists of:
|
FSE_ID_MKDIR | FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING | A directory (or node) has been successfully created within the filesystem.
The data consists of:
|
FSE_ID_MOUNT | FSE_TYPE_GENERAL, FSE_CLASS_INFO, FSE_DATA_ZSTRING | A volume has been successfully mounted (e.g., mount /dev/umass0 /fs/usb0).
The data consists of:
|
FSE_ID_OPENFD | Reserved for future use. | |
FSE_ID_OPEN_OTHER | Reserved for future use. | |
FSE_ID_OPEN_UPDATE | FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING | The open update event is a result of the first open of an inode which includes write access.
Subsequent opens with write access of the inode (regardless of the source file name) aren't reported.
Note that if the inode is opened again, but through a different link, there will be no additional event.
The data consists of:
|
FSE_ID_READ | Reserved for future use. | |
FSE_ID_READLINK | Reserved for future use. | |
FSE_ID_RENAME | FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING | Sent as a result of a successful renaming operation within a single filesystem.
Renaming operations across filesystems are generally implemented as a copy and delete sequence.
The data consists of:
|
FSE_ID_SEEK | Reserved for future use. | |
FSE_ID_STAT | Reserved for future use. | |
FSE_ID_TRUNCATE | FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING | Sent upon a truncate operation that results in a change to a file size.
The data consists of:
|
FSE_ID_UNLINK | FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING | Sent as a result of a successful unlink operation.
The data consists of:
|
FSE_ID_UNMOUNT | FSE_TYPE_GENERAL, FSE_CLASS_ACCESS, FSE_DATA_ZSTRING | A volume has been successfully unmounted.
The data consists of:
|
FSE_ID_WRITE | Reserved for future use. |
Here's an example of extracting the information associated with an event:
char *data, *mntpath, *spacestr; size_t len; uint64_t freespace; if (FSE_ID_VAL(event) == FSE_ID_FREE_SPACE) { data = FSE_DATA_PTR(event); len = FSE_DATA_LEN(event); /* Determine the starting buffer offsets for the mount path and freespace integer value. */ mntpath = data; spacestr = data + strlen(mntpath) + 1; /* If the path exceeds the data buffer, then there's no freespace value present. */ if (spacestr >= (data + len)) { LOG(LOG_ERROR, "freespace data exceeds event buffer length (%p >= %p)", spacestr, data+len); return; } /* Convert the freespace string to a 64-bit unsigned integer value. */ else if (sscanf(spacestr, "%" PRIu64, &freespace) != 1) { LOG(LOG_ERROR, "freespace data conversion failed"); return; } }
Notes
There are several unique situations that clients of the event manager should be aware of:
Initializing events
If your client application has opened the event manager's device for writing, you can inject events. You can initialize an event structure by using the FSE_INIT_EVENT() macro:
#define FSE_INIT_EVENT(p, cmd, loc, id, prop, len)...
The arguments are:
The event manager checks the event data to ensure it's well-formed; if it isn't, the event manager aborts the writing of all events that were sent in the write operation.