Использование dup2 при работе с каналами завершается неудачно, несмотря на создание допустимых файловых дескрипторов

#c #shell #pipe

Вопрос:

Я создаю свою собственную оболочку UNIX и пытаюсь реализовать поддержку (нескольких) команд канала. Как вы можете видеть ниже, я создаю необходимые файловые дескрипторы для каждого канала, а затем создаю дочерний процесс для каждой используемой команды fork() . Внутри цикла я использую dup2 для копирования соответствующих файловых дескрипторов, унаследованных родителем, и перенаправления моего ввода/вывода. Однако, когда я тестирую его с помощью echo tst | cw -w , Failed to write output for the next command.. блок срабатывает. Я не понимаю, в чем причина этой проблемы здесь. Я создал каналы с их файловыми дескрипторами, я добавил соответствующие проверки для первой и последней команд, я закрываю унаследованные каналы перед выполнением команды и т. Д.

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

 void execPipedCommands(char *input, char **commands) {  int numOfPipes = countCharOccurences(input, '|');  int fds[2 * numOfPipes]; // two file descriptors per pipe needed for interprocess communication  int i;   // initialize all pipes and store their respective fds in the appropriate place in the array  for (i = 0; i lt; 2 * numOfPipes; i  )  {  if (pipe(fds   2 * i) == -1)  {  printf("Failed to create file descriptors for pipe commands!n");  exit(EXIT_FAILURE);  }  }   for (i = 0; i lt; numOfPipes 1; i  )  {  if (commands[i] == NULL)  break;  pid_t cpid;  char *args[MAX_NUM_OF_COMMAND_WORDS] = {  NULL,  };  parseCommandWords(commands[i], args);  cpid = fork(); // start a child process  if (cpid == -1)  {  printf("Failed to fork..n");  exit(EXIT_FAILURE);  }   if (cpid == 0)  { // child process is executing  if (i != 0)  { // if this is not the first command in the chain  // duplicate the file descriptor to read from the previous command's output  if (dup2(fds[(i - 1) * 2], STDIN_FILENO) lt; 0)  {  printf("Failed to read input from previous command..n");  exit(EXIT_FAILURE);  }  }   // if this is not the last command in the chain  if (i != numOfPipes 1 amp;amp; commands[i   1] != NULL)  {  // duplicate write file descriptor in order to output to the next command  if (dup2(fds[(i * 2   1)], STDOUT_FILENO) lt; 0)  {  printf("Failed to write output for the next command..n");  exit(EXIT_FAILURE);  }  }   // close the pipes  int j;  for (j = 0; j lt; numOfPipes * 2; j  )  { // close all copies of the file descriptors  close(fds[j]);  }   // execute command  if (execvp(commands[i], args) lt; 0)  {  printf("Failed to execute given command..");  return;  }  }  }  // parent closes all original file descriptors  for (i = 0; i lt; numOfPipes * 2; i  )  {  close(fds[i]);  }   // parent waits for all child processes to finish  for (i = 0; i lt; numOfPipes   1; i  )  wait(0); }  

input Аргумент-это просто строка, считываемая из командной строки, и commands аргумент содержит все команды в прочитанной строке. Поэтому для примера, который я привел ранее, он будет содержать:

 commands[0] = echo tst commands[1] = cw -w  

Комментарии:

1. две ошибки (не уверен, вызывают ли они проблему): а) цикл для создания канала должен идти только вверх i lt; numOfPipes . То, как это происходит, вызывает переполнение буфера б) if (i != numOfPipes 1 amp;amp; commands[i 1] != NULL) должно if(i != numOfPipes amp;amp; ...) происходить по мере того, как ваш цикл увеличивается до i lt;= numOfPipes - 1

2. Кроме того, пожалуйста, заведите привычку проверять аргументы функции в начале функции. Например, if (input == NULL || commands == NULL) exit(EXIT_FAILURE); что-то в этом роде

3. @kiner_shah Вы правы, я должен был упомянуть, что они уже проверены, если эта функция вызывается 🙂

4. @IngoLeonhardt Спасибо, я совсем по ним соскучился.

5. @IngoLeonhardt, похоже, это были проблемы. Как только я их исправил, все получилось!