2012-10-10 6 views
1

필자는 foo가 file1.txt 파일에 쓰는 C : echo 'some string' | foo에서이 작업을 수행하고 싶습니다. foo를 실행하면 차단되고 stdin에서 입력을 기다린 후 file1.txt에 기록합니다. stdin을 통해 성공적으로 foo에 데이터를 보내고 있지만 foo는 C 파이프를 사용할 때 로컬 파일을 열지 못합니다.C에서, 다른 프로그램에 파이핑 입력이 실패했을 때

는 여기에 내가 무슨 짓을했는지의 :

#include <stdlib.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/wait.h> 

int main() { 

    FILE *stream; 
    int fds[2]; 
    int status; 
    pid_t pid; 
    char *cmd[] = { "foo", NULL }; 

    pipe(fds); 
    pid = fork(); 

    if (pid < 0) { 
     fprintf(stderr, "Fork failed\n"); 
     return 1; 
    } 
    if (pid > 0) { 
     // Parent process 
     close(fds[0]); 
     stream = fdopen(fds[1], "w"); 
     fprintf(stream, "some string\n"); 
     fflush(stream); 
     close(fds[1]); 
     waitpid(pid, &status, 0); 
     if (WIFEXITED(status) == 0 || WEXITSTATUS(status) < 0) 
      return 1; 
    } 
    else { 
     // Child process 
     close(fds[1]); 
     dup2(fds[0], STDIN_FILENO); 

     execv("foo", cmd); 
     return 1; 
    } 

    return 0; 
} 

내부적으로 foo는 로컬 파일에 fopen 호출을하고 오류없는 14 실패하지 않습니다 : EFAULT를. 또한 fork/pipe/dup2/execv 대신 popen/pclose를 사용하여이 작업을 시도했습니다.

이 작업을 수행하려면 어떻게해야합니까?

+0

'fopen'이 EFAULT로 실패하면'fopen' 코드를 보여줄 수 있습니까? 파이프없이 작동합니까? 'fopen'에 제공된 파일 이름이 유효하다는 것을 확신합니까? – cdarke

+0

fopen 코드는 NULL을 반환하는'fopen (file1_name, "w")'처럼 보입니다. 그것은 파이프없이 작동합니다. 제공된 파일 이름이 유효합니다. –

+0

별도로 표시하지 않으려면'자식 프로세스 '라고 표시된 코드 섹션에'fopen'을 포함하는 코드를 넣을 수 있습니다 – anatolyg

답변

0

나는 foo 코드를 읽고 stdin에서 읽고 파일을 쓰는 부분을 추출했습니다. 여기에서 파일을 볼 수 있습니다 : https://gist.github.com/3868421

echo 'some string' | foo이 작동하고 pipedata 프로그램을 실행하면 데이터가 foo로 파이프되고 파일에 기록됨을 확인했습니다.

이 예제에서는 모든 것이 잘 작동하므로 문제는 foo의 소스 코드에 있어야합니다.

0

fooPATH 디렉토리라고 가정하고 Yu는 execvp을 사용해야 할 수도 있습니다. 그 외의 경우 전체 경로를 제공해야 할 수도 있습니다. execv("/full/path/to/foo", cmd);

+0

나는 운과 운 모두를 시험해 보았다. –

0

코드에 경쟁 조건이 있습니다. 부모 프로세스는 파이프에 물건을 작성하고 닫습니다. 자식 프로세스는 파이프에서 읽습니다. 이것은 당신이 마주 치게되는 문제의 이유가 아닐 수도 있지만 결코 좋은 것은 아닙니다.

레이스를 제거하십시오 :

stream = fdopen(fds[1], "w"); 
    fprintf(stream, "some string\n"); 
    fflush(stream); 
    waitpid(pid, &status, 0); 
    close(fds[1]); // close it when the child process doesn't use it anymore 

참고 : 당신은 아무것도에 관계없이 fclose 대신 close를 사용해야합니다.

편집 : 다른 사람이 지적한 것처럼이 대답은 잘못되었습니다. 경쟁 조건이 없습니다.

+0

자식이 끝나면 fds [1]을 닫으면 EOF가 stdin을 통해 foo로 보내지지 않는다는 것을 의미합니다. 파이프를 닫아야 foo가 계속 실행하고 파일에 쓸 수 있습니다 (fopen 호출로 인해 실패합니다). –

+0

이것은 경쟁 조건이 아니므로 파이프에 내용을 쓰고 글씨를 쓰는 것이 좋습니다. 파이프의 읽기 끝 부분은 데이터 읽기 시작 시점과 관계없이 데이터와 EOF를 수신합니다. (그리고 fork() 호출이 있기 때문에 close (fds [1]);은 괜찮습니다. 자식은 여전히 ​​파이프에 대한 참조를 가지고 있습니다) – nos

+1

@Maros Hluska echo 'some string'을 실제로 실행합니까? foo는 작동합니까? 즉, 게시 된 코드에 오류가 포함되어 있는지 확인하고 오류가 foo에 없다는 것을 확인하십시오. 또 다른 메모. 당신은 닫아야합니다 (fds [0]); 'dup2 (fds [0], STDIN_FILENO);'의 직후에 자식 프로세스에서''그렇지 않으면 파이프의 읽기 끝을 참조하는 2 개의 파일 디스크립터가 남아있다. – nos

0

stdlib 함수 popen/pclose는 이런 종류의 일을 훨씬 쉽게합니다. 그들은 당신을 위해 모든 파이프와 자식 관리를합니다. 프로그램은 다음과 같이됩니다 :

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

int main() { 
    FILE *stream; 
    if (!(stream = popen("./foo", "w"))) { 
     fprintf(stderr, "popen failed\n"); 
     return 1; 
    } 
    fprintf(stream, "some string\n"); 
    fflush(stream); 
    if (pclose(stream) < 0) { 
     fprintf(stderr, "pclose failed\n"); 
     return 1; 
    } 
    return 0; 
} 
+0

예,이 방법으로 훨씬 더 깨끗해 보입니다. 그러나 popen/close와 fork/pipe 솔루션 모두 문제를 일으켰습니다. 나는 그것이 작동하고 있다고 대답을 게시했습니다. –

관련 문제