16.6.2. Простые способы открытия псевдотерминалов

We use cookies. Read the Privacy and Cookie Policy

16.6.2. Простые способы открытия псевдотерминалов

В библиотеке libutil glibc предлагает две функции — openpty() и forkpty(), — выполняющие почти всю работу по поддержке псевдотерминалов.

#include <pty.h>

int openpty(int * masterfd, int * slavefd, char * name,

 struct termios * term, struct winsize * winp);

int forkpty(int * masterfd, char * name,

 struct termios * term, struct winsize * winp);

Функция openpty() открывает ведущие и подчиненные псевдотерминалы, необязательно используя структуры struct termios и struct winsize, передаваемые как опции настройки псевдотерминала, возвращая 0 в случае успеха и -1 в случае ошибки. Файловые дескрипторы ведущего устройства и подчиненного компонента возвращаются аргументам masterfd и slavefd соответственно. Аргументы term и winp могут быть NULL, в случае чего они игнорируются, и настройка не выполняется.

Функция forkpty() работает так же, как и openpty(), но вместо возврата файлового дескриптора подчиненного компонента она разветвляет псевдотерминал как управляющий терминал stdin, stdout и stderr для дочернего процесса, а затем, подобно fork(), возвращает идентификатор дочернего процесса родительскому и 0 дочернему либо -1 при возникновении ошибки.

Даже с этими удобными интерфейсами связана значительная проблема: аргумент name был изначально предназначен для возврата имени устройства псевдотерминала вызывающему коду, но его использование небезопасно, поскольку openpty() и forkpty() не знают размера буфера. Всегда передавайте NULL в аргументе name. Используйте функцию ttyname(), описанную в начале этой главы, чтобы получить путевое имя файла устройства псевдотерминала.

Предпочтительный способ работы с struct termios заключается в использовании цикла чтение-модификация-запись, но данному случаю это не соответствует по двум причинам. Можно передать NULL и принять значения по умолчанию, что достаточно в большинстве случаев; а когда вы хотите предоставить настройки termios, вы часто заимствуете настройки у другого tty, или знаете точно, какими они должны быть (например, в случае концентратора последовательного порта SCSI, описанного ранее в этой главе).

tcgetattr(STDIN_FILENO, &term);

ioctl(STDIN_FILENO, TIOCGWINSZ, &ws);

pid = forkpty(&masterfd, NULL, &term, &ws);