#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdbool.h>
typedef struct command {
char **argv;
int argc;
} command;
enum{
READ = 0,
WRITE = 1,
};
int *create_pipefd(int num){
int *pipes = malloc(sizeof *pipes * num * 2); // allocate memory for the pipes
if(pipes == NULL){
perror("malloc() failed");
exit(EXIT_FAILURE);
}
for(size_t i = 0; i < num; i++){
if(pipe(pipes + i*2) == -1){ // create the pipes
perror("pipe() failed");
exit(EXIT_FAILURE);
}
}
return pipes;
}
bool configure_pipes(int *pipefd, int command, int pipe_count){
if(command == 0){
// first command
return dup2(pipefd[command*2 + WRITE], STDOUT_FILENO) != -1;
}else if(command == pipe_count){
// last command
return dup2(pipefd[(command-1)*2 + READ], STDIN_FILENO) != -1;
}else {
return dup2(pipefd[command*2 + WRITE], STDOUT_FILENO) != -1 &&
dup2(pipefd[(command-1) * 2 + READ], STDIN_FILENO) != -1;
}
}
int main(){
int pipe_count = 2;
int command_count = 3;
command *commands = malloc(3 * sizeof(command));
commands[0].argv = malloc(4096 * sizeof *commands[0].argv);
commands[1].argv = malloc(4096 * sizeof *commands[1].argv);
commands[2].argv = malloc(4096 * sizeof *commands[2].argv);
#define BUFFER_SIZE 4096
#define COMMAND_SIZE 512
for(size_t x = 0; x < BUFFER_SIZE; x++){
commands[0].argv[x] = malloc(COMMAND_SIZE*sizeof(char)); // malloc each element of the array seperately
memset(commands[0].argv[x], 0, COMMAND_SIZE); // zero out the memory
commands[1].argv[x] = malloc(COMMAND_SIZE*sizeof(char)); // malloc each element of the array seperately
memset(commands[1].argv[x], 0, COMMAND_SIZE); // zero out the memory
commands[2].argv[x] = malloc(COMMAND_SIZE*sizeof(char)); // malloc each element of the array seperately
memset(commands[2].argv[x], 0, COMMAND_SIZE); // zero out the memory
}
memcpy(commands[0].argv[0], "/bin/w", strlen("/bin/w"));
commands[0].argv[1] = NULL;
commands[0].argc = 1;
memcpy(commands[1].argv[0], "/bin/grep", strlen("/bin/grep"));
memcpy(commands[1].argv[1], "tty2", strlen("tty2"));
commands[1].argv[2] = NULL;
commands[1].argc = 2;
memcpy(commands[2].argv[0], "/bin/grep", strlen("/bin/grep"));
memcpy(commands[2].argv[1], "t", strlen("t"));
commands[2].argv[2] = NULL;
commands[2].argc = 2;
printf("commands[1].argv[1]: %s\n", commands[0].argv[0]);
printf("pipe_count 2: %d\n", pipe_count);
printf("command_count 2: %d\n", command_count);
for (int i = 0; i < command_count; i++) {
for(int j = 0; j < commands[i].argc+1; j++){
fprintf(stderr, "commands[%d].argv[%d]: %s\n", i, j, commands[i].argv[j]);
}
}
int* pipes = create_pipefd(pipe_count);
for(size_t i = 0; i < command_count; i++){
pid_t child = fork();
switch (child) {
case -1:
fprintf(stderr, "Failed to fork()");
exit(EXIT_FAILURE);
case 0:
/* child */
if(configure_pipes(pipes, i, pipe_count) == false){
perror("configure_pipes failed\n");
return 1;
}
for (size_t j = 0; j < pipe_count; j++) {
close(pipes[j*2+READ]);
close(pipes[j*2+WRITE]);
}
free(pipes);
if(execvp(commands[i].argv[0], commands[i].argv) != 0){
perror("execvp() failed");
exit(EXIT_FAILURE);
}
break;
default:
break;
}
}
}