LogicProgrammer
LogicProgrammer

Reputation: 77

Shell CTRL-C ignore

I want to the following in my implementation of shell.

When shell is launched, the prompt is printed. When I click CTRL+C it should ignore the signal and print the prompt on new line. No enter key should pressed.

When I launch an external program like top, I should be able to kill it with CTRL+C and get back to my shell.

Finally, when I launch a program like 'python', I want to be able to click CTRL+C and only receive KeyboardInterrupt and >> printed on new line as in real shell. Currently, I get this:

Shell> python
Type "help", "copyright", "credits" or "license" for more information.
>>>
Shell>
KeyboardInterrupt
>>>
Shell>
KeyboardInterrupt
>>>
Shell>
KeyboardInterrupt
>>>

Where you can see that Shell> is printed in the middle of CTRL+C interrupt. A relevant excerpt of code is:

void signal_handler(int dummy) {
    #ifdef DEBUG
        printf("CTRL-C is disabled.\n");
    #endif
    printf("\n");
}

int main(int argc, char **argv) {
    char *command;
    char **args;
    int status;

    /* Register a signal handler for Ctrl-C */
    sigset(SIGINT, signal_handler);

    while (1) {
        printf("Shell> ");
        command = read_command();
        args = tokenize_command(command);
        status = execute(args);

        #ifdef DEBUG
            printf("The newest status code was: %d\n", status);
        #endif

        free(command);
        free(args);
    }
}

Upvotes: 0

Views: 2235

Answers (1)

Ctx
Ctx

Reputation: 18420

You will have to create a new process group for your executed command and make it the foreground process group.

i.e. between fork() and execve() in the child process:

setpgid(0, 0);
tcsetpgrp(fileno(stdin), getpgrp());

When the child terminates and waitpid() in your shell returns, you have to reset the foreground process group:

tcsetpgrp(fileno(stdin), getpgrp()); // Called in the shell main process

Explanation: The processes in the foreground process group may read from the terminal and receive the signals from keyboard-input (Ctrl-C, Ctrl-Z, etc.). When a new command is executed by your shell, it is still in the same process group as the shell, which is also the foreground process group. So you have to create a new process group for your executed command (setpgid) and make it the foreground process group (tcsetpgrp).

Upvotes: 3

Related Questions