简体   繁体   中英

Handling Ctrl + C as in original shell

I'm trying to implement small shell program in C which will read commands from stdin, parse them and execute. I faced with problem of handling Ctrl+C as in original shell - when you type several letters, or doesn't type anything, and then press Cntrl+C, shell just returns new prompt back:

user@user-pc:/$ some letters^C
user@user-pc:/$ 

Here is a simplified code to show my approach of doing that:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

char        interruption;

void        read_line(char **str)
{
    char    c;
    int     size;
    int     i;

    c = 0;
    size = 30;
    i = -1;
    *str = (char*)malloc(sizeof(char) * size + 1);
    while (c != '\n' && !interruption)
    {
        i++;
        if (i == size)
            *str = realloc((void*)*str, (size_t)((size *= 2) + 1));
        read(0, &c, 1);
        (*str)[i] = c;
    }
    if (interruption)
    {
        free(*str);
        *str = NULL;
        interruption = 0;
    }
    else
        (*str)[i] = '\0';
}

void        handler(int sig_num)
{
    (void)sig_num;
    signal(SIGINT, handler);
    interruption = 1;
    printf("\ninterruption happened\n");
}

int         main()
{
    char    *str;

    signal(SIGINT, handler);
    interruption = 0;
    while (1)
    {
        str = NULL;
        write(1, "%> ", 3);
        read_line(&str);
        if (str)
            printf("parsing %s\n", str);
        else
            printf("skipping...\n");
    }
    return (0);
}

The problem in my approach is that after pressing Ctrl+C prompt does not return, because read() starts actually reading from input only when I press Enter. It is my school assignment and I can't use any functions except read() to read characters from stdin.

What is the right way to reproduce the behavior of shell in this case?

First of all... NEVER, EVER use printf or any other functions that are not guaranteed to be async-signal-safe inside a signal handler.

Really. Just don't.

Secondly, use sigaction function instead of signal function to install your signal handler, just like that. So here's the code for signal handler:

void handler(int sig_num) {
    (void)sig_num;
    interruption = 1;
}

And here's the code to install the handler:

struct sigaction action = { 0 }; /* if your compiler frowns at it use {{ 0 }} */
action.sa_handler = handler;
sigaction(SIGINT, &action, NULL);

Now your program should work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM