

/* cc gkqueuefilemonitor.c kqueue_fnm.c -O0 -DDEBUG -lpthread -o gkqueuefilemonitor */

#include <sys/param.h>
#include <sys/types.h>

#include <inttypes.h>
#include <stdlib.h> /* malloc, exit */
#include <stdio.h> /* snprintf, fprintf */
#include <unistd.h> /* close, write, sysconf */
#include <string.h> /* bcopy, bzero, memcpy, memmove, memset, strerror... */
#include <errno.h>
#include <err.h>
#include <pthread.h>
#include <sys/mount.h>

#include "kqueue_fnm.h"


#define LOG_INFO_FMT(fmt, args...)					\
	    fprintf(stdout, fmt"\n", ##args)

static volatile kqueue_fnm_p kqueue_fnm = NULL;


static void
signal_install(sig_t func) {

	signal(SIGINT, func);
	signal(SIGTERM, func);
	//signal(SIGKILL, func);
	signal(SIGHUP, func);
	signal(SIGUSR1, func);
	signal(SIGUSR2, func);
	signal(SIGPIPE, SIG_IGN);
}

static void
signal_handler(int sig) {
	kqueue_fnm_p kfnm;

	switch (sig) {
	case SIGINT:
	case SIGTERM:
	case SIGKILL:
		kfnm = kqueue_fnm;
		kqueue_fnm = NULL;
		kqueue_fnm_free(kfnm);
		break;
	case SIGHUP:
	case SIGUSR1:
	case SIGUSR2:
		break;
	}
}

static void
kqueue_file_mon_event_handler(kqueue_fnm_p kfnm,
    kqueue_file_mon_data_p fmd __unused, void *udata __unused,  uint32_t event,
    const char *base, const char *filename, const char *new_filename) {

	if (NULL == kfnm || NULL == filename)
		return;
	switch (event) {
	case KF_EVENT_CREATED:
		LOG_INFO_FMT("add %s: %s", base, filename);
		break;
	case KF_EVENT_DELETED:
		LOG_INFO_FMT("del %s: %s", base, filename);
		break;
	case KF_EVENT_RENAMED:
		LOG_INFO_FMT("ren %s: %s -> %s", base, filename, new_filename);
		break;
	case KF_EVENT_CHANGED:
		LOG_INFO_FMT("mod %s: %s", base, filename);
		break;
	}
}


int
main(int argc __unused, char *argv[] __unused) {
	int idx;
	struct statfs stfs;
	kqueue_file_mon_settings_t kfms;
	static const char *non_local_fs[] = {
		"fusefs.sshfs",
		NULL
	};
	const char *paths[] = {
		"/home/rim/",
		"/home/rim/mnt/storage/",
		"/tmp",
		"/usr/ports",
		"/home/rim/mnt/172.16.0.254/tmp/",
		NULL
	};

	signal_install(signal_handler);

	memset(&kfms, 0x00, sizeof(kqueue_file_mon_settings_t));
	kfms.mon_local_subfiles = 1;
	kfms.local_fs = NULL;
	kfms.non_local_fs = non_local_fs;
	kqueue_fnm = kqueue_fnm_create(&kfms, kqueue_file_mon_event_handler);

	for (idx = 0; NULL != paths[idx]; idx ++) {
		statfs(paths[idx], &stfs);
		LOG_INFO_FMT("%s, local = %i",
		    stfs.f_fstypename,
		    (int)(0 != (MNT_LOCAL & stfs.f_flags)));
		kqueue_fnm_add(kqueue_fnm, paths[idx], NULL);
	}

#if 1
	for (; NULL != kqueue_fnm;) {
		sleep(1);
	}
#else
	sleep(2);
	signal_handler(SIGKILL);
#endif

	return (0);
}
