tags:

views:

452

answers:

3

EDIT: I used, finally, inotify. As stefanB says, inotify is the thing to use. I found a tail clone that uses inotify to implement the -f mode, inotail.

Original question text:

I'm trying to implement the "tail -f" logic in a C project, for prototyping purposes I developed it in python as follow:


    # A forever loop, each 5 seconds writes a line into file.txt
    from time import *

    while 1:
        sleep(5)
        file = open("file.txt", "a")
        file.write("This is a test\n")
        file.close()

The next code follows the eof of file.txt (updated by the code above)


    # tail -f 
    from time import *

    file = open("file.txt", "r")
    file.seek(0, 2)

    while 1:
      line = file.readline()
      if not line:
          sleep(1)
      else:
          print line

    file.close()

All works fine but the C implementation is not working (there are no check-error code). The inclusion of stdio.h, string.h and unistd.h is omitted (the colorization hides the header inclusion code).


    #define LINE_LEN 256

    int main(int argc, char **argv)
    {
        FILE *f;
        char line[LINE_LEN];

        f = fopen("file.txt", "r");

        fseek(f, 0, SEEK_END);

        while (1)
        {
            fgets(line, LINE_LEN, f);

            if (strlen(line) == 0)
            {
                sleep(1);
            }
            else
            {
                printf("Readed: %s", line);
            } 
        }

        fclose(f);

        return 0;
    }

Some idea?

Is a good idea implement it with a poll() instead the presented solution?.

Thanks in advance.

+3  A: 

Once a FILE * has seen an error or eof, it has its internal status set so that it continues to return error or eof on subsequent calls. You need to call clearerr(f); after the sleep returns to clear the eof setting and get it to try to read more data from the file.

Chris Dodd
I tried it but I obtained the same behaviour. Thanks!
Enric Ruiz
+2  A: 

From the tail man page:

-f Do not stop when end-of-file is reached, but rather to wait for additional data to be appended to the input. If the file is replaced (i.e., the inode number changes), tail will reopen the file and continue. If the file is truncated, tail will reset its position to the beginning. This makes tail more useful for watching log files that may get rotated. The -f option is ignored if the standard input is a pipe, but not if it is a FIFO.

So, you could do the same thing:

  1. Use stat() to read the inode number of the file
  2. Display the contents of that file. Store the position of the file descriptor eg, p = ftell(fd)
  3. Use stat() again, and see if the inode has changed. If so, display the contents of the file from position p onward
  4. Repeat
rascher
Nice! I ignored the man pages section. Thanks!
Enric Ruiz
+2  A: 

EDIT: Seems like inotify is the thing to use. It should be included in linux kernel since 2.6.13 . An article from IBM developerworks about inotify.

Previous answer:

Have a look at Linux File Alteration Monitor (in linux kernels 2.4.x >). It's a framework that let's you subscribe for file changes and you get callback from kernel when change happens. This should be better than polling.

Examples how to poll for file changes, check out sections Waiting for file changes and Polling for file changes.

I haven't tried it yet.

stefanB