inotify_qnx_ext()

Updated: April 19, 2023

Enable QNX Neutrino-specific extensions to the inotify interface

Synopsis:

#include <sys/inotify_ext.h>

int inotify_qnx_ext( int fd,
                     uint32_t extensions );

Arguments:

fd
A valid file descriptor returned by inotify_init().
extensions
A bitwise OR of one or more of the following extensions:
  • INOTIFY_QNX_EXT_FREESPACE — Generate an event whenever the amount of freespace in any mounted filesystem changes. To avoid spamming the event system, the change in freespace must exceed a certain threshold. The event is of type inotify_qnx_ext_freespace and has a freespace member that stores the amount of freespace (in bytes) at the time the event was generated.
  • INOTIFY_QNX_EXT_MOUNT — Generate an event whenever a filesystem that supports inotify is mounted. The event is of type inotify_qnx_ext_mount and has a name member that contains the mountpoint path.
  • INOTIFY_QNX_EXT_UNMOUNT — Generate an event whenever a filesystem that supports inotify is unmounted. The event is of type inotify_qnx_ext_mount and has a name member that contains the mountpoint that was unmounted.
  • INOTIFY_QNX_EXT_RECURSE — Reserved for future use.
  • INOTIFY_QNX_EXT_SECURITY — Generate an event whenever a security-related violation is detected. Currently the only violations are data verification errors from fs-qtd.so. The data structure is type inotify_qnx_ext_security_t and has a subtype member that indicates the type of the payload member.

Library:

libc

Use the -l c option to qcc to link against this library. This library is usually included automatically.

Description:

The inotify_qnx_ext() function is used to indicate to the inotify framework that your program can interpret and would like to receive QNX Neutrino extended inotify event types. The extensions argument indicates which types of extended events you want to receive. Because QNX Neutrino extended events don't require you to add a watch, they are globally enabled. The data structure that inotify_qnx_ext() returns contains a pathname to the mountpoint associated with the event.

QNX Neutrino extended types are returned to your program embedded in a standard inotify_event structure. You can use the mask member of inotify_event to identify an extended event. All extended events have a mask of 0. The extended data structure is stored in the name member of the inotify_event.

For you to use this function, the filesystem event manager (fsevmgr) manager needs to be running.

For an overview of inotify, see http://www.linuxjournal.com/article/8478?page=0,0 in the Linux Journal, but note that there are differences between the Linux and QNX Neutrino implementations. Currently, only io-blk.so-based filesystems support inotify.

Returns:

0 on success, or -1 if an error occurred (errno is set).

Examples:

#include <sys/inotify.h>
#include <sys/inotify_ext.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <inttypes.h>


/* Print out the next inotify event in the stream, and return the number
 * of bytes consumed by that event.
 */
