summaryrefslogblamecommitdiffstats
path: root/freebsd/kqueue.c
blob: e8825db368b901c504c37285f27ad0255fd3128b (plain) (tree)













































































































































                                                                                     
#include <sys/types.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/event.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

int printer_ready;
char * printer;
char * queue_dir;
char * trigger;
#define BUFLEN 50
char queue_dir_new[BUFLEN];
char trigger_cmd[BUFLEN];

int open_and_subscribe(struct kevent * change, const char * path)
{
	int f;
	f = open(path, O_RDONLY);
	if (f == -1) {
		perror("open");
		return -1;
	}

	EV_SET(change, f, EVFILT_VNODE,
	                  EV_ADD | EV_ENABLE | EV_ONESHOT,
	                  NOTE_DELETE | NOTE_EXTEND |
	                  NOTE_WRITE | NOTE_ATTRIB,
	       0, 0);
}

int check_printer_status(){
	struct stat buf;
	//printf("%s\n", printer);
	int r = stat(printer, &buf);
	if (r<0) {
		if (printer_ready != 0) {
			printf("Printer offline\n");
		}
		printer_ready = 0;
		if (errno == ENOENT) {
			printf("Printer not detected\n");
		} else {
			perror("stat");
			return -1;
		}
	} else {
		if (printer_ready != 1) {
			printf("Printer online\n");
			print_loop(printer, queue_dir);
		}
		printer_ready = 1;
	}
	return 0;
}

int print_loop()
{
	FILE * p;
	int status;
	char buf[BUFLEN];
	printf("Print loop\n");
	p = popen(trigger_cmd, "r");
	if (p == NULL)
		perror("popen");
	while (fgets(buf, BUFLEN, p) != NULL)
		printf("%s", buf);
	status = pclose(p);
	if (status != 0) {
		printf("Trigger exited with status %d\n", status);
	}
	return status;
}

int main(int argc, const char * argv[])
{
	int fd, fq, kq, nev;
	struct kevent change;
	struct kevent event;

	int len;

	if (argc != 4) {
		fprintf(stderr, "usage: %s printer queue_dir trigger\n", argv[0]);
		return -1;
	}
	printer = strdup(argv[1]);
	queue_dir = strdup(argv[2]);
	trigger = strdup(argv[3]);

	len = snprintf(trigger_cmd, BUFLEN, "%s %s %s", trigger, printer, queue_dir);
	if (len >= BUFLEN - 1) {
		printf("Buffer too small\n");
		return -1;
	}

	len = snprintf(queue_dir_new, BUFLEN, "%s/new", queue_dir);
	if (len >= BUFLEN - 1) {
		printf("Buffer too small\n");
		return -1;
	}

	printer_ready = 0;

	kq = kqueue();
	if (kq == -1)
		perror("kqueue");

	fq = open_and_subscribe(&change, queue_dir_new);

	struct timespec timeout;
	timeout.tv_sec = 5;
	timeout.tv_nsec = 0;

	check_printer_status();
	for (;;) {
		nev = kevent(kq, &change, 1, &event, 1, &timeout);
		if (nev == -1)
			perror("kevent");
		if (nev == 0) { // timeout
			check_printer_status();
		} else if (nev > 0) {
			if (event.fflags & NOTE_DELETE) {
				continue;
			}
			printf("Got event for %d\n", event.ident);
			if (printer_ready) {
				print_loop(printer, queue_dir, trigger);
			}
		}
	}

	close(kq);
	close(fq);
	close(fd);
	return EXIT_SUCCESS;
}