Parece que um simples redirecionamento de shell /dev/ptmx
me dá um novo pseudo-terminal.
$ ls /dev/pts; ls /dev/pts </dev/ptmx
0 1 2 ptmx
0 1 2 3 ptmx
Ele desaparece assim que o processo que possui a reivindicação fd é /dev/ptmx
encerrado, mas é simples o suficiente para mantê-lo:
$ 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
Portanto, parece que o simples open()
é /dev/ptmx
suficiente para obter um pseudo-terminal. Acho que isso faria a concha...(ou o processo para o qual ele faz o redirecionamento)- o proprietário do lado mestre do prédio.
Mas como atribuo o lado escravo - oupodeEu atribuo o lado escravo? E se eu puder, o que posso fazer com isso? Posso afetar seus tempos de leitura/gravação/liberação com stty
? Um processo do lado escravo será vinculado ao meu novo pty ao fazer referência /dev/tty
?
Responder1
Então, como @muru aponta nos comentários, não parece haver uma maneira simples de fazer a interface do pty criado para você apenas com o shell. Eu consegui tudo menos uma unlockpt()
parte. De acordo com algo que liaquipode haver algumas opções de tempo de compilação no kernel para desabilitar o bloqueio de pty recém-criado, mas eu não queria fazer isso. Então, fiz outra coisa.
Na verdade , eu não precisava grantpt()
. De acordo com a descrição encontradaaquitudo o que faz é alterar o UID/GID do /dev/pts/[num]
arquivo do dispositivo. Mas de acordo com man mount
existem maneiras mais fáceis de lidar com isso. Aqui estão algumas devpts
opções de montagem:
uid=value
egid=value
- Isto define o proprietário ou o grupo de PTYs recém-criados para os valores especificados. Quando nada for especificado, eles serão definidos para o UID e GID do processo de criação. Por exemplo, se houver um tty grupo com GID 5,
gid=5
fará com que os PTYs recém-criados pertençam aottygrupo.
- Isto define o proprietário ou o grupo de PTYs recém-criados para os valores especificados. Quando nada for especificado, eles serão definidos para o UID e GID do processo de criação. Por exemplo, se houver um tty grupo com GID 5,
Esse já era o caso no meu sistema por padrão. Mas depois de ler isso, percebi que, afinal, talvez eu quisesse fazer uma mudança. A próxima seção diz:
ptmxmode=value
- Defina o modo para o novo nó do dispositivo ptmx no
devpts
sistema de arquivos. - Com suporte para múltiplas instâncias de
devpts
(vejanewinstance
a opção acima), cada instância possui um nó ptmx privado na raiz dodevpts
sistema de arquivos(normalmente/dev/pts/ptmx
). - Para compatibilidade com versões mais antigas do kernel, o modo padrão do novo nó ptmx é
0000
.ptmxmode=value
especifica um modo mais útil para o nó ptmx e é altamente recomendado quando anewinstance
opção é especificada.
- Defina o modo para o novo nó do dispositivo ptmx no
Embora teria funcionado sem isso, gostei da ideia e defini-a conforme 0640
recomendado nodocumentação do kernel. A propósito, o link do documento do kernel detalha a newinstance
opção de montagem - o que é muito legal e basicamente permite que você obtenha um grupo de ptys com espaçamento de nome separado por /dev/ptmx
montagem.
De qualquer forma, então oalgo maistotalizou principalmente:
mount -o remount,newinstance,gid=5,ptmxmode=0640 /dev/pts
mount --bind /dev/pts/ptmx /dev/ptmx
... como recomendam os documentos do kernel - veja o link sobre o porquê. Também tornei o efeito dos comandos acima permanente adicionando algumas linhas ao meu arquivo /etc/fstab
.
E...
<<\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
Que apenas compila um pequeno programa C que tenta chamar unlockpt()
seu stdin e, se for bem-sucedido, imprime o nome do pty recém-criado e desbloqueado stdout
ou então retorna silenciosamente 2.
Feito isso, eu poderia criar o meu própriorastreadosprocessos como:
exec 3<>/dev/ptmx
... para obter o fd do lado mestre no shell atual então ...
(setsid -c "$0" -i 2>&1|tee log) <>"$(./pts <&3)" 3>&- >&0 &
Isso faz com que um shell interativo seja executado na outra extremidade do pseudoterminal em segundo plano. Ele interpretará qualquer coisa impressa >&3
como entrada do usuário.
mikeserv@localhost$ echo echo hey >&3
mikeserv@localhost$ cat log
$ hey
$
mikeserv@localhost$ echo echo hey >&3
mikeserv@localhost$ cat log
$ hey
$ hey
$
O que basicamente me dá um intérprete interativo, registrado e com experiência(ou qualquer outra coisa que eu queira usar)ala, screen
sem tanta sobrecarga e em qualquer descritor de arquivo que eu escolher.
O fd do lado mestre de propriedade do meu shell atual é o único meio de servir a entrada do lado escravo e só pode ser gravado pelo meu processo atual do shell(e seus filhos). Posso me comunicar com o outro lado escrevendo >&3
e posso ler o mesmo ou um arquivo de log, conforme desejar.
E stty
afinal funciona no terminal:
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