Проблема с перенаправлением и конвейеризацией в моей простой оболочке UNIX - PullRequest
0 голосов
/ 29 ноября 2010

РЕДАКТИРОВАТЬ: Я не могу заставить некоторые отступы работать правильно, но код завершен и правильно заблокирован. К сожалению.

Для назначения класса мне пришлось реализовать часть простой оболочки UNIX. Он должен поддерживать перенаправление, трубопроводы и фоновую обработку. Мне предоставили синтаксический анализатор, который заполняет структуру с именем Command_line (я включу прототип структуры ниже). Моя работа состоит в том, чтобы написать функцию, которая обрабатывает эти Command_lines (обрабатывает перенаправление, фоновый режим, конвейерную обработку и выполняет программы).

У меня почти все работает, но по какой-то причине он неправильно обрабатывает команды вида program1 | программа2 - файл . Например, cat

Когда я запускаю одну из этих проблемных командных строк, вывод первой программы выводится на печать, и процесс зависает (мне приходится вручную приостанавливать и уничтожать его). После этого он не выдает подсказки пользователю и не реагирует на ввод (кроме Ctrl + Z, который я использую для приостановки процесса).

Любой совет о том, как заставить это работать, был бы очень признателен.

Вот структура:

/* This is the structure that holds the information about a parsed
 * command line.  The argvs array is an array of string vectors; in
 * other words, for some int i, argvs[i] is an array of strings.
 * You should be able to use argvs[i] in calls to one of the execv*()
 * functions.
 */
typedef struct {
  char *argvs[MAX_PROGS + 1][MAX_ARGS + 1];
  int num_progs;  /* Number of argument vectors; if > 1, piping is requested */
  char *infile;   /* Name of stdin redirect file; NULL if no redirection */
  char *outfile;  /* Name of stdout redirect file; NULL if no redirection */
  int append;     /* Is output redirection appending? */
  int bg;         /* Put command into background? */
} Command_line;

И мой код, который обрабатывает одну из этих структур (я пропустил #include).

pid_t runproc(int fd[][2], int num, Command_line *cmd);

void execute_command_line(Command_line *cmd) {
  int n;
  int temp_pipe[2];
  int fd[MAX_PROGS-1][2];
  pid_t pids[MAX_PROGS];

  /* Clears pipes (sets all values to -1*/
  for(n = 0; n < cmd->num_progs; n++){
    fd[n][0] = -1;
    fd[n][1] = -1;
  }

  /*Uses temp_pipe to connect write end of nth pipe to read end of (n+1)th 
    pipe*/
  for(n = 0; n < cmd->num_progs - 1; n++){
    pipe(temp_pipe);
    fd[n][1] = temp_pipe[1];
    fd[n+1][0] = temp_pipe[0];
  }

  /*If input file redirection is occuring, redirects read end of first pipe to
    file*/
  if(cmd->infile){
    fd[0][0] = open(cmd->infile, O_RDONLY);
    if(fd[0][0] < 0){
      printf("Error executing command\n");
      exit(1);
    }
  }

  /*If output file redirection is occurring, redirects write end of last pipe to
    file. Sets append option according to append field of command*/
  if(cmd->outfile){
    if(cmd->append){
      fd[cmd->num_progs - 1][1] = open(cmd->outfile, O_APPEND | O_WRONLY);
      if(fd[cmd->num_progs - 1][1] < 0){
printf("Error executing command\n");
exit(1);
      }
    }else{
      fd[cmd->num_progs - 1][1] = open(cmd->outfile, O_WRONLY);
      if(fd[cmd->num_progs - 1][1] < 0){
 printf("Error executing command\n");
 exit(1);
      }
    }
  }

  /*Runs runproc for every program in pipe, stores return values (pids of
    children) in array*/
  for(n = 0; n < cmd->num_progs; n++){
    pids[n] = runproc(fd, n, cmd);
  }

  /*Closes all pipes*/
  for(n = 0; n < cmd->num_progs; n++){
    if(fd[n][0] >= 0) close(fd[n][0]);
    if(fd[n][1] >= 0) close(fd[n][1]);
  }

  /*Waits for all children*/
  for(n = 0; n < cmd->num_progs; n++){
    wait(NULL);
  }

}

pid_t runproc(int fd[][2], int num, Command_line *cmd){
  pid_t pid;
  int n;
  int frk_chk;

  pid = fork();
  if(pid < 0){
    printf("Error executing command\n");
    exit(1);
  }else if (!pid){ /*Child code*/
    /*Redirects stdin/stdout of process to read/write end of corresponding
      pipe*/
    if(fd[num][0] >= 0) dup2(fd[num][0], STDIN_FILENO);
    if(fd[num][1] >= 0) dup2(fd[num][1], STDOUT_FILENO);

    /*Closes pipe ends*/
    for(n=0; n < cmd->num_progs - 1; n++){
      if(fd[num][0] >= 0) close(fd[num][0]);
      if(fd[num][1] >= 0) close(fd[num][1]);
    }

    /*If backgrounding: forks, parent exits, child executes program. 
      If not backgrounding: program just executes*/
    if(cmd->bg){
      if((frk_chk = fork()) < 0){
 printf("Error executing command\n");
 exit(1);
      }else if(frk_chk){
 exit(0);
      }else{
 if(!(cmd->infile) && num == 0) close(STDIN_FILENO);
 execvp(cmd->argvs[num][0], cmd->argvs[num]);
      }
    }else{
      if(!num){
 dup2(fd[0][1], STDOUT_FILENO);
      }
      execvp(cmd->argvs[num][0], cmd->argvs[num]);
    }
    printf("Error executing command\n");
    exit(1);
  }else{ /*Parent code*/
    /*Returns pid of child, used for reaping loop*/
    return pid;
  }
}

1 Ответ

0 голосов
/ 30 января 2011

В пределах run_proc() в цикле /*close pipe ends*/ должно быть

for(n=0; n < cmd->num_progs - 1; n++)
   {
      if(fd[n][0] >= 0) close(fd[n][0]);
      if(fd[n][1] >= 0) close(fd[n][1]);
    }
...