0

I'm working on building a custom command line interpreter in C, and I'm running into issues with process group management and terminal control when executing commands. Below is the main code I'm using:

static void exec(list* lst) 
{
    int len, pid, analyze_res, i;
    cmd_params params;
    int gid = -1;
    analyze_res = get_cmd_info(&params, lst);
    if (analyze_res == -1) 
        return;

    if (strcmp(lst->first->word, "cd") == 0) {
        cd(lst);
        return;
    }

    int fd[params.cnt_prog - 1][2];
    for (i = 0; i < params.cnt_prog; i++) {
        len = proc_len(lst);
        char* buf[len + 1];
        proc2buf(&lst, buf);
        buf[len] = NULL;

        if (i < params.cnt_prog - 1) {  // No need to create pipe for the last command
            pipe(fd[i]);
        }

        pid = fork();
        if (pid == 0) {
            if (gid == -1) {
                setpgid(0, 0);
            } else {
                setpgid(0, gid);
            }

            close(fd[i][0]); //close current read descriptor for this process
            if (i > 0) {  // Set input from previous pipe if not the first command
                dup2(fd[i - 1][0], 0);
                close(fd[i - 1][0]);
            } else {
                if (!redirect_in(&params)) {
                    exit(1);
                }
            }

            if (i < params.cnt_prog - 1) {  // Set output to the next pipe if not the last command
                dup2(fd[i][1], 1);
                close(fd[i][1]);
            } else {
                if (!redirect_out(&params)) {
                    exit(1);
                }
            }

            execvp(buf[0], buf);
            perror(buf[0]);
            exit(1);
        }

        if (gid == -1) {
            gid = pid; //group id is equal to first child id
        } 
        
        // Close pipe ends in the parent
        if (i > 0) {
            close(fd[i - 1][0]);  // Close the reading end of the previous pipe
        }
        if (i < params.cnt_prog - 1) {
            close(fd[i][1]);  // Close the writing end of the current pipe
        }
    }

    if (!params.bg) {
        tcsetpgrp(STDIN_FILENO, gid);
        for (i = 0; i < params.cnt_prog; i++) {
            waitpid(-gid, NULL, 0);  // Wait for any child in the process group
        }
        tcsetpgrp(STDIN_FILENO, getpgrp());
    }
}

this part is executed, if command group is in foreground:

    if (!params.bg) {
        tcsetpgrp(STDIN_FILENO, gid);
        for (i = 0; i < params.cnt_prog; i++) {
            waitpid(-gid, NULL, 0);  // Wait for any child in the process group
        }
        tcsetpgrp(STDIN_FILENO, getpgrp());
    }

  • I'm using setpgid(0, 0) to create a new process group for the first child process and setpgid(0, gid) for the subsequent processes in the pipeline to join the same group. However, I'm encountering issues where my shell doesn't regain control of the terminal after the command execution.

  • Even though I'm using tcsetpgrp(STDIN_FILENO, gid) to give the terminal to the process group and later tcsetpgrp(STDIN_FILENO, getpgrp()) to regain control, my shell remains in the background.

3
  • Side note: in general, STDIN_FILENO is not guaranteed to be the file descriptor of the session's controlling terminal. Commented Aug 27, 2024 at 15:49
  • Are one or both of your tcsetpgrp() calls failing? You don't know, because you don't check. Likewise several other library function calls in this code. Except where in fact you don't care, it is important to check for failing function calls, and to handle them gracefully (as much as is possible) in the event that they occur. Commented Aug 27, 2024 at 15:58
  • @MwahMallah, Why buf[len] = NULL; instead of buf[len] = 0;? NULL best used with pointers. Commented Aug 27, 2024 at 19:23

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.