2009-11-05 02:16:22 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2009 Mark Heily <mark@heily.com>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
|
2010-02-03 02:52:44 +00:00
|
|
|
/* Create an empty file */
|
|
|
|
static void
|
2011-05-25 02:10:36 +00:00
|
|
|
testfile_create(const char *path)
|
2010-02-03 02:52:44 +00:00
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
if ((fd = open(path, O_CREAT | O_WRONLY, 0600)) < 0)
|
2010-02-07 05:03:21 +00:00
|
|
|
die("open");
|
2010-02-03 02:52:44 +00:00
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2011-05-25 02:10:36 +00:00
|
|
|
testfile_touch(const char *path)
|
2010-02-03 02:52:44 +00:00
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
snprintf(&buf[0], sizeof(buf), "touch %s", path);
|
2010-02-03 02:52:44 +00:00
|
|
|
if (system(buf) != 0)
|
2010-02-07 05:03:21 +00:00
|
|
|
die("system");
|
2010-02-03 02:52:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2011-05-25 02:10:36 +00:00
|
|
|
testfile_write(const char *path)
|
2010-02-03 02:52:44 +00:00
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
snprintf(&buf[0], sizeof(buf), "echo hi >> %s", path);
|
2010-02-03 02:52:44 +00:00
|
|
|
if (system(buf) != 0)
|
2010-02-07 05:03:21 +00:00
|
|
|
die("system");
|
2010-02-03 02:52:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2011-05-25 02:10:36 +00:00
|
|
|
testfile_rename(const char *path, int step)
|
2010-02-03 02:52:44 +00:00
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
snprintf(&buf[0], sizeof(buf), "%s.tmp", path);
|
2010-02-03 02:52:44 +00:00
|
|
|
/* XXX-FIXME use of 'step' conceals a major memory corruption
|
|
|
|
when the file is renamed twice.
|
|
|
|
To replicate, remove "if step" conditional so
|
|
|
|
two renames occur in this function.
|
|
|
|
*/
|
|
|
|
if (step == 0) {
|
2011-05-25 02:10:36 +00:00
|
|
|
if (rename(path, buf) != 0)
|
2010-02-03 02:52:44 +00:00
|
|
|
err(1,"rename");
|
|
|
|
} else {
|
2011-05-25 02:10:36 +00:00
|
|
|
if (rename(buf, path) != 0)
|
2010-02-03 02:52:44 +00:00
|
|
|
err(1,"rename");
|
|
|
|
}
|
|
|
|
}
|
2009-11-05 02:16:22 +00:00
|
|
|
|
|
|
|
void
|
2011-05-25 02:10:36 +00:00
|
|
|
test_kevent_vnode_add(struct test_context *ctx)
|
2009-11-05 02:16:22 +00:00
|
|
|
{
|
|
|
|
struct kevent kev;
|
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
testfile_create(ctx->testfile);
|
2010-02-03 02:52:44 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
ctx->vnode_fd = open(ctx->testfile, O_RDWR);
|
|
|
|
if (ctx->vnode_fd < 0)
|
|
|
|
err(1, "open of %s", ctx->testfile);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD,
|
2009-11-05 02:16:22 +00:00
|
|
|
NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME | NOTE_DELETE, 0, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-05-25 02:10:36 +00:00
|
|
|
test_kevent_vnode_note_delete(struct test_context *ctx)
|
2009-11-05 02:16:22 +00:00
|
|
|
{
|
2011-05-25 02:10:36 +00:00
|
|
|
struct kevent kev, ret;
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
if (unlink(ctx->testfile) < 0)
|
2010-02-07 05:03:21 +00:00
|
|
|
die("unlink");
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_get(&ret, ctx->kqfd);
|
|
|
|
kevent_cmp(&kev, &ret);
|
2009-11-05 02:16:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-05-25 02:10:36 +00:00
|
|
|
test_kevent_vnode_note_write(struct test_context *ctx)
|
2009-11-05 02:16:22 +00:00
|
|
|
{
|
2011-05-25 02:10:36 +00:00
|
|
|
struct kevent kev, ret;
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_WRITE, 0, NULL);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
testfile_write(ctx->testfile);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
|
|
|
/* BSD kqueue adds NOTE_EXTEND even though it was not requested */
|
|
|
|
/* BSD kqueue removes EV_ENABLE */
|
|
|
|
kev.flags &= ~EV_ENABLE; // XXX-FIXME compatibility issue
|
|
|
|
kev.fflags |= NOTE_EXTEND; // XXX-FIXME compatibility issue
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_get(&ret, ctx->kqfd);
|
|
|
|
kevent_cmp(&kev, &ret);
|
2009-11-05 02:16:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-05-25 02:10:36 +00:00
|
|
|
test_kevent_vnode_note_attrib(struct test_context *ctx)
|
2009-11-05 02:16:22 +00:00
|
|
|
{
|
|
|
|
struct kevent kev;
|
|
|
|
int nfds;
|
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
testfile_touch(ctx->testfile);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL);
|
2009-11-05 02:16:22 +00:00
|
|
|
if (nfds < 1)
|
2010-02-07 05:03:21 +00:00
|
|
|
die("kevent");
|
2011-05-25 02:10:36 +00:00
|
|
|
if (kev.ident != ctx->vnode_fd ||
|
2009-11-05 02:16:22 +00:00
|
|
|
kev.filter != EVFILT_VNODE ||
|
|
|
|
kev.fflags != NOTE_ATTRIB)
|
|
|
|
err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
|
|
|
|
test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-05-25 02:10:36 +00:00
|
|
|
test_kevent_vnode_note_rename(struct test_context *ctx)
|
2009-11-05 02:16:22 +00:00
|
|
|
{
|
|
|
|
struct kevent kev;
|
|
|
|
int nfds;
|
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_RENAME, 0, NULL);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
testfile_rename(ctx->testfile, 0);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL);
|
2009-11-05 02:16:22 +00:00
|
|
|
if (nfds < 1)
|
2010-02-07 05:03:21 +00:00
|
|
|
die("kevent");
|
2011-05-25 02:10:36 +00:00
|
|
|
if (kev.ident != ctx->vnode_fd ||
|
2009-11-05 02:16:22 +00:00
|
|
|
kev.filter != EVFILT_VNODE ||
|
|
|
|
kev.fflags != NOTE_RENAME)
|
|
|
|
err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
|
|
|
|
test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
|
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
testfile_rename(ctx->testfile, 1);
|
2010-02-03 02:52:44 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
test_no_kevents(ctx->kqfd);
|
2009-11-05 02:16:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-05-25 02:10:36 +00:00
|
|
|
test_kevent_vnode_del(struct test_context *ctx)
|
2009-11-05 02:16:22 +00:00
|
|
|
{
|
|
|
|
struct kevent kev;
|
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
|
2009-11-05 02:16:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-05-25 02:10:36 +00:00
|
|
|
test_kevent_vnode_disable_and_enable(struct test_context *ctx)
|
2009-11-05 02:16:22 +00:00
|
|
|
{
|
|
|
|
struct kevent kev;
|
|
|
|
int nfds;
|
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
test_no_kevents(ctx->kqfd);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
|
|
|
/* Add the watch and immediately disable it */
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
|
2009-11-05 02:16:22 +00:00
|
|
|
kev.flags = EV_DISABLE;
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_update(ctx->kqfd, &kev);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
|
|
|
/* Confirm that the watch is disabled */
|
2011-05-25 02:10:36 +00:00
|
|
|
testfile_touch(ctx->testfile);
|
|
|
|
test_no_kevents(ctx->kqfd);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
|
|
|
/* Re-enable and check again */
|
|
|
|
kev.flags = EV_ENABLE;
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_update(ctx->kqfd, &kev);
|
|
|
|
testfile_touch(ctx->testfile);
|
|
|
|
nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL);
|
2009-11-05 02:16:22 +00:00
|
|
|
if (nfds < 1)
|
2010-02-07 05:03:21 +00:00
|
|
|
die("kevent");
|
2011-05-25 02:10:36 +00:00
|
|
|
if (kev.ident != ctx->vnode_fd ||
|
2009-11-05 02:16:22 +00:00
|
|
|
kev.filter != EVFILT_VNODE ||
|
|
|
|
kev.fflags != NOTE_ATTRIB)
|
|
|
|
err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
|
|
|
|
test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
|
|
|
|
}
|
|
|
|
|
2013-01-06 17:28:12 +00:00
|
|
|
#ifdef EV_DISPATCH
|
2009-11-05 02:16:22 +00:00
|
|
|
void
|
2011-05-25 02:10:36 +00:00
|
|
|
test_kevent_vnode_dispatch(struct test_context *ctx)
|
2009-11-05 02:16:22 +00:00
|
|
|
{
|
2011-05-25 02:10:36 +00:00
|
|
|
struct kevent kev, ret;
|
2009-11-05 02:16:22 +00:00
|
|
|
int nfds;
|
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
test_no_kevents(ctx->kqfd);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_DISPATCH, NOTE_ATTRIB, 0, NULL);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
testfile_touch(ctx->testfile);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL);
|
2009-11-05 02:16:22 +00:00
|
|
|
if (nfds < 1)
|
2010-02-07 05:03:21 +00:00
|
|
|
die("kevent");
|
2011-05-25 02:10:36 +00:00
|
|
|
if (kev.ident != ctx->vnode_fd ||
|
2009-11-05 02:16:22 +00:00
|
|
|
kev.filter != EVFILT_VNODE ||
|
|
|
|
kev.fflags != NOTE_ATTRIB)
|
|
|
|
err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
|
|
|
|
test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
|
|
|
|
|
|
|
|
/* Confirm that the watch is disabled automatically */
|
2011-05-25 02:10:36 +00:00
|
|
|
testfile_touch(ctx->testfile);
|
|
|
|
test_no_kevents(ctx->kqfd);
|
2009-11-05 02:16:22 +00:00
|
|
|
|
2010-07-24 01:04:27 +00:00
|
|
|
/* Re-enable the kevent */
|
|
|
|
/* FIXME- is EV_DISPATCH needed when rearming ? */
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ENABLE | EV_DISPATCH, 0, 0, NULL);
|
2010-07-24 01:04:27 +00:00
|
|
|
kev.flags = EV_ADD | EV_DISPATCH; /* FIXME: may not be portable */
|
|
|
|
kev.fflags = NOTE_ATTRIB;
|
2011-05-25 02:10:36 +00:00
|
|
|
testfile_touch(ctx->testfile);
|
|
|
|
kevent_get(&ret, ctx->kqfd);
|
|
|
|
kevent_cmp(&kev, &ret);
|
|
|
|
test_no_kevents(ctx->kqfd);
|
2010-07-24 01:04:27 +00:00
|
|
|
|
2009-11-05 02:16:22 +00:00
|
|
|
/* Delete the watch */
|
2011-05-25 02:10:36 +00:00
|
|
|
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_DELETE, NOTE_ATTRIB, 0, NULL);
|
2009-11-05 02:16:22 +00:00
|
|
|
}
|
2013-01-06 17:28:12 +00:00
|
|
|
#endif /* EV_DISPATCH */
|
2009-11-05 02:16:22 +00:00
|
|
|
|
|
|
|
void
|
2011-05-25 02:10:36 +00:00
|
|
|
test_evfilt_vnode(struct test_context *ctx)
|
2009-11-05 02:16:22 +00:00
|
|
|
{
|
2011-01-08 21:49:29 +00:00
|
|
|
#if (defined(__sun) && !defined(HAVE_PORT_SOURCE_FILE))
|
|
|
|
puts("**NOTE** EVFILT_VNODE is not supported on this version of Solaris");
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
|
2012-11-26 03:59:02 +00:00
|
|
|
char *tmpdir = getenv("TMPDIR");
|
|
|
|
if (tmpdir == NULL)
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
tmpdir = "/data/local/tmp";
|
|
|
|
#else
|
|
|
|
tmpdir = "/tmp";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
snprintf(ctx->testfile, sizeof(ctx->testfile), "%s/kqueue-test%d.tmp",
|
|
|
|
tmpdir, testing_make_uid());
|
2010-02-03 02:52:44 +00:00
|
|
|
|
2011-05-25 02:10:36 +00:00
|
|
|
test(kevent_vnode_add, ctx);
|
|
|
|
test(kevent_vnode_del, ctx);
|
|
|
|
test(kevent_vnode_disable_and_enable, ctx);
|
2013-01-06 17:28:12 +00:00
|
|
|
#ifdef EV_DISPATCH
|
2011-05-25 02:10:36 +00:00
|
|
|
test(kevent_vnode_dispatch, ctx);
|
2009-11-05 02:16:22 +00:00
|
|
|
#endif
|
2011-05-25 02:10:36 +00:00
|
|
|
test(kevent_vnode_note_write, ctx);
|
|
|
|
test(kevent_vnode_note_attrib, ctx);
|
|
|
|
test(kevent_vnode_note_rename, ctx);
|
|
|
|
test(kevent_vnode_note_delete, ctx);
|
2012-11-25 22:31:57 +00:00
|
|
|
/* TODO: test r590 corner case where a descriptor is closed and
|
|
|
|
the associated knote is automatically freed. */
|
2011-05-25 02:10:36 +00:00
|
|
|
unlink(ctx->testfile);
|
2009-11-05 02:16:22 +00:00
|
|
|
}
|