Отключение терминала родительского процесса

Я экспериментирую с пространствами имен в Linux, поэтому пишу небольшую программу на C, чтобы изолировать среду Debian Wheezy, созданную с помощью debootstrap.

Я мог бы успешно запустить sysv-init и получить приглашение на вход в систему, но когда я закрываю изолированную среду, либо выключаю систему, либо убиваю -9 init, терминал остается в состоянии, в котором, похоже, нет контролирующего терминала, подключенного к оболочке. В частности, если я запускаю sudo, он жалуется, что нет терминала.

Я сузил точку отказа в sudo до следующего утверждения:

open("/dev/tty", O_RDWR|O_NOCTTY);

с ошибкой ENXIO (т.е. "Нет такого устройства или адреса").

Я пытаюсь понять, почему это происходит, и я чувствую, что это что-то, связанное с системным вызовом setsid() в init, но я не смог воспроизвести точный сценарий, поэтому я не могу предоставить правильный тестовый пример.

Что мне действительно кажется странным, так это то, что не только init (разветвленный процесс и, следовательно, дочерний элемент оболочки) отсоединяется от текущего терминала, но также и вся иерархия процессов вплоть до GUI-терминала отсоединяется от tty, который я не могу понять, как это происходит.

Кроме того, есть некоторые несоответствия между различными командами:

➜  namespaces  tty
/dev/pts/19
➜  namespaces  sudo -s
sudo: no tty present and no askpass program specified
➜  namespaces  ls -l /proc/$$/fd
total 0
lrwx------ 1 paris paris 64 gen 15 23:24 0 -> /dev/pts/19
lrwx------ 1 paris paris 64 gen 15 23:24 1 -> /dev/pts/19
lrwx------ 1 paris paris 64 gen 15 23:24 10 -> /dev/pts/19
lrwx------ 1 paris paris 64 gen 15 23:24 2 -> /dev/pts/19
➜  namespaces  

Любая подсказка об этой ситуации приветствуется.

РЕДАКТИРОВАТЬ: глядя на исходный код ядра для "/dev/tty", я думаю, что проблема связана с подсчетом ссылок устройства char на стороне ядра. Действительно, чтобы перенаправить вывод "/dev/{console|tty0|tty1}" в текущий pty, я привязал подключенный управляющий терминал оболочки к файлу этих устройств в смонтированном контейнере dev.

РЕДАКТИРОВАТЬ: Кажется, что в ядре Linux ошибка сообщается на этом шаге в функции "tty_open_current_tty()":

static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
{
     struct tty_struct *tty;
     int retval;

     if (device != MKDEV(TTYAUX_MAJOR, 0))
         return NULL;

     tty = get_current_tty();
     if (!tty)
         return ERR_PTR(-ENXIO);
     ...
}

РЕДАКТИРОВАТЬ: Кажется, что проблема связана с концепцией "кража" контролирующего TTY. Это можно сделать под CAP_SYS_ADMIN возможность и вызов ioctl() в дескрипторе файла tty, используя TIOCSCTTY в качестве команды и 1 в качестве параметра (см. tty_ioctl (4)). Я постараюсь написать контрольный пример, чтобы подтвердить это и доложить.

2 ответа

Я думаю, что ваша догадка о setsid() вероятно, близко. Здесь fork() заклинания близко к setsid() вызов? Потому что обычная техника для превращения процесса в демона состоит в следующем:

  • fork()
  • setsid()
  • fork() еще раз, чтобы убедиться, что все отделено

редактировать

Исходный код для рассматриваемой функции (init_main): http://svn.savannah.nongnu.org/viewvc/sysvinit/trunk/src/init.c?root=sysvinit&view=markup

Имеет общее fork, setsid, fork шаблон повторяется несколько раз. Это обеспечит отделение от телетайпа.

Хорошо, я мог бы успешно отследить проблему.

См. Эту суть для примера рабочего кода (замените /dev/pts/17 с выходом tty команда).

Проблема связана со следующим шагом в sysvinit"s spawn() функция:

(void)ioctl(f, TIOCSCTTY, 1);

ioctl() на самом деле ворует контрольный TTY /dev/console который, в моем случае, является креплением pty текущего процесса.

Другие вопросы по тегам