Короткая программа, приведенная ниже, предназначена для перебора аргументов argv, переданных из командной строки, и выполнения каждого аргумента. Это не моя домашняя работа, а то, чем я занимаюсь, готовясь к домашней работе.
Первый аргумент получает входные данные из STDIN и STDOUT и записывает в канал. В конце каждой итерации (кроме последней) файловые дескрипторы меняются местами, так что канал, записанный последним exec, будет прочитан следующим. Таким образом, я намерен, например, для
./a.out /bin/pwd /usr/bin/wc
для распечатки только длины рабочего каталога. Код следует
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
main(int argc, char * argv[]) {
int i;
int left[2], right[2], nbytes; /* arrays for file descriptors */
/* pointers for swapping */
int (* temp);
int (* leftPipe) = left;
int (* rightPipe) = right;
pid_t childpid;
char readbuffer[80];
/* for the first iteration, leftPipe is STDIN */
leftPipe[0] = STDIN_FILENO;
leftPipe[1] = STDOUT_FILENO;
for (i = 1; i < argc; i++) {
/* reopen the right pipe (is this necessary?) */
pipe(rightPipe);
fprintf(stderr, "%d: %s\n", i, argv[i]);
fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);
if ((childpid = fork()) == -1) {
perror("fork");
exit(1);
}
if (childpid == 0) {
/* read input from the left */
close(leftPipe[1]); /* close output */
dup2(leftPipe[0], STDIN_FILENO);
close(leftPipe[0]); /* is this necessary? A tutorial seemed to be doing this */
/* write output to the right */
close(rightPipe[0]); /* close input */
dup2(rightPipe[1], STDOUT_FILENO);
close(rightPipe[1]);
execl(argv[i], argv[i], NULL);
exit(0);
}
wait();
/* on all but the last iteration, swap the pipes */
if (i + 1 < argc) {
/* swap the pipes */
fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);
temp = leftPipe;
leftPipe = rightPipe;
rightPipe = temp;
fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);
}
}
/* read what was last written to the right pipe */
close(rightPipe[1]); /* the receiving process closes 1 */
nbytes = read(rightPipe[0], readbuffer, sizeof(readbuffer));
readbuffer[nbytes] = 0;
fprintf(stderr, "Received string: %s\n", readbuffer);
return 0;
}
ОБНОВЛЕНИЕ : во всех нижеприведенных тестовых примерах я изначально использовал / bin / wc, но который показал, что унитаз совсем не там, где я думал. Я нахожусь в процессе исправления результатов.
Выход в тривиальном случае (./a.out / bin / pwd), как и ожидалось:
1: /bin/pwd
Received string: /home/zeigfreid/Works/programmatical/Langara/spring_2012/OS/labs/lab02/play
Результат запуска этой программы с первым примером (./a.out / bin / pwd / usr / bin / wc):
1: /bin/pwd
0 1 3 4
3 4 0 1
2: /bin/wc
В этот момент терминал зависает (возможно, ожидает ввода).
Как видите, строка не принимается. То, что я представляю себе, это то, что я сделал что-то неправильное выше, либо при обмене указателями, либо что я не понимаю дескрипторы файлов Unix. В конце концов, мое задание будет заключаться в интерпретации произвольно длинных труб, и это одна из идей, которые у меня были для решения проблемы. У меня проблемы с оценкой, нахожусь ли я на правильном пути, чтобы лаять дерево. Я понимаю дескрипторы файлов Unix?
UPDATE:
Запустив его с / bin / ls в качестве второго аргумента, я получил следующий результат (числа - это дескрипторы файлов в разных точках):
1: /bin/pwd
0 1 3 4
0 1 3 4
3 4 0 1
2: /bin/ls
3 4 5 6
Received string: a.out
log
pipe2.c
play.c
@
В конце все еще есть какой-то мусор, но я теперь больше обеспокоен тем, что не понимаю указателей! Эти две команды независимы друг от друга, но они на самом деле не используют канал.
ОБНОВЛЕНИЕ : символ мусора не был закрыт строкой. Теперь я его закрываю, а мусора нет.