1cb5fe245SEnji Cooper /*
2cb5fe245SEnji Cooper * Copyright (c) 2009 Mark Heily <mark@heily.com>
3cb5fe245SEnji Cooper *
4cb5fe245SEnji Cooper * Permission to use, copy, modify, and distribute this software for any
5cb5fe245SEnji Cooper * purpose with or without fee is hereby granted, provided that the above
6cb5fe245SEnji Cooper * copyright notice and this permission notice appear in all copies.
7cb5fe245SEnji Cooper *
8cb5fe245SEnji Cooper * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9cb5fe245SEnji Cooper * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10cb5fe245SEnji Cooper * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11cb5fe245SEnji Cooper * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12cb5fe245SEnji Cooper * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13cb5fe245SEnji Cooper * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14cb5fe245SEnji Cooper * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15cb5fe245SEnji Cooper */
16cb5fe245SEnji Cooper
17cb5fe245SEnji Cooper #include <sys/types.h>
18cb5fe245SEnji Cooper
19cb5fe245SEnji Cooper #include "config.h"
20cb5fe245SEnji Cooper #include "common.h"
21cb5fe245SEnji Cooper
22cb5fe245SEnji Cooper int kqfd;
23c9c283bdSAlex Richardson static char *cur_test_id = NULL;
24c9c283bdSAlex Richardson static int testnum = 1;
25cb5fe245SEnji Cooper
26cb5fe245SEnji Cooper /* Checks if any events are pending, which is an error. */
27cb5fe245SEnji Cooper void
_test_no_kevents(const char * file,int line)28*c728c56cSMark Johnston _test_no_kevents(const char *file, int line)
29cb5fe245SEnji Cooper {
30cb5fe245SEnji Cooper int nfds;
31cb5fe245SEnji Cooper struct timespec timeo;
32cb5fe245SEnji Cooper struct kevent kev;
3353e992cfSDavid Bright char *kev_str;
34cb5fe245SEnji Cooper
35cb5fe245SEnji Cooper puts("confirming that there are no events pending");
36cb5fe245SEnji Cooper memset(&timeo, 0, sizeof(timeo));
37cb5fe245SEnji Cooper nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo);
38cb5fe245SEnji Cooper if (nfds != 0) {
39*c728c56cSMark Johnston printf("\n[%s:%d]: Unexpected event:", file, line);
4053e992cfSDavid Bright kev_str = kevent_to_str(&kev);
4153e992cfSDavid Bright puts(kev_str);
4253e992cfSDavid Bright free(kev_str);
43cb5fe245SEnji Cooper errx(1, "%d event(s) pending, but none expected:", nfds);
44cb5fe245SEnji Cooper }
45cb5fe245SEnji Cooper }
46cb5fe245SEnji Cooper
4795c05062SDavid Bright /* Checks if any events are pending, which is an error. Do not print
4895c05062SDavid Bright * out anything unless events are found.
4995c05062SDavid Bright */
5095c05062SDavid Bright void
test_no_kevents_quietly(void)5195c05062SDavid Bright test_no_kevents_quietly(void)
5295c05062SDavid Bright {
5395c05062SDavid Bright int nfds;
5495c05062SDavid Bright struct timespec timeo;
5595c05062SDavid Bright struct kevent kev;
5653e992cfSDavid Bright char *kev_str;
5795c05062SDavid Bright
5895c05062SDavid Bright memset(&timeo, 0, sizeof(timeo));
5995c05062SDavid Bright nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo);
6095c05062SDavid Bright if (nfds != 0) {
6195c05062SDavid Bright puts("\nUnexpected event:");
6253e992cfSDavid Bright kev_str = kevent_to_str(&kev);
6353e992cfSDavid Bright puts(kev_str);
6453e992cfSDavid Bright free(kev_str);
6595c05062SDavid Bright errx(1, "%d event(s) pending, but none expected:", nfds);
6695c05062SDavid Bright }
6795c05062SDavid Bright }
6895c05062SDavid Bright
69cb5fe245SEnji Cooper /* Retrieve a single kevent */
70cb5fe245SEnji Cooper struct kevent *
kevent_get(int fd)71c9c283bdSAlex Richardson kevent_get(int fd)
72cb5fe245SEnji Cooper {
73cb5fe245SEnji Cooper int nfds;
74cb5fe245SEnji Cooper struct kevent *kev;
75cb5fe245SEnji Cooper
76cb5fe245SEnji Cooper if ((kev = calloc(1, sizeof(*kev))) == NULL)
77cb5fe245SEnji Cooper err(1, "out of memory");
78cb5fe245SEnji Cooper
79c9c283bdSAlex Richardson nfds = kevent(fd, NULL, 0, kev, 1, NULL);
80cb5fe245SEnji Cooper if (nfds < 1)
81cb5fe245SEnji Cooper err(1, "kevent(2)");
82cb5fe245SEnji Cooper
83cb5fe245SEnji Cooper return (kev);
84cb5fe245SEnji Cooper }
85cb5fe245SEnji Cooper
86cb5fe245SEnji Cooper /* Retrieve a single kevent, specifying a maximum time to wait for it. */
87cb5fe245SEnji Cooper struct kevent *
kevent_get_timeout(int fd,int seconds)88c9c283bdSAlex Richardson kevent_get_timeout(int fd, int seconds)
89cb5fe245SEnji Cooper {
90cb5fe245SEnji Cooper int nfds;
91cb5fe245SEnji Cooper struct kevent *kev;
92cb5fe245SEnji Cooper struct timespec timeout = {seconds, 0};
93cb5fe245SEnji Cooper
94cb5fe245SEnji Cooper if ((kev = calloc(1, sizeof(*kev))) == NULL)
95cb5fe245SEnji Cooper err(1, "out of memory");
96cb5fe245SEnji Cooper
97c9c283bdSAlex Richardson nfds = kevent(fd, NULL, 0, kev, 1, &timeout);
98cb5fe245SEnji Cooper if (nfds < 0) {
99cb5fe245SEnji Cooper err(1, "kevent(2)");
100cb5fe245SEnji Cooper } else if (nfds == 0) {
101cb5fe245SEnji Cooper free(kev);
102cb5fe245SEnji Cooper kev = NULL;
103cb5fe245SEnji Cooper }
104cb5fe245SEnji Cooper
105cb5fe245SEnji Cooper return (kev);
106cb5fe245SEnji Cooper }
107cb5fe245SEnji Cooper
108c9c283bdSAlex Richardson static char *
kevent_fflags_dump(struct kevent * kev)109cb5fe245SEnji Cooper kevent_fflags_dump(struct kevent *kev)
110cb5fe245SEnji Cooper {
111cb5fe245SEnji Cooper char *buf;
112cb5fe245SEnji Cooper
113cb5fe245SEnji Cooper #define KEVFFL_DUMP(attrib) \
114cb5fe245SEnji Cooper if (kev->fflags & attrib) \
115cb5fe245SEnji Cooper strncat(buf, #attrib" ", 64);
116cb5fe245SEnji Cooper
117cb5fe245SEnji Cooper if ((buf = calloc(1, 1024)) == NULL)
118cb5fe245SEnji Cooper abort();
119cb5fe245SEnji Cooper
120cb5fe245SEnji Cooper /* Not every filter has meaningful fflags */
121cb5fe245SEnji Cooper if (kev->filter == EVFILT_PROC) {
122cb5fe245SEnji Cooper snprintf(buf, 1024, "fflags = %x (", kev->fflags);
123cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_EXIT);
124cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_FORK);
125cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_EXEC);
126cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_CHILD);
127cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_TRACKERR);
128cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_TRACK);
129cb5fe245SEnji Cooper buf[strlen(buf) - 1] = ')';
130cb5fe245SEnji Cooper } else if (kev->filter == EVFILT_PROCDESC) {
131cb5fe245SEnji Cooper snprintf(buf, 1024, "fflags = %x (", kev->fflags);
132cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_EXIT);
133cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_FORK);
134cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_EXEC);
135cb5fe245SEnji Cooper buf[strlen(buf) - 1] = ')';
136cb5fe245SEnji Cooper } else if (kev->filter == EVFILT_VNODE) {
137cb5fe245SEnji Cooper snprintf(buf, 1024, "fflags = %x (", kev->fflags);
138cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_DELETE);
139cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_WRITE);
140cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_EXTEND);
141cb5fe245SEnji Cooper #if HAVE_NOTE_TRUNCATE
142cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_TRUNCATE);
143cb5fe245SEnji Cooper #endif
144cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_ATTRIB);
145cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_LINK);
146cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_RENAME);
147cb5fe245SEnji Cooper #if HAVE_NOTE_REVOKE
148cb5fe245SEnji Cooper KEVFFL_DUMP(NOTE_REVOKE);
149cb5fe245SEnji Cooper #endif
150cb5fe245SEnji Cooper buf[strlen(buf) - 1] = ')';
151cb5fe245SEnji Cooper } else {
152cb5fe245SEnji Cooper snprintf(buf, 1024, "fflags = %x", kev->fflags);
153cb5fe245SEnji Cooper }
154cb5fe245SEnji Cooper
155cb5fe245SEnji Cooper return (buf);
156cb5fe245SEnji Cooper }
157cb5fe245SEnji Cooper
158c9c283bdSAlex Richardson static char *
kevent_flags_dump(struct kevent * kev)159cb5fe245SEnji Cooper kevent_flags_dump(struct kevent *kev)
160cb5fe245SEnji Cooper {
161cb5fe245SEnji Cooper char *buf;
162cb5fe245SEnji Cooper
163cb5fe245SEnji Cooper #define KEVFL_DUMP(attrib) \
164cb5fe245SEnji Cooper if (kev->flags & attrib) \
165cb5fe245SEnji Cooper strncat(buf, #attrib" ", 64);
166cb5fe245SEnji Cooper
167cb5fe245SEnji Cooper if ((buf = calloc(1, 1024)) == NULL)
168cb5fe245SEnji Cooper abort();
169cb5fe245SEnji Cooper
170cb5fe245SEnji Cooper snprintf(buf, 1024, "flags = %d (", kev->flags);
171cb5fe245SEnji Cooper KEVFL_DUMP(EV_ADD);
172cb5fe245SEnji Cooper KEVFL_DUMP(EV_ENABLE);
173cb5fe245SEnji Cooper KEVFL_DUMP(EV_DISABLE);
174cb5fe245SEnji Cooper KEVFL_DUMP(EV_DELETE);
175cb5fe245SEnji Cooper KEVFL_DUMP(EV_ONESHOT);
176cb5fe245SEnji Cooper KEVFL_DUMP(EV_CLEAR);
177cb5fe245SEnji Cooper KEVFL_DUMP(EV_EOF);
178cb5fe245SEnji Cooper KEVFL_DUMP(EV_ERROR);
179cb5fe245SEnji Cooper #if HAVE_EV_DISPATCH
180cb5fe245SEnji Cooper KEVFL_DUMP(EV_DISPATCH);
181cb5fe245SEnji Cooper #endif
182cb5fe245SEnji Cooper #if HAVE_EV_RECEIPT
183cb5fe245SEnji Cooper KEVFL_DUMP(EV_RECEIPT);
184cb5fe245SEnji Cooper #endif
185cb5fe245SEnji Cooper buf[strlen(buf) - 1] = ')';
186cb5fe245SEnji Cooper
187cb5fe245SEnji Cooper return (buf);
188cb5fe245SEnji Cooper }
189cb5fe245SEnji Cooper
190cb5fe245SEnji Cooper /* Copied from ../kevent.c kevent_dump() and improved */
19153e992cfSDavid Bright char *
kevent_to_str(struct kevent * kev)192cb5fe245SEnji Cooper kevent_to_str(struct kevent *kev)
193cb5fe245SEnji Cooper {
194cb5fe245SEnji Cooper char buf[512];
19553e992cfSDavid Bright char *flags_str = kevent_flags_dump(kev);
19653e992cfSDavid Bright char *fflags_str = kevent_fflags_dump(kev);
197cb5fe245SEnji Cooper
198cb5fe245SEnji Cooper snprintf(&buf[0], sizeof(buf),
1992b34e843SKonstantin Belousov "[ident=%ju, filter=%d, %s, %s, data=%jd, udata=%p, "
2002b34e843SKonstantin Belousov "ext=[%jx %jx %jx %jx]",
2012b34e843SKonstantin Belousov (uintmax_t) kev->ident,
202cb5fe245SEnji Cooper kev->filter,
20353e992cfSDavid Bright flags_str,
20453e992cfSDavid Bright fflags_str,
2052b34e843SKonstantin Belousov (uintmax_t)kev->data,
2062b34e843SKonstantin Belousov kev->udata,
2072b34e843SKonstantin Belousov (uintmax_t)kev->ext[0],
2082b34e843SKonstantin Belousov (uintmax_t)kev->ext[1],
2092b34e843SKonstantin Belousov (uintmax_t)kev->ext[2],
2102b34e843SKonstantin Belousov (uintmax_t)kev->ext[3]);
211cb5fe245SEnji Cooper
21253e992cfSDavid Bright free(flags_str);
21353e992cfSDavid Bright free(fflags_str);
21453e992cfSDavid Bright
215cb5fe245SEnji Cooper return (strdup(buf));
216cb5fe245SEnji Cooper }
217cb5fe245SEnji Cooper
218cb5fe245SEnji Cooper void
kevent_add(int fd,struct kevent * kev,uintptr_t ident,short filter,u_short flags,u_int fflags,intptr_t data,void * udata)219c9c283bdSAlex Richardson kevent_add(int fd, struct kevent *kev,
220cb5fe245SEnji Cooper uintptr_t ident,
221cb5fe245SEnji Cooper short filter,
222cb5fe245SEnji Cooper u_short flags,
223cb5fe245SEnji Cooper u_int fflags,
224cb5fe245SEnji Cooper intptr_t data,
225cb5fe245SEnji Cooper void *udata)
226cb5fe245SEnji Cooper {
22745bed28cSDavid Bright char *kev_str;
22845bed28cSDavid Bright
229c9c283bdSAlex Richardson EV_SET(kev, ident, filter, flags, fflags, data, udata);
230c9c283bdSAlex Richardson if (kevent(fd, kev, 1, NULL, 0, NULL) < 0) {
23145bed28cSDavid Bright kev_str = kevent_to_str(kev);
232cb5fe245SEnji Cooper printf("Unable to add the following kevent:\n%s\n",
23345bed28cSDavid Bright kev_str);
23445bed28cSDavid Bright free(kev_str);
235cb5fe245SEnji Cooper err(1, "kevent(): %s", strerror(errno));
236cb5fe245SEnji Cooper }
237cb5fe245SEnji Cooper }
238cb5fe245SEnji Cooper
239cb5fe245SEnji Cooper void
_kevent_cmp(struct kevent * k1,struct kevent * k2,const char * file,int line)240*c728c56cSMark Johnston _kevent_cmp(struct kevent *k1, struct kevent *k2, const char *file, int line)
241cb5fe245SEnji Cooper {
24245bed28cSDavid Bright char *kev1_str;
24345bed28cSDavid Bright char *kev2_str;
24445bed28cSDavid Bright
245cb5fe245SEnji Cooper /* XXX-
246cb5fe245SEnji Cooper Workaround for inconsistent implementation of kevent(2)
247cb5fe245SEnji Cooper */
248cb5fe245SEnji Cooper #ifdef __FreeBSD__
249cb5fe245SEnji Cooper if (k1->flags & EV_ADD)
250cb5fe245SEnji Cooper k2->flags |= EV_ADD;
251cb5fe245SEnji Cooper #endif
2522b34e843SKonstantin Belousov if (k1->ident != k2->ident || k1->filter != k2->filter ||
2532b34e843SKonstantin Belousov k1->flags != k2->flags || k1->fflags != k2->fflags ||
2542b34e843SKonstantin Belousov k1->data != k2->data || k1->udata != k2->udata ||
2552b34e843SKonstantin Belousov k1->ext[0] != k2->ext[0] || k1->ext[1] != k2->ext[1] ||
2562b34e843SKonstantin Belousov k1->ext[0] != k2->ext[2] || k1->ext[0] != k2->ext[3]) {
25745bed28cSDavid Bright kev1_str = kevent_to_str(k1);
25845bed28cSDavid Bright kev2_str = kevent_to_str(k2);
259*c728c56cSMark Johnston printf("[%s:%d]: kevent_cmp: mismatch:\n %s !=\n %s\n",
260*c728c56cSMark Johnston file, line, kev1_str, kev2_str);
26145bed28cSDavid Bright free(kev1_str);
26245bed28cSDavid Bright free(kev2_str);
263cb5fe245SEnji Cooper abort();
264cb5fe245SEnji Cooper }
265cb5fe245SEnji Cooper }
266cb5fe245SEnji Cooper
267cb5fe245SEnji Cooper void
test_begin(const char * func)268cb5fe245SEnji Cooper test_begin(const char *func)
269cb5fe245SEnji Cooper {
270cb5fe245SEnji Cooper if (cur_test_id)
271cb5fe245SEnji Cooper free(cur_test_id);
272cb5fe245SEnji Cooper cur_test_id = strdup(func);
273cb5fe245SEnji Cooper if (!cur_test_id)
274cb5fe245SEnji Cooper err(1, "strdup failed");
275cb5fe245SEnji Cooper
276cb5fe245SEnji Cooper printf("\n\nTest %d: %s\n", testnum++, func);
277cb5fe245SEnji Cooper }
278cb5fe245SEnji Cooper
279cb5fe245SEnji Cooper void
success(void)280cb5fe245SEnji Cooper success(void)
281cb5fe245SEnji Cooper {
282cb5fe245SEnji Cooper printf("%-70s %s\n", cur_test_id, "passed");
283cb5fe245SEnji Cooper free(cur_test_id);
284cb5fe245SEnji Cooper cur_test_id = NULL;
285cb5fe245SEnji Cooper }
286cb5fe245SEnji Cooper
287c9c283bdSAlex Richardson static void
test_kqueue(void)288cb5fe245SEnji Cooper test_kqueue(void)
289cb5fe245SEnji Cooper {
290cb5fe245SEnji Cooper test_begin("kqueue()");
291cb5fe245SEnji Cooper if ((kqfd = kqueue()) < 0)
292cb5fe245SEnji Cooper err(1, "kqueue()");
293cb5fe245SEnji Cooper test_no_kevents();
294cb5fe245SEnji Cooper success();
295cb5fe245SEnji Cooper }
296cb5fe245SEnji Cooper
297c9c283bdSAlex Richardson static void
test_kqueue_close(void)298cb5fe245SEnji Cooper test_kqueue_close(void)
299cb5fe245SEnji Cooper {
300cb5fe245SEnji Cooper test_begin("close(kq)");
301cb5fe245SEnji Cooper if (close(kqfd) < 0)
302cb5fe245SEnji Cooper err(1, "close()");
303cb5fe245SEnji Cooper success();
304cb5fe245SEnji Cooper }
305cb5fe245SEnji Cooper
306cb5fe245SEnji Cooper int
main(int argc,char ** argv)307cb5fe245SEnji Cooper main(int argc, char **argv)
308cb5fe245SEnji Cooper {
309cb5fe245SEnji Cooper int test_proc = 1;
310cb5fe245SEnji Cooper int test_socket = 1;
311cb5fe245SEnji Cooper int test_signal = 1;
312cb5fe245SEnji Cooper int test_vnode = 1;
313cb5fe245SEnji Cooper int test_timer = 1;
314cb5fe245SEnji Cooper #ifdef __FreeBSD__
315cb5fe245SEnji Cooper int test_user = 1;
316cb5fe245SEnji Cooper #else
317cb5fe245SEnji Cooper /* XXX-FIXME temporary */
318cb5fe245SEnji Cooper int test_user = 0;
319cb5fe245SEnji Cooper #endif
320cb5fe245SEnji Cooper
321cb5fe245SEnji Cooper while (argc) {
322cb5fe245SEnji Cooper if (strcmp(argv[0], "--no-proc") == 0)
323cb5fe245SEnji Cooper test_proc = 0;
324cb5fe245SEnji Cooper if (strcmp(argv[0], "--no-socket") == 0)
325cb5fe245SEnji Cooper test_socket = 0;
326cb5fe245SEnji Cooper if (strcmp(argv[0], "--no-timer") == 0)
327cb5fe245SEnji Cooper test_timer = 0;
328cb5fe245SEnji Cooper if (strcmp(argv[0], "--no-signal") == 0)
329cb5fe245SEnji Cooper test_signal = 0;
330cb5fe245SEnji Cooper if (strcmp(argv[0], "--no-vnode") == 0)
331cb5fe245SEnji Cooper test_vnode = 0;
332cb5fe245SEnji Cooper if (strcmp(argv[0], "--no-user") == 0)
333cb5fe245SEnji Cooper test_user = 0;
334cb5fe245SEnji Cooper argv++;
335cb5fe245SEnji Cooper argc--;
336cb5fe245SEnji Cooper }
337cb5fe245SEnji Cooper
338cb5fe245SEnji Cooper /*
339cb5fe245SEnji Cooper * Some tests fork. If output is fully buffered,
340cb5fe245SEnji Cooper * the children inherit some buffered data and flush
341cb5fe245SEnji Cooper * it when they exit, causing some data to be printed twice.
342cb5fe245SEnji Cooper * Use line buffering to avoid this problem.
343cb5fe245SEnji Cooper */
344cb5fe245SEnji Cooper setlinebuf(stdout);
345cb5fe245SEnji Cooper setlinebuf(stderr);
346cb5fe245SEnji Cooper
347cb5fe245SEnji Cooper test_kqueue();
348cb5fe245SEnji Cooper test_kqueue_close();
349cb5fe245SEnji Cooper
350cb5fe245SEnji Cooper if (test_socket)
351cb5fe245SEnji Cooper test_evfilt_read();
352cb5fe245SEnji Cooper if (test_signal)
353cb5fe245SEnji Cooper test_evfilt_signal();
354cb5fe245SEnji Cooper if (test_vnode)
355cb5fe245SEnji Cooper test_evfilt_vnode();
356cb5fe245SEnji Cooper #if HAVE_EVFILT_USER
357cb5fe245SEnji Cooper if (test_user)
358cb5fe245SEnji Cooper test_evfilt_user();
359cb5fe245SEnji Cooper #endif
360cb5fe245SEnji Cooper if (test_timer)
361cb5fe245SEnji Cooper test_evfilt_timer();
362cb5fe245SEnji Cooper if (test_proc)
363cb5fe245SEnji Cooper test_evfilt_proc();
364cb5fe245SEnji Cooper
365cb5fe245SEnji Cooper printf("\n---\n"
366cb5fe245SEnji Cooper "+OK All %d tests completed.\n", testnum - 1);
367cb5fe245SEnji Cooper return (0);
368cb5fe245SEnji Cooper }
369