'SIGINT with getchar()

I'm new to C and am attempting to write a minishell program that should stop the child process (as a result of a fork to run exec) or jump back to the start of the loop (print out [currentdir/]> and wait for input) as soon as I run into a SIGINT. Currently, I have to hit enter after ^C in order for the SIGINT to be processed, but ideally, I should not have to. Any help with this issue would be greatly appreciated!

volatile sig_atomic_t interrupted = 0; //interrupted is originally set to false.

void sig_handler(int sig)
{
    interrupted = 1;
    //printf("\n");
}

int main_helper()
{
    struct sigaction sa;

    memset(&sa, 0, sizeof(struct sigaction));
    sa.sa_handler = sig_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;

    if (sigaction(SIGINT, &sa, NULL) == -1)
    {
        fprintf(stderr, "Error: Cannot register signal handler. %s.\n", strerror(errno));
        exit(1);
    }
    
    /* code to get current directory and print it in the format [dir/]> */

    while (is_exit == 0) //because no booleans
    {
        /*
            getting user input.
        */
        input_str = malloc(sizeof(char)); //starting out w a str of length 1.

        if (input_str == NULL)
        { //if the malloc fails for some reason.
            fprintf(stderr, "Error: malloc() failed. %s.\n", strerror(errno));
            exit(1);
        }

        int c; //the character that we're at
        int i = 0;
        //read chars until null term or eof found
        while ((c = getchar()) != '\n')
        {
            if (c == EOF)
            {
                fprintf(stderr, "Error: Failed to read from stdin. %s.\n", strerror(errno));
                exit(1);
            }
            input_str[i++] = c;
            input_str = realloc(input_str, i + 1); //adding space for another

            if (input_str == NULL)
            { //if it can't realloc for some reason.
                fprintf(stderr, "Error: realloc() failed. %s.\n", strerror(errno));
                exit(1);
            }
        }
        input_str[i] = '\0'; //adding null terminator at the end.
        
        /*
            dealing with the input using exec or built-in functions
        */

        free(input_str); //free the input that we just realloced stuff for

        interrupted = 0;

    }
    return EXIT_SUCCESS;
}

Now, I'm not completely sure why exactly this is happening, but if I'm understanding some other StackOverflow threads correctly, the getchar() function may blocking the SIGINT until after enter is pressed. Does anyone know how to fix this? Would using setjmp/longjmp help? How would I implement these if they could solve it?



Solution 1:[1]

I'm not sure about SIGINT, but you can write a non-blocking getchar using fread.

unsigned char buffer;
while (fread(&buffer, sizeof(buffer), 1, stdin) == 0) {
    // Check signal in here
    
    // If no character was read, check if it was due to EOF or an error
    if (feof(stdin)) {
        // We reached the end of the file
    }

    if (ferror(stdin)) {
        // An error occurred when we tried to read from stdin
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Locke