2015-10-18 2 views
-3

Я пытаюсь написать базовую оболочку, и для облегчения построения трубопроводов я написал следующую функцию, где tokens - это строка, которая должна быть выполнена, а index - это местоположение в tokens символ трубы (на данный момент для труб требуются пробелы с обеих сторон). Каждый раз, когда я запускаю командную строку в оболочке, обе команды выполняются так, как ожидалось, но не могут писать/читать из канала с ошибкой «Плохой дескриптор файла». Причина, по которой это вызывает недоумение, заключается в том, что перенаправление файлов работает отлично, поэтому я не понимаю, почему он не работает с каналом. Я прочитал документы и посмотрел на примерный код, и я не могу придумать ничего, что я делаю неправильно. Через несколько часов я в недоумении, где я ошибся?
ошибка файлового дескриптора fork и pipe

int pipeit(vector<string> tokens,unsigned int index){ 
    //separate the entire line into two delimited by the pipe 
    vector<string> firstline; 
    vector<string> secondline; 
    for(unsigned int i=0;i<tokens.size();i++){ 
     if(i==index){ 
      continue; 
     } 
     else if(i<index){ 
      firstline.push_back(tokens[i]); 
     } 
     else{ 
      secondline.push_back(tokens[i]); 
     } 
    } 

    //make sure the lines aren't empty 
    if(secondline.size()==0||firstline.size()==0){ 
     fprintf(stderr, "ERROR, expected at least one command at both ends of pipe\n"); 
    } 

    //open a pipe, check that it was successfully created 
    int pip[2]; 
    if(pipe(pip)<0){ 
     perror("pipe failure"); 
     return -1; 
    } 

    //attempt to fork 
    int parentstatus=0; 
    int childstatus=0; 
    switch(fork()){ 

     //fork failed, close the pipe and return -1 (failure) 
     case -1: 
     { 
      close(pip[0]); 
      close(pip[1]); 
      perror("fork failure"); 
      return -1; 
     } 

     //pid of 0 indicates this is the child process 
     case 0: 
     { 
      //close the write end of the pipe and redirect stdin to the read end 
      close(pip[0]); 
      int stdIn=dup(0); 
      dup2(pip[1],0); 

      //once redirect is done, can close the other end of the pipe 
      close(pip[1]); 

      //parse the second line as a list of commands (not important for question) 
      //then restore stdin, close the old file descriptor pointing to the pipe 
      execute_line(secondline,builtins); 
      dup2(stdIn,0); 
      close(stdIn); 
      break; 
     } 

     //pid other than 0 indicates this is the parent process 
     default: 
     { 
      //close the read end of the pipe 
      close(pip[1]); 

      //redirect stdout to the write end of the pipe 
      int stdOut=dup(1); 
      dup2(pip[0],1); 
      close(pip[0]); 

      //execute this line (not important for question) 
      parentstatus=execute_line(firstline,builtins); 

      //restore stdout and close the temporary fd pointing to the pipe 
      dup2(stdOut,1); 
      close(stdOut); 

      //wait for child process to exit and store it's return value in 'status' (then childstatus) 
      int status; 
      wait(&status); 
      childstatus=status; 
      break; 
     } 
    } 

    //return a combination of the parent and child's return status 
    //(not standard, I know, just easy and irrelevant for the question) 
    return childstatus & parentstatus; 
    } 

tokens просто разделенных пробелами std::vector<string>, содержащий команды, которые будут выполняться (да что вам нужно, чтобы дополнить «|» с пробелами для этого, чтобы работать, не беспокоиться о том, что только пока) и index - это место в списке, где '|' был найден персонаж, чтобы все было проще. Для целей в работоспособном исходном файл, просто вставить выше определение функции в нижней части:

#include <unistd.h> //pipe, dup2, fork 
#include <iostream> 
#include <string> 

int builtins = 0xf00; //not what this actually is, but that doesn't matter atm 

using namespace std; 

int pipeit(vector<string> tokens, unsigned int index); 

void execute_line(vector<string> cmds, int biltins){ 
    cout << "Executing: " << endl; 
    for(unsigned int i = 0; i < cmds.size(); ++i){ 
     cout<<cmds[i]<< " "; 
    } 
    cout << endl; 
} 

int main(){ 
    vector<string> cmds; 
    cmds.push_back(new string("cmd1")); 
    cmds.push_back(new string("|")); 
    cmds.push_back(new string("cmd2")); 
    return pipeit(cmds, 1); 
} 
+0

Вы получите лучшие ответы на свой код, если вы помечаете его 'C++'. – EOF

+0

О, да, я забыл, что использую C++ не только c. Благодаря! – ocket8888

+0

«Вопросы, требующие помощи по отладке (« почему этот код не работает? ») Должны включать в себя желаемое поведение, конкретную проблему или ошибку и кратчайший код, необходимый для воспроизведения в самом вопросе. полезно для других читателей. См.: [Как создать минимальный, полный и проверенный пример.] (http://stackoverflow.com/help/mcve) " – melpomene

ответ

0

Проблема заключается в том, что я читал с конца записи трубы и запись считанного конца. Всякий раз, когда вы используете pipe(my_pipe), my_pipe[0] является только для чтения, а my_pipe[1] является только для записи. Это не значит, что мой код работает для бесконечного трубопровода, для кого-то другого, смотрящего это, но сейчас он делает отдельные трубы.
CTC: IRC пользователь C--