/*
 * fwatch.c  -  Watching file change, then nofity
 *
 *
 *   Usage: fwatch path [prog]
 *
 * This program watches specified file (or directory).
 * If contents of such file will be changed,
 * fwatch invoke prog with passing path as arg1.
 * Or prog not specified, it'll be just printed.
 *
 *
 * KAWAMATA, Yoshihiro
 * kaw@on.rim.or.jp
 *
 *
 * $Id: fwatch.c,v 1.2 2005/07/21 14:36:40 kaw Exp $
 */

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <sys/wait.h>

#define PATHLEN (250)
#define STRLEN (501)

main (int argc, char *argv[]) {

  char fname[PATHLEN+1], pname[PATHLEN+1];

 /*
  *  parsing arguments
  */
  if (argc < 2) {
    fprintf(stderr, "Usage: %s path [program]\n", argv[0]);
    exit(1);
  } else {
    strlcpy(&fname, argv[1], PATHLEN);
    strlcpy(&pname, (2 < argc) ? argv[2] : "", PATHLEN);
  }

 /*
  *  open specified file
  */
  int fd;
  int err;

  if ((fd = open(fname, O_RDONLY, 0)) < 0) {
    perror("open");
    exit(1);
  }
    
 /*
  *  create and register kernel event queue
  */
  int kq;
  struct kevent kev;
  
  if ((kq = kqueue()) == -1) {
    perror("kqueue");
    closedir(fd);
    exit(1);
  }

  EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, NOTE_WRITE, 0, NULL);

  if (kevent(kq, &kev, 1, NULL, 0, NULL) < 0) {
    perror("kevent on register");
    close(fd);
    exit(1);
  }

  int retval;
  char cmdln[STRLEN+1];

 /*
  *  then go monitoring
  */
  while (1) {
    if (0 < kevent(kq, NULL, 0, &kev, 1, NULL)) {
      if (pname[0]) {
	snprintf(cmdln, STRLEN, "%s %s", pname, fname);
	system(cmdln);
      } else {
	printf("%s\n", fname);
      }
    } else {
      perror("kevent on nofity");
      close(fd);
      exit(1);
    }
  }

 /*
  *  normal exit
  */
  close(fd);
  exit(0);
}
