Exemplo n.º 1
0
/*
 * Wait for file to become accessible and register a kevent to watch it
 */
void
watch_file(int kq, WatchFile *file) {
	struct kevent evSet;
	int i;
	struct timespec delay = { 0, 100 * 1000000 };

	/* wait up to 1 second for file to become available */
	for (i=0; i < 10; i++) {
		#ifdef O_EVTONLY
		file->fd = xopen(file->fn, O_RDONLY|O_EVTONLY);
		#else
		file->fd = xopen(file->fn, O_RDONLY);
		#endif
		if (file->fd == -1) nanosleep(&delay, NULL);
		else break;
	}
	if (file->fd == -1)
		err(1, "cannot open '%s'", file->fn);

	EV_SET(&evSet, file->fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_ALL, 0,
	    file);
	if (xkevent(kq, &evSet, 1, NULL, 0, NULL) == -1) {
		if (errno == ENOSPC)
			errx(1, "Unable to allocate memory for kernel queue."
			    " Please consult"
			    " http://entrproject.org/limits.html");
		else
			err(1, "failed to register VNODE event");
	}
}
Exemplo n.º 2
0
/*
 * Wait for file to become accessible and register a kevent to watch it
 */
void
watch_file(int kq, WatchFile *file) {
	struct kevent evSet;
	int i;
	struct timespec delay = { 0, 100 * 1000000 };

	/* wait up to 1 second for file to become available */
	for (i=0; i < 10; i++) {
		#ifdef O_EVTONLY
		file->fd = xopen(file->fn, O_RDONLY|O_EVTONLY);
		#else
		file->fd = xopen(file->fn, O_RDONLY);
		#endif
		if (file->fd == -1) nanosleep(&delay, NULL);
		else break;
	}
	if (file->fd == -1)
		err(1, "cannot open `%s'", file->fn);

	EV_SET(&evSet, file->fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_ALL, 0,
	    file);
	if (xkevent(kq, &evSet, 1, NULL, 0, NULL) == -1)
		err(1, "failed to register VNODE event");
}
Exemplo n.º 3
0
/*
 * Wait for events to and execute a command. Four major concerns are in play:
 *   leading_edge: Global reference to the first file to have changed
 *   reopen_only : Unlink or rename events which require us to spin while
 *                 waiting for the file to reappear. These must always be
 *                 processed
 *   collate_only: Changes that indicate that more events are likely to occur.
 *                 Watch for more events using a short timeout
 *   do_exec     : Delay execution until all events have been processed. Allow
 *                 the user to edit files while the utility is running without
 *                 any visible side-effects
 *   dir_modified: The number of files changed for a directory under watch
 */
void
watch_loop(int kq, char *argv[]) {
	struct kevent evSet;
	struct kevent evList[32];
	int nev;
	WatchFile *file;
	int i;
	struct timespec evTimeout = { 0, 1000000 };
	int reopen_only = 0;
	int collate_only = 0;
	int do_exec = 0;
	int dir_modified = 0;
	int leading_edge_set = 0;
	struct stat sb;

	leading_edge = files[0]; /* default */
	if (postpone_opt == 0)
		run_utility(argv);

main:
	if ((reopen_only == 1) || (collate_only == 1))
		nev = xkevent(kq, NULL, 0, evList, 32, &evTimeout);
	else {
		nev = xkevent(kq, NULL, 0, evList, 32, NULL);
		dir_modified = 0;
	}
	/* escape for test runner */
	if ((nev == -2) && (collate_only == 0))
		return;

	for (i=0; i<nev; i++) {
		if (evList[i].filter != EVFILT_VNODE)
			continue;
		file = (WatchFile *)evList[i].udata;
		if (file->is_dir == 1)
			dir_modified += compare_dir_contents(file);
		else if (leading_edge_set == 0)
			if ((reopen_only == 0) && (collate_only == 0)) {
				leading_edge = file;
				leading_edge_set = 1;
			}
	}

	collate_only = 0;
	for (i=0; i<nev; i++) {
		file = (WatchFile *)evList[i].udata;
		if (evList[i].fflags & NOTE_DELETE ||
		    evList[i].fflags & NOTE_RENAME) {
			EV_SET(&evSet, file->fd, EVFILT_VNODE, EV_DELETE,
			    NOTE_ALL, 0, file);
			if (xkevent(kq, &evSet, 1, NULL, 0, NULL) == -1)
				err(1, "failed to remove VNODE event");
			if ((file->fd != -1) && (close(file->fd) == -1))
				err(1, "unable to close file");
			watch_file(kq, file);
			collate_only = 1;
		}
	}
	if (reopen_only == 1) {
		reopen_only = 0;
		goto main;
	}

	for (i=0; i<nev && reopen_only == 0; i++) {
		file = (WatchFile *)evList[i].udata;
		if ((file->is_dir == 1) && (dir_modified == 0))
			continue;
		if (evList[i].fflags & NOTE_DELETE ||
		    evList[i].fflags & NOTE_WRITE  ||
		    evList[i].fflags & NOTE_RENAME ||
		    evList[i].fflags & NOTE_TRUNCATE) {
			if ((dir_modified > 0) && (restart_opt == 1))
				continue;
			do_exec = 1;
		}
		if (evList[i].fflags & NOTE_ATTRIB &&
		    S_ISREG(file->mode) != 0 &&
		    xstat(file->fn, &sb) == 0 &&
		    file->mode != sb.st_mode) {
			do_exec = 1;
			file->mode = sb.st_mode;
		}
	}

	if (collate_only == 1)
		goto main;
	if (do_exec == 1) {
		do_exec = 0;
		run_utility(argv);
		reopen_only = 1;
		leading_edge_set = 0;
	}
	if (dir_modified > 0) {
		terminate_utility();
		xerrx(2, "directory altered");
	}

	goto main;
}
Exemplo n.º 4
0
/*
 * Wait for events to and execute a command or write filename to a FIFO.
 * Four major concerns are in play here:
 *   leading_edge: Global reference to the first file to have changed
 *   reopen_only : Unlink or rename events which require us to spin while
 *                 waiting for the file to reappear. These must always be
 *                 processed
 *   collate_only: Changes that indicate that more events are likely to occur.
 *                 Watch for more events using a short timeout
 *   do_exec     : Delay execution until all events have been processed. Allow
 *                 the user to edit files while the utility is running without
 *                 any visible side-effects
 *   dir_modified: The number of files changed for a directory under watch
 */
void
watch_loop(int kq, char *argv[]) {
	struct kevent evSet;
	struct kevent evList[32];
	int nev;
	WatchFile *file;
	int i;
	struct timespec evTimeout = { 0, 1000000 };
	int reopen_only = 0;
	int collate_only = 0;
	int do_exec = 0;
	int dir_modified = 0;

	leading_edge = files[0]; /* default */
	if (restart_opt)
		run_utility(argv);

main:
	if ((reopen_only == 1) || (collate_only == 1))
		nev = xkevent(kq, NULL, 0, evList, 32, &evTimeout);
	else {
		nev = xkevent(kq, NULL, 0, evList, 32, NULL);
		dir_modified = 0;
	}
	/* escape for test runner */
	if ((nev == -2) && (collate_only == 0))
		return;

	for (i=0; i<nev; i++) {
		#ifdef DEBUG
		fprintf(stderr, "event %d/%d: ident %d filter %d flags 0x%x "
		    "fflags 0x%x udata %d udata %p\n", i+1,
		    nev,
		    evList[i].ident,
		    evList[i].filter,
		    evList[i].flags,
		    evList[i].fflags,
		    evList[i].data,
		    evList[i].udata);
		#endif
		if (evList[i].filter != EVFILT_VNODE)
			continue;
		file = (WatchFile *)evList[i].udata;
		if (file->is_dir == 1)
			dir_modified += compare_dir_contents(file);
		if ((i == 0) && (reopen_only == 0) && (collate_only == 0))
			leading_edge = file;
	}

	collate_only = 0;
	for (i=0; i<nev; i++) {
		file = (WatchFile *)evList[i].udata;
		if (evList[i].fflags & NOTE_DELETE ||
		    evList[i].fflags & NOTE_RENAME) {
			EV_SET(&evSet, file->fd, EVFILT_VNODE, EV_DELETE,
			    NOTE_ALL, 0, file);
			if (xkevent(kq, &evSet, 1, NULL, 0, NULL) == -1)
				err(1, "failed to remove VNODE event");
			if ((file->fd != -1) && (close(file->fd) == -1))
				err(1, "unable to close file");
			watch_file(kq, file);
			collate_only = 1;
		}
	}
	if (reopen_only == 1) {
		reopen_only = 0;
		goto main;
	}

	for (i=0; i<nev && reopen_only == 0; i++) {
		file = (WatchFile *)evList[i].udata;
		if ((file->is_dir == 1) && (dir_modified == 0))
			continue;
		if (evList[i].fflags & NOTE_DELETE ||
		    evList[i].fflags & NOTE_WRITE  ||
		    evList[i].fflags & NOTE_RENAME ||
		    evList[i].fflags & NOTE_TRUNCATE) {
			if (fifo.fd == 0) {
				if ((dir_modified > 0) && (restart_opt == 1))
					continue;
				do_exec = 1;
			}
			else {
				write(fifo.fd, file->fn, strlen(file->fn));
				write(fifo.fd, "\n", 1);
				fsync(fifo.fd);
				reopen_only = 1;
			}
		}
	}

	if (collate_only == 1)
		goto main;
	if (do_exec == 1) {
		do_exec = 0;
		run_utility(argv);
		reopen_only = 1;
	}
	if (dir_modified > 0)
		xerrx(2, "directory altered");

	goto main;
}