• При возобновлении работы, инициированном сигналом SIGCONT, обработчик повторно сохраняет текущие параметры терминала в переменной userTermios
Листинг 58.4. Демонстрация режима без обработки и cbreak
tty/test_tty_functions.c
#include
#include
#include
#include "tty_functions.h" /* Объявление ttySetCbreak() и ttySetRaw() */
#include "tlpi_hdr.h"
/* Параметры терминала, определенные пользователем */
static void /* Общий обработчик: восстанавливает параметры tty и завершается */
handler(int sig)
{
errExit("tcsetattr");
_exit(EXIT_SUCCESS);
}
static void /* Обработчик для SIGTSTP */
{
struct termios ourTermios; /* Для сохранения параметров нашего терминала */
sigset_t tstpMask, prevMask;
struct sigaction sa;
int savedErrno;
savedErrno = errno; /* Здесь можно было бы изменить 'errno' */
/* Сохраняем текущие параметры терминала, возвращаем терминал
к состоянию, в котором он был на момент запуска программы */
errExit("tcgetattr");
errExit("tcsetattr");
/* Устанавливаем для SIGTSTP действие по умолчанию, посылаем сигнал
еще раз и разблокируем его, чтобы программа могла остановиться */
if (signal(SIGTSTP, SIG_DFL) == SIG_ERR)
errExit("signal");
raise(SIGTSTP);
sigemptyset(&tstpMask);
sigaddset(&tstpMask, SIGTSTP);
if (sigprocmask(SIG_UNBLOCK, &tstpMask, &prevMask) == -1)
errExit("sigprocmask");
/* Выполнение возобновляется после SIGCONT */
if (sigprocmask(SIG_SETMASK, &prevMask, NULL) == -1)
errExit("sigprocmask"); /* Повторно блокируем SIGTSTP */
sigemptyset(&sa.sa_mask); /* Заново устанавливаем обработчик */
sa.sa_flags = SA_RESTART;
sa.sa_handler = tstpHandler;
if (sigaction(SIGTSTP, &sa, NULL) == -1)
errExit("sigaction");
/* С момента остановки программы пользователь мог изменить параметры
терминала; сохраняем параметры, чтобы позже их восстановить */
errExit("tcgetattr");
/* Восстанавливаем наши параметры терминала */
errExit("tcsetattr");
errno = savedErrno;
}
int
main(int argc, char *argv[])
{
char ch;
struct sigaction sa, prev;
ssize_t n;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
errExit("ttySetCbreak");
/* В режиме cbreak специальные символы терминала могут генерировать сигналы.
Перехватываем их, чтобы откорректировать режим терминала. Устанавливаем
обработчики только для сигналов, которые не игнорируются. */
if (sigaction(SIGQUIT, NULL, &prev) == -1)
errExit("sigaction");
if (prev.sa_handler!= SIG_IGN)
if (sigaction(SIGQUIT, &sa, NULL) == -1)
errExit("sigaction");
if (sigaction(SIGINT, NULL, &prev) == -1)
errExit("sigaction");
if (prev.sa_handler!= SIG_IGN)
if (sigaction(SIGINT, &sa, NULL) == -1)
errExit("sigaction");
if (sigaction(SIGTSTP, NULL, &prev) == -1)
errExit("sigaction");
if (prev.sa_handler!= SIG_IGN)
if (sigaction(SIGTSTP, &sa, NULL) == -1)
errExit("sigaction");
} else { /* Используем режим без обработки */
errExit("ttySetRaw");
}
if (sigaction(SIGTERM, &sa, NULL) == -1)
errExit("sigaction");
setbuf(stdout, NULL); /* Отключаем буферизацию стандартного вывода */
n = read(STDIN_FILENO, &ch, 1);
if (n == -1) {
errMsg("read");
break;
}
if (n == 0) /* Может произойти после отключения терминала */
break;
putchar(tolower((unsigned char) ch));
else if (ch == '\n' || ch == '\r')
putchar(ch);
else if (iscntrl((unsigned char) ch))
printf("^%c", ch ^ 64); /* Выводим Ctrl+A как ^A и т. д. */
else
putchar('*'); /* Остальные символы выводятся как '*' */
break;
}
errExit("tcsetattr");
exit(EXIT_SUCCESS);
}
tty/test_tty_functions.c
Пример запуска программы из листинга 58.4 в режиме без обработки показан ниже:
$ stty
speed 38400 baud; line = 0;
$ ./test_tty_functions
abc
def
^C^Z
q$