mirror of https://github.com/mkerrisk/man-pages
inotify.7: Add example program
This example of the usage of the inotify API shows the usage of inotify_init1(2) and inotify_add_watch(2) as well as polling and reading from the inotify file descriptor. Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
parent
9fb49a3a80
commit
ecd96f7c0e
228
man7/inotify.7
228
man7/inotify.7
|
@ -1,5 +1,6 @@
|
||||||
'\" t
|
'\" t
|
||||||
.\" Copyright (C) 2006, 2014 Michael Kerrisk <mtk.manpages@gmail.com>
|
.\" Copyright (C) 2006, 2014 Michael Kerrisk <mtk.manpages@gmail.com>
|
||||||
|
.\" Copyright (C) 2014 Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||||
.\"
|
.\"
|
||||||
.\" %%%LICENSE_START(VERBATIM)
|
.\" %%%LICENSE_START(VERBATIM)
|
||||||
.\" Permission is granted to make and distribute verbatim copies of this
|
.\" Permission is granted to make and distribute verbatim copies of this
|
||||||
|
@ -23,7 +24,7 @@
|
||||||
.\" the source, must acknowledge the copyright and authors of this work.
|
.\" the source, must acknowledge the copyright and authors of this work.
|
||||||
.\" %%%LICENSE_END
|
.\" %%%LICENSE_END
|
||||||
.\"
|
.\"
|
||||||
.TH INOTIFY 7 2014-05-08 "Linux" "Linux Programmer's Manual"
|
.TH INOTIFY 7 2014-05-23 "Linux" "Linux Programmer's Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
inotify \- monitoring filesystem events
|
inotify \- monitoring filesystem events
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
|
@ -752,6 +753,231 @@ if the older had not yet been read)
|
||||||
instead checked if the most recent event could be coalesced with the
|
instead checked if the most recent event could be coalesced with the
|
||||||
.I oldest
|
.I oldest
|
||||||
unread event.
|
unread event.
|
||||||
|
.SH EXAMPLE
|
||||||
|
The following program demonstrates the usage of the inotify API.
|
||||||
|
It marks the directories passed as a command-line arguments
|
||||||
|
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 <poll.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/inotify.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_events(int fd, int *wd, int argc, char* argv[])
|
||||||
|
{
|
||||||
|
/* Some systems cannot read integer variables if they are
|
||||||
|
not properly aligned. On other systems incorrect alignment
|
||||||
|
may decrease performance.
|
||||||
|
Hence, the buffer used for reading from the inotify file
|
||||||
|
descriptor should have the same alignment as
|
||||||
|
struct inotify_event. */
|
||||||
|
char buf[4096]
|
||||||
|
__attribute__ ((aligned(__alignof__(struct inotify_event))));
|
||||||
|
const struct inotify_event *event;
|
||||||
|
int i;
|
||||||
|
ssize_t len;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
/* Loop while events can be read from inotify file descriptor. */
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
/* Read some events. */
|
||||||
|
|
||||||
|
len = read(fd, buf, sizeof buf);
|
||||||
|
if (len == \-1 && errno != EAGAIN) {
|
||||||
|
perror("read");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the nonblocking read() found no events to read, then
|
||||||
|
it returns \-1 with errno set to EAGAIN. In that case,
|
||||||
|
we exit the loop. */
|
||||||
|
|
||||||
|
if (len <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Loop over all events in the buffer */
|
||||||
|
|
||||||
|
for (ptr = buf; ptr < buf + len;
|
||||||
|
ptr += sizeof(struct inotify_event) + event\->len) {
|
||||||
|
|
||||||
|
event = (const struct inotify_event *) ptr;
|
||||||
|
|
||||||
|
/* 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]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print the name of the file */
|
||||||
|
|
||||||
|
if (event\->len)
|
||||||
|
printf("%s", event\->name);
|
||||||
|
|
||||||
|
/* Print type of filesystem object */
|
||||||
|
|
||||||
|
if (event\->mask & IN_ISDIR)
|
||||||
|
printf(" [directory]\\n");
|
||||||
|
else
|
||||||
|
printf(" [file]\\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
char buf;
|
||||||
|
int fd, i, poll_num;
|
||||||
|
int *wd;
|
||||||
|
nfds_t nfds;
|
||||||
|
struct pollfd fds[2];
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("Usage: %s PATH [PATH ...]\\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 = 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) {
|
||||||
|
fprintf(stderr, "Cannot watch '%s'\\n", argv[i]);
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Wait for events and/or terminal input */
|
||||||
|
|
||||||
|
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");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
.fi
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.BR inotifywait (1),
|
.BR inotifywait (1),
|
||||||
.BR inotifywatch (1),
|
.BR inotifywatch (1),
|
||||||
|
|
Loading…
Reference in New Issue