diff --git a/answerback.c b/answerback.c new file mode 100644 index 0000000..9f2ed5b --- /dev/null +++ b/answerback.c @@ -0,0 +1,130 @@ +#define _POSIX_C_SOURCE 200112L + +#include /* for signal handling */ +#include /* fopen(), et al. */ +#include /* for ssize_t, read, write */ +#include /* for EXIT_SUCCESS, EXIT_FAILURE */ +#include /* ctermid, et al. */ + +int main() +{ + const char *cterm = ctermid(NULL); + + if (cterm == NULL) + { + fputs("Cannot get the path to the console", stderr); + } + + FILE *fp; + if((fp = fopen(cterm, "r+b")) == NULL) + { + perror("open"); + return EXIT_SUCCESS; + } + + int fd = fileno(fp); + if (fd == -1) + { + perror("fileno"); + return EXIT_FAILURE; + } + + setbuf(fp, NULL); + + sigset_t new_sig; + if (sigemptyset(&new_sig) == -1) + { + perror("sigemptyset"); + return EXIT_FAILURE; + } + if (sigaddset(&new_sig, SIGINT) == -1) + { + perror("sigaddset"); + return EXIT_FAILURE; + } + if (sigaddset(&new_sig, SIGTSTP) == -1) + { + perror("sigaddset"); + return EXIT_FAILURE; + } + sigset_t old_sig; + if (sigprocmask(SIG_BLOCK, &new_sig, &old_sig) == -1) + { + perror("sigprocmask"); + return EXIT_FAILURE; + } + + struct termios old_term; + if (tcgetattr(fd, &old_term) == -1) + { + perror("tcgetattr"); + return EXIT_FAILURE; + } + + struct termios new_term = old_term; + new_term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON); + new_term.c_cc[VMIN] = 0; + new_term.c_cc[VTIME] = 10; + + if (tcsetattr(fd, TCSAFLUSH, &new_term) == -1) + { + perror("tcsetattr"); + if (tcsetattr(fd, TCSAFLUSH, &old_term) == -1) + { + perror("tcsetattr"); + } + return EXIT_FAILURE; + } + + char code[1] = { 5 }; + for (;;) + { + ssize_t ret = write(fd, code, sizeof(code)); + if (ret == -1) + { + perror("write"); + tcsetattr(fd, TCSAFLUSH, &old_term); + return EXIT_FAILURE; + } + else if (ret > 0) + { + break; + } + } + + char buffer[16] = { 0 }; + ssize_t ret = read(fd, buffer, sizeof(buffer) - 1); + if (ret == -1) + { + perror("read"); + tcsetattr(fd, TCSAFLUSH, &old_term); + return EXIT_FAILURE; + } + buffer[ret] = '\0'; + + if (tcsetattr(fd, TCSAFLUSH, &old_term) == -1) + { + perror("tcsetattr"); + return EXIT_FAILURE; + } + + if (sigprocmask(SIG_SETMASK, &old_sig, NULL) == -1) + { + perror("sigprocmask"); + return EXIT_FAILURE; + } + + if (fclose(fp) == EOF) + { + perror("fclose"); + return EXIT_FAILURE; + } + + if (ret > 0) + { + puts(buffer); + return EXIT_SUCCESS; + } + + return EXIT_FAILURE; +}