$stdin->manual_stty(1)
para hacer que controles como ^Z suspendan la terminal
local y no la terminal remota.
lhp@nereida:~/Lperl/src/expect/tutorial$ cat -n etsii_interconnect
1 #!/usr/bin/perl -w
2 use strict;
3 use Expect;
4
5 # $Expect::Debug=2;
6 $Expect::Exp_Internal=1;
7
8 my $RSH='/usr/bin/ssh';
9 my $host_to_login_to='username@etsii';
10 my $machine='tomillo';
11
12 # Get the password.
13 print "Enter password: ";
14 my $stdin=Expect->exp_init(\*STDIN);
15 $stdin->exp_stty('-echo'); # Now turn off echoing
16 my ($match_num,$error,$match,$before,$after)=$stdin->expect(undef,"\n");
17 my $password = $before;
18 $stdin->exp_stty('echo'); # Turn echo back on
19 print "\n"; # print that newline that wasn't echoed
20
21 my $rsh=Expect->spawn($RSH,$host_to_login_to);
22
23 # Look for a password prompt in the bastion
24 $rsh->expect(30,'-re','word:\s$')||(die"Never got password prompt\n");
25 print $rsh "$password\r";
26
27 # Look for machine prompt.
28 $rsh->expect(30,'-re','salir\)(\s)+$')||(die"Never got machine prompt\n");
29
30 print $rsh "$machine\r";
31
32 # Look for a password prompt in the new machine.
33 $rsh->expect(30,'-re','word:\s$')||(die"Never got password prompt\n");
34 print $rsh "$password\r";
35
36 # Look for a prompt. Prompt can be # $ > or ] followed by a whitespace.
37 my $prompt = '[\]\$\>\#]\s$';
38
39 # Note the use of -re
40 $rsh->expect(30,'-re',$prompt)||(die "Never got prompt on host\n");
41
42 # OK, now return control to user.
43 $stdin->manual_stty(1);
44 $stdin->set_group($rsh);
45 Expect::interconnect($stdin, $rsh);
Normalmente, cuando establecemos interacción de STDIN
con un proceso se pone STDIN en modo raw.
En modo raw, el texto pasa directamente desde la seudoterminal ( PTY )
al dispositivo terminal ( TTY ). Esto es diferente del modo
cooked en el cuál se hacen cambios a los datos
en su paso del PTY al TTY. Por ejemplo, la aplicación obtiene líneas
de entrada completas y puede enviar un linefeed cuando requiere
una nueva línea. Además el texto tecleado es devuelto a la pantalla
( echo ). Lo habitual cuando un programa arranca es que,
para facilitar la entrada/salida de texto, la
terminal esté en modo cooked. Cuando se requiere un mayor control,
como ocurre con las PTY, se comienza en modo raw.
Cuando hacemos ssh a la shell en la máquina remota
estamos usando el modo raw. Si pulsamos
^Z irá directamente sin ser procesado a la TTY
en la máquina remota. Allí será interpretado y el proceso
suspendido será el que esté ejecutándose en la máquina remota.
La llamada a $stdin->manual_stty(1) establece que Expect
debe establecer los parámetros de la terminal de manera razonable.
Asi queda desactivado el modo raw y cuando pulsamos
^Z suspendemos Expect:
............ Arrancamos la conexión y ...
Matchlist: ()
Returning from expect successfully.
St Security Monitor 3.2 actived
/home/username[4]> uname -a
uname -a
Linux tomillo.remote_machine 2.4.22-1.2188.nptlsmp #1 SMP Wed Apr 21
20:12:56 EDT 2004 i686 i686 i386 GNU/Linux
/home/username[5]> ## <-- PULSAMOS ^Z
[2]+ Stopped ./etsii_interconnect
lhp@nereida:~/Lperl/src/expect/tutorial$ uname -a ## MAQUINA LOCAL
Linux nereida.deioc.ull.es 2.4.20-perfctr #6 SMP vie abr 2 18:36:12 WEST
2004 i686 GNU/Linux
lhp@nereida:~/Lperl/src/expect/tutorial$ fg # VOLVAMOS CON LA CONEXION
./etsii_interconnect
hp@nereida:~/Lperl/src/expect/tutorial$ fg
./etsii_interconnect
/home/username[5]> pwd
pwd
/home/username
/home/username[6]> uname -a
uname -a
Linux tomillo.remote_machine 2.4.22-1.2188.nptlsmp #1 SMP Wed Apr 21
20:12:56 EDT 2004 i686 i686 i386 GNU/Linux
............
Para que este esquema de trabajo funcione debe evitarse
el uso del método interact. Parece que este método
se empeña en establecer su propio juego de modos que entra
en conflicto con lo que queremos. El método interact
es una macro que llama a interconnect para conectar
dos procesos. De aqui las dos últimas líneas del código:
44 $stdin->set_group($rsh); 45 Expect::interconnect($stdin, $rsh);
El método interconnect tiene la sintáxis Expect::interconnect(@objects).
Lee desde @objects (en nuestro ejemplo desde $stdin y $rsh)
e imprime en sus @listen_groups. Esta llamada junto con
la llamada a $stdin->set_group($rsh)
establecen que las escrituras en $stdin deben ser propagadas
a $rsh. Por defecto, los miembros de @objects
y sus @listen_groups se ponen a raw -echo durante
la interconexión. Al establecer $object->manual_stty()
podemos modificar esta conducta. Los valores originales
del TTY se restauran al finalizar la interconexión.
Casiano Rodríguez León
