An example for the usage of the inotify API is provided. It shows the usage of inotify_init1(2),inotify_add_watch(2) as well as polling and reading form the inotify file descriptor. Signed-off-by: Heinrich Schuchardt <xypron.glpk@xxxxxx> --- man7/inotify.7 | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) diff --git a/man7/inotify.7 b/man7/inotify.7 index 8e848b2..a422eda 100644 --- a/man7/inotify.7 +++ b/man7/inotify.7 @@ -752,6 +752,232 @@ if the older had not yet been read) instead checked if the most recent event could be coalesced with the .I oldest unread event. +.SH EXAMPLE +The following program demonstrates the usage of the inotify API. +It marks the directories passed as a command-line argument +and waits for events of type +.BR IN_OPEN , +.BR IN_CLOSE_NOWRITE +and +.BR IN_CLOSE_WRITE . +.PP +The following output was recorded while editing the file +.I /home/user/temp/foo +and listing directory +.IR /tmp . +Before the file and the directory were opened, +.B IN_OPEN +events occurred. +After the file was closed, an +.B IN_CLOSE_WRITE +event occurred. +After the directory was closed, an +.B IN_CLOSE_NOWRITE +event occurred. +Execution of the program ended when the user pressed the ENTER key. +.SS Example output +.in +4n +.nf +$ ./inotify.7.example /tmp /home/user/temp +Press enter key to terminate. +Listening for events. +IN_OPEN: /home/user/temp/foo [file] +IN_CLOSE_WRITE: /home/user/temp/foo [file] +IN_OPEN: /tmp/ [directory] +IN_CLOSE_NOWRITE: /tmp/ [directory] + +Listening for events stopped. +.fi +.in +.SS Program source +.nf +#include <errno.h> +#include <malloc.h> +#include <poll.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/inotify.h> +#include <unistd.h> + +/* Macros for looping over inotify events. */ + +#define EVENT_LEN ( sizeof (struct inotify_event) ) +#define EVENT_OK(event, len) \\ + ((long)(len) >= (long)EVENT_LEN && \\ + (long)(len) >= (long)EVENT_LEN + (long)(event)\->len) +#define EVENT_NEXT(event, len) \\ + ((len) \-= EVENT_LEN + (event)\->len, \\ + (struct inotify_event*)(((char *)(event)) + \\ + (event)\->len)) + +/* Read all available inotify events from the file descriptor 'fd' + wd is the table of watch descriptors for the directories in argv + argc is the length of wd and argv + argv is the list of watched directories + Entry 0 of wd and argv is unused. */ + +void +handle_events(int fd, int *wd, int argc, char* argv[]) +{ + const struct inotify_event *event; + char buf[4096]; + int i; + ssize_t len; + + /* Loop while events can be read from inotify file descriptor. */ + + for(;;) { + + /* Read some events. */ + + len = read(fd, (void *) &buf, sizeof(buf)); + if (len == \-1 && errno != EAGAIN) { + perror("read"); + exit(EXIT_FAILURE); + } + + /* Check if end of available data reached. */ + + if (len <= 0) + break; + + /* Point to the first event in the buffer. */ + + event = (struct inotify_event *) buf; + + /* Loop over all events in the buffer. */ + + while(EVENT_OK(event, len)) { + + /* Print event type. */ + + if (event\->mask & IN_OPEN) + printf("IN_OPEN: "); + if (event\->mask & IN_CLOSE_NOWRITE) + printf("IN_CLOSE_NOWRITE: "); + if (event\->mask & IN_CLOSE_WRITE) + printf("IN_CLOSE_WRITE: "); + + /* Print the name of the watched directory. */ + + for(i = 1; i < argc; ++i) { + if(wd[i] == event\->wd) + printf("%s/", argv[i]); + } + + /* Print the name of the file. */ + + if (event\->len) + printf("%s", event\->name); + + /* Print type of file system object. */ + + if (event\->mask & IN_ISDIR) + printf(" [directory]\\n"); + else + printf(" [file]\\n"); + + event = EVENT_NEXT(event, len); + } + } +} + +int +main(int argc, char* argv[]) +{ + char buf; + int fd, i, poll_num; + int *wd = NULL; + nfds_t nfds; + struct pollfd fds[2]; + + if (argc < 2) { + printf("Usage: %s DIRECTORY [DIRECTORY ...]\\n", argv[0]); + exit(EXIT_FAILURE); + } + + printf("Press enter key to terminate.\\n"); + + /* Create the file descriptor for accessing the inotify API. */ + + fd = inotify_init1(IN_NONBLOCK); + if (fd == \-1) { + perror("inotify_init1"); + exit(EXIT_FAILURE); + } + + /* Allocate memory for watch descriptors. */ + + wd = (int *) calloc(argc, sizeof(int)); + if (wd == NULL) { + perror("calloc"); + exit(EXIT_FAILURE); + } + + /* Mark directories for events + \- file was opened + \- file was closed */ + + for (i = 1; i < argc; i++) { + wd[i] = inotify_add_watch(fd, argv[i], + IN_OPEN | IN_CLOSE); + if (wd[i] == \-1) { + perror("inotify_add_watch"); + exit(EXIT_FAILURE); + } + } + + /* Prepare for polling. */ + + nfds = 2; + + /* Console input. */ + + fds[0].fd = STDIN_FILENO; + fds[0].events = POLLIN; + + /* Inotify input. */ + + fds[1].fd = fd; + fds[1].events = POLLIN; + + /* This is the loop to wait for incoming events. */ + + printf("Listening for events.\\n"); + while (1) { + poll_num = poll(fds, nfds, \-1); + if (poll_num == \-1) { + if (errno == EINTR) + continue; + perror("poll"); + exit(EXIT_FAILURE); + } + if (poll_num > 0) { + + if (fds[0].revents & POLLIN) { + + /* Console input is available. Empty stdin and quit. */ + + while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\\n') + continue; + break; + } + if (fds[1].revents & POLLIN) { + + /* Inotify events are available. */ + handle_events(fd, wd, argc, argv); + } + } + } + + /* Close inotify file descriptor. */ + + close(fd); + free(wd); + printf("Listening for events stopped.\\n"); + return EXIT_SUCCESS; +} +.fi .SH SEE ALSO .BR inotifywait (1), .BR inotifywatch (1), -- 2.0.0.rc2 -- To unsubscribe from this list: send the line "unsubscribe linux-man" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html