Буфер, с помощью которого возвращается имя, обычно выделяется статическим способом. Это значит, что при следующем вызове ptsname() он будет перезаписан.
#define _XOPEN_SOURCE 500
#include
char *ptsname(int
Возвращает указатель на (возможно, статически выделенную) строку при успешном завершении или NULL при ошибке
Библиотека GNU языка C предоставляет реентерабельную версию вызова ptsname() в виде ptsname_r(mfd, strbuf, buflen). Однако данная функция является нестандартной и доступна лишь в нескольких UNIX-системах. Чтобы получить объявление ptsname_r() из заголовочного файла
Разблокировав вторичное устройство с помощью функции unlockpt(), можно его открыть, воспользовавшись традиционным системным вызовом open().
Пришло время познакомиться с функцией ptyMasterOpen(), которая использует вызовы, описанные в предыдущих разделах, для открытия первичного устройства псевдотерминала и получения имени связанного с ним вторичного конца. Мы описываем эту функцию по следующим причинам:
• большинство программ выполняют описанные действия точно таким же образом, так что для удобства их можно объединить в единую функцию;
• наша версия ptyMasterOpen() инкапсулирует все подробности и особенности псевдотерминалов стандарта UNIX 98.
#include "pty_master_open.h"
int ptyMasterOpen(char *
Возвращает файловый дескриптор при успешном завершении или -1 при ошибке
Функция ptyMasterOpen() открывает неиспользуемый первичный конец псевдотерминала, вызывает для него grantpt() и unlockpt() и копирует имя связанного с ним вторичного устройства в буфер, на который указывает аргумент slaveName. Вызывающий процесс должен указать в аргументе snLen количество памяти, доступной этому буферу. Реализация данной функции показана в листинге 60.1.
Листинг 60.1. Реализация функции ptyMasterOpen()
pty/pty_master_open.c
#define _XOPEN_SOURCE 600
#include
#include
#include "pty_master_open.h" /* Объявляет ptyMasterOpen() */
#include "tlpi_hdr.h"
int
ptyMasterOpen(char *slaveName, size_t snLen)
{
int masterFd, savedErrno;
char *p;
masterFd = posix_openpt(O_RDWR | O_NOCTTY);
/* Открываем первичный pty */
if (masterFd == -1)
return -1;
if (grantpt(masterFd) == -1) { /* Разрешаем доступ ко вторичному pty */
savedErrno = errno;
close(masterFd); /* Может изменить 'errno' */
errno = savedErrno;
return -1;
}
if (unlockpt(masterFd) == -1) { /* Разблокируем вторичный pty */
savedErrno = errno;
close(masterFd); /* Может изменить 'errno' */
errno = savedErrno;
return -1;
}
p = ptsname(masterFd); /* Получаем имя вторичного pty */
if (p == NULL) {
savedErrno = errno;
close(masterFd); /* Может изменить 'errno' */
errno = savedErrno;
return -1;
}
if (strlen(p) < snLen) {
strncpy(slaveName, p, snLen);
} else { /* Возвращаем ошибку, если буфер слишком маленький */
close(masterFd);
errno = EOVERFLOW;
return -1;
}
return masterFd;
}
pty/pty_master_open.c
Точно так же мы могли бы отказаться от применения аргументов slaveName и snLen, давая вызывающему процессу возможность самостоятельно получить имя вторичного устройства псевдотерминала с помощью вызова ptsname(). Мы этого не сделали, поскольку в системе BSD псевдотерминалы не имеют аналога функции ptsname().
Теперь мы готовы реализовать функцию, выполняющую всю работу по установке соединения между двумя процессами, используя два конца псевдотерминала (см. рис. 60.2). Функция ptyFork() создает дочерний процесс, который подключается к родителю через псевдотерминал.
#include "pty_fork.h"
pid_t ptyFork(int *
const struct termios *
const struct winsize *
В родителе: возвращает идентификатор потомка при успешном завершении или -1 при ошибке; в успешно созданном потомке: всегда возвращает 0
Реализация функции ptyFork() показана в листинге 60.2. Рассмотрим работу функции.
1. Открывает первичное устройство псевдотерминала с помощью функции ptyMasterOpen() (листинг 60.1)
2. Если аргумент slaveName равен NULL, то копирует имя вторичного устройства в буфер
3. Делает вызов fork() с целью создать дочерний процесс