
Похоже, что простое перенаправление оболочки с /dev/ptmx
даёт мне новый псевдотерминал.
$ ls /dev/pts; ls /dev/pts </dev/ptmx
0 1 2 ptmx
0 1 2 3 ptmx
Он исчезает, как только процесс, которому принадлежит претензия fd, завершается /dev/ptmx
, но его достаточно просто сохранить:
$ PS1='<$(ls -1 "$@" /dev/pts/*|uniq -u)> $ ' \
exec 3<>/dev/ptmx "$0" -si -- /dev/pts/*
</dev/pts/3> $ ls /dev/pts; exec 3>&-
0 1 2 3 ptmx
<> $ ls /dev/pts; exec 3<>/dev/ptmx
0 1 2 ptmx
</dev/pts/3> $ exit
Так что, похоже, простого open()
on /dev/ptmx
достаточно, чтобы получить псевдотерминал. Я думаю, это сделало бы оболочку -(или процесс, для которого выполняется перенаправление)- владелец основной стороны объекта недвижимости.
Но как мне назначить сторону раба - илиможетЯ назначаю подчиненную сторону? И если могу - что я могу с ней сделать? Могу ли я повлиять на ее время чтения/записи/очистки с помощью stty
? Будет ли подчиненный процесс ссылаться на мой новый pty при обращении к /dev/tty
?
решение1
Итак, как @muru указывает в комментариях, похоже, нет простого способа связать созданный для вас pty только с оболочкой. Я справился со всем, кроме части unlockpt()
. Согласно тому, что я читалздесьможет быть, в ядре есть какие-то опции компиляции для отключения блокировки вновь созданных pty, но я не хотел этого делать. Поэтому я сделал кое-что другое.
Мне на самом деле не нужно grantpt()
. Согласно найденному описаниюздесьвсе, что он делает, это меняет UID/GID для /dev/pts/[num]
файла устройства. Но, согласно man mount
есть более простые способы справиться с этим. Вот некоторые devpts
параметры монтирования:
uid=value
иgid=value
- Это устанавливает владельца или группу вновь созданных PTY на указанные значения. Если ничего не указано, они будут установлены на UID и GID процесса создания. Например, если есть телетайп группа с GID 5, то
gid=5
вновь созданные PTY будут принадлежатьтелетайпгруппа.
- Это устанавливает владельца или группу вновь созданных PTY на указанные значения. Если ничего не указано, они будут установлены на UID и GID процесса создания. Например, если есть телетайп группа с GID 5, то
Это уже было по умолчанию в моей системе. Но после прочтения я понял, что, возможно, мне все-таки захочется внести изменения. В следующем разделе говорится:
ptmxmode=value
- Установите режим для нового узла устройства ptmx в
devpts
файловой системе. - Благодаря поддержке нескольких экземпляров
devpts
(см.newinstance
опцию выше) каждый экземпляр имеет частный узел ptmx в корне файловойdevpts
системы.(обычно/dev/pts/ptmx
). - Для совместимости со старыми версиями ядра режимом по умолчанию нового узла ptmx является
0000
.ptmxmode=value
определяет более полезный режим для узла ptmx и настоятельно рекомендуется, еслиnewinstance
указана эта опция.
- Установите режим для нового узла устройства ptmx в
Хотя это работало бы и без этого, мне понравилась эта идея, и я установил значение, 0640
рекомендованное вдокументация ядра. Кстати, ссылка на документацию ядра подробно описывает newinstance
опцию монтирования, которая довольно крута и, по сути, позволяет вам получить отдельную группу пространств имен pty для каждого /dev/ptmx
монтирования.
В любом случае, так чточто-то другоев основном составили:
mount -o remount,newinstance,gid=5,ptmxmode=0640 /dev/pts
mount --bind /dev/pts/ptmx /dev/ptmx
...как рекомендует документация ядра - см. ссылку, почему. Я также сделал эффект вышеприведенных команд постоянным, добавив пару строк в свой /etc/fstab
.
И...
<<\C cc -xc - -o pts
#include <stdio.h>
int main(int argc, char *argv[]) {
if(unlockpt(0)) return 2;
char *ptsname(int fd);
printf("%s\n",ptsname(0));
return argc - 1;
}
C
Которая просто компилирует маленькую программу на языке C, которая пытается вызвать unlockpt()
свой stdin и в случае успеха выводит имя недавно созданного и разблокированного pty stdout
или молча возвращает 2.
Как только это будет сделано, я смогу создать свой собственныйэкранированныйтакие процессы как:
exec 3<>/dev/ptmx
...чтобы получить главный файловый дескриптор в текущей оболочке, то...
(setsid -c "$0" -i 2>&1|tee log) <>"$(./pts <&3)" 3>&- >&0 &
Это запускает интерактивную оболочку на другом конце псевдотерминала в фоновом режиме. Она будет интерпретировать все, что выводится на печать, >&3
как пользовательский ввод.
mikeserv@localhost$ echo echo hey >&3
mikeserv@localhost$ cat log
$ hey
$
mikeserv@localhost$ echo echo hey >&3
mikeserv@localhost$ cat log
$ hey
$ hey
$
Что по сути дает мне фонового, зарегистрированного, интерактивного переводчика.(или что-нибудь еще, что я захочу запустить на этих устройствах)ala screen
без особых накладных расходов и с любым выбранным мной файловым дескриптором.
Файловый дескриптор на стороне мастера, принадлежащий моей текущей оболочке, является единственным средством обслуживания ввода на стороне подчинённого устройства и доступен для записи только моему текущему процессу оболочки.(и его дети)Я могу общаться с другим концом, отправляя ему сообщения >&3
, и могу читать оттуда же или из файла журнала по своему усмотрению.
И stty
работает ли это на терминале в конце концов:
mikeserv@localhost$ echo stty -a ">$(tty)" >&3
speed 38400 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc
-ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl
echoke