You should use select() to check if data is available before reading from stdin:
void handler (int arg) {
    // handle signal
}
int main (void) {
    char buf[100];
    signal(SIGINT, handler);
    do {
       fd_set f;
       FD_ZERO(&f);
       FD_SET(fileno(stdin), &f);
       int st = select(fileno(stdin)+1, &f, NULL, NULL, NULL);
       if (st == 1) {
          fgets(buf, sizeof(buf), stdin);
          // Handle input
       }
    } while (st >= 0);
    exit(EXIT_SUCCESS);
}
select() will return with -1 (errno EINTR) after returning from the signal handler whereas the read() (invoked by (f)gets) would be automatically resumed.
With linux, there is another possibility using sigaction():
void handler (int arg) {
    // handle signal
}
int main (void) {
    char buf[100], *p;
    struct sigaction sa = { .sa_handler = handler, .sa_flags = 0, .sa_mask = 0 };
    sigaction(SIGINT, &sa, NULL);
    do {    
            p = fgets(buf, sizeof(buf), stdin);
            // handle input
    } while (p);
    printf("Byebye\n");
    exit(EXIT_SUCCESS);
}
Since the flag SA_RESTART is not specified in the sa_flags for the signal handler, a read() on a slow device (i.e. terminals, pipes, sockets) will return with -1 (EINTR), too (see also signal(7)).
While being a bit simpler, the behaviour may vary between the different unix-flavors (and even kernel-versions), so the first version is a safer and more portable/reliable way.