]> rtime.felk.cvut.cz Git - novaboot.git/blobdiff - novaboot
Detect errors when starting tftpd
[novaboot.git] / novaboot
index 69631992326a312a110528251ff5c8c1288942da..4d9c8fbb8786b9931686ab5846745869c9c35bf2 100755 (executable)
--- a/novaboot
+++ b/novaboot
@@ -40,14 +40,14 @@ my $invocation_dir = $ENV{PWD} || getcwd();
 $CFG::hypervisor = "";
 $CFG::hypervisor_params = "serial";
 $CFG::genisoimage = "genisoimage";
-$CFG::qemu = 'qemu -cpu coreduo -smp 2';
+$CFG::qemu = 'qemu-system-i386 -cpu coreduo -smp 2';
 $CFG::default_target = 'qemu';
 %CFG::targets = (
     'qemu' => '--qemu',
     "tud" => '--server=erwin.inf.tu-dresden.de:~sojka/boot/novaboot --rsync-flags="--chmod=Dg+s,ug+w,o-w,+rX --rsync-path=\"umask 002 && rsync\"" --grub --grub-prefix=(nd)/tftpboot/sojka/novaboot --grub-preamble="timeout 0" --concat --iprelay=141.76.48.80:2324 --scriptmod=s/\\\\bhostserial\\\\b/hostserialpci/g',
     "novabox" => '--server=rtime.felk.cvut.cz:/srv/tftp/novaboot --rsync-flags="--chmod=Dg+s,ug+w,o-w,+rX --rsync-path=\"umask 002 && rsync\"" --pulsar --iprelay=147.32.86.92:2324',
     "localhost" => '--scriptmod=s/console=tty[A-Z0-9,]+// --server=/boot/novaboot/$NAME --grub2 --grub-prefix=/boot/novaboot/$NAME --grub2-prolog="  set root=\'(hd0,msdos1)\'"',
-    "ryuglab" => '--server=pc-sojkam.felk.cvut.cz:/srv/tftp --uboot --uboot-init="mw f0000b00 \${psc_cfg}; sleep 1" --remote-cmd="ssh -t pc-sojkam.felk.cvut.cz \"cu -l /dev/ttyUSB0 -s 115200\"" --remote-expect="Connected." --reset-cmd="ssh -t pc-sojkam.felk.cvut.cz \"dtrrts /dev/ttyUSB0 1 1\""',
+    "ryuglab" => '--server=pc-sojkam.felk.cvut.cz:/srv/tftp --uboot --uboot-init="mw f0000b00 \${psc_cfg}; sleep 1" --remote-cmd="ssh -tt pc-sojkam.felk.cvut.cz \"sterm -d -s 115200 /dev/ttyUSB0\""',
     "ryulocal" => '--dhcp-tftp --serial --uboot --uboot-init="dhcp; mw f0000b00 \${psc_cfg}; sleep 1" --reset-cmd="if which dtrrts; then dtrrts $NB_SERIAL 0 1; sleep 0.1; dtrrts $NB_SERIAL 1 1; fi"',
 
     );
@@ -99,16 +99,35 @@ 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 ($amt, @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, $kernel_opt, $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, $tftp, $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 = (
-    "append|a=s"     => \$append,
+    "amt=s"         => \$amt,
+    "append|a=s"     => \@append,
     "bender|b"       => \$bender,
     "build-dir=s"    => sub { my ($n, $v) = @_; $builddir = File::Spec->rel2abs($v); },
     "concat"        => \$concat,
@@ -117,6 +136,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,
@@ -125,6 +147,7 @@ my %opt_spec;
     "grub2-prolog=s" => \$grub2_prolog,
     "iprelay=s"             => \$iprelay,
     "iso:s"         => \$iso_image,
+    "kernel|k=s"     => \$kernel_opt,
     "interactive|i"  => \$interactive,
     "name=s"        => \$config_name_opt,
     "make|m:s"      => \$make,
@@ -142,21 +165,26 @@ 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 = ''; },
     "stty=s"        => \$stty,
-    "uboot"         => \$uboot,
-    "uboot-init=s"   => \$uboot_init,
+    "tftp"          => \$tftp,
+    "uboot:s"       => \$uboot,
+    "uboot-init=s"   => \@uboot_init,
     "h"             => \$help,
     "help"          => \$man,
     );
 
 # First process target options
 {
-    my $t = $explicit_target || $CFG::default_target;
-    exists $CFG::targets{$t} or die("Unknown target '$t' (valid targets are: ".join(", ", sort keys(%CFG::targets)).")");
-    GetOptionsFromString($CFG::targets{$t}, %opt_spec);
+    my $t = defined($explicit_target) ? $explicit_target : $CFG::default_target;
+    if ($t) {
+       exists $CFG::targets{$t} or die("Unknown target '$t' (valid targets are: ".join(", ", sort keys(%CFG::targets)).")");
+       GetOptionsFromString($CFG::targets{$t}, %opt_spec);
+    }
 }
 
 # Then process other command line options - some of them may override
@@ -199,14 +227,14 @@ if (defined $grub2_config) { $grub2_config ||= "grub.cfg"; }
 ## Parse the novaboot script(s)
 my @scripts;
 my $file;
-my $line;
 my $EOF;
 my $last_fn = '';
 my ($modules, $variables, $generated, $continuation);
