Проблемы с псевдотерминалом (Mac/Linux): SIGTTOU и неподходящий ioctl

Я работаю над псевдотерминальной библиотекой. Код реализован в коде C, и код используется веб-терминалом. Код работает, пока я не использую sudo или логин.

Это ошибка, которую я получаю, когда запускаю сервер на Mac:

sh-3.2$ sudo ls
Password:
[1]+  Stopped(SIGTTOU)
sh-3.2$

Вышеупомянутое работает в Linux:

$ sudo ls
  readme.txt

Однако в Linux с помощью sudo bash я получаю следующее:

$ sudo bash
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
]0;root@ubuntu: /tmproot@ubuntu:/tmp#

Примечание: вышеизложенное работает, но у меня нет контроля над заданиями.

Я, вероятно, забыл установить некоторые управляющие биты на терминале, но Google не очень помог в поиске этого. Кроме того, знаете ли вы какие-нибудь хорошие книги, в которых очень подробно объясняется управление псевдотерминалом.

У меня есть вызов setsid, но я не использую openpty. Я использую следующий код при открытии pty:

static int createPty(lua_State* L, char* ttyName, int* pty)
{
   *pty = getpt();
   if (*pty < 0 || grantpt(*pty) < 0 || unlockpt(*pty) < 0)
      return lDoErr(L,"Cannot open PTY: %s",strerror(errno));
   if(ptsname_r(*pty, ttyName, PTY_NAME_SIZE-1))
      return lDoErr(L,"ptsname_r: %s",strerror(errno));
   return 0;
}

Я отредактировал приведенный ниже код, и этот код работает. Причина, по которой моя первая версия не работала, заключалась в том, что я пытался создать два канала PTY. Я хотел иметь возможность различать stdout и stderr, но ядро ​​Linux не допускает многократных вызовов TIOCSCTTY.

static int
childOpenTTY(const char* ttyName)
{
   struct termios termbuf;
   int fd=open(ttyName, O_RDWR);
   if(fd < 0)
      doClientError("open %s: %s",ttyName, strerror(errno));
   tcsetpgrp(fd, getpid());
   ioctl(fd,TIOCSCTTY,NULL);
   tcgetattr(fd, &termbuf);
   cfmakeraw(&termbuf); /* turn off NL to CR/NL mapping on output. */
   tcsetattr(fd, TCSANOW, &termbuf);
   return fd;
}

if( (ret = createPty(L, ttyName, &te->pty)) != 0)
   return ret;
if ((te->pid = zzbafork()) < 0)
   return lDoErr(L,"fork: %s",strerror(errno));
if(te->pid == 0)
{  /* Child process */
   static const char efmt[]={"Cannot set '%s' (dup2 err)"};
   int fd;
   if(setsid() < 0) /* make new process group */
      doClientError("setsid: %s",strerror(errno));
   fd=childOpenTTY(ttyName);
   if(dup2(fd, STDIN_FILENO) != STDIN_FILENO)
      doClientError(efmt,"stdin");
   if(dup2(fd, STDOUT_FILENO) != STDOUT_FILENO)
      doClientError(efmt,"stdout");
   if(dup2(fd, STDERR_FILENO) != STDERR_FILENO)
      doClientError(efmt,"stderr");
   if(fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
      close(fd);
   execve(cmd, (char**)cmdArgv, environ);
   /* execve should not return, unless error exec cmd */
   doClientError("Executing %s failed: %s",cmd,strerror(errno));
}

person Will    schedule 20.03.2013    source источник


Ответы (1)


Трудно быть уверенным, так как здесь нет фактического кода, но я подозреваю, что вы работаете с управлением сеансом в стиле POSIX. Вам нужно выполнить вызов setsid, затем открыть pty (ведомую сторону), чтобы он стал управляющим терминалом. Подпрограммы openpty и login_tty выполняют за вас низкоуровневую гранжевую работу; ты их используешь?

person torek    schedule 20.03.2013
comment
Спасибо torek, но у меня есть setsid. Я включил код выше. - person Will; 21.03.2013
comment
Ах. Попробуйте без флага O_NOCTTY: это тот, который подавляет установку вновь открытого устройства в качестве управляющего терминала. Вы могли бы подумать, что это было бы хорошо из-за TIOCSCTTY, но возможно, что этот ioctl теперь не работает в OS X (я точно не знаю). - person torek; 21.03.2013
comment
Различные дистрибутивы UNIX не идентичны, поэтому предпочтительным способом, который должен быть совместим со всеми разновидностями UNIX, является открытие PTY с помощью O_NOCTTY, а затем установка TIOCSCTTY, поскольку вызов ioctl(fd,TIOCSCTTY,NULL) совместим со всеми разновидностями. Другой вариант — просто игнорировать ошибку, возвращаемую ioctl(fd,TIOCSCTTY,NULL). Кстати, я обнаружил проблему и изменил приведенный выше пример. - person Will; 27.03.2013