0

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?

Hemul
  • 81
  • 2
  • 8

1 Answers1

1

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.

nsilent22
  • 2,763
  • 10
  • 14