Como injetar dados no início do stdin de um processo filho?

2

TL; DR Como posso consertar este modelo de linha de comando, que falha quando o gato (no lado do cliente) enfrenta o ssh solicitando uma senha?

{ echo some stuff; cat; } | ssh SERVER cat
{ echo some stuff; cat; } | ssh SERVER ls

Não estou perguntando sobre como criar chaves públicas / privadas. Eu não quero consumir stdin antecipadamente, uma vez que o comando remoto pode ser algo que ignora seu stdin (nesse caso, forçar o usuário a digitar ^ D é uma dor). Não quero que o usuário tenha que especificar uma opção para o modelo para indicar se o comando remoto lerá ou não seu stdin. Eu quero que o modelo funcione independentemente de o comando remoto ler ou não seu stdin.

Detalhes: Eu quero escrever wrappers do lado do cliente e do servidor para um comando ser executado remotamente via ssh. O comando em questão pode ser qualquer comando da escolha do usuário. O objetivo dos wrappers é configurar o ambiente do comando. O wrapper do lado do cliente precisa enviar uma pequena quantidade de dados para o wrapper do lado do servidor, mas eu não quero enviar esses dados na linha de comando (eu quero enviá-lo no stdin).

Veja um exemplo de como isso pode ser chamado:

$ wrapper1 HOST wrapper2 sh -c "cat >file"
This data is sent to the remote side
^D

O Wrapper1 calcula alguns dados, passa para o wrapper2, que configura o ambiente antes de executar sh. Gato lê stdin e escreve em arquivo no lado remoto.

Para isso, desejo que o wrapper do lado do cliente injete alguns dados no início do fluxo de stdin que é enviado para o wrapper do lado do servidor. Esses dados extras serão consumidos do stdin pelo wrapper do lado do servidor antes que o comando real seja executado.

Após os dados injetados terem sido enviados e consumidos, eu quero que o pipeline stdin para o comando remoto seja o mesmo que teria sido sem essa injeção de dados. O comando remoto pode ou não se incomodar em ler qualquer coisa de seu stdin - isso depende do comando específico que está sendo executado.

Como o comando que está sendo executado não é conhecido de antemão, e não é conhecido de antemão se ele precisa ler qualquer coisa de stdin, eu não quero que o lado do cliente consuma seu stdin inteiro antes de chamar o comando remoto. / p>

Aqui estão mais detalhes do que estou tentando fazer:

Eu quero escrever wrapper1 em torno de "ssh HOST wrapper2 CMD", onde o CMD não é conhecido antecipadamente (suponha que não exija um tty, mas pode ou não ler stdin). O wrapper1 enviará alguns dados extras para o lado remoto para serem lidos pelo wrapper2 antes do wrapper2 execs CMD. Eu quero wrapper1 para ser mais ou menos transparente; ele deve funcionar da mesma forma que o ssh funciona, exceto para enviar os dados extras e executar o wrapper2 como o comando remoto para ler os dados extras antes de executar o CMD. Se o CMD remoto ler stdin, quero que ele obtenha o conteúdo do stdin do wrapper1, como se "ssh HOST CMD" fosse executado.

Eu codifiquei isso tendo o wrapper1 criando um processo filho que grava os dados extras no stdout, seguido pelo execing cat para copiar o stdin para stdout. Wrapper1 canaliza a saída do processo filho para o stdin do comando ssh. No entanto, essa abordagem falha quando o ssh solicita uma senha, pois tanto o cat quanto o ssh estão disputando a entrada do teclado (quando o CMD está sendo executado de forma interativa). Se eu inserir um sono antes do gato da criança, ele funcionará, mas obviamente isso não é o ideal.

Como não sei se o CMD lê stdin, não consigo consumir todos os stdin antes de executar o ssh para evitar o conflito. Em qualquer caso, é suboptimal para ler todos os stdin em muitos cenários (como quando é muito grande, ou precisa ser consumido de forma incremental).

Existe alguma maneira de fazer o que eu quero? Agora tudo o que posso pensar é uma opção para wrapper1 que dá a escolha de:

  1. Consumir todo o seu stdin e enviá-lo para o lado remoto ou
  2. Redirecionar stdin de / dev / null.

Mas, seria melhor evitar que o usuário escolha uma das duas opções e permitir que os dados de stdin sejam lidos de forma incremental, como normalmente seria sem os wrappers.

    
por jrw32982 26.03.2014 / 19:32

2 respostas

0

Não tenho certeza se entendi a pergunta corretamente:

wrapper1 () {
    host="$1"
    shift
    {
         echo "nonsensical statement involving wrapper2"
         cat
    } | ssh $host wrapper2 "$@"
}

Talvez esteja atento ao armazenamento em buffer.

    
por 26.03.2014 / 22:03
0

Então você pode tentar configurar o CMD para que ele sempre redirecione um arquivo como STDIN, assim

cmd < file.txt

ou talvez leia o arquivo primeiro, limpe e envie-o como uma string

cmd <<< "string"

Então, quando você chama o script CMD, você pode inserir os argumentos como estavam no arquivo antes de chamar ./wrapper2. Quando não houver necessidade do STDIN, certifique-se de não enviar nada de errado excluindo automaticamente o arquivo temporário ou truncando-o após a execução.

    
por 26.03.2014 / 19:58

Tags