LINUX.ORG.RU

Форкнуться в другой виртуальный терминал

 


0

1

Здравствуй дорогой all!

Меня давно мучает один вопрос, и вот видимо пришло время его задать:

А можно ли форкнуть текущий процесс так, чтобы его ввод-вывод начал работать через другой виртуальный терминал? Например через другое окно в tmux’е? Я с одной стороны не вижу концептуальных причин почему так нельзя. А с другой стороны не вижу никаких реальных возможностей этого сделать…

Кто-нибудь знает, возможно ли это вообще в принципе, если да, то как?

Update:

Правильный ответ такой:

#!/usr/bin/perl

use strict;
use POSIX;

my $pid = fork();
if ($pid)
{ 
  print "$pid\n";
  sleep 10;
  while (1) {print ".\n"; sleep 1};
} else
{
  my $i=0;
   (setpgid($$,$$) != -1)           || die "Can't create own group: $!";
  sleep 10;
  while (1) {print "$i\n"; sleep 1; $i++};
}

Он напечатает в консоли pid дочернего процесса, и в другой консоли надо дать команду

$ reptyr [это самый pid]

Подробности и полезные ссылки см. в комментариях

★★★

Последнее исправление: shaplov (всего исправлений: 2)

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

setsid program_name >> /dev/pts/123 2>> /dev/pts/123 < /dev/pts/123

Перед этим желательно сделать kill -STOP тому кто занимает терминал, который ты хочешь использовать, иначе он будет лезть со своим вводом-выводом в него и всё портить.

setsid нужно для того, чтобы отвязать прогу от старого controlling tty, после чего она сможет привязаться к новому (в линуксе при открывании терминального устройства, если у тебя него контролирующего терминала, оно вроде (не проверял) привязывается, а вот в фрибсд это не так - там привязывать надо вручную).

Если нужно только перенаправить стандартные потоки - то можно без setsid.

Если же нужно просто что-то писать в другое окно - можно даже не привязывать его в stdin/stdout, а просто открыть устройство и писать/читать, можно и не форкаясь и хоть в 10 терминалов одновременно.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 5)
Ответ на: комментарий от alnkapa

Нет, openpty создаёт виртуальный терминал, который твоя прога будет обслуживать. А автору надо подключиться к виртуальному терминалу, который уже кем-то создан и обслуживается.

firkax ★★★★★
()
Ответ на: комментарий от arrecck

https://github.com/nelhage/reptyr

Похоже, что штука крутая. Только вот отфоркнутый процесс оно отрывать не желает. Вот если запустистить вот такой скрипт

#!/usr/bin/perl

my $pid = fork();
if ($pid)
{ 
  print "$pid\n";
  sleep 10;
  while (1) {print ".\n"; sleep 1}
} else
{
  my $i=0;
  sleep 10;
  while (1) {print "$i\n"; sleep 1; $i++}
}

И попытаться сделать reptyr на напчеатанный ей pid, то она будет ругаться:

[-] Process 21272 (test.pl) shares 21273's process group. Unable to attach.
(This most commonly means that 21273 has sub-processes).
Unable to attach to pid 21273: Invalid argument

Вот что с этим можно сделать? Как-то дочерний процесс оторвать от родителя?

shaplov ★★★
() автор топика
Последнее исправление: shaplov (всего исправлений: 2)
Ответ на: комментарий от arrecck

Нашел в сети про setsid. Теперь скрипт выглядит так:

#!/usr/bin/perl

use strict;
use POSIX;

my $pid = fork();
if ($pid)
{ 
  print "$pid\n";
  sleep 10;
  while (1) {print ".\n"; sleep 1};
} else
{
  my $i=0;
  (setsid() != -1)           || die "Can't start a new session: $!";
  sleep 10;
  while (1) {print "$i\n"; sleep 1; $i++};
}

Но все равно не работает. В этом варианте reptyr выводит

[-] Timed out waiting for child stop.

И ждет. Из родительской консоли вывод при этом пропадает. В целевой не появляется. И если в новой консоли нажать ctrl-C то процесс вроде как завершается…

Пока не знаю куда копать дальше…

shaplov ★★★
() автор топика
Последнее исправление: shaplov (всего исправлений: 1)
23 апреля 2024 г.
Ответ на: комментарий от shaplov

Я ее таки победил.

Ключевым моментом в понимании была статья https://blog.nelhage.com/2011/02/changing-ctty/ рекомендую всем заинтересованным лицам.

То что пытался сделать я, в примере я дочерний процесс выдирал в отдельную сессию. И по какой-то причине reptyr с этим не справлялся. А вот если выдрать дочерний процесс в отдельную группу в рамках той же сессии, то reptyr это уже осиливает. Делается это вызовом setpgid($$,$$) который назначает процесс группой самому себе.

Суммарно код примера выглядит так:

#!/usr/bin/perl

use strict;
use POSIX;

my $pid = fork();
if ($pid)
{ 
  print "$pid\n";
  sleep 10;
  while (1) {print ".\n"; sleep 1};
} else
{
  my $i=0;
   (setpgid($$,$$) != -1)           || die "Can't create own group: $!";
  sleep 10;
  while (1) {print "$i\n"; sleep 1; $i++};
}

Он напечатает в консоли pid дочернего процесса, и в другой консоли надо дать команду

$ reptyr [это самый pid]

В результате точки из родительского процесса станут печататься в старой консоли, а циферки из дочернего процесса – в новой. Чего собственно говоря и хотелось добиться…

shaplov ★★★
() автор топика
Последнее исправление: shaplov (всего исправлений: 1)

Ничего не понял, что тут обсуждается, но как можно послать команду

sudo reboot now

, если в Терминале сейчас выполняется и не закончилась команда

sudo apt autoremove -y && sudo apt update && sudo apt upgrade -y #&& sudo reboot now

?

SerW
()