static size_t printwatch (struct inotify_event* ieventp) {
	char watch_type_string [120];
	size_t eventsize = sizeof(*ieventp) + ieventp->len;
	memset(watch_type_string, 0, sizeof(watch_type_string));

	/* Extended events have a mask of zero */
	if (ieventp->mask == 0) {
		inotify_qnx_ext_hdr* hdr = (inotify_qnx_ext_hdr*)(&ieventp->name[0]);
		switch (hdr->type){
			case INOTIFY_QNX_EXT_MOUNT:
			{
				inotify_qnx_ext_mount* mountp = (inotify_qnx_ext_mount*)hdr;
				printf("MOUNT of %s\n", mountp->name);
			}
				break;
			case INOTIFY_QNX_EXT_SECURITY:
			{
				inotify_qnx_ext_security_t* sec = (inotify_qnx_ext_security_t*)hdr;
				if (sec->subtype == INOTIFY_QNX_EXT_SECURITY_BLOCK_VALIDATION_FAILED) {
						struct blk_validation_failure* bfail = &(sec->payload.blk_hash);
						printf("block validation failure at block %"PRIu64", hashblk %u\n", bfail->blkno, bfail->hashblkno);
				}
				break;
			}
			default:
				printf("Unknown QNX extended type\n");
				break;
		}
	}
	/* The event could have multiple bits set in mask, so concatenate
	 * the string.
	 */
	if (ieventp->mask & IN_ACCESS) {
		strlcat(watch_type_string, "ACCESS ", sizeof(watch_type_string));
	}
	if (ieventp->mask & IN_MODIFY) {
		strlcat(watch_type_string, "MODIFY ", sizeof(watch_type_string));
	}
	if (ieventp->mask & IN_ATTRIB) {
		strlcat(watch_type_string, "ATTRIB ", sizeof(watch_type_string));
	}
	if (ieventp->mask & IN_CLOSE_WRITE) {
		strlcat(watch_type_string, "CLOSE_WRITE ", sizeof(watch_type_string));
	}
	if (ieventp->mask & IN_CLOSE_NOWRITE) {
		strlcat(watch_type_string, "CLOSE_NOWRITE ", sizeof(watch_type_string));
	}
	if (ieventp->mask & IN_OPEN) {
		strlcat(watch_type_string, "OPEN ", sizeof(watch_type_string));
	}
	if (ieventp->mask & IN_MOVED_FROM) {
		strlcat(watch_type_string, "MOVED FROM ", sizeof(watch_type_string));
	}
	if (ieventp->mask & IN_MOVED_TO) {
		strlcat(watch_type_string, "MOVED_TO ", sizeof(watch_type_string));
	}
	if (ieventp->mask & IN_CREATE) {
		strlcat(watch_type_string, "CREATE ", sizeof(watch_type_string));
	}
	if (ieventp->mask & IN_DELETE) {
		strlcat(watch_type_string, "DELETE ", sizeof(watch_type_string));
	}
	if (ieventp->mask & IN_DELETE_SELF) {
		strlcat(watch_type_string, "DELETE SELF ", sizeof(watch_type_string));
	}
	if (ieventp->mask & IN_MOVE_SELF) {
		strlcat(watch_type_string, "MOVE SELF ", sizeof(watch_type_string));
	}
	/* The ieventp->len only describes the name in the case of non-extended
	 * events.
	 */
	if ((ieventp->len > 0) && (ieventp->mask)) {
		strlcat(watch_type_string, ieventp->name, sizeof(watch_type_string));
	}
	strlcat  (watch_type_string, "\n", sizeof(watch_type_string));
	printf(watch_type_string);
	return eventsize;
}

/* Set a watch on the specified path, and loop, listening for any events and printing out
 * each event received.
 */
int main(int argc, char* argv[]) {		
	int watchid;
	int result = 0;
	int inotifyfd = inotify_init();
	
	watchid = inotify_add_watch (inotifyfd, argv[1], IN_MODIFY | IN_ACCESS | IN_CREATE | IN_DELETE); 
	if (watchid < 0){ 
	        perror ("inotify_add_watch"); 
	        exit(0); 
	} 
	
	if (-1 == inotifyfd) {
		printf("Could not connect to inotify service (%d).\n", errno);
		result = 1;
	} else {
		/* Enable extension events */
		inotify_qnx_ext(inotifyfd, INOTIFY_QNX_EXT_SECURITY|INOTIFY_QNX_EXT_MOUNT);
	}

	if (0 == result) {
		void* ieventbuf = malloc(sizeof(struct inotify_event) + PATH_MAX);
		result = 0;
		while (0 == result) {
			/* Sit and catch all the events */
			const ssize_t watch_data = read(inotifyfd, ieventbuf, sizeof(struct inotify_event) + PATH_MAX);
			if (watch_data < sizeof(struct inotify_event)){
				/* Oops, had a read error, bail out. */
				printf("%s: Encountered error %d on watch read, exiting..\n", argv[0], errno);
				result = 1;
				free (ieventbuf);
				close(inotifyfd);
			} else {
				/* Iterate through the entire buffer, printing event details */
				size_t tot_handled = 0;
				while(tot_handled < watch_data) {
					const size_t curr_handled = printwatch(ieventbuf);
					if (curr_handled > 0){
						tot_handled += curr_handled;
						ieventbuf += curr_handled;
					} else {
						/* Hit end-of-buffer */
						break;
					}
				}
			}
		}
	}
}

Classification:

Linux

Safety:  
Cancellation point No
Interrupt handler No
Signal handler No
Thread Yes