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