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()
не делает ничего нового. Все функции описываются в других местах этой книги, поэтому здесь они не объясняются.
16.6.4. Примеры псевдотерминалов
Возможно, одной из самых простых программ, которая может быть написана для использования pty, является программа, открывающая пару pty и запускающая оболочку на подчиненном компоненте pty, соединяя его с управляющим устройством pty. Написав эту программу, вы можете расширять ее любым подходящим способом, forkptytest.с
является примером использования функции forkpty()
, a ptytest.с
— это пример, который использует функции, определенные в ptypair.с
, и является несколько более сложным.
1: /* forkptytest.с */
2:
3: #include
4: #include
5: #include
6: #include
7: #include
8: #include
9: #include
10: #include
11: #include
12:
13:
14: volatile int propagate_sigwinch = 0;
15:
16: /* sigwinch_handler
17: * распространяет изменения размеров окна из входного файлового
18: * дескриптора на ведущую сторону pty.
19: */
20: void sigwinch_handler(int signal) {
21: propagate_sigwinch = 1;
22: }
23:
24:
25: /* forkptytest пытается открыть пару pty с запуском оболочки
26: * на подчиненной стороне pty.
27: */
28: int main(void) {
29: int master;
30: int pid;
31: struct pollfd ufds[2];
32: int i;
33: #define BUFSIZE 1024
34: char buf[1024];
Читать дальше