TEE(2)

名前
tee - パイプの中身を複製する

書式
#define _GNU_SOURCE         /* feature_test_macros(7) 参照 */
#include <fcntl.h>
ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);

説明
tee() は、ファイルディスクリプター fd_in が参照するパイプからファイルディスクリプター fd_out が参照するパイプへ最大 len バイトのデータを複製する。 この操作では、複製されるデータは fd_in からは消費されない。したがって、これらのデータをこの後の splice(2) でコピーすることができる。 flags は一連の修飾フラグであり、 splice(2) や vmsplice(2) と共通の名前である。

SPLICE_F_MOVE
    現在のところ tee() では何の効果もない。 splice(2) 参照。

SPLICE_F_NONBLOCK
    入出力で停止 (block) しない。詳細は splice(2) 参照。

SPLICE_F_MORE
    現在のところ tee() では何の効果もないが、将来的には実装される可能性がある。 splice(2) 参照。

SPLICE_F_GIFT
    tee() では未使用。 vmsplice(2) 参照。

返り値
成功して完了すると、 tee() は入出力間で複製されたバイト数を返す。 返り値 0 はデータの転送が行われなかったことを示す。 この場合、処理を停止 (block) しても無意味である。 なぜなら、 fd_in が参照するパイプの書き込み側に接続されている者がいないからである。 エラーの場合、 tee() は -1 を返し、 errno にエラーを示す値を設定する。

エラー

EAGAIN
    SPLICE_F_NONBLOCK が flags に指定されていて、かつ操作が停止するような状態であった。

EINVAL
    fd_in と fd_out のどちらかがパイプを参照していない。もしくは fd_in と fd_out が同じパイプを参照している。

ENOMEM
    メモリー不足。

バージョン
tee() システムコールは Linux 2.6.17 で初めて登場した。 ライブラリによるサポートは glibc バージョン 2.5 で追加された。

準拠
このシステムコールは Linux 固有である。

注意
概念としては、 tee() は二つのパイプ間でデータのコピーを行う。 しかし、実際には実データのコピーは行われない。 内部では、 tee() は入力側に対する参照だけを作成することで出力側にデータを 追加する。

例
以下の例は、 tee() システムコールを使って、 基本的な tee(1) プログラムを実装したものである。 以下は利用例である。
$ date |./a.out out.log | cat
Tue Oct 28 10:06:00 CET 2014
$ cat out.log
Tue Oct 28 10:06:00 CET 2014

  プログラムのソース
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
int
main(int argc, char *argv[])
{
    int fd;
    int len, slen;
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <file>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }
    do {
        /*
         * tee stdin to stdout.
         */
        len = tee(STDIN_FILENO, STDOUT_FILENO,
                  INT_MAX, SPLICE_F_NONBLOCK);
        if (len < 0) {
            if (errno == EAGAIN)
                continue;
            perror("tee");
            exit(EXIT_FAILURE);
        } else
            if (len == 0)
                break;
        /*
         * Consume stdin by splicing it to a file.
         */
        while (len > 0) {
            slen = splice(STDIN_FILENO, NULL, fd, NULL,
                          len, SPLICE_F_MOVE);
            if (slen < 0) {
                perror("splice");
                break;
            }
            len -= slen;
        }
    } while (1);
    close(fd);
    exit(EXIT_SUCCESS);
}

関連項目
splice(2), vmsplice(2)

この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。