Функции для работы с псевдотерминалами
В курсе [1] мы уже останавливались на понятии псевдотерминала. Опишем теперь соответствующие функции.
Первым действием при работе с псевдотерминалами является открытие главного устройства, осуществляемое функцией posix_openpt() (см. листинг 9.49).
#include <stdlib.h> #include <fcntl.h> int posix_openpt (int oflag);
Листинг 9.49. Описание функции открытия главного устройства псевдотерминала. (html, txt)
В значении аргумента oflag есть смысл устанавливать флаги O_RDWR и O_NOCTTY (последний означает, что терминал не будет управляющим для процесса).
Разумеется, нормальным результатом функции posix_openpt()> служит файловый дескриптор; в случае ошибки возвращается -1.
Считается, что после открытия главного устройства подчиненное устройство псевдотерминала блокируется, и эту блокировку необходимо явным образом снять, вызвав функцию unlockpt() (см. листинг 9.50).
#include <stdlib.h> int unlockpt (int masterfd);
Листинг 9.50. Описание функции разблокирования подчиненного устройства псевдотерминала. (html, txt)
Здесь masterfd – файловый дескриптор главного устройства псевдотерминала, полученный в результате вызова функции posix_openpt().
Нормальным для unlockpt() является нулевой результат.
Функция grantpt() (см. листинг 9.51) позволяет сформировать нужные права доступа к подчиненному устройству псевдотерминала. Владелец устройства устанавливается в соответствии с реальным идентификатором пользователя вызывающего процесса; ему (владельцу) предоставляются права на чтение и запись.
#include <stdlib.h> int grantpt (int masterfd);
Листинг 9.51. Описание функции формирования прав доступа к подчиненному устройству псевдотерминала. (html, txt)
Применительно к функции grantpt() в стандарте POSIX-2001 оговаривается одна тонкость: вызывающий процесс не должен обрабатывать сигнал SIGCHLD. Это можно понять (и оправдать), поскольку grantpt() выполняет суперпользовательское действие, реализация которого в некоторых ОС может быть сопряжена с порождением процессов.
Чтобы узнать имя подчиненного устройства псевдотерминала, следует обратиться к функции ptsname() (см. листинг 9.52).
#include <stdlib.h> char *ptsname (int masterfd);
Листинг 9.52. Описание функции получения имени подчиненного устройства псевдотерминала. (html, txt)
Разумеется, результирующий указатель может ссылаться на статическую область, перезаписываемую при каждом вызове ptsname(), поэтому рекомендуется полученное имя скопировать или поскорее использовать. Использование очевидно – посредством обычной функции open() открыть подчиненное устройство псевдотерминала и получить его файловый дескриптор.
Таким образом, в стандарте POSIX-2001 выстроена пятиэтапная модель получения доступа к псевдотерминалу:
- открытие главного устройства псевдотерминала, получение его файлового дескриптора (осуществляется функцией posix_openpt());
- разблокирование подчиненного устройства псевдотерминала (функция unlockpt());
- формирование прав доступа к подчиненному устройству псевдотерминала (grantpt());
- получение имени подчиненного устройства псевдотерминала (ptsname());
- открытие подчиненного устройства псевдотерминала, получение его файлового дескриптора (open()).
Применение описанных функций иллюстрируется переработанным вариантом программы из курса [1], запускающей командный интерпретатор на псевдотерминале (см. листинг 9.53).
Листинг 9.53. Пример программы, использующей псевдотерминалы. (html, txt)
Здесь все пять упоминавшихся подготовительных этапов вошли в состав одного условного оператора. Обратим внимание на применение флага O_NOCTTY при вызове posix_openpt(), а также на то, что обращение к grantpt() выполнено до установки функции обработки сигнала SIGCHLD.