Hello,
Sorry if I chose the wrong place to ask such a question.
I have been learning C for a couple of months and along with reading
"C Primer Plus" by Stephen Prata and doing some exercises from it I took
a hard (for me) task to replicate a tail program in its simplest form.
I was able to reproduce watching for new data and truncation of the
file using kqueue but I do not quite understand how the original tail
watches when the file appears again after deletion or renaming.
By reading the original tail sources downloaded from OpenBSD mirror I
see that this is done by calling tfreopen function which seems to use a
"for" loop to (continuously?) stat(2) the file name till stat(2) successfully
returns and it does not seem to load a CPU as a simple continuous "for"
loop would do.
Can someone explain how it is done?
May be there is a better way to watch for the file to appear correctly?
Is inserting a sleep(3) in a loop an appropriate way?

Below is the function how it is done in tail:
"""
#define AFILESINCR 8
static const struct timespec *
tfreopen(struct tailfile *tf) {
        static struct tailfile          **reopen = NULL;
        static int                        nfiles = 0, afiles = 0;
        static const struct timespec      ts = {1, 0};

        struct stat                       sb;
        struct tailfile                 **treopen, *ttf;
        int                               i;

        if (tf && !(tf->fp == stdin) &&
            ((stat(tf->fname, &sb) != 0) || sb.st_ino != tf->sb.st_ino)) {
                if (afiles < ++nfiles) {
                        afiles += AFILESINCR;
                        treopen = reallocarray(reopen, afiles, sizeof(*reopen));
                        if (treopen)
                                reopen = treopen;
                        else
                                afiles -= AFILESINCR;
                }
                if (nfiles <= afiles) {
                        for (i = 0; i < nfiles - 1; i++)
                                if (strcmp(reopen[i]->fname, tf->fname) == 0)
                                        break;
                        if (i < nfiles - 1)
                                nfiles--;
                        else
                                reopen[nfiles-1] = tf;
                } else {
                        warnx("Lost track of %s", tf->fname);
                        nfiles--;
                }
        }

        for (i = 0; i < nfiles; i++) {
                ttf = reopen[i];
                if (stat(ttf->fname, &sb) == -1)
                        continue;
                if (sb.st_ino != ttf->sb.st_ino) {
                        (void) memcpy(&(ttf->sb), &sb, sizeof(ttf->sb));
                        ttf->fp = freopen(ttf->fname, "r", ttf->fp);
                        if (ttf->fp == NULL)
                                ierr(ttf->fname);
                        else {
                                warnx("%s has been replaced, reopening.",
                                    ttf->fname);
                                tfqueue(ttf);
                        }
                }
                reopen[i] = reopen[--nfiles];
        }

        return nfiles ? &ts : NULL;
}
"""

-- 
Maksim Rodin

Reply via email to