2015-11-26 2 views
1

Я немного новичок в программировании Linux на C (я искал похожие темы, но ни один не помог), поэтому я застрял в следующей проблеме:C: Перенаправить дочерний процесс на другой дочерний процесс ввода и stdout

Я хочу создать оболочку в C для Linux (используя fork(), exec(), pipe(), которая получает команду с параметрами и трубами в качестве входных данных из терминала stdin (например, sort foo | uniq -c | wc -l "), он выполняет его, а затем запрашивает следующую команду и т. д.

Я отделил разные команды, их параметры и т. д., я создал 1 дочерний процесс для каждого из них, но я не могу связать вывод каждого дочернего процесса на вход следующего (и последний вывод на stdout в Терминал).

Может ли кто-нибудь помочь сделать правильный трубопровод, чтобы его запустить?

Для любой дополнительной информации, просто спросить ... Заранее спасибо

Полный код ниже:

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

#define P_READ 0 
#define P_WRITE 1 

pid_t pID, chID; 
char input[100]; 
char * params[100][100]; 
char * funcs[100]; 
char * par; 
char * fun; 
int i, j, k, stat, infd[2], outfd[2]; 


//Pipe read 
void read_en(int * infd) 
{ 
    dup2(infd[P_READ], STDIN_FILENO); 
    close(infd[P_READ]); 
    close(infd[P_WRITE]); 
} 

//Pipe write 
void write_en(int * outfd) 
{ 
    dup2(outfd[P_WRITE], STDOUT_FILENO); 
    close(outfd[P_READ]); 
    close(outfd[P_WRITE]); 
} 

//Fork, read from pipe, write to pipe, exec 
void fork_chain(int * infd, int * outfd, int i) 
{ 
     pID = fork(); 

     if (pID == 0) 
     { 
      if (infd != NULL) 
      { 
       read_en(infd); 
      } 

      if (outfd != NULL) 
      { 
       write_en(outfd); 
      } 

      execvp(params[i][0], params[i]); 
      fprintf(stderr, "Command not found!\n"); 
      exit(1); 
     } 
     else if (pID < 0) 
     { 
      fprintf(stderr, "Fork error!\n"); 
      exit(1); 
     } 
     else 
     { 
      chID = waitpid(-1, &stat, 0); 
     } 
} 


int main() 
{ 
    printf("\n$"); 
    fgets(input, sizeof(input), stdin); 
    strtok(input, "\n"); 


    while (strcmp(input, "exit") != 0) 
    { 
     //Separate each command 
     k = 0; 
     fun = strtok(input, "|"); 

     while (fun != NULL) 
     { 
      funcs[k] = fun; 
      fun = strtok(NULL, "|"); 
      k++; 
     } 


     //Separate each command's parameters 
     for (i = 0; i < k; i++) 
     { 
      j = 0; 
      par = strtok(funcs[i], " "); 

      while (par != NULL) 
      { 
       params[i][j] = par; 
       par = strtok(NULL, " "); 
       j++; 
      } 
      params[i][j] = NULL; 
     } 

     //Fork, pipe and exec for each command 
     for (i = 0; i < k; i++) 
     { 
      if (i == 0) 
      { 
       pipe(outfd); 
       fork_chain(NULL, outfd, 0); 
       infd[P_READ] = outfd[P_READ]; 
       infd[P_WRITE] = outfd[P_WRITE]; 
      } 
      else if (i == k-1) 
      { 
       fork_chain(infd, NULL, 1); 
       close(infd[P_READ]); 
       close(infd[P_WRITE]); 
      } 
      else 
      { 
       pipe(outfd); 
       fork_chain(infd, outfd, i); 
       close(infd[P_READ]); 
       close(infd[P_WRITE]); 
       infd[P_READ] = outfd[P_READ]; 
       infd[P_WRITE] = outfd[P_WRITE]; 
      } 
     } 

     //Ask for next input 
     printf("\n$"); 
     fgets(input, sizeof(input), stdin); 
     strtok(input, "\n"); 
    } 

    return (0); 
} 
+0

Связанный, если не дубликат: http://stackoverflow.com/q/5060350/694576 – alk

+0

Тема, о которой вы говорили, составляет всего 2 ребенка. Я хочу больше 2, вот в чем проблема ... – Ezlen

ответ

0

Процесс оболочки должен закрыть конец записи трубы, так как в противном случае дочерний процесс не получает EOF на своем входе и блокирует навсегда при вызове read(). Ваш код закроет конец записи, но слишком поздно в случае последнего дочернего элемента, потому что fork_chain() ждет его выхода (что имеет другую проблему, если буфер буфера заполняется) перед возвратом. Если мы закрываем конец записи в нужное время, close(infd[P_WRITE]) должен быть удален с read_en(), так как он уже будет закрыт к тому времени.
Помимо, есть ошибка, связанная с кодом умножения на

  else if (i == k-1) 
      { 
       fork_chain(infd, NULL, 1); 

Аргумент 1 является единственно правильным, если к равно 2, в общем случае она должна быть i.

Таким образом, наряду с изменением read_en(), основной вилочных труб и-Exec цикл может быть переписан

 for (i = 0; i < k; i++) 
     { 
      fork_chain(i ? infd : NULL, i < k-1 ? pipe(outfd), outfd : NULL, i); 
      if (i) 
       close(infd[P_READ]); 
      if (i < k-1) 
       infd[P_READ] = outfd[P_READ], 
       close(outfd[P_WRITE]); // shell is done with it 
     } 

(обратите внимание, что infd[P_WRITE] больше не используется в любом месте).

Смежные вопросы