Указатель файла появляется, чтобы остановить продвижение

Я портирую программу просмотра журналов из Linux, которая использует sys/inotify.h, в OS X, которая будет использовать kqueues. Идея состоит в том, что kqueue будет использовать файловый дескриптор для отслеживания изменений в файле. Как только файл был изменен, другой функции будет передан указатель файла, который отсканирует изменения в файле в поисках конкретных данных. Исходные данные файла будут распечатаны на стандартный вывод, а данные, отсканированные, найдены на стандартный вывод. Кажется, что kqueues отлично отслеживают журнал, возвращая правильное количество байтов на изменение. Это функция сканирования, которая не работает должным образом.

Цикл kqueue:

#define BUFLEN 2048

int i, kq, off, rval, fplen;
char *path = "file_to_watch";
FILE *fp;
struct kevent ke_mon, ke_data;
struct stat stats;

fp = fopen(path, "r");

fstat(fileno(fp), &stats);
fplen = stats.st_size;

kq = open(path, O_RDONLY);

EV_SET(&ke_mon, kq, EVFILT_VNODE, EV_ADD, NOTE_DELETE|NOTE_RENAME, 0, path);
EV_SET(&ke_mon, kq, EVFILT_READ, EV_ADD, 0, 0, path);

off = 0;
rval = 0;
while(off < BUFLEN) {
    memset(&ke, 0x00, sizeof(ke));

    i = kevent(kq, NULL, 0, &ke_data, 1, NULL); // wait indefinitely for log to update

    if (i < 0 || ke_data.flags & EV_ERROR) 
        continue;
    if (ke_data.flags & EVFILT_READ)
        rval |= LOG_MODIFIED;
    if (ke_data.flags & EVFILT_VNODE)
        // rval |= LOG_DELETED or LOG_RENAMED, depending on ke_data.fflags

    off += ke_data.data;
    lseek(kq, ke_data.data, SEEK_CUR); // Update the descriptor's location
}

if (rval & LOG_MODIFIED) {
    // check for truncation.
    if (truncated) {
        // do some stuff
    } else {
        fplen = scan_log(fp);
    }
}

if (rval & (LOG_DELETED|LOG_RENAMED)
    // log was moved or renamed (rotation) so we would start over with new log

функция scan_log:

int scan_log(FILE *fp)
{
    char buf[1024];
    int ct = 0;

    while (fgets(buf, 1024, fp) != NULL {
        ct += strlen(buf);
        fprintf(stdout, "%s", buf);

        for ( some looping construct) {
            // Sometimes we don't ever enter this loop. It all depends on if there
            // is data we are expecting to see.
            // If we are in this loop however, do the following...
            // Match data that I'm looking for and print to stderr.
            // Print all log data to stdout
        }
    }

    fflush(stdout);
    fflush(stderr);
    return ct;
}

Функция scan_log не изменяется в Linux-версии этой программы, которая проверена на правильность работы, даже если цикл for в scan_log никогда не вводится. Иногда это не нужно.

Что происходит, так это то, что ничего из журнала не выводится на stderr или stdout. Я использую вызовы ftell до и после scan_log, чтобы посмотреть позицию fp. Он движется в первый раз, но не двигается после. В любом случае данные не выводятся в stdout/stderr.

РЕДАКТИРОВАТЬ: Обновлен код scan_log(), чтобы включить отсутствующий вызов fprintf.

1 ответ

Решение

Проблема, с которой я столкнулся, связана с тонкими различиями с Linux и Unix. Указатель файла в Unix устанавливает флаг EOF, который должен быть очищен вручную при вызове clearerr(FILE *) для того, чтобы указатель файла продвигался после того, как файл вышел за пределы своего старого EOF.

Другие вопросы по тегам