2015-03-17 2 views
0

Итак, я думал, что на правильном пути я попытаюсь подражать оболочке bash, но у меня возникают проблемы с трубопроводом. Я получаю ошибку, выполняя вторую команду. Мне было интересно, может ли кто-нибудь объяснить мне, как это исправить и почему это происходит неправильно. Я очень новичок в C & Linux-командах, поэтому любая дополнительная информация, которая могла бы помочь мне на этом пути, также была бы оценена.Трубопровод в C - ошибка в команде 2

Большое вам спасибо за ваше время. Мой код ниже, но его много. Моя проблема возникает в функции exec_pipe. Обычно я включаю то, что я использовал для ввода, и то, что я получаю для вывода, но мой пример ввода - это фактически исполняемые файлы, которые мой профессор дал нам для тестирования. К сожалению, моя работа не работает, как в оболочке. Я просто получаю мою ошибку распечатку:

Inside Case 5 
Inside Exec_Pipe 
Error in Pipe EXECVP cmd2 

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <stdbool.h> 
#include <time.h> 
#include <limits.h> 
#include <fcntl.h> 
#include <sys/wait.h> 
#define BUFSIZE 1024 
#define CSTRSIZE 100 
#define CMDSIZE 30 
#define DEBUG 1 

//I referenced our blackboard source code files to create the fork functions and to deal with file descriptors 
void exec_cmd(char** cmd1){ 
    pid_t pid; 
    if((pid = fork()) < 0){ 
     printf("Child Process Failed\n"); 
    }else if(pid == 0){ 
     if(execvp(cmd1[0], cmd1) < 0){ 
      printf("Execution Failed\n"); 
      exit(1); 
     } 
    }else{ 
     wait(NULL); 
    } 
} 
void exec_cmd_in(char** cmd1, char* infile){ 
    pid_t pid; 
    int fdi; 
    if((pid = fork()) < 0){ 
      printf("Child Process Failed\n"); 
    }else if(pid == 0){ 
     fdi = open(infile, O_RDONLY); 
     if(fdi == -1){ 
      printf("No Infile"); 
     } 
    } 
} 
void exec_cmd_opt_in_append(char** cmd1, char* infile, char* outfile){ 
    /* pid_t pid; 
    int fdi, fdo; 
    if((pid = fork()) < 0){ 
      printf("Child Process Failed\n"); 
    }else if(pid == 0){ 
     fdo = open(outfile, O_RDWR | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); 
     if(fdo == -1){ 
      printf("No Outfile"); 
     } 
     if(dup2(fdi, 0) == -1){ 
      printf("Infile not updated"); 
     } 
     if(dup2(fdo, 1) == -1){ 
      printf("Outfile not updated"); 
     } 
     close(fdi); 
     close(fdo); 
     if(execvp(cmd1[0], cmd1) < 0){ 
      printf("Execution Failed\n"); 
      exit(1); 
     } 
    }else{ 
     wait(NULL); 
    } */ 
} 
void exec_cmd_opt_in_write(char** cmd1, char* infile, char* outfile){ 
    /* pid_t pid; 
    int fdi, fdo; 
    if((pid = fork()) < 0){ 
     printf("Fork Error"); 
     exit(1); 
    }else if(pid == 0){ 
     fdo = open(outfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 
     if(fdo == -1){ 
       printf("No Outfile"); 
     } 

     if(dup2(fdi, 0) == -1){ 
      printf("Infile not updated"); 
     } 
     if(dup2(fdo, 1) == -1){ 
      printf("Outfile not updated"); 
     } 
     close(fdi); 
     close(fdo); 
     if(execvp(cmd1[0], cmd1) < 0){ 
      printf("Execution Failed\n"); 
      exit(1); 
     } 
    }else{ 
     wait(NULL); 
    } 
    */ 
} 
void exec_pipe(char** cmd1, char** cmd2){ 
    pid_t pid; 
    int pipefd[2]; 
    // pipe[1] is the write end of the pipe 
    // pipe[0] is the read end of the pipe 
    // making a pipe 
    printf("Inside Exec_Pipe\n"); 
    pid = fork(); 
    switch(pid){ 
     case -1: 
      //error in fork 
      printf("Fork Error\n"); 
      //Exit 
      exit(1); 
     case 0: 
      //child 
      break; 
     default: 
      //parent 
      wait(NULL); 
    } 
    //This will be executed by child process 
    if(pipe(pipefd) < 0) { 
     //error condition 
     printf("Pipe Error"); 
     exit(1); 
    } 
    pid = fork(); 
    switch(pid){ 
     case -1: 
      //error in fork 
      printf("Fork Error\n"); 
      //Exit 
     case 0: 
      //child 
      close(STDIN_FILENO); 
      //direct STDOUT to the pipe 
      dup2(pipefd[1], STDOUT_FILENO); 
      //Close descriptors 
      close(pipefd[0]); 
      close(pipefd[1]); 
      //Execute Command1 
      execvp(cmd1[0], cmd1); 
      //execvp should not return, so if it does 
      //there is an error! 
      printf("Error in EXECVP cmd1"); 
      exit(1); 
     default: 
      //parent 
      close(STDIN_FILENO); 
      //direct input to the pipe 
      dup2(pipefd[0],STDIN_FILENO); 
      //close descriptors 
      close(pipefd[0]); 
      close(pipefd[1]); 
      //execute command 2 
      execvp(cmd2[0],cmd2); 
      //if execvp makes it back, error condition 
      printf("Error in Pipe EXECVP cmd2"); 
      exit(1); 
    } 
} 
void exec_pipe_opt_in_append(char** cmd1, char** cmd2, char* infile, char* outfile){ 

} 
void exec_pipe_opt_in_write(char** cmd1, char** cmd2, char* infile, char* outfile){ 

} 
int parse_command(char* line, char** cmd1, char** cmd2, char* infile, char* outfile){ 
/* 
    (1)Create a bunch of flags to compare for the right return value 
    (2)Loop over the entire line and set the flags 
    (3)Add a bunch of if statements to compare flags 
    (4)If there is more than one flag for pipe, we can't handle it. Regurn 9. 
    (5)If there is &, we can't handle. 
    (6)Return the right value 
*/ 
    int pipe_found = 0; 
    int input_found = 0; 
    int redirection = 0; 
    int i = 0; 
    int spaces = 0; 
    int append = 0; 
    int special = 0; 
    while(line[i] != '\0'){ 
     if(line[i] == '|'){ 
      pipe_found++; 
     } 
     if(line[i] == '<'){ 
      input_found = 1; 
     } 
     if((line[i] == '&') || (line[i] == '*') || (line[i] == '^') || (line[i] == '%') || (line[i] == '#') || (line[i] == '!') || (line[i] == '@') || (line[i] == '(') || (line[i] == ')')){ 
      special = 1; 
     } 
     if(line[i] == '>'){ 
      redirection = 1; 
      if(line[i+1] == '>'){ 
       append = 1; 
      } 
     } 
     if(line[i] == ' '){ 
      spaces++; 
     } 
     i++; 
    } 
    if((strlen(line) >=4) && (line[0] == 'q') && (line[1] == 'u') && (line[2] == 'i') && (line[3] == 't')){ 
     return 0; 
    } 
    if((pipe_found == 0) && (special == 0)){ 
     if((redirection == 0) && (input_found == 0)){ 
      return 1; 
     }else if((redirection == 0) && (input_found == 1)){ 
      return 2; 
     }else if(append == 1){ 
      return 3; 
     }else if(redirection == 1){ 
      return 4; 
     } 
    }else if((pipe_found == 1) && (special == 0)){ 
     if((redirection == 0) && (input_found == 0)){ 
      return 5; 
     }else if((redirection == 0) && (input_found == 1)){ 
      return 6; 
     }else if(append == 1){ 
      return 7; 
     }else if(redirection == 1){ 
      return 8; 
     } 

    } 
      return 9; 
} 
//I referenced StackOverflow and some online libraries to get this tokenize function 
char ** tokenize(char *str, char *delim, unsigned int *number_tokens) { 
    char *pch = strtok(str, delim); 
    unsigned int ntok = 0; 
    if(pch != NULL) { 
     ntok = 1; 
    }else{ 
     return NULL; 
    } 
    char **tokens = realloc(NULL, sizeof(char *)*ntok); 
    tokens[ntok-1] = pch; 
    while(pch != NULL) { 
     pch = strtok(NULL, delim); 
     ntok++; 
     tokens = realloc(tokens, sizeof(char *)*ntok); 
     tokens[ntok-1] = pch; 
    } 
    if(number_tokens) { 
     *number_tokens = ntok; 
    } 
    return tokens; 
} 
//I referenced StackOverflow.com for this trim function 
char *trim(char *str) { 
    char *end; 
    if(str == NULL){ 
    return NULL; 
    } 
    while(isspace(*str)){ 
     str++; 
    } 
    end = str + strlen(str) - 1; 
    while(end > str && isspace(*end)) { 
     end--; 
    } 
    *(end+1) = 0; 
    return str; 
} 

