keventでtail -f

BSDで使えるkevent。
FreeBSDで簡単tail -fを作ってみた。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/event.h>
#include <errno.h>

int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "Usage: TEST filename\n");
exit(EXIT_FAILURE);
}

FILE *fp = fopen(argv[1], "r+");
if (fp == NULL) {
fprintf(stderr, "Error: Could not open file [%s].\n", argv[1]);
exit(EXIT_FAILURE);
}
fseek(fp, 0, SEEK_END);

struct kevent ev;
int kq = kqueue();
EV_SET(&ev, fileno(fp)
, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, 0);

if (kevent(kq, &ev, 1, NULL, 0, NULL) == -1) {
fprintf(stderr, "Error: Could not use 'kevent'\n");
exit(EXIT_FAILURE);
}

while (1) {
int n = kevent(kq, NULL, 0, &ev, 1, NULL);
if (n < 0) {
fprintf(stderr, "Error: %d\n", errno);
fclose(fp);
break;
}
else if (n == 0) {
// timeout
}
else if (ev.filter == EVFILT_READ) {
char buf[1024];
int r = fread(buf, 1, sizeof buf, fp);
fwrite(buf, r, 1, stdout);
(void)fflush(stdout);
clearerr(fp);
}
}

return 0;
}

実際のtailのソースを見ると、複数ファイル指定の処理とか、VNODE変更の処理とか、keventが失敗する場合のselectでのポーリング処理とかが入って少々複雑になっているが、tail -f の基本的な処理としてはこんな感じ。
実業務で使うなら、freadのエラー処理なんかも必要かも。
スポンサーサイト

コメントの投稿

非公開コメント

No title

みつかりましたか?

No title

うまい話は転がってないねぇ orz
プロフィール

f_yamaki

Author:f_yamaki

アクセスカウンタ
最近の記事
最近のコメント
最近のトラックバック
月別アーカイブ
カテゴリー
ブロとも申請フォーム

この人とブロともになる

ブログ内検索
RSSフィード
リンク