Enable QNX Neutrino-specific extensions to the inotify interface
#include <sys/inotify_ext.h> int inotify_qnx_ext( int fd, uint32_t extensions );
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
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.
0 on success, or -1 if an error occurred (errno is set).
#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; } } } } } }
Safety: | |
---|---|
Cancellation point | No |
Interrupt handler | No |
Signal handler | No |
Thread | Yes |