]> rtime.felk.cvut.cz Git - novaboot.git/commitdiff
Add command line interface to Expect.pm functionality
authorMichal Sojka <sojkam1@fel.cvut.cz>
Sun, 19 Jan 2014 09:53:57 +0000 (10:53 +0100)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Sun, 19 Jan 2014 09:53:57 +0000 (10:53 +0100)
README.md
novaboot
tests/Makefile
tests/expect.wv [new file with mode: 0755]
tests/novaboot.wv
tests/wvtest.sh

index 22480483a79c50c0b50ab20190c7fe8e69e50114..d6051aee34da4cf12f0eb419c9ce65f398597f8f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -274,8 +274,8 @@ user/instance.
 
 - \--remote-expect=_string_
 
-    Wait for reception of _string_ on the remote connection before
-    continuing.
+    Wait for reception of _string_ after establishing the the remote
+    connection before continuing.
 
 ## File deployment phase
 
@@ -362,16 +362,14 @@ to a particular location, e.g. to a TFTP boot server or to the
 
 - \--uboot-init
 
-    Command(s) to send the uBoot bootloader before loading the images and
-    botting them.
+    Command(s) to send the U-Boot bootloader before loading the images and
+    booting them.
 
 ## Target interaction phase
 
-In this phase, target's serial output is passed to `novaboot` stdout.
-If `novaboot`'s stdin is on TTY, the stdin is passed to the target
-allowing interactive work with the target.
-
-This phase end when the target hangs up or when Ctrl-C is pressed.
+In this phase, target's serial output is redirected to stdout and if
+stdin is a TTY, it is redirected to the target's serial input allowing
+interactive work with the target.
 
 - \--exiton=_string_
 
@@ -392,6 +390,38 @@ This phase end when the target hangs up or when Ctrl-C is pressed.
     to the target and does no longer interrupt novaboot. Use "~~."
     sequence to exit novaboot.
 
+- \--expect=_string_
+
+    When _string_ is received from the target, send the string specified
+    with the subsequent __\--send\*__ option to the target.
+
+- \--expect-re=_regex_
+
+    When target's output matches regular expression _regex_, send the
+    string specified with the subsequent __\--send\*__ option to the target.
+
+- \--expect-raw=_perl-code_
+
+    Provides direct control over Perl's Expect module.
+
+- \--send=_string_
+
+    Send _string_ to the target after the previously specified
+    __\--expect\*__ was matched in the target's output. The _string_ may
+    contain escape sequences such as "\\n".
+
+    Note that _string_ is actually interpreted by Perl, so it can contain
+    much more that escape sequences. This behavior may change in the
+    future.
+
+    Example: `--expect='login: ' --send='root\n'`
+
+- \--sendcont=_string_
+
+    Similar to __\--send__ but continue expecting more input.
+
+    Example: `--expect='Continue?' --sendcont='yes\n'`
+
 # NOVABOOT SCRIPT SYNTAX
 
 The syntax tries to mimic POSIX shell syntax. The syntax is defined with the following rules.
index 126597fa0e03b9864b51b216e7eb0f745ae58a31..fe74d1991d27262955b6d3205b953712749bb7bb 100755 (executable)
--- a/novaboot
+++ b/novaboot
@@ -99,12 +99,30 @@ read_config($_) foreach $cfg or reverse @cfgs;
 my $explicit_target;
 GetOptions ("target|t=s" => \$explicit_target);
 
-my ($append, $bender, @chainloaders, $concat, $config_name_opt, $dhcp_tftp, $dump_opt, $dump_config, @exiton, $gen_only, $grub_config, $grub_prefix, $grub_preamble, $grub2_prolog, $grub2_config, $help, $iprelay, $iso_image, $interactive, $make, $man, $no_file_gen, $off_opt, $on_opt, $pulsar, $pulsar_root, $qemu, $qemu_append, $qemu_flags_cmd, $remote_cmd, $remote_expect, $reset_cmd, $rom_prefix, $rsync_flags, @scriptmod, $scons, $serial, $server, $stty, $uboot, $uboot_init);
+my ($append, $bender, @chainloaders, $concat, $config_name_opt, $dhcp_tftp, $dump_opt, $dump_config, @exiton, @expect_raw, $gen_only, $grub_config, $grub_prefix, $grub_preamble, $grub2_prolog, $grub2_config, $help, $iprelay, $iso_image, $interactive, $make, $man, $no_file_gen, $off_opt, $on_opt, $pulsar, $pulsar_root, $qemu, $qemu_append, $qemu_flags_cmd, $remote_cmd, $remote_expect, $reset_cmd, $rom_prefix, $rsync_flags, @scriptmod, $scons, $serial, $server, $stty, $uboot, $uboot_init);
 
 $rsync_flags = '';
 $rom_prefix = 'rom://';
 $stty = 'raw -crtscts -onlcr 115200';
 
+my @expect_seen = ();
+sub handle_expect
+{
+    my ($n, $v) = @_;
+    push(@expect_seen, '-re') if $n eq "expect-re";
+    push(@expect_seen, $v);
+}
+
+sub handle_send
+{
+    my ($n, $v) = @_;
+    unless (@expect_seen) { die("No --expect before --send"); }
+    my $ret = ($n eq "sendcont") ? exp_continue : 0;
+    unshift(@expect_raw, sub { shift->send(eval("\"$v\"")); $ret; });
+    unshift(@expect_raw, @expect_seen);
+    @expect_seen = ();
+}
+
 Getopt::Long::Configure(qw/no_ignore_case no_pass_through/);
 my %opt_spec;
 %opt_spec = (
@@ -117,6 +135,9 @@ my %opt_spec;
     "dump"          => \$dump_opt,
     "dump-config"    => \$dump_config,
     "exiton=s"       => \@exiton,
+    "expect=s"      => \&handle_expect,
+    "expect-re=s"    => \&handle_expect,
+    "expect-raw=s"   => sub { my ($n, $v) = @_; unshift(@expect_raw, eval($v)); },
     "gen-only"      => \$gen_only,
     "grub|g:s"              => \$grub_config,
     "grub-preamble=s"=> \$grub_preamble,
@@ -142,6 +163,8 @@ my %opt_spec;
     "rsync-flags=s"  => \$rsync_flags,
     "scons:s"       => \$scons,
     "scriptmod=s"    => \@scriptmod,
+    "send=s"        => \&handle_send,
+    "sendcont=s"     => \&handle_send,
     "serial|s:s"     => \$serial,
     "server:s"              => \$server,
     "strip-rom"             => sub { $rom_prefix = ''; },
@@ -772,7 +795,7 @@ if (defined $exp) {
     print "novaboot: Serial line interaction (press $interrupt to interrupt)...\n";
     $exp->log_stdout(1);
     if (@exiton) {
-       $exp->expect(undef, @exiton);
+       $exp->expect(undef, @expect_raw, @exiton);
     } else {
        my @inputs = ($exp);
        if (-t STDIN) { # Set up bi-directional communication if we run on terminal
@@ -789,7 +812,10 @@ if (defined $exp) {
            }
            push(@inputs, $in_object);
        }
-       Expect::interconnect(@inputs);
+       #use Data::Dumper;
+       #print Dumper(\@expect_raw);
+       $exp->expect(undef, @expect_raw) if @expect_raw;
+       Expect::interconnect(@inputs) unless defined($exp->exitstatus);
     }
 }
 
@@ -1107,8 +1133,8 @@ example C<ssh server 'cu -l /dev/ttyS0'>.
 
 =item --remote-expect=I<string>
 
-Wait for reception of I<string> on the remote connection before
-continuing.
+Wait for reception of I<string> after establishing the the remote
+connection before continuing.
 
 =back
 
@@ -1207,18 +1233,16 @@ future!
 
 =item --uboot-init
 
-Command(s) to send the uBoot bootloader before loading the images and
-botting them.
+Command(s) to send the U-Boot bootloader before loading the images and
+booting them.
 
 =back
 
 =head2 Target interaction phase
 
-In this phase, target's serial output is passed to C<novaboot> stdout.
-If C<novaboot>'s stdin is on TTY, the stdin is passed to the target
-allowing interactive work with the target.
-
-This phase end when the target hangs up or when Ctrl-C is pressed.
+In this phase, target's serial output is redirected to stdout and if
+stdin is a TTY, it is redirected to the target's serial input allowing
+interactive work with the target.
 
 =over 8
 
@@ -1241,6 +1265,38 @@ special characters). This, among others, means that Ctrl-C is passed
 to the target and does no longer interrupt novaboot. Use "~~."
 sequence to exit novaboot.
 
+=item --expect=I<string>
+
+When I<string> is received from the target, send the string specified
+with the subsequent B<--send*> option to the target.
+
+=item --expect-re=I<regex>
+
+When target's output matches regular expression I<regex>, send the
+string specified with the subsequent B<--send*> option to the target.
+
+=item --expect-raw=I<perl-code>
+
+Provides direct control over Perl's Expect module.
+
+=item --send=I<string>
+
+Send I<string> to the target after the previously specified
+B<--expect*> was matched in the target's output. The I<string> may
+contain escape sequences such as "\n".
+
+Note that I<string> is actually interpreted by Perl, so it can contain
+much more that escape sequences. This behavior may change in the
+future.
+
+Example: C<--expect='login: ' --send='root\n'>
+
+=item --sendcont=I<string>
+
+Similar to B<--send> but continue expecting more input.
+
+Example: C<--expect='Continue?' --sendcont='yes\n'>
+
 =back
 
 =head1 NOVABOOT SCRIPT SYNTAX
index 1431280536dadd89d40101cd434100f5778c4f9d..5a9f298d00a1273b09cc45e79d2317256e48f942 100644 (file)
@@ -1,7 +1,9 @@
-TESTS=$(shell find -name '*.wv')
-
 all:
        ./wvtestrun $(MAKE) run-all
 
-run-all:
-       $(foreach t,$(TESTS),$(t); )
+run-all: novaboot.wv *.wv
+
+.PHONY: $(wildcard *.wv)
+
+*.wv:
+       ./$@
diff --git a/tests/expect.wv b/tests/expect.wv
new file mode 100755 (executable)
index 0000000..d47ab76
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+cd $(dirname $0)
+. wvtest.sh
+
+WVSTART Exiton
+WVPASS create_dummy
+WVPASS ./script -t '' --exiton=Hello --remote-cmd="echo Hello; cat"
+
+WVSTART Expect send
+WVPASS create_dummy
+WVPASS ./script -t '' --expect=question --send="answer\n" \
+    --remote-cmd='echo question; read x; echo $x > output'
+WVPASS grep answer output
+
+WVSTART Expect send
+WVPASS create_dummy
+WVPASS ./script -t '' --expect=question --send="answer\n" \
+    --remote-cmd='echo question; read x; echo $x > output'
+WVPASS grep answer output
+
+WVSTART Expect regexp send
+WVPASS create_dummy
+WVPASS ./script -t '' --expect-re=q..st..n --send="answer\n" \
+    --remote-cmd='echo question; read x; echo $x > output'
+WVPASS grep answer output
+
+WVSTART Expect sendcond
+WVPASS create_dummy
+WVPASS ./script -t '' --expect=More --sendcont="\n" \
+    --remote-cmd='seq 100|more'
index 0b21f5f94af87a1271c6816c5c6a54239820f3a6..1f2e163f0a91d44744a0be488b5605193876718a 100755 (executable)
@@ -2,23 +2,6 @@
 
 cd $(dirname $0)
 . wvtest.sh
-PATH=$(dirname $PWD):$PATH # Find our version of novaboot first
-
-function create_script ()
-{
-    (echo "#!/usr/bin/env novaboot"; cat) > script
-    chmod +x script
-}
-
-function create_dummy ()
-{
-    create_script <<EOF
-kernel
-file
-EOF
-    touch kernel
-    touch file
-}
 
 WVSTART Invoke with no script
 WVPASS novaboot -t '' < /dev/null
@@ -93,7 +76,7 @@ echo '$hypervisor="HYP";' > .novaboot
 WVPASS ./script --gen-only --pulsar
 WVPASS grep "exec HYP" config-novaboot
 
-exit
+exit 0
 
 # Broken
 WVSTART ISO image generation
index f3fa327ae9fcf7989d41e422ec680385cd296ae5..ac5f65afbc1a2f75e2335fb7eaf7f772425351cd 100644 (file)
@@ -146,3 +146,21 @@ WVSTART()
 
 WV_BASE_DIR="$PWD"
 export NOVABOOT_TEST=1
+
+PATH=$(dirname $PWD):$PATH # Find our version of novaboot first
+
+function create_script ()
+{
+    (echo "#!/usr/bin/env novaboot"; cat) > script
+    chmod +x script
+}
+
+function create_dummy ()
+{
+    create_script <<EOF
+kernel
+file
+EOF
+    touch kernel
+    touch file
+}