Книга: Разработка приложений в среде Linux. Второе издание
16.6.3. Сложные способы открытия псевдотерминалов
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: }
45: }
46:
47: /* Остаток этой функции — нейтрализация ошибки для старых систем */
48:
49: /* создать фиктивное имя для заполнения */
50: *name = strdup("/dev/ptyXX");
51:
52: /* искать неиспользуемый pty */
53: for (i=0; i<16 && master <= 0; i++) {
54: for (j = 0; j<16 && master <= 0; j++) {
55: (*name)[8] = "pqrstuvwxyzPQRST"[i];
56: (*name)[9] = "0123456789abcdef"[j];
57: /* открыть ведущее устройство pty */
58: if ((master = open(*name, O_RDWR)) < 0) {
59: if (errno == ENOENT) {
60: /* устройства pty исчерпаны */
61: free(*name);
62: return(master);
63: }
64: }
65: }
66: }
67:
68: if ((master < 0) && (i == 16) && (j == 16)) {
69: /* необходимо для каждого неудачного pty */
70: free(*name);
71: return(master);
72: }
73:
74: /* Подставляя букву, изменить имя ведущего устройства pty
75: * в имени подчиненного компонента pty.
76: */
77: (*name)[5] = 't';
78:
79: return(master);
80: }
81:
82: /* get_slave_pty() возвращает целочисленный файловый дескриптор.
83: * Если возвращается значение < 0, значит, возникла ошибка.
84: * В противном случае возвращается файловый дескриптор подчиненного
85: * компонента. */
86:
87: int get_slave_pty(char * name) {
88: struct group *gptr;
89: gid_t gid;
90: int slave = -1;
91:
92: if (strcmp(name, "/dev/pts/")) {
93: /* Интерфейс Unix98 не использовался, необходима
94: * специальная обработка полномочий или прав владения.
95: *
96: * Выполнить chown/chmod для соответствующего pty, если возможно.
97: * Это будет работать, только если имеет полномочия root.
98: * В качестве альтернативы можно написать и запустить небольшую
99: * setuid-программу, которая сделает все это.
100: *
101: * В противном случае все проигнорировать и пользоваться
102: * только интерфейсом Unix98.
103: */
104: if ((gptr = getgrnam("tty")) != 0) {
105: gid = gptr->gr_gid;
106: } else {
107: /* если группа tty не существует, не изменять группу
108: * на подчиненном компоненте pty, а только владельца
109: */
110: gid = -1;
111: }
112:
113: /* Обратите внимание, что здесь не осуществляется проверка на ошибки.
114: * Однако если выполняемые действия являются критически важными,
115: * проверка ошибок должна быть. */
116: chown(name, getuid(), gid);
117:
118: /* Этот код делает подчиненный компонент доступным для чтения/записи
119: * только конкретному пользователю. Если код предназначен для
120: * интерактивной оболочки, которая должна получать сообщения
121: * "write" и "wall", добавьте ниже "ИЛИ" с S_IWGRP во второй аргумент.
122: * В таком случае потребуется перенести эту строку за пределы
123: * оператора if(), чтобы код мог выполняться для интерфейсов как
124: * BSD-стиля, так и Unix98-стиля.
125: */
126: chmod(name, S_IRUSR|S_IWUSR);
127: }
128:
129: /* открыть соответствующий подчиненный компонент pty */
130: slave = open(name, O_RDWR);
131:
132: return(slave);
133: }
Функция get_slave_pty()
не делает ничего нового. Все функции описываются в других местах этой книги, поэтому здесь они не объясняются.
- Глава 3 Способы монетизации
- Способы «запуска» слухов
- Можно ли выполнять сложные вычисления, используя Калькулятор Windows?
- Как добавить свою папку в окно открытия документа?
- В Microsoft Word не всегда удобно выделять большие фрагменты текста мышью. Есть ли другие способы?
- Способы подключения к Интернету
- III. Способы повышения доверия к тексту
- Более сложные трансформации
- Способы заключения сделки. Последний вопрос решает ваш прирост
- Способы обработки возражений
- Способы продвижения
- 4.2.6. Способы задавания ролей и ситуации в ролевой игре