1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#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;
    }

  }
}