размера буфера. Всегда передавайте 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>
12:
13:
14: /* get_master_pty() принимает дважды косвенный символьный указатель на
15: * место помещения имени подчиненного компонента pty и возвращает целочисленный
16: * файловый дескриптор. Если возвращается значение < 0, значит, возникла ошибка.
17: * В противном случае возвращается файловый дескриптор ведущего устройства pty
18: * и заполняет *name именем соответствующего подчиненного компонента pty. После
19: * открытия подчиненного компонента pty, вы отвечаете за освобождение *name.
20: */
21:
22: int get_master_pty(char **name) {
23: int i, j;
24: /* значение по умолчанию, соответствующее ошибке */
25: int master = -1;
26: char *slavename;
27:
28: master = open('/dev/ptmx', O_RDWR);
29: /* Это эквивалентно, хотя и более широко реализовано,
30: * но теоретически менее переносимо, следующему:
31: * master = posix_openpt(O_RDWR);
32: */
33:
34: if (master >= 0 && grantpt(master) >= 0 &&
35: unlockpt(master) >= 0) {
36: slavename = ptsname(master);
37: if (!slavename) {
38: close(master);
39: master = -1;
40: /* сквозной проход для нейтрализации ошибки */
41: } else {
42: *name = strdup(slavename);
43: return master;
44: }
