Control de la Terminal Local

Este ejemplo es igual al anterior salvo por las tres últimas líneas. En la línea 43 se establece $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
Licencia de Creative Commons
Programación Distribuida y Mejora del Rendimiento
por Casiano Rodríguez León is licensed under a Creative Commons Reconocimiento 3.0 Unported License.

Permissions beyond the scope of this license may be available at http://campusvirtual.ull.es/ocw/course/view.php?id=44.
2012-06-19