#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, похоже, это были проблемы. Как только я их исправил, все получилось!