11.1Spgoyette#include <err.h>
21.1Spgoyette#include <fcntl.h>
31.1Spgoyette#include <stdlib.h>
41.1Spgoyette#include <unistd.h>
51.1Spgoyette
61.1Spgoyette#include <sys/event.h>
71.1Spgoyette#include <sys/time.h>
81.1Spgoyette
91.1Spgoyette/*
101.2Spgoyette * External test set-up code is expected to do the equivalent of
111.1Spgoyette *	cd $TOPDIR
121.1Spgoyette *	mkdir realdir
131.1Spgoyette *	mkdir nulldir
141.1Spgoyette *	mount -t null $TOPDIR/realdir $TOPDIR/nulldir
151.1Spgoyette *	rm -f $TOPDIR/realdir/afile
161.1Spgoyette *	touch $TOPDIR/realdir/afile
171.1Spgoyette * then execute this test program:
181.1Spgoyette *	./h_nullmnt $TOPDIR/realdir/afile $TOPDIR/nulldir/afile
191.1Spgoyette *
201.1Spgoyette * The expected result is that the write() to the nullfile will
211.1Spgoyette * queue up a preexisting kevent which will then be detected by
221.1Spgoyette * the (second) call to kevent(); the failure mode is that the
231.1Spgoyette * write()'s extension to the file is not seen, and the kevent
241.1Spgoyette * call times out after 5 seconds.
251.1Spgoyette *
261.1Spgoyette * Clean-up code should undo the null mount and delete everything
271.1Spgoyette * in the test directory.
281.1Spgoyette */
291.1Spgoyette
301.1Spgoyetteint main(int argc, char **argv)
311.1Spgoyette{
321.2Spgoyette	int watch_file, write_file;
331.1Spgoyette	int kq, nev, rsize;
341.1Spgoyette	struct timespec timeout;
351.1Spgoyette	struct kevent eventlist;
361.1Spgoyette	const char outbuf[] = "new\n";
371.1Spgoyette	char inbuf[20];
381.1Spgoyette
391.1Spgoyette	if (argc <= 2)
401.1Spgoyette		errx(EXIT_FAILURE, "insufficient args %d", argc);
411.1Spgoyette
421.2Spgoyette	watch_file = open(argv[1], O_RDONLY);
431.2Spgoyette	if (watch_file == -1)
441.2Spgoyette		err(EXIT_FAILURE, "failed to open watch_file %s",
451.1Spgoyette		    argv[1]);
461.1Spgoyette
471.2Spgoyette	write_file = open(argv[2], O_WRONLY, O_APPEND);
481.2Spgoyette	if (write_file == -1)
491.2Spgoyette		err(EXIT_FAILURE, "failed to open write_file %s",
501.1Spgoyette		    argv[2]);
511.1Spgoyette
521.1Spgoyette	if ((kq = kqueue()) == -1)
531.1Spgoyette		err(EXIT_FAILURE, "Cannot create kqueue");
541.1Spgoyette
551.1Spgoyette	timeout.tv_sec = 5;
561.1Spgoyette	timeout.tv_nsec = 0;
571.1Spgoyette
581.2Spgoyette	EV_SET(&eventlist, watch_file,
591.1Spgoyette	    EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
601.1Spgoyette	    NOTE_WRITE | NOTE_EXTEND, 0, 0);
611.1Spgoyette	if (kevent(kq, &eventlist, 1, NULL, 0, NULL) == -1)
621.1Spgoyette		err(EXIT_FAILURE, "Failed to set eventlist for fd %d",
631.2Spgoyette		    watch_file);
641.1Spgoyette
651.2Spgoyette	rsize = read(watch_file, &inbuf, sizeof(inbuf));
661.1Spgoyette	if (rsize)
671.1Spgoyette		errx(EXIT_FAILURE, "Ooops we got %d bytes of data!\n", rsize);
681.1Spgoyette
691.2Spgoyette	write(write_file, &outbuf, sizeof(outbuf) - 1);
701.1Spgoyette
711.1Spgoyette	nev = kevent(kq, NULL, 0, &eventlist, 1, &timeout);
721.1Spgoyette	if (nev == -1)
731.1Spgoyette		err(EXIT_FAILURE, "Failed to retrieve event");
741.1Spgoyette
751.1Spgoyette	errx((nev == 0) ? EXIT_FAILURE : EXIT_SUCCESS,
761.1Spgoyette	    "Retrieved %d events, first 0x%x", nev, eventlist.flags);
771.1Spgoyette}
78