int main(int argc, char *argv[]){ 
    int returnValue = 0; 
    char *infile = NULL; 
    char *outfile = NULL; 
    char **cmd = NULL; 
    char **cmd1_tokens = NULL; 
    char **cmd2_tokens = NULL; 
    char *input; 
    int current_cmd = 0; 
    /* 
    (1)If the user does not enter a command line argument, get one after typing "myshell-%" 
    (2)Call parse_command on the user input to get the right return value 
    (3)Begin parsing the user input within main 
    */ 
    if(argc == 1){ 
     printf("myshell-%%\n"); 
     fgets (input, 20, stdin); 
     returnValue = parse_command(input, cmd1_tokens, cmd2_tokens, infile, outfile); 
     cmd = tokenize(input, "|", NULL); 
    }else{ 
     returnValue = parse_command(argv[1], cmd1_tokens, cmd2_tokens, infile, outfile); 
     cmd = tokenize(argv[1], "|", NULL); 
    } 
    int infileIt = 0; 
    while(cmd[current_cmd] != NULL) { 
     unsigned int number_tokens = 0; 
     char **infile_token = tokenize(cmd[current_cmd], "<", &number_tokens); 
     if(number_tokens > 1){ 
      while(infile_token[infileIt] != NULL){ 
       infileIt++; 
      } 
     } 
     if(infile_token[1] != NULL) { 
      number_tokens = 0; 
      char **infile_outfile_token = tokenize(infile_token[1], ">", &number_tokens); 
      if(number_tokens > 1){ 
       infile = infile_outfile_token[0]; 

        infile = infile_token[1]; 
      } 
     } 
     number_tokens = 0; 
     char **outfile_token = tokenize(cmd[current_cmd], ">", &number_tokens); 
     if(number_tokens > 1){ 

        outfile = outfile_token[1]; 
     } 
     current_cmd++; 
    } 
    //Trim the in/outfiles 
    infile = trim(infile); 
    outfile = trim(outfile); 
    /* 
    Start breaking up cmd[0] and cmd[1] into smaller chunks and saving into the appropriate cmd 
    */ 
    cmd1_tokens = tokenize(cmd[0], " ", NULL); 
    if(cmd[1] != NULL){ 
     cmd2_tokens = tokenize(cmd[1], " ", NULL); 
    } 
    int cmd1Args = 0; 
    while(cmd1_tokens[cmd1Args] != NULL){ 
     cmd1Args++; 
    } 
    int cmd2Args= 0; 
    if(cmd2_tokens != NULL){ 
     while(cmd2_tokens[cmd2Args] != NULL){ 
      cmd2Args++; 
     } 
    } 
    int iterator = 0; 
    while((iterator < cmd1Args) && (cmd1Args != 0)){ 
     printf("Cmd1: %s\n", cmd1_tokens[iterator]); 
     iterator++; 
    } 
    iterator = 0; 
     while((iterator < cmd2Args)&&(cmd2Args != 0)){ 
     printf("Cmd2: %s\n", cmd2_tokens[iterator]); 
     iterator++; 
    } 
    if(infile != NULL){ 
     printf("Infile: %s\n", infile); 
    } 
    if(outfile != NULL){ 
     printf("Outfile: %s\n", outfile); 
    } 

    /*Use a switch statement to process all the return values (0 ot 9) of parse_command. 
    Our program should execute the “line” if the return code from parse_command 
    function is 0 to 8, that is the line is deemed “valid”. For return code 9, 
    our program simply output ”Not handled at this time!”.*/ 
    switch(returnValue){ 
    case 0 : 
     printf("Exiting Program.\n"); 
     exit(1); 
     break; 
    case 1 : 
     printf("Inside Case 1\n"); 
     exec_cmd(cmd1_tokens); 
     break; 
    case 2 : 
     printf("Inside Case 2\n"); 
     exec_cmd_in(cmd1_tokens, infile); 
     break; 
    case 3 : 
     printf("Inside Case 3\n"); 
     exec_cmd_opt_in_append(cmd1_tokens, infile, outfile); 
     break; 
    case 4 : 
     printf("Inside Case 4\n"); 
     exec_cmd_opt_in_write(cmd1_tokens, infile, outfile); 
     break; 
    case 5 : 
     printf("Inside Case 5\n"); 
     exec_pipe(cmd1_tokens, cmd2_tokens); 
     break; 
    case 6 : 
     printf("Inside Case 6\n"); 
     //exec_pipe_in(cmd1_tokens, cmd2_tokens, infile); 
     break; 
    case 7 : 
     printf("Inside Case 7\n"); 
     exec_pipe_opt_in_append(cmd1_tokens, cmd2_tokens, infile, outfile); 
     break; 
    case 8 : 
     printf("Inside Case 8\n"); 
     exec_pipe_opt_in_write(cmd1_tokens, cmd2_tokens, infile, outfile); 
     break; 
    default : 
     printf("Inside Case 9\n"); 
     printf("Not handled at this time!\n"); 
} 

    return 0; 
} 
+0

Относительно: меня больше беспокоит [исправление ваших предупреждений] (http://pastebin.com/3v0VqEmN) перед чем-либо еще. – WhozCraig

+0

Я исправил столько, сколько смогу на данный момент. Извиняюсь за то, что раньше не проверяли их дважды. – GiH

+1

Сделайте себе одолжение: лучше сообщайте об ошибках. Например, у вас есть: 'execvp (cmd1 [0], cmd1); printf («Ошибка в EXECVP cmd1»); exit (1); 'Это почти хорошо, но сообщения об ошибках должны быть напечатаны на стандартной ошибке, должны заканчиваться новой строкой и содержать полезную информацию, такую ​​как команда, которая не была выполнена, и, возможно, номер ошибки и соответствующее сообщение : 'fprintf (stderr,"% s: ошибка в execvp CMD1 для '% s' (% d:% s) \ n ", arg0, cmd1 [0], errno, strerror (errno));' где 'arg0' является указателем на имя программы оболочки, установленной при запуске оболочки. –

ответ

3

Не имея доступа к входному файлу, который вы даете его, это немного трудно сказать, что происходит, но вот некоторые советы по ее отладке.

Во-первых, когда что-то, что вы не понимаете, происходит, может быть хорошей идеей разбить его на minimal, working, self contained example, который демонстрирует проблему. Иногда, просто процесс его сокращения до этого небольшого примера может помочь вам найти проблему; но если нет, это дает вам гораздо меньший пример, о котором нужно спросить.

Далее, при установке этих операторов печати для отладки, что происходит, дайте себе немного больше контекста. Особенно в том, что указывает на ошибку; распечатать, что такое ошибка, и какие аргументы были для функции, которая не удалась. Вместо того, чтобы просто:

printf("Error in Pipe EXECVP cmd2"); 

Вы можете использовать strerror, чтобы получить строку, представляющую число ошибок:

printf("Error %d in Pipe EXECVP cmd2: %s\n", errno, strerror(errno)); 

И вы также можете распечатать то, что были командой и все ваши аргументы:

for (char **arg = cmd2; *arg != NULL; ++arg) { 
    printf("cmd2[%ld] = %s", arg - cmd2, *arg); 
} 

Между печатью фактической ошибки и печать имени команды и всех аргументов, которые должны помочь вам отладить проблему.

Если вы могли бы добавить эту информацию к своему вопросу и, возможно, сократить свой пример до более минимального примера, а также показать минимальный пример ввода, который вызывает проблему, мы, вероятно, могли бы помочь намного больше.

+0

Спасибо за ваше время. :) Я извиняюсь за то, что не был таким наглядным, каким должен был быть, но я ценю ваши усилия. Я отвечу на ваш совет. – GiH