title: portable way to monitor a file for changes
body: <p>I'm actually implementing a very simple version of tail(1). In FreeBSD, I use <code>kqueue</code> to monitor a file for changes and then printing appended lines to the output. But this is not a portable way, as <code>kqueue</code> is only available in BSD family. Is there a general, efficient and platform-independent way to monitor files for changes in UNIX? I prefer not to use external libraries.</p>
  
  <p>This is the code I've written:</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;string.h&gt;
  
  #include &lt;sys/types.h&gt;
  #include &lt;sys/event.h&gt;
  #include &lt;sys/time.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;unistd.h&gt;
  
  void die(const char*);
  
  #define MAXLINE     1024
  
  int main(int argc, char *argv[])
  {
      int fdes;
      int kq;
      int nev;
      int flags;
      off_t curoff;
  
      char line[MAXLINE + 1];
      ssize_t nbytes;
  
      struct kevent change, event;
  
      if (2 != argc)
      {
          fprintf(stderr, "Usage: %s path\n", argv[0]);
          exit(EXIT_FAILURE);
      }
  
      if (-1 == (fdes = open(argv[1], O_RDONLY)))
          die("open()");
  
      if (-1 == (curoff = lseek(fdes, 0, SEEK_END)))
          die("lseek()");
  
      int ch = 0;
      int i = 0;
      while (i &lt; 10)
      {
          read(fdes, &amp;ch, 1);
  
          if (ch == '\n')
              i++;
  
          if (10 &gt; i)
              lseek(fdes, --curoff, SEEK_SET);
      }
  
      if (-1 == (flags = fcntl(fdes, F_GETFL)))
          die("fcntl()");
  
      flags |= O_NONBLOCK;
  
      if (-1 == fcntl(fdes, F_SETFL, flags))
          die("fcntl()1");
  
      while ((nbytes = read(fdes, line, MAXLINE)) &gt; 0)
          if (write(STDOUT_FILENO, line, nbytes) != nbytes)
              die("write()");
  
      if (-1 == (kq = kqueue()))
          die("kqueue()");
  
      EV_SET(&amp;change, fdes, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
       NOTE_EXTEND | NOTE_WRITE | NOTE_DELETE, 0, NULL);
  
      if (-1 == kevent(kq, &amp;change, 1, NULL, 0, NULL))
          die("kevent()");
  
      for (;;)
      {
          if (-1 == (nev = kevent(kq, NULL, 0, &amp;event, 1, NULL)))
              die("kevent()");
  
          if (nev &gt; 0)
          {
              if (event.fflags &amp; NOTE_WRITE || event.fflags &amp; NOTE_EXTEND)    
              {
                  while ((nbytes = read(fdes, line, MAXLINE)) &gt; 0)
                      if (write(STDOUT_FILENO, line, nbytes) != nbytes)
                          die("write()");
              }
              else if (NOTE_DELETE &amp; event.fflags)
              {
                  printf("The file has been deleted\n");
                  break;
              }
          }
      }
  
      return 0;
  }
  
  void die(const char *str)
  {
      perror(str);
      exit(EXIT_FAILURE);
  }
  </code></pre>