h_nullmnt.c revision 1.1
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.1Spgoyette * External 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.1Spgoyette	int realfile, nullfile;
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.1Spgoyette	realfile = open(argv[1], O_RDONLY);
431.1Spgoyette	if (realfile == -1)
441.1Spgoyette		err(EXIT_FAILURE, "failed to open realfile %s",
451.1Spgoyette		    argv[1]);
461.1Spgoyette
471.1Spgoyette	nullfile = open(argv[2], O_WRONLY, O_APPEND);
481.1Spgoyette	if (nullfile == -1)
491.1Spgoyette		err(EXIT_FAILURE, "failed to open nullfile %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.1Spgoyette	EV_SET(&eventlist, realfile,
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.1Spgoyette		    realfile);
641.1Spgoyette
651.1Spgoyette	rsize = read(realfile, &inbuf, sizeof(inbuf));
661.1Spgoyette	if (rsize)
671.1Spgoyette		errx(EXIT_FAILURE, "Ooops we got %d bytes of data!\n", rsize);
681.1Spgoyette
691.1Spgoyette	write(nullfile, &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