Writing my own Linux shell with unnamed pipes

I am experimenting with Linux, and now I'm working on writing a program that mimics the Linux shell.

I have a main function that analyzes the input data and is now irrelevant for my question. After each line, the process line method is analyzed, which processes everything. At the moment, I support regular processes, background processes, and am currently working on unnamed channels that contain only 2 commands (cmd1 | cmd2).

Here is the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include <unistd.h>

void wait_for_background_process(void* arg) {
  int status;
  pid_t* pid = (pid_t*) arg;
  do {
    printf("Waiting for %d\n", *pid);
    waitpid(*pid, &status, WUNTRACED);
  } while (!WIFEXITED(status) && !WIFSIGNALED(status));
}

/************************
function: void pipeCommand(char** cmd1, char** cmd2)
comment: This pipes the output of cmd1 into cmd2.
**************************/
void pipe_command(char** cmd1, char** cmd2) {
  int fds[2]; // file descriptors
  if(pipe(fds) < 0) {
    perror("myShell");
    exit(EXIT_FAILURE);
  }
  pid_t pid;

  pid = fork();
  if(pid == 0) {
    dup2(fds[1], 1);
    if(execvp(cmd1[0], cmd1) < 0) {
      perror("myShell");
      exit(EXIT_FAILURE);
    }
    execvp(cmd1[0], cmd1);
  } else if(pid < 0) {
    perror("myShell");
    exit(EXIT_FAILURE);
  } else {
    wait(NULL);
    dup2(fds[0], 0);
    if(execvp(cmd2[0], cmd2)) {
      perror("myShell");
      exit(EXIT_FAILURE);
    }
  }
}
/*
* Checks if the command is pipe command, if so we will return the
* index of the pipe
*/
int is_pipe_command(char** arglist, int count) {
  int i = 0;
  for(i = 0; i < count; i++) {
    if(strcmp(arglist[i], "|") == 0) {
      return i;
    }
  }
  return 0;
}

int process_arglist(int count, char** arglist) {
    pid_t pid;
    int pipe_index;
    pid = fork();
    if (pid == 0) {
      // Child process
      if(strcmp(arglist[count-1],"&") == 0) {
        char** background_arglist = (char**) malloc((count)*sizeof(char*));
        if(background_arglist == NULL) {
          printf("malloc failed: %s\n", strerror(errno));
                exit(EXIT_FAILURE);
        }
        int i = 0;
        for(i = 0; i < count - 1; i++) {
          background_arglist[i] = arglist[i];
        }
        background_arglist[count - 1] = NULL;
        if (execvp(background_arglist[0], background_arglist) == -1) {
          perror("myShell");
        }
      } else if(pipe_index = is_pipe_command(arglist, count)) {
          char** cmd1 = (char**) malloc((pipe_index+1)*sizeof(char*));
          if(cmd1 == NULL) {
            printf("malloc failed: %s\n", strerror(errno));
            exit(EXIT_FAILURE);
          }
          int i;
          int cmd1index = 0;
          for(i = 0; i < pipe_index; i++) {
            cmd1[cmd1index] = arglist[i];
            cmd1index++;
          }
          cmd1[pipe_index] = NULL;
          char** cmd2 = (char**) malloc((count - pipe_index)*sizeof(char*));
          if(cmd2 == NULL) {
            printf("malloc failed: %s\n", strerror(errno));
                exit(EXIT_FAILURE);
          }
          int cmd2index = 0;
          for(i = pipe_index+1; i < count; i++) {
            cmd2[cmd2index] = arglist[i];
            cmd2index++;
          }
          cmd2[count-pipe_index-1] = NULL;
          pipe_command(cmd1, cmd2);
      } else {
          if (execvp(arglist[0], arglist) == -1) {
            perror("myShell");
          }
      }
      exit(EXIT_FAILURE);
    } else if (pid < 0) {
      // Error forking
      perror("myShell");
      exit(EXIT_FAILURE);
    } else {
      // Parent process
      if(strcmp(arglist[count-1],"&") == 0) {
        // The child is a background process
        pthread_t thread;
        pthread_create(&thread, NULL, wait_for_background_process, &pid);
      }
      else {
        // Regular process
      }
    }

    return 1;
}

We can focus on the pipe_command function that correctly executes two commands, I cannot understand why I am not getting any output for calling, for example, ls -l | sortor ls -l | grep "a".

Thanks.

+4
1

dup fds[1]. (sort grep ) EOF stdin. EOF , , .

else pipe_command close :

} else {
    wait(NULL);
    dup2(fds[0], 0);
    close(fds[1]); /* ADDED THIS LINE */
    if(execvp(cmd2[0], cmd2)) {
       perror("myShell");
       exit(EXIT_FAILURE);
    }
}

. close(fds[0]);. , execvp, , .

+2

Source: https://habr.com/ru/post/1621821/


All Articles