Search code examples
cshellexit

Hide ^C pressing ctrl-c in C


I'm creating my own shell and I would like to disable ^C when any user on any Linux distributation press ctrl+c.

I don't need to handle the signal SIGINT, I already did it for don't stop the program on ctrl+c. I just want to know how to hide these two characters ^C.

Is there any function to call or env variables to set at the start of my program?

EDIT

  int a = fork();
  if (!a) {
    char *cmd[] = {"/bin/stty", 0 };
    char *cmd_args[] = {" ", "-echoctl", 0};
    execve(cmd[0], cmd_args, env);
  }

Tried this. It removes my ^C on ctrl-c but it still displays a square character, like if the character can't be displayed. It seems to be EOT (003 ascii)


Solution

  • You can use ANSI escape codes to delete ^C characters. In the function that processes the SIGINT signal, print the characters that move the cursor twice to the left, then delete all the characters on the right up to the end of the line.

    The example below works on macOS and Raspberry Pi OS.

    On Windows this trick is not needed as pressing ctrl+c is silent.

    /**
        remove_ctrl_c.c
        gcc remove_ctrl_c.c -o remove_ctrl_c && ./remove_ctrl_c
    
        Remove the characters ^C with ANSI escape codes.
        (see https://en.wikipedia.org/wiki/ANSI_escape_code)
    
        \b     : Move cursor one character on the left.
        \b     : Idem
        \033[K : Delete all the characters on the right of
                 the cursor until the end of the line.
                 You can also use two spaces if you prefer,
                 but they will be present in the output although
                 they are not visible.
        \n     : Add a new line. This is optional,
                 but if you remove it and some characters
                 are printed on the last line, the terminal
                 will add an extra % character to indicate
                 that the new line character was absent.
    
        Note that, as the printf command is buffered,
        we need to use the fflush command before the end
        of the program to force stdout to be updated.
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    
    volatile sig_atomic_t KEYBOARD_INTERRUPT = 0;
    
    void handleSignal(int signal)
    {
        KEYBOARD_INTERRUPT = 1;
    }
    
    int main()
    {
        signal(SIGINT, handleSignal);
        printf("Remove ^C on exit!");
        fflush(stdout);
        while (!KEYBOARD_INTERRUPT)
        {
        }
        printf("\b\b\033[K\n");
        fflush(stdout);
        return 0;
    }