Выбрать главу

 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() не делает ничего нового. Все функции описываются в других местах этой книги, поэтому здесь они не объясняются.

16.6.4. Примеры псевдотерминалов

Возможно, одной из самых простых программ, которая может быть написана для использования pty, является программа, открывающая пару pty и запускающая оболочку на подчиненном компоненте pty, соединяя его с управляющим устройством pty. Написав эту программу, вы можете расширять ее любым подходящим способом, forkptytest.с является примером использования функции forkpty(), a ptytest.с — это пример, который использует функции, определенные в ptypair.с, и является несколько более сложным.

  1: /* forkptytest.с */

  2:

  3: #include <errno.h>

  4: #include <signal.h>

  5: #include <stdio.h>

  6: #include <stdlib.h>

  7: #include <sys/ioctl.h>

  8: #include <sys/poll.h>

  9: #include <termios.h>

 10: #include <unistd.h>

 11: #include <pty.h>

 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];

 35:  struct termios ot, t;

 36:  struct winsize ws;

 37:  int done = 0;

 38:  struct sigaction act;

 39:

 40:  if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) {

 41:   perror("ptypair: не удается получить размеры окна");

 42:   exit(1);

 43:  }

 44:

 45:  if ((pid = forkpty(&master, NULL, NULL, &ws)) < 0) {

 46:   perror("ptypair");