Троан Эрик В.
Шрифт:
В библиотеке
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);
16.6.3. Сложные способы открытия псевдотерминалов
Интерфейс Unix98 для распределения пары псевдотерминала представляет собой следующий набор функций.
#define _XOPEN_SOURCE 600
#include <stdlib.h>
#include <fcntl.h>
int posix_openpt(int oflag);
int grantpt(int fildes);
int unlockpt(int fildes);
char * ptsname(int fildes);
Функция
posix_openpt
— это то же, что и открытие устройства /dev/ptmx
, но теоретически она более переносима (поскольку везде принимается). Рекомендуется в этот раз использовать open("/dev/ptmx", oflag)
для максимальной практической переносимости. Если вы хотите установить один или два флага open
или posix_openpt
, используйте O_RDWR
, как обычно; если вы вместо этого не открываете управляющий tty для процесса, используйте O_RDWR | O_NOCTTY
. open
или posix_openpt
вернет открытый файловый дескриптор управляющему устройству псевдотерминала. Затем вызовите grantpt
с файловым дескриптором управляющего устройства псевдотерминала, возвращенным из posix_openpt
, для изменения режима и владельца подчиненного компонента псевдотерминала, а потом — unlockpt
, чтобы сделать подчиненный компонент псевдотерминала доступным для открытия. Интерфейс Unix98 для открытия подчиненного устройства псевдотерминала должен просто открыть имя, возвращенное ptsname
. Все эти функции возвращают – 1
в случае ошибки, кроме ptsname
, возвращающей в такой ситуации NULL
. Функции в
ptypair.c
распределяют согласованную пару устройств pty. Пример функции get_master_pty
в строке 22 ptypair.с
открывает управляющее устройство pty и возвращает файловый дескриптор родительскому процессу, а также предоставляет имя соответствующему подчиненному компоненту pty. Он сначала испытывает интерфейс Unix98 на распределение управляющего устройства pty, а если это не работает (например, если ядро скомпилировано без поддержки pty Unix98, возможно, для встроенных систем), возвращается к старому интерфейсу стиля BSD. Соответствующая функция get_slave_pty
в строке 87 может быть использована после fork
для открытия соответствующего подчиненного компонента pty. 1: /* ptypair.c */
2:
3: #define _XOPEN_SOURCE 600
4: #include <errno.h>
5: #include <fcntl.h>
6: #include <grp.h>
7: #include <stdlib.h>
8: #include <string.h>
9: #include <sys/types.h>
10: #include <sys/stat.h>
11: #include <unistd.h>