Я пытаюсь написать простую оболочку (просто пытаюсь понять, как работают оболочки).Первая часть (анализ аргументов командной строки) работает нормально, но я не могу заставить работать вторую часть (выполнение команды).
Я пытаюсь создать пару каналов для каждых двух последовательныхпрограммы.Текущая команда записывает в pdes [0], а следующая читает из pdes [1];Поскольку я создаю несколько процессов в цикле, переменная с именем prev_out используется для запоминания конца чтения предыдущей команды в списке.Первая команда в списке читает свой ввод из стандартного ввода, а не из канала.Аналогично, последняя программа также записывает свои выходные данные в стандартный вывод, а не в канал.
pipe1 pipe2
* * * *
* * * *
--> CMD1 CMD2 CMD3 --> stdout
Что-то похожее на приведенную выше схему.Каждая команда записывает в pdes [0] и читает соответствующие pdes [1].
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <assert.h>
#include <unistd.h>
#include <sys/wait.h>
#define MAXLINE 255
#define MAXARG 32
#define MAXNCMD 16
extern char **environ;
int
main(int argc, char *argv[])
{
char *cmds[MAXNCMD][MAXARG];
char line [MAXLINE + 1];
pid_t childs [MAXNCMD];
char *cmdcur, *argcur;
char *linecp;
int c , st;
int i , j, k;
int prev_in , prev_out;
for (;;) {
printf("%% ");
i = 0;
while ('\n' != (c = getc(stdin)) && i < MAXLINE) {
if (c == EOF)
exit(EXIT_SUCCESS);
/* NOTREACHED */
line[i++] = c;
}
line[i] = 0; /* null-terminate */
if (0 == strncmp(line, "exit", 4)) {
exit(EXIT_SUCCESS);
/* NOTREACHED */
}
if (0 == strncmp(line, "cd ", 3)) {
if (-1 == chdir(line + 3)) {
perror("chdir()");
}
continue;
}
linecp = line;
j = 0;
k = 0;
while (NULL != (cmdcur = strsep(&linecp, "|"))) {
while (*cmdcur == ' ')
cmdcur++;
k = 0;
while (NULL != (argcur = strsep(&cmdcur, " "))) {
while (*argcur == ' ')
argcur++;
if (NULL == (cmds[j][k] = malloc(strlen(argcur) + 1))) {
perror("malloc()");
exit(EXIT_FAILURE);
}
strncpy(cmds[j][k], argcur, strlen(argcur));
k++;
if (k == MAXARG) {
fprintf(stderr, "%s: Too many args\n", argv[0]);
exit(EXIT_FAILURE);
} /* NOTREACHED */
}
cmds[j][k] = NULL;
j++;
if (j == MAXNCMD) {
fprintf(stderr, "%s: Too many args\n", argv[0]);
exit(EXIT_FAILURE);
/* NOTREACHED */
}
}
*cmds[j] = NULL;
int nc = j;
for (int m = 0; m < nc; m++) {
int pdes [2];
if (-1 == pipe(pdes)) {
perror("pipe()");
exit(EXIT_FAILURE);
}
if (-1 == (childs[m] = fork())) {
perror("fork()");
exit(EXIT_FAILURE);
}
prev_out = pdes[1];
if (0 == childs[m]) {
/* child */
if (0 == m) {
close(STDOUT_FILENO); /* the first process in the pipe group needs
dup(pdes[0]); * only to set its stdout, the next process
prev_out = pdes[1]; * will use the other end */
} else if (m == (nc - 1)) {
close(STDIN_FILENO); /* the last process only needs to set its stdin
dup(prev_out); * it will use termical as stdout by default */
} else {
close(STDIN_FILENO); /* inner processes should set both stdin and stdout */
dup(prev_out);
close(STDOUT_FILENO);
dup(pdes[0]);
prev_out = pdes[1];
}
if (-1 == execvp(cmds[i][0], cmds[i])) {
perror("execvp()");
exit(EXIT_FAILURE);
}
} else if (childs[m] > 0) {
if (childs[m] != wait(NULL)) {
perror("wait()");
exit(EXIT_FAILURE);
}
}
}
}
return 0;
}