?
Gut. Jetzt, wo du ne eigene Lösung hast, so finge ich das an:
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
static char *const argv_ps [] = { "ps" , "aux", NULL };
static char *const argv_sort[] = { "sort", "-n" , NULL };
static char *const argv_head[] = { "head", "-20", NULL };
static char *const *const prc_specs[] = { NULL,
argv_ps,
argv_sort,
argv_head };
#define PRC_COUNT (ARRAY_SIZE(prc_specs) - 1)
void tie_pipe(int pipe, int stream) {
if(pipe != stream) {
dup2(pipe, stream);
}
}
void close_pipe(int pipe) {
if(pipe != STDIN_FILENO && pipe != STDOUT_FILENO) {
close(pipe);
}
}
void collect_children(size_t children_count) {
size_t i;
for(i = 0; i < children_count; ++i) {
wait(NULL);
}
}
int main(void) {
pid_t pid[PRC_COUNT + 1];
int pipes[PRC_COUNT + 1][2];
size_t i;
char *line = NULL;
size_t line_len = 0;
pipes[0][0] = STDIN_FILENO;
pipes[0][1] = STDOUT_FILENO;
for(i = 1; i <= PRC_COUNT; ++i) {
pipe(pipes[i]);
pid[i] = fork();
if(pid[i] == -1) {
fprintf(stderr, "Fehler beim %luten Forken!\n", i);
collect_children(i - 1);
return -1;
} else if(pid[i] == 0) {
tie_pipe(pipes[i - 1][0], STDIN_FILENO );
tie_pipe(pipes[i ][1], STDOUT_FILENO);
execvp(prc_specs[i][0], prc_specs[i]);
} else {
close_pipe(pipes[i - 1][0]);
close_pipe(pipes[i ][1]);
}
}
tie_pipe(pipes[i - 1][0], STDIN_FILENO);
while(getline(&line, &line_len, stdin) != -1) {
fputs(line, stdout);
}
free(line);
collect_children(i);
return 0;
}
Der wesentliche Unterschied ist, dass hier der Hauptprozess für jedes Kommando in der Kanalisation einen eigenen Prozess aufmacht und sie am Ende wieder einsammelt (mit wait), anstatt einen Rattenschwanz vorheriger Prozesse zu spawnen, sich selbst in den letzten zu verwandeln und sich für das Einsammeln auf init zu verlassen. Falls später notwendig, ist eine Kontrolle der Kindprozesse (etwa Abschießen hängender Prozesse) so einfacher zu implementieren, und es ist einfacher erweiterbar.
Allerdings ist dein Ansatz für die Aufgabenstellung völlig ausreichend.