examples: Add a demo program for inotify
MFC after: 3 months Sponsored by: Klara, Inc.
This commit is contained in:
@@ -304,6 +304,8 @@
|
|||||||
..
|
..
|
||||||
indent
|
indent
|
||||||
..
|
..
|
||||||
|
inotify
|
||||||
|
..
|
||||||
ipfilter
|
ipfilter
|
||||||
..
|
..
|
||||||
ipfw
|
ipfw
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ LDIRS= BSD_daemon \
|
|||||||
find_interface \
|
find_interface \
|
||||||
flua \
|
flua \
|
||||||
indent \
|
indent \
|
||||||
|
inotify \
|
||||||
ipfw \
|
ipfw \
|
||||||
jails \
|
jails \
|
||||||
kld \
|
kld \
|
||||||
@@ -97,6 +98,10 @@ SE_FLUA= libjail.lua
|
|||||||
SE_DIRS+= indent
|
SE_DIRS+= indent
|
||||||
SE_INDENT= indent.pro
|
SE_INDENT= indent.pro
|
||||||
|
|
||||||
|
SE_DIRS+= inotify
|
||||||
|
SE_INOTIFY= inotify.c \
|
||||||
|
Makefile
|
||||||
|
|
||||||
.if ${MK_IPFILTER} != "no"
|
.if ${MK_IPFILTER} != "no"
|
||||||
SUBDIR+= ipfilter
|
SUBDIR+= ipfilter
|
||||||
.endif
|
.endif
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
PROG= inotify
|
||||||
|
MAN=
|
||||||
|
|
||||||
|
LIBADD= xo
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
/*-
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 Klara, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A simple program to demonstrate inotify. Given one or more paths, it watches
|
||||||
|
* all events on those paths and prints them to standard output.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/event.h>
|
||||||
|
#include <sys/inotify.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <libxo/xo.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
xo_errx(1, "usage: inotify <path1> [<path2> ...]");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
ev2str(uint32_t event)
|
||||||
|
{
|
||||||
|
switch (event & IN_ALL_EVENTS) {
|
||||||
|
case IN_ACCESS:
|
||||||
|
return ("IN_ACCESS");
|
||||||
|
case IN_ATTRIB:
|
||||||
|
return ("IN_ATTRIB");
|
||||||
|
case IN_CLOSE_WRITE:
|
||||||
|
return ("IN_CLOSE_WRITE");
|
||||||
|
case IN_CLOSE_NOWRITE:
|
||||||
|
return ("IN_CLOSE_NOWRITE");
|
||||||
|
case IN_CREATE:
|
||||||
|
return ("IN_CREATE");
|
||||||
|
case IN_DELETE:
|
||||||
|
return ("IN_DELETE");
|
||||||
|
case IN_DELETE_SELF:
|
||||||
|
return ("IN_DELETE_SELF");
|
||||||
|
case IN_MODIFY:
|
||||||
|
return ("IN_MODIFY");
|
||||||
|
case IN_MOVE_SELF:
|
||||||
|
return ("IN_MOVE_SELF");
|
||||||
|
case IN_MOVED_FROM:
|
||||||
|
return ("IN_MOVED_FROM");
|
||||||
|
case IN_MOVED_TO:
|
||||||
|
return ("IN_MOVED_TO");
|
||||||
|
case IN_OPEN:
|
||||||
|
return ("IN_OPEN");
|
||||||
|
default:
|
||||||
|
switch (event) {
|
||||||
|
case IN_IGNORED:
|
||||||
|
return ("IN_IGNORED");
|
||||||
|
case IN_Q_OVERFLOW:
|
||||||
|
return ("IN_Q_OVERFLOW");
|
||||||
|
case IN_UNMOUNT:
|
||||||
|
return ("IN_UNMOUNT");
|
||||||
|
}
|
||||||
|
warnx("unknown event %#x", event);
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_handler(int kq, int sig)
|
||||||
|
{
|
||||||
|
struct kevent kev;
|
||||||
|
|
||||||
|
(void)signal(sig, SIG_IGN);
|
||||||
|
EV_SET(&kev, sig, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
|
||||||
|
if (kevent(kq, &kev, 1, NULL, 0, NULL) < 0)
|
||||||
|
xo_err(1, "kevent");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct inotify_event *iev, *iev1;
|
||||||
|
struct kevent kev;
|
||||||
|
size_t ievsz;
|
||||||
|
int ifd, kq;
|
||||||
|
|
||||||
|
argc = xo_parse_args(argc, argv);
|
||||||
|
if (argc < 2)
|
||||||
|
usage();
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
|
||||||
|
ifd = inotify_init1(IN_NONBLOCK);
|
||||||
|
if (ifd < 0)
|
||||||
|
xo_err(1, "inotify");
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
int wd;
|
||||||
|
|
||||||
|
wd = inotify_add_watch(ifd, argv[i], IN_ALL_EVENTS);
|
||||||
|
if (wd < 0)
|
||||||
|
xo_err(1, "inotify_add_watch(%s)", argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
xo_set_version("1");
|
||||||
|
xo_open_list("events");
|
||||||
|
|
||||||
|
kq = kqueue();
|
||||||
|
if (kq < 0)
|
||||||
|
xo_err(1, "kqueue");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle signals in the event loop so that we can close the xo list.
|
||||||
|
*/
|
||||||
|
set_handler(kq, SIGINT);
|
||||||
|
set_handler(kq, SIGTERM);
|
||||||
|
set_handler(kq, SIGHUP);
|
||||||
|
set_handler(kq, SIGQUIT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Monitor the inotify descriptor for events.
|
||||||
|
*/
|
||||||
|
EV_SET(&kev, ifd, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
||||||
|
if (kevent(kq, &kev, 1, NULL, 0, NULL) < 0)
|
||||||
|
xo_err(1, "kevent");
|
||||||
|
|
||||||
|
ievsz = sizeof(*iev) + NAME_MAX + 1;
|
||||||
|
iev = malloc(ievsz);
|
||||||
|
if (iev == NULL)
|
||||||
|
err(1, "malloc");
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
ssize_t n;
|
||||||
|
const char *ev;
|
||||||
|
|
||||||
|
if (kevent(kq, NULL, 0, &kev, 1, NULL) < 0)
|
||||||
|
xo_err(1, "kevent");
|
||||||
|
if (kev.filter == EVFILT_SIGNAL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
n = read(ifd, iev, ievsz);
|
||||||
|
if (n < 0)
|
||||||
|
xo_err(1, "read");
|
||||||
|
assert(n >= (ssize_t)sizeof(*iev));
|
||||||
|
|
||||||
|
for (iev1 = iev; n > 0;) {
|
||||||
|
assert(n >= (ssize_t)sizeof(*iev1));
|
||||||
|
|
||||||
|
ev = ev2str(iev1->mask);
|
||||||
|
xo_open_instance("event");
|
||||||
|
xo_emit("{:wd/%3d} {:event/%16s} {:name/%s}\n",
|
||||||
|
iev1->wd, ev, iev1->name);
|
||||||
|
xo_close_instance("event");
|
||||||
|
|
||||||
|
n -= sizeof(*iev1) + iev1->len;
|
||||||
|
iev1 = (struct inotify_event *)(void *)
|
||||||
|
((char *)iev1 + sizeof(*iev1) + iev1->len);
|
||||||
|
}
|
||||||
|
(void)xo_flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
xo_close_list("events");
|
||||||
|
|
||||||
|
if (xo_finish() < 0)
|
||||||
|
xo_err(1, "stdout");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user