Конвейерная команда ps -j | все еще висит после закрытия всех каналов и изменения PGID

Я пытаюсь создать свою собственную оболочку. Идея состоит в том, что, когда я делаю многоступенчатую конвейерную команду, такую ​​как ps -j | more, первый процесс ps -j будет лидером группы процессов, и все последующие процессы будут использовать один и тот же идентификатор группы процессов.

По какой-то причине это работает для таких команд, как ls | grep pipes, но висит на ps -j | more,

Вот картинка для демонстрации:

Вещи, которые я сделал:

  • Закрывая все трубы, я делаю любую dup2() позвонить в детей и родителей
  • призвание setpgid() перед любым execvp() звоните и у ребенка и у родителя

Код ниже. Краткое объяснение того, как это работает: каждый процесс вызывает fork_process() который принимает строку позиции: FIRST | MIDDLE | FINAL | ONLY, который указывает, какой процесс находится в конвейере.

Например ps-j = ПЕРВЫЙ и more = Финал

fork_process() затем создает каналы, разветвляется и выполняет команду внутри дочернего процесса. Это также где setpgid() называется. Если разветвленный процесс является либо ПЕРВЫМ, либо ТОЛЬКО форком, то он сохраняет свой pid в cmd_group->pgid так может другой процесс setpgid() к этому пгид.

execute_commands:

int execute_commands(Command_Group* cmd_group) {
  int cmd_count = cmd_group->cmd_count;
  int fd_count = cmd_group->fd_count;
  int pipe_count = cmd_group->pipe_count;  

  for (int i = 0; i < cmd_count; i++) {

    if (i == 0 && pipe_count == 0 && cmd_count == 1) {
      if (fork_process(cmd_group, i, NULL, NULL, ONLY) < 0) {
        perror("invalid error executing command");
        return -1;
      }
    }
    else if (i == 0 && pipe_count > 0) { 
      int* fd = cmd_group->pipe_fds[fd_count++];
      if (fork_process(cmd_group, i, fd, NULL, FIRST) < 0) {
        perror("invalid error executing command");
        return -1;
      }
    }
    else if (i == (cmd_count - 1) && pipe_count > 0) {
      int* fd = cmd_group->pipe_fds[fd_count - 1];
      if (fork_process(cmd_group, i, fd, NULL, FINAL) < 0) {
        perror("invalid error executing command");
        return -1;
      }
    } 
    else {
      int* previous_fd = cmd_group->pipe_fds[fd_count - 1];
      int* fd = cmd_group->pipe_fds[fd_count++];
      if (fork_process(cmd_group, i, previous_fd, fd, MIDDLE) < 0) {
        perror("invalid error executing command");
        return -1;
      }
    }
  }
  close_pipes(cmd_group->pipe_fds, pipe_count);

  printf("PARENT pid: %d, pgid: %d, ppid: %d\n", getpid(), getpgid(0), getppid());

  for (int i = 0; i < cmd_group->cmd_count; i++) {
    int pid = cmd_group->cmd_list[i]->pid;
    char* cmd = cmd_group->cmd_list[i]->cmd;
    printf("CHILD cmd: %s, pid: %d, pgid: %d\n", cmd, pid, getpgid(pid));
  }


  int status;
  int corpse;

  while ((corpse = waitpid(-1, &status, 0)) > 0) {
    fprintf(stderr, "%d: child %d exited with status 0x%.4X\n",
              (int)getpid(), corpse, (unsigned)status);
  }

  return 0;
}

fork_process:

int fork_process(Command_Group* cmd_group, int cmd_idx, int fd[2], int second_fd[2], char* position) {

  if (cmd_group == NULL) {
    perror("invalid null command passed to fork_process");
    return -1;
  }

  Command* cmd = cmd_group->cmd_list[cmd_idx];

  pid_t pid;

  if (strcmp(position, FIRST) == 0) {
    pipe(fd);
  } else if (strcmp(position, MIDDLE) == 0) {
    pipe(second_fd);
  }

  if ((pid = fork()) < 0) {
    perror("invalid fork command\n");
    exit(EXIT_FAILURE);
  } else if (pid == 0) { // Child
    if (strcmp(position, FIRST) == 0) {
      if (dup2(fd[OUT], STDOUT_FILENO) < 0) {
        perror("invalid piping: dup2 failure");
        return -1;
      }
      if (setpgid(pid, pid) < 0) {
        perror("invalid setpgid failure");
      }
    } 
    else if (strcmp(position, MIDDLE) == 0) {
      if (dup2(fd[IN], STDIN_FILENO) < 0 || dup2(second_fd[OUT], STDOUT_FILENO) < 0) {
        perror("invalid piping: dup2 failure");
        return -1;
      }
      if (setpgid(pid, cmd_group->pgid) < 0) {
        perror("invalid setpgid failure");
      }
    } 
    else if (strcmp(position, FINAL) == 0) {
      if (dup2(fd[IN], STDIN_FILENO) < 0) {
        perror("invalid piping: dup2 failure");
        return -1;
      }
      if (setpgid(pid, cmd_group->pgid) < 0) {
        perror("invalid setpgid failure");
      }
    }
    close_pipes(cmd_group->pipe_fds, cmd_group->pipe_count);

    if (create_redirects(cmd) < 0) {
      perror("invalid redirection error");
      return -1;
    }

    if (execvp(cmd->cmd, cmd->args) < 0) {
      perror("invalid: execvp failure");
      return -1;
    }
  }
  // Parent
  if (strcmp(position, FIRST) == 0 || strcmp(position, ONLY) == 0) {
    setpgid(pid, pid);
    cmd_group->pgid = pid;
  } else {  
    setpgid(pid, cmd_group->pgid);
  }
  cmd->pid = pid;

  return 0;
}

0 ответов

Другие вопросы по тегам