kenkovlog

けんこふたんっオフィシャユブヨグッ
アンッ!アンッ!アンッ!アンッ!

pipe とdup とfork とっ

おっとっとっ。パイプをどうやってpipe, dup, fork で実現するか。

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

/*
 * man cat | fold -w 1k
 */

int main(int argc, char *argv[]) {
    pid_t pid1, pid2;
    int pfd1[2], pfd2[2];
    int c;

    if (pipe(pfd1) == -1 || pipe(pfd2) == -1) {
        perror("pipe");
        exit(1);
    }

    if ((pid1 = fork()) == -1) {
        perror("pid1");
        exit(1);
    }
    if (pid1 == 0) { // child
        /* execlp は標準出力に出力しようとするので、
         * 標準出力への出力がpfd1[0] にいくようにする。
         */
        close(pfd1[0]);
        close(1);
        dup2(pfd1[1], 1);
        close(pfd1[1]);
        /* これで、execlp は標準出力1 へ出力しようとするが、
         * それはdup[1] へ出力したことになる。
         * ポイントはexeclp 自体は標準出力へ出力していると思い、
         * それがdup[1] への出力とは知らないこと。
         */
        execlp("/usr/bin/man", "man", "cat", NULL);
    } else { // parent
        /* parent では、pfd1[0] に来たものを標準入力からきたもののようにみせるために
         * dup2(pfd1[0], 0) する。
         */
        close(pfd1[1]);
        close(0);
        dup2(pfd1[0], 0);
        close(pfd1[0]);
        if ((pid2 = fork()) == -1) {
            perror("pid2");
            exit(1);
        }
        if (pid2 == 0) { // child
            /// pid1 のchild と同様
            close(pfd2[0]);
            close(1);
            dup2(pfd2[1], 1);
            close(pfd2[1]);
            execlp("/usr/bin/fold", "fold", "-w", "10", NULL);
        } else {
            /// pid1 のparent と同様
            close(pfd2[1]);
            close(0);
            dup2(pfd2[0], 0);
            close(pfd2[0]);
            // 標準入力からきたものをそのままoutput する
            while((c = fgetc(stdin)) != EOF) {
                if (fputc(c, stdout) == EOF) {
                    exit(1);
                }
            }
        }
    }
    return 0;
}

ポイント

child では出力する時にdup して標準出力に出すようにみせて、 parent では入力する時にdup して標準入力から入るようにみせる。

けんこふたん