[メモ] UNIXの子プロセスの標準入力にパイプでデータを渡したい


やりたいこと

UNIXで子プロセスを起動して任意のコマンドをexecで実行したい。
そのコマンドの標準入力に対してパイプでデータを渡したい。

プログラム例

子プロセスを起動してcatを引数なしで呼ぶ。catは引数なしなので標準入力を待つ。
親プロセスからは"Hello, World."をパイプで流す。

つまり、shellで

$ echo "Hello, World" | cat

を実行したのと同じ。

コード

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void)
{
    int     fd[2];

    // pipe を作成する。fd[0]は受信用、fd[1]は送信用
    pipe(fd);

    // プロセス生成
    switch(fork()) {
    case -1:
        perror("fork");
        return 1;
    case 0: // 子プロセス
        {
            close(fd[1]); // 送信用fdを閉じる

            // 受信用fdをstdinのfdに上書きする
            if (dup2(fd[0], STDIN_FILENO)==-1) {
                perror("cannot redirect stdin"); 
                exit(1); 
            }
            close(fd[0]); // 受信用fdは複数いらないので閉じる

            // cat を実行する
            execlp("cat", "cat", NULL) ;

            perror("execlp: failed."); // ここに来たということはexeclpに失敗した
        }
    default:
        { // 親プロセス
            const char send_str[] = "Hello, World.\n";

            close(fd[0]); // 受信側fdを閉じる
            write(fd[1], send_str, strlen(send_str)+1);
            close(fd[1]); // 送信後は必ず閉じる ★①

            int status;
            wait(&status);
        }
    }

    return (0);
}

はまったこと

"Hello, World"は出力されるが、子プロセスが終了しない。

原因

親プロセスがwrite()後にfd[1]に対してcloseをしていなかった。(上記ソースの★①)
子プロセス側は標準入力をずっと待っている状態だった。

参考になったもの

以上。