-while (<>) {
+my $skip_reading = defined($on_opt) || defined($off_opt);
+while (!$skip_reading && ($_ = <>)) {
     if ($ARGV ne $last_fn) { # New script
        die "Missing EOF in $last_fn" if $file;
-       die "Unfinished line in $last_fn" if $line;
+       die "Unfinished line in $last_fn" if $continuation;
        $last_fn = $ARGV;
        push @scripts, { 'filename' => $ARGV,
                         'modules' => $modules = [],
@@ -217,22 +245,20 @@ while (<>) {
     chomp();
     next if /^#/ || /^\s*$/;   # Skip comments and empty lines
 
-    foreach my $mod(@scriptmod) { eval $mod; }
-
-    print "$_\n" if $dump_opt;
+    $_ =~ s/^[[:space:]]*// if ($continuation);
 
-    if (/^([A-Z_]+)=(.*)$/) {  # Internal variable
-       $$variables{$1} = $2;
-       push(@exiton, $2) if ($1 eq "EXITON");
+    if (/\\$/) {               # Line continuation
+       $continuation .= substr($_, 0, length($_)-1);
        next;
     }
-    if (/^([^ ]*)(.*?)[[:space:]]*<<([^ ]*)$/) { # Heredoc start
-       push @$modules, "$1$2";
-       $file = [];
-       push @$generated, {filename => $1, content => $file};
-       $EOF = $3;
-       next;
+
+    if ($continuation) {       # Last continuation line
+       $_ = $continuation . $_;
+       $continuation = '';
     }
+
+    foreach my $mod(@scriptmod) { eval $mod; }
+
     if ($file && $_ eq $EOF) { # Heredoc end
        undef $file;
        next;
@@ -241,29 +267,67 @@ while (<>) {
        push @{$file}, "$_\n";
        next;
     }
-    $_ =~ s/^[[:space:]]*// if ($continuation);
-    if (/\\$/) {               # Line continuation
-       $line .= substr($_, 0, length($_)-1);
-       $continuation = 1;
+    if (/^([A-Z_]+)=(.*)$/) {  # Internal variable
+       $$variables{$1} = $2;
+       push(@exiton, $2) if ($1 eq "EXITON");
+       next;
+    }
+    if (s/^load *//) {         # Load line
+       die("novaboot: '$last_fn' line $.: Missing file name\n") unless /^[^ <]+/;
+       if (/^([^ ]*)(.*?)[[:space:]]*<<([^ ]*)$/) { # Heredoc start
+           push @$modules, "$1$2";
+           $file = [];
+           push @$generated, {filename => $1, content => $file};
+           $EOF = $3;
+           next;
+       }
+       if (/^([^ ]*)(.*?)[[:space:]]*< ?(.*)$/) { # Command substitution
+           push @$modules, "$1$2";
+           push @$generated, {filename => $1, command => $3};
+           next;
+       }
+       push @$modules, $_;
        next;
     }
-    $continuation = 0;
-    $line .= $_;
-    $line .= " $append" if ($append && scalar(@$modules) == 0);
-
-    if ($line =~ /^([^ ]*)(.*?)[[:space:]]*< ?(.*)$/) { # Command substitution
-       push @$modules, "$1$2";
-       push @$generated, {filename => $1, command => $3};
-       $line = '';
+    if (/^run (.*)/) {         # run line
+       push @$generated, {command => $1};
        next;
     }
-    push @$modules, $line;
-    $line = '';
+
+    die("novaboot: Cannot parse script '$last_fn' line $.. Didn't you forget 'load' keyword?\n");
+}
+# use Data::Dumper;
+# print Dumper(\@scripts);
+
+foreach my $script (@scripts) {
+    $modules = $$script{modules};
+    @$modules[0] =~ s/^[^ ]*/$kernel_opt/ if $kernel_opt;
+    @$modules[0] .= ' ' . join(' ', @append) if @append;
+
+    my $kernel;
+    if (exists $variables->{KERNEL}) {
+       $kernel = $variables->{KERNEL};
+    } else {
+       if ($CFG::hypervisor) {
+           $kernel = $CFG::hypervisor . " ";
+           if (exists $variables->{HYPERVISOR_PARAMS}) {
+               $kernel .= $variables->{HYPERVISOR_PARAMS};
+           } else {
+               $kernel .= $CFG::hypervisor_params;
+           }
+       }
+    }
+    @$modules = ($kernel, @$modules) if $kernel;
+    @$modules = (@chainloaders, @$modules);
+    @$modules = ("bin/boot/bender", @$modules) if ($bender || defined $ENV{'NOVABOOT_BENDER'});
 }
-#use Data::Dumper;
-#print Dumper(\@scripts);
 
-exit if $dump_opt;
+if ($dump_opt) {
+    foreach my $script (@scripts) {
+       print join("\n", @{$$script{modules}})."\n";
+    }
+    exit(0);
+}
 
 ## Helper functions
 
@@ -280,7 +344,11 @@ sub generate_configs($$$) {
        print "novaboot: Created $fn\n";
       } elsif (exists $$g{command} && ! $no_file_gen) {
        $ENV{SRCDIR} = dirname(File::Spec->rel2abs( $filename, $invocation_dir ));
-       system_verbose("( $$g{command} ) > $$g{filename}");
+       if (exists $$g{filename}) {
+           system_verbose("( $$g{command} ) > $$g{filename}");
+       } else {
+           system_verbose($$g{command});
+       }
       }
     }
 }
@@ -310,6 +378,39 @@ sub generate_grub_config($$$$;$)
     return $filename;
 }
 
+sub generate_syslinux_config($$$$)
+{
+    my ($filename, $title, $base, $modules_ref) = @_;
+    if ($base && $base !~ /\/$/) { $base = "$base/"; };
+    open(my $fg, '>', $filename) or die "$filename: $!";
+    print $fg "LABEL $title\n";
+    #TODO print $fg "MENU LABEL $human_readable_title\n";
+
+    my ($kbin, $kcmd) = split(' ', @$modules_ref[0], 2);
+
+    if (system("file $kbin|grep 'Linux kernel'") == 0) {
+       my $initrd = @$modules_ref[1];
+       die('To many "load" lines for Linux kernel') if (scalar @$modules_ref > 2);
+       print $fg "LINUX $base$kbin\n";
+       print $fg "APPEND $kcmd\n";
+       print $fg "INITRD $base$initrd\n";
+    } else {
+       print $fg "KERNEL mboot.c32\n";
+       my @append;
+       foreach (@$modules_ref) {
+           s|\brom://([^ ]*)|$rom_prefix$base$1|g; # Translate rom:// files - needed for vdisk parameter of sigma0
+           push @append, "$base$_";
+           print $fg "APPEND ".join(' --- ', @append)."\n";
+       }
+    }
+    #TODO print $fg "TEXT HELP\n";
+    #TODO print $fg "some help here\n";
+    #TODO print $fg "ENDTEXT\n";
+    close($fg);
+    print("novaboot: Created $builddir/$filename\n");
+    return $filename;
+}
+
 sub generate_grub2_config($$$$;$$)
 {
     my ($filename, $title, $base, $modules_ref, $preamble, $prolog) = @_;
@@ -374,6 +475,7 @@ sub exec_verbose(@)
 {
     print "novaboot: Running: ".shell_cmd_string(@_)."\n";
     exec(@_);
+    exit(1); # should not be reached
 }
 
 sub system_verbose($)
@@ -394,7 +496,7 @@ if (exists $variables->{WVDESC}) {
     print "Testing \"all\" in $last_fn:\n";
 }
 
-## Connect to the target and check whether is not occupied
+## Connect to the target and check whether it is not occupied
 
 # We have to do this before file generation phase, because file
 # generation is intermixed with file deployment phase and we want to
@@ -483,10 +585,109 @@ elsif ($serial) {
     system_verbose("stty -F $serial $stty");
     open($CONN, "+<", $serial) || die "open $serial: $!";
     $exp = Expect->init(\*$CONN);
-} elsif ($remote_cmd) {
+}
+elsif ($remote_cmd) {
     print "novaboot: Running: $remote_cmd\n";
     $exp = Expect->spawn($remote_cmd);
 }
+elsif (defined $amt) {
+    require LWP::UserAgent;
+    require LWP::Authen::Digest;
+
+    sub genXML {
+        my ($host, $username, $password, $schema, $className, $pstate) = @_;
+       #AMT numbers for PowerStateChange (MNI => bluescreen on windows;-)
+       my %pstates = ("on"        => 2,
+                      "standby"   => 4,
+                      "hibernate" => 7,
+                      "off"       => 8,
+                      "reset"     => 10,
+                      "MNI"       => 11);
+        return <<END;
+               <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">
+               <s:Header><a:To>http://$host:16992/wsman</a:To>
+               <w:ResourceURI s:mustUnderstand="true">$schema</w:ResourceURI>
+               <a:ReplyTo><a:Address s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo>
+               <a:Action s:mustUnderstand="true">$schema$className</a:Action>
+               <w:MaxEnvelopeSize s:mustUnderstand="true">153600</w:MaxEnvelopeSize>
+               <a:MessageID>uuid:709072C9-609C-4B43-B301-075004043C7C</a:MessageID>
+               <w:Locale xml:lang="en-US" s:mustUnderstand="false" />
+               <w:OperationTimeout>PT60.000S</w:OperationTimeout>
+               <w:SelectorSet><w:Selector Name="Name">Intel(r) AMT Power Management Service</w:Selector></w:SelectorSet>
+               </s:Header><s:Body>
+               <p:RequestPowerStateChange_INPUT xmlns:p="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_PowerManagementService">
+               <p:PowerState>$pstates{$pstate}</p:PowerState>
+               <p:ManagedElement><a:Address>http://$host:16992/wsman</a:Address>
+               <a:ReferenceParameters><w:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ComputerSystem</w:ResourceURI>
+               <w:SelectorSet><w:Selector Name="Name">ManagedSystem</w:Selector></w:SelectorSet>
+               </a:ReferenceParameters></p:ManagedElement>
+               </p:RequestPowerStateChange_INPUT>
+               </s:Body></s:Envelope>
+END
+    }
+
+    sub sendPOST {
+        my ($host, $username, $password, $content) = @_;
+
+        my $ua = LWP::UserAgent->new();
+        $ua->agent("novaboot");
+
+       my $req = HTTP::Request->new(POST => "http://$host:16992/wsman");
+        my $res = $ua->request($req);
+        die ("Unexpected AMT response: " . $res->status_line) unless $res->code == 401;
+
+        my ($realm) = $res->header("WWW-Authenticate") =~ /Digest realm="(.*?)"/;
+        $ua->credentials("$host:16992", $realm, $username => $password);
+
+        # Create a request
+        $req = HTTP::Request->new(POST => "http://$host:16992/wsman");
+        $req->content_type('application/x-www-form-urlencoded');
+        $req->content($content);
+        $res = $ua->request($req);
+        die ("AMT power change request failed: " . $res->status_line) unless $res->is_success;
+        $res->content() =~ /<g:ReturnValue>(\d+)<\/g:ReturnValue>/;
+        return $1;
+    }
+
+    sub powerChange  {
+        my ($host, $username, $password, $pstate)=@_;
+        my $schema="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_PowerManagementService";
+        my $className="/RequestPowerStateChange";
+        my $content = genXML($host, $username, $password ,$schema, $className, $pstate);
+        return sendPOST($host, $username, $password, $content);
+    }
+
+    my ($user,$amt_password,$host,$port) = ($amt =~ /(?:(.*?)(?::(.*))?@)?([^:]*)(?::([0-9]*))?/);;
+    $user ||= "admin";
+    $amt_password ||= $ENV{'AMT_PASSWORD'} || die "AMT password not specified";
+    $host || die "AMT host not specified";
+    $port ||= 16994;
+
+    $target_power_off = sub {
+       $exp->close();
+       my $result = powerChange($host,$user,$amt_password, "off");
+       die "AMT power off failed (ReturnValue $result)" if $result != 0;
+    };
+
+    $target_power_on = sub {
+       my $result = powerChange($host,$user,$amt_password, "on");
+       die "AMT power on failed (ReturnValue $result)" if $result != 0;
+    };
+
+    $target_reset = sub {
+       my $result = powerChange($host,$user,$amt_password, "reset");
+       if ($result != 0) {
+           print STDERR "Warning: Cannot reset $host, trying power on. ";
+           $result = powerChange($host,$user,$amt_password, "on");
+       }
+       die "AMT reset failed (ReturnValue $result)" if $result != 0;
+    };
+
+    my $cmd = "amtterm -u $user -p $amt_password $host $port";
+    print "novaboot: Running: $cmd\n" =~ s/\Q$amt_password\E/???/r;
+    $exp = Expect->spawn($cmd);
+    $exp->expect(10, "RUN_SOL") || die "Expect for 'RUN_SOL' timed out";
+}
 
 if ($remote_expect) {
     $exp->expect(10, $remote_expect) || die "Expect for '$remote_expect' timed out";
@@ -533,23 +734,6 @@ foreach my $script (@scripts) {
        print "novaboot: Entering directory `$builddir'\n";
     }
 
-    my $kernel;
-    if (exists $variables->{KERNEL}) {
-       $kernel = $variables->{KERNEL};
-    } else {
-       if ($CFG::hypervisor) {
-           $kernel = $CFG::hypervisor . " ";
-           if (exists $variables->{HYPERVISOR_PARAMS}) {
-               $kernel .= $variables->{HYPERVISOR_PARAMS};
-           } else {
-               $kernel .= $CFG::hypervisor_params;
-           }
-       }
-    }
-    @$modules = ($kernel, @$modules) if $kernel;
-    @$modules = (@chainloaders, @$modules);
-    @$modules = ("bin/boot/bender", @$modules) if ($bender || defined $ENV{'NOVABOOT_BENDER'});
-
     my $prefix;
     ($prefix = $grub_prefix) =~ s/\$NAME/$config_name/ if defined $grub_prefix;
     $prefix ||= $builddir;
@@ -566,7 +750,7 @@ foreach my $script (@scripts) {
     {
        my @files = map({ ($file) = m/([^ ]*)/; $file; } @$modules);
        # Filter-out generated files
-       my @to_build = grep({ my $file = $_; !scalar(grep($file eq $$_{filename}, @$generated)) } @files);
+       my @to_build = grep({ my $file = $_; !scalar(grep($file eq ($$_{filename} || ''), @$generated)) } @files);
 
        system_verbose($scons || $CFG::scons." ".join(" ", @to_build)) if (defined $scons);
        system_verbose($make  || $CFG::make ." ".join(" ", @to_build)) if (defined $make);
@@ -596,7 +780,7 @@ foreach my $script (@scripts) {
     if (defined $iso_image) {
        generate_configs("(cd)", $generated, $filename);
        my $menu;
-       generate_grub_config(\$menu, $config_name, "(cd)", $modules);
+       generate_syslinux_config(\$menu, $config_name, "/", $modules);
        $menu_iso .= "$menu\n";
        map { ($file,undef) = split; $files_iso{$file} = 1; } @$modules;
     }
@@ -604,12 +788,26 @@ foreach my $script (@scripts) {
 
 ## Generate ISO image
 if (defined $iso_image) {
-    open(my $fh, ">menu-iso.lst");
-    print $fh "timeout 5\n\n$menu_iso";
+    system_verbose("mkdir -p isolinux");
+    system_verbose('cp /usr/lib/syslinux/isolinux.bin /usr/lib/syslinux/mboot.c32 /usr/lib/syslinux/menu.c32 isolinux');
+    open(my $fh, ">isolinux/isolinux.cfg");
+    if ($#scripts) {
+       print $fh "TIMEOUT 50\n";
+       print $fh "DEFAULT menu\n";
+    } else {
+       print $fh "DEFAULT $config_name\n";
+    }
+    print $fh "$menu_iso";
     close($fh);
-    my $files = "boot/grub/menu.lst=menu-iso.lst " . join(" ", map("$_=$_", keys(%files_iso)));
+
+    my $files = join(" ", map("$_=$_", (keys(%files_iso), 'isolinux/isolinux.bin', 'isolinux/isolinux.cfg', 'isolinux/mboot.c32', 'isolinux/menu.c32')));
     $iso_image ||= "$config_name.iso";
-    system_verbose("$CFG::genisoimage -R -b stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -hide-rr-moved -J -joliet-long -o $iso_image -graft-points bin/boot/grub/ $files");
+
+    # Note: We use -U flag below to "Allow 'untranslated' filenames,
+    # completely violating the ISO9660 standards". Without this
+    # option, isolinux is not able to read files names for example
+    # bzImage-3.0.
+    system_verbose("$CFG::genisoimage -R -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -hide-rr-moved -U -o $iso_image -graft-points $files");
     print("ISO image created: $builddir/$iso_image\n");
 }
 
@@ -631,7 +829,7 @@ sub trim($) {
     return $str
 }
 
-### Qemu
+### Start in Qemu
 
 if (defined $qemu) {
     # Qemu
@@ -645,7 +843,7 @@ if (defined $qemu) {
 
     if (defined $iso_image) {
        # Boot NOVA with grub (and test the iso image)
-       push(@qemu_flags, ('-cdrom', "$config_name.iso"));
+       push(@qemu_flags, ('-cdrom', $iso_image));
     } else {
        # Boot NOVA without GRUB
 
@@ -702,15 +900,20 @@ host server {
     # process group (e.g. Ctrl-C on terminal).
     $dhcpd_pid = fork();
     exec_verbose("sudo dhcpd -d -cf dhcpd.conf -lf dhcpd.leases -pf dhcpd.pid") if ($dhcpd_pid == 0);
-    $tftpd_pid = fork();
-    exec_verbose("sudo in.tftpd --foreground --secure -v -v -v --pidfile tftpd.pid $builddir") if ($tftpd_pid == 0);
+}
+
+if (defined $dhcp_tftp || defined $tftp) {
+    system_verbose("sudo in.tftpd --listen --secure -v -v -v --pidfile tftpd.pid $builddir");
 
     # Kill server when we die
-    $SIG{__DIE__} = sub { system_verbose('sudo pkill --pidfile=dhcpd.pid');
+    $SIG{__DIE__} = sub { system_verbose('sudo pkill --pidfile=dhcpd.pid') if (defined $dhcp_tftp);
                          system_verbose('sudo pkill --pidfile=tftpd.pid'); };
+
+    # We have to kill tftpd explicitely, because it is not in our process group
+    $SIG{INT} = sub { system_verbose('sudo pkill --pidfile=tftpd.pid'); exit(0); };
 }
 
-### Serial line or IP relay
+### Reset target (IP relay, AMT, ...)
 
 if (defined $target_reset) {
     print "novaboot: Reseting the test box... ";
@@ -718,48 +921,58 @@ if (defined $target_reset) {
     print "done\n";
 }
 
+### U-boot conversation
 if (defined $uboot) {
+    my $uboot_prompt = $uboot || '=> ';
     print "novaboot: Waiting for uBoot prompt...\n";
     $exp->log_stdout(1);
+    #$exp->exp_internal(1);
     $exp->expect(20,
                 [qr/Hit any key to stop autoboot:/, sub { $exp->send("\n"); exp_continue; }],
-                '=> ') || die "No uBoot prompt deteceted";
-    $exp->send("$uboot_init\n") if $uboot_init;
-    $exp->expect(10, '=> ') || die "uBoot prompt timeout";
-
-    my ($kbin, $kcmd) = split(' ', shift(@$modules), 2);
-    my $dtb;
-    @$modules = map { if (/\.dtb$/) { $dtb=$_; (); } else { $_ } } @$modules;
-    my $initrd = shift @$modules;
-
-    my $kern_addr = '800000';
-    my $initrd_addr = '-';
-    my $dtb_addr = '';
-
-    $exp->send("tftp $kern_addr $kbin\n");
-    $exp->expect(10,
-                [qr/#/, sub { exp_continue; }],
-                '=> ') || die "Kernel load failed";
-    if (defined $dtb) {
-       $dtb_addr = '7f0000';
-       $exp->send("tftp $dtb_addr $dtb\n");
-       $exp->expect(10,
-                    [qr/#/, sub { exp_continue; }],
-                    '=> ') || die "Device tree load failed";
+                $uboot_prompt) || die "No uBoot prompt deteceted";
+    while (@uboot_init) {
+       my $cmd = shift @uboot_init;
+       $exp->send("$cmd\n");
+       $exp->expect(10, $uboot_prompt) || die "uBoot prompt timeout";
     }
-    if (defined $initrd) {
-       $initrd_addr = 'b00000';
-       $exp->send("tftp $initrd_addr $initrd\n");
+
+    # Boot the system if there are some load lines in the script
+    if (scalar(@$modules) > 0) {
+       my ($kbin, $kcmd) = split(' ', shift(@$modules), 2);
+       my $dtb;
+       @$modules = map { if (/\.dtb$/) { $dtb=$_; (); } else { $_ } } @$modules;
+       my $initrd = shift @$modules;
+
+       my $kern_addr = '800000';
+       my $initrd_addr = '-';
+       my $dtb_addr = '';
+
+       $exp->send("tftp $kern_addr $kbin\n");
        $exp->expect(10,
                     [qr/#/, sub { exp_continue; }],
-                    '=> ') || die "Initrd load failed";
+                    $uboot_prompt) || die "Kernel load failed";
+       if (defined $dtb) {
+           $dtb_addr = '7f0000';
+           $exp->send("tftp $dtb_addr $dtb\n");
+           $exp->expect(10,
+                        [qr/#/, sub { exp_continue; }],
+                        $uboot_prompt) || die "Device tree load failed";
+       }
+       if (defined $initrd) {
+           $initrd_addr = 'b00000';
+           $exp->send("tftp $initrd_addr $initrd\n");
+           $exp->expect(10,
+                        [qr/#/, sub { exp_continue; }],
+                        $uboot_prompt) || die "Initrd load failed";
+       }
+       $exp->send("set bootargs '$kcmd'\n");
+       $exp->expect(5, $uboot_prompt)  || die "uBoot prompt timeout";
+       $exp->send("bootm $kern_addr $initrd_addr $dtb_addr\n");
+       $exp->expect(5, "\n")  || die "uBoot command timeout";
     }
-    $exp->send("set bootargs $kcmd\n");
-    $exp->expect(1, '=> ')  || die "uBoot prompt timeout";
-    $exp->send("bootm $kern_addr $initrd_addr $dtb_addr\n");
-    $exp->expect(1, "\n")  || die "uBoot command timeout";
 }
 
+### Serial line interaction
 if (defined $exp) {
     # Serial line of the target is available
     my $interrupt = 'Ctrl-C';
@@ -769,7 +982,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
@@ -786,12 +999,15 @@ 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);
     }
 }
 
 ## Kill dhcpc or tftpd
-if (defined $dhcp_tftp) {
+if (defined $dhcp_tftp || defined $tftp) {
     die("novaboot: This should kill servers on background\n");
 }
 
@@ -803,22 +1019,28 @@ novaboot - A tool for booting various operating systems on various hardware or i
 
 =head1 SYNOPSIS
 
-B<novaboot> [ options ] [--] script...
+B<novaboot> --help
 
-B<./script> [ options ]
+B<novaboot> [option]... [--] script...
 
-=head1 DESCRIPTION
+B<./script> [option]...
 
-This program makes it easier to boot NOVA or other operating system
-(OS) on different targets (machines or emulators). It reads a so
-called novaboot script, that specifies the boot configuration, and
-setups the target to boot that configuration. Setting up the target
-means to generate the bootloader configuration files, deploy the
-binaries and other needed files to proper locations, perhaps on a
-remote boot server and reset the target. Then, target's serial output
-is redirected to standard output if that is possible.
+=head1 DESCRIPTION
 
-A typical way of using novaboot is to make the novaboot script
+This program makes booting of an operating system (e.g. NOVA or Linux)
+as simple as running a local program. It facilitates booting on local
+or remote hosts or in emulators such as qemu. Novaboot operation is
+controlled by command line options and by a so called novaboot script,
+which can be thought as a generalization of bootloader configuration
+files (see L</"NOVABOOT SCRIPT SYNTAX">). Based on this input,
+novaboot setups everything for the target host to boot the desired
+configuration, i.e. it generates the bootloader configuration file in
+the proper format, deploy the binaries and other needed files to
+required locations, perhaps on a remote boot server and reset the
+target host. Finally, target host's serial output is redirected to
+standard output if that is possible.
+
+Typical way of using novaboot is to make the novaboot script
 executable and set its first line to I<#!/usr/bin/env novaboot>. Then,
 booting a particular OS configuration becomes the same as executing a
 local program - the novaboot script.
@@ -832,24 +1054,24 @@ For example, with C<novaboot> you can:
 Run an OS in Qemu. This is the default action when no other action is
 specified by command line switches. Thus running C<novaboot ./script>
 (or C<./script> as described above) will run Qemu and make it boot the
-configuration specified in the I<script>.
+configuration specified in the F<script>.
 
 =item 2.
 
 Create a bootloader configuration file (currently supported
-bootloaders are GRUB, GRUB2, Pulsar and uBoot) and copy it with all
-other files needed for booting to another, perhaps remote, location.
+bootloaders are GRUB, GRUB2, Pulsar and U-Boot) and copy it with all
+other files needed for booting to a remote boot server.
 
  ./script --server=192.168.1.1:/tftp --iprelay=192.168.1.2
 
 This command copies files to the TFTP server and uses
-TCP/IP-controlled relay to reset the test box and receive its serial
-output.
+TCP/IP-controlled relay to reset the target host and receive its
+serial output.
 
 =item 3.
 
-Run DHCP and TFTP server on developer's machine to PXE-boot the OS
-from it. E.g.
+Run DHCP and TFTP server on developer's machine to PXE-boot the target
+host from it. E.g.
 
  ./script --dhcp-tftp
 
@@ -869,8 +1091,8 @@ configurations.
 =back
 
 Note that the options needed for a specific target can be stored in a
-L</"CONFIGURATION FILE"> and then it is sufficient to use only the
-B<-t> option to specify the name of the target.
+L</"CONFIGURATION FILE">. Then it is sufficient to use only the B<-t>
+option to specify the name of the target.
 
 =head1 PHASES AND OPTIONS
 
@@ -934,9 +1156,9 @@ used in the later phases.
 
 =item -a, --append=I<parameters>
 
-Appends a string to the first "filename" line in the novaboot script.
-This can be used to append parameters to the kernel's or root task's
-command line.
+Append a string to the first C<load> line in the novaboot script. This
+can be used to append parameters to the kernel's or root task's
+command line. Can appear multiple times.
 
 =item -b, --bender
 
@@ -951,9 +1173,14 @@ in the novaboot script. E.g. 'bin/boot/bender promisc'.
 
 =item --dump
 
-Prints the content of the novaboot script after removing comments and
-evaluating all I<--scriptmod> expressions. Exit after reading (and
-dumping) the script.
+Print the modules to boot and their parameters after this phase
+finishes. Then exit. This is useful for seeing the effect of other
+options in this section.
+
+=item -k, --kernel=F<file>
+
+Replace the first word on the first C<load> line in the novaboot
+script with F<file>.
 
 =item --scriptmod=I<perl expression>
 
@@ -967,21 +1194,16 @@ from the configuration file, which has the same effect. If this option
 is given multiple times all expressions are evaluated in the command
 line order.
 
-=item --strip-rom
-
-Strip I<rom://> prefix from command lines and generated config files.
-The I<rom://> prefix is used by NUL. For NRE, it has to be stripped.
-
 =back
 
 =head2 File generation phase
 
 In this phase, files needed for booting are generated in a so called
-I<build directory> (see TODO). In most cases configuration for a
-bootloader is generated automatically by novaboot. It is also possible
-to generate other files using I<heredoc> or I<"<"> syntax in novaboot
-scripts. Finally, binaries can be generated in this phases by running
-C<scons> or C<make>.
+I<build directory> (see L</--build-dir>). In most cases configuration
+for a bootloader is generated automatically by novaboot. It is also
+possible to generate other files using I<heredoc> or I<"<"> syntax in
+novaboot scripts. Finally, binaries can be generated in this phases by
+running C<scons> or C<make>.
 
 =over 8
 
@@ -994,6 +1216,8 @@ configuration file defines the C<$builddir> variable, its value is
 used. Otherwise, it is the directory that contains the first processed
 novaboot script.
 
+See also L</BUILDDIR> variable.
+
 =item -g, --grub[=I<filename>]
 
 Generates grub bootloader menu file. If the I<filename> is not
@@ -1047,8 +1271,9 @@ server directory where the boot files are copied to.
 
 =item --no-file-gen
 
-Do not generate files on the fly (i.e. "<" syntax) except for the
-files generated via "<<WORD" syntax.
+Do not run external commands to generate files (i.e. "<" syntax and
+C<run> keyword). This switch does not influence generation of files
+specified with "<<WORD" syntax.
 
 =item -p, --pulsar[=mac]
 
@@ -1061,6 +1286,11 @@ I<novaboot>.
 Runs C<scons> to build files that are not generated by novaboot
 itself.
 
+=item --strip-rom
+
+Strip I<rom://> prefix from command lines and generated config files.
+The I<rom://> prefix is used by NUL. For NRE, it has to be stripped.
+
 =item --gen-only
 
 Exit novaboot after file generation phase.
@@ -1075,6 +1305,15 @@ user/instance.
 
 =over 8
 
+=item --amt=I<"[user[:password]@]host[:port]>
+
+Use Intel AMT technology to control the target machine. WS management
+is used to powercycle it and Serial-Over-Lan (SOL) for input/output.
+The hostname or (IP address) is given by the I<host> parameter. If
+I<password> is not specified, environment variable AMT_PASSWORD is
+used. The I<port> specifies a TCP port for SOL. If not specified, the
+default is 16992. Default I<user> is admin.
+
 =item --iprelay=I<addr[:port]>
 
 Use TCP/IP relay and serial port to access the target's serial port
@@ -1104,8 +1343,9 @@ 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
 
@@ -1128,7 +1368,20 @@ uses C<sudo> command to obtain those. You can put the following to
 I</etc/sudoers> to allow running the necessary commands without
 asking for password.
 
- Cmnd_Alias NOVABOOT = /bin/ip a add 10.23.23.1/24 dev eth0, /bin/ip l set dev eth0 up, /usr/sbin/dhcpd -d -cf dhcpd.conf -lf dhcpd.leases -pf dhcpd.pid, /usr/sbin/in.tftpd --foreground --secure -v -v -v --pidfile tftpd.pid *, /usr/bin/touch dhcpd.leases, /usr/bin/pkill --pidfile=dhcpd.pid, /usr/bin/pkill --pidfile=tftpd.pid
+ Cmnd_Alias NOVABOOT = /bin/ip a add 10.23.23.1/24 dev eth0, /bin/ip l set dev eth0 up, /usr/sbin/dhcpd -d -cf dhcpd.conf -lf dhcpd.leases -pf dhcpd.pid, /usr/sbin/in.tftpd --listen --secure -v -v -v --pidfile tftpd.pid *, /usr/bin/touch dhcpd.leases, /usr/bin/pkill --pidfile=dhcpd.pid, /usr/bin/pkill --pidfile=tftpd.pid
+ your_login ALL=NOPASSWD: NOVABOOT
+
+=item --tftp
+
+Starts a TFTP server on your workstation. This is similar to
+B<--dhcp-tftp> except that DHCP server is not started.
+
+The TFTP server require root privileges in order to listen on TFTP
+port and C<novaboot> uses C<sudo> command to obtain those. You can put
+the following to I</etc/sudoers> to allow running the necessary
+commands without asking for password.
+
+ Cmnd_Alias NOVABOOT =  /usr/sbin/in.tftpd --listen --secure -v -v -v --pidfile tftpd.pid *, /usr/bin/pkill --pidfile=tftpd.pid
  your_login ALL=NOPASSWD: NOVABOOT
 
 =item --iso[=filename]
@@ -1167,8 +1420,9 @@ copying files as a result of I<--server> option.
 
 =item --on, --off
 
-Switch on/off the target machine. Currently works only with
-B<--iprelay>.
+Switch on/off the target machine and exit. The script (if any) is
+completely ignored. Currently it works only with B<--iprelay> or
+B<--amt>.
 
 =item -Q, --qemu[=I<qemu-binary>]
 
@@ -1195,27 +1449,27 @@ Command that resets the target.
 
 =over 8
 
-=item --uboot
+=item --uboot[=I<prompt>]
 
 Interact with uBoot bootloader to boot the thing described in the
-novaboot script. Implementation of this option is currently tied to a
-particular board that we use. It may be subject to changes in the
-future!
+novaboot script. I<prompt> specifies the U-Boot's prompt (default is
+"=> ", other common prompts are "U-Boot> " or "U-Boot# ").
+Implementation of this option is currently tied to a particular board
+that we use. It may be subject to changes in the 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. This option can be given multiple times. After sending
+commands from each option novaboot waits for U-Boot I<prompt>.
 
 =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
 
@@ -1238,50 +1492,98 @@ 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
 
-The syntax tries to mimic POSIX shell syntax. The syntax is defined with the following rules.
+The syntax tries to mimic POSIX shell syntax. The syntax is defined
+with the following rules.
 
-Lines starting with "#" are ignored.
+Lines starting with "#" and empty lines are ignored.
 
 Lines that end with "\" are concatenated with the following line after
 removal of the final "\" and leading whitespace of the following line.
 
-Lines in the form I<VARIABLE=...> (i.e. matching '^[A-Z_]+=' regular
-expression) assign values to internal variables. See VARIABLES
+Lines of the form I<VARIABLE=...> (i.e. matching '^[A-Z_]+=' regular
+expression) assign values to internal variables. See L</VARIABLES>
 section.
 
-Otherwise, the first word on the line represents the filename
-(relative to the build directory (see B<--build-dir>) of the module to
-load and the remaining words are passed as the command line
-parameters.
+Lines starting with C<load> keyword represent modules to boot. The
+word after C<load> is a file name (relative to the build directory
+(see B<--build-dir>) of the module to load and the remaining words are
+passed to it as the command line parameters.
 
-When the line ends with "<<WORD" then the subsequent lines until the
-line containing only WORD are copied literally to the file named on
-that line.
+When the C<load> line ends with "<<WORD" then the subsequent lines
+until the line containing solely WORD are copied literally to the file
+named on that line. This is similar to shell's heredoc feature.
+
+When the C<load> line ends with "< CMD" then command CMD is executed
+with F</bin/sh> and its standard output is stored in the file named on
+that line. The SRCDIR variable in CMD's environment is set to the
+absolute path of the directory containing the interpreted novaboot
+script.
+
+Lines starting with C<run> keyword contain shell commands that are run
+during file generation phase. This is the same as the "< CMD" syntax
+for C<load> keyboard except that the command's output is not
+redirected to a file. The ordering of commands is the same as they
+appear in the novaboot script.
+
+Example (Linux):
+
+  #!/usr/bin/env novaboot
+  load bzImage console=ttyS0,115200
+  run  make -C buildroot
+  load rootfs.cpio < gen_cpio buildroot/images/rootfs.cpio "myapp->/etc/init.d/S99myapp"
 
-When the line ends with "< CMD" the command CMD is executed with
-C</bin/sh> and its standard output is stored in the file named on that
-line. The SRCDIR variable in CMD's environment is set to the absolute
-path of the directory containing the interpreted novaboot script.
+Example (NOVA User Land - NUL):
 
-Example:
   #!/usr/bin/env novaboot
   WVDESC=Example program
-  bin/apps/sigma0.nul S0_DEFAULT script_start:1,1 \
-    verbose hostkeyb:0,0x60,1,12,2
-  bin/apps/hello.nul
-  hello.nulconfig <<EOF
+  load bin/apps/sigma0.nul S0_DEFAULT script_start:1,1 \
+                           verbose hostkeyb:0,0x60,1,12,2
+  load bin/apps/hello.nul
+  load hello.nulconfig <<EOF
   sigma0::mem:16 name::/s0/log name::/s0/timer name::/s0/fs/rom ||
   rom://bin/apps/hello.nul
   EOF
 
-This example will load three modules: sigma0.nul, hello.nul and
-hello.nulconfig. sigma0 gets some command line parameters and
-hello.nulconfig file is generated on the fly from the lines between
-<<EOF and EOF.
+This example will load three modules: F<sigma0.nul>, F<hello.nul> and
+F<hello.nulconfig>. sigma0 receives some command line parameters and
+F<hello.nulconfig> file is generated on the fly from the lines between
+C<<<EOF> and C<EOF>.
 
 =head2 VARIABLES
 
@@ -1303,25 +1605,26 @@ option.
 =item HYPERVISOR_PARAMS
 
 Parameters passed to hypervisor. The default value is "serial", unless
-overriden in configuration file.
+overridden in configuration file.
 
 =item KERNEL
 
-The kernel to use instead of NOVA hypervisor specified in the
-configuration file. The value should contain the name of the kernel
-image as well as its command line parameters. If this variable is
-defined and non-empty, the variable HYPERVISOR_PARAMS is not used.
+The kernel to use instead of the hypervisor specified in the
+configuration file with the C<$hypervisor> variable. The value should
+contain the name of the kernel image as well as its command line
+parameters. If this variable is defined and non-empty, the variable
+HYPERVISOR_PARAMS is not used.
 
 =item QEMU
 
-Use a specific qemu binary (can be overriden with B<-Q>) and flags
+Use a specific qemu binary (can be overridden with B<-Q>) and flags
 when booting this script under qemu. If QEMU_FLAGS variable is also
 specified flags specified in QEMU variable are replaced by those in
 QEMU_FLAGS.
 
 =item QEMU_FLAGS
 
-Use specific qemu flags (can be overriden with B<-q>).
+Use specific qemu flags (can be overridden with B<-q>).
 
 =item WVDESC
 
@@ -1345,7 +1648,7 @@ specified with the B<-c> switch or with the NOVABOOT_CONFIG
 environment variable. The configuration file has perl syntax and
 should set values of certain Perl variables. The current configuration
 can be dumped with the B<--dump-config> switch. Some configuration
-variables can be overriden by environment variables (see below) or by
+variables can be overridden by environment variables (see below) or by
 command line switches.
 
 Supported configuration variables include: