]> rtime.felk.cvut.cz Git - novaboot.git/blobdiff - novaboot
Preparation for storing U-Boot output to local files
[novaboot.git] / novaboot
index c5c85b7a4899f9faa050cef4130b87351048c790..5f2b3ed1ef34ca5a899bc04fb129354a87a551a1 100755 (executable)
--- a/novaboot
+++ b/novaboot
@@ -13,6 +13,8 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+## Initialization
+
 use strict;
 use warnings;
 use warnings (exists $ENV{NOVABOOT_TEST} ? (FATAL => 'all') : ());
@@ -25,7 +27,7 @@ use Time::HiRes("usleep");
 use Socket;
 use FileHandle;
 use IPC::Open2;
-use POSIX qw(:errno_h);
+use POSIX qw(:errno_h sysconf);
 use Cwd qw(getcwd abs_path);
 use Expect;
 
@@ -41,19 +43,25 @@ $CFG::hypervisor = "";
 $CFG::hypervisor_params = "serial";
 $CFG::genisoimage = "genisoimage";
 $CFG::qemu = 'qemu-system-i386 -cpu coreduo -smp 2';
-$CFG::default_target = 'qemu';
+$CFG::default_target = '';
 %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 -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"',
-
+    "ryu" =>  '--uboot --uboot-init="mw f0000b00 \${psc_cfg}; sleep 1" --uboot-addr kernel=800000 --uboot-addr ramdisk=b00000 --uboot-addr fdt=7f0000',
+    "ryuglab" => '--target ryu --server=pc-sojkam.felk.cvut.cz:/srv/tftp --remote-cmd="ssh -tt pc-sojkam.felk.cvut.cz \"sterm -d -s 115200 /dev/ttyUSB0\""',
+    "ryulocal" => '--target ryu --dhcp-tftp --serial --reset-cmd="if which dtrrts; then dtrrts $NB_SERIAL 0 1; sleep 0.1; dtrrts $NB_SERIAL 1 1; fi"',
     );
-chomp(my $nproc = `nproc`);
-$CFG::scons = "scons -j$nproc";
-$CFG::make = "make -j$nproc";
+
+{
+    my %const;
+    $const{linux}->{_SC_NPROCESSORS_CONF} = 83;
+    my $nproc = sysconf($const{$^O}->{_SC_NPROCESSORS_CONF});
+
+    $CFG::scons = "scons -j$nproc";
+    $CFG::make = "make -j$nproc";
+}
 
 my $builddir;
 
@@ -61,6 +69,7 @@ sub read_config($) {
     my ($cfg) = @_;
     {
        package CFG; # Put config data into a separate namespace
+
        my $rc = do($cfg);
 
        # Check for errors
@@ -89,6 +98,10 @@ my @cfgs;
        $dir = File::Spec->catdir(@dirs[0..$#dirs-1]);
     }
     @cfgs = reverse @cfgs;
+
+    my $xdg_config_home = $ENV{'XDG_CONFIG_HOME'} || $ENV{'HOME'}.'/.config';
+    unshift(@cfgs, "$xdg_config_home/novaboot") if -r "$xdg_config_home/novaboot";
+
     $dir = $ENV{'NOVABOOT_CONFIG_DIR'} || '/etc/novaboot.d';
     if (opendir(my $dh, $dir)) {
        my @etccfg = map { "$dir/$_" } grep { /^[-_a-zA-Z0-9]+$/ && -f "$dir/$_" } readdir($dh);
@@ -104,14 +117,24 @@ read_config($_) foreach $cfg or @cfgs;
 
 ## Command line handling
 
-my $explicit_target;
+my $explicit_target = $ENV{'NOVABOOT_TARGET'};
 GetOptions ("target|t=s" => \$explicit_target);
 
-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, $ider, $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, $tftp_port, $uboot, @uboot_init);
+my ($amt, @append, $bender, @chainloaders, $concat, $config_name_opt, $dhcp_tftp, $dump_opt, $dump_config, @exiton, $exiton_timeout, @expect_raw, $final_eol, $gen_only, $grub_config, $grub_prefix, $grub_preamble, $grub2_prolog, $grub2_config, $help, $ider, $interaction, $iprelay, $iso_image, $interactive, $kernel_opt, $make, $man, $netif, $no_file_gen, $off_opt, $on_opt, $pulsar, $pulsar_root, $qemu, $qemu_append, $qemu_flags_cmd, $remote_cmd, $remote_expect, $remote_expect_silent, $reset, $reset_cmd, $reset_send, $rom_prefix, $rsync_flags, @scriptmod, $scons, $serial, $server, $stty, $tftp, $tftp_port, $uboot, %uboot_addr, $uboot_cmd, @uboot_init);
 
+# Default values of certain command line options
+%uboot_addr = (
+    'kernel'  => '${kernel_addr_r}',
+    'ramdisk' => '${ramdisk_addr_r}',
+    'fdt'     => '${fdt_addr_r}',
+    );
 $rsync_flags = '';
 $rom_prefix = 'rom://';
 $stty = 'raw -crtscts -onlcr 115200';
+$reset = 1;                    # Reset target by default
+$interaction = 1;              # Perform target interaction by default
+$final_eol = 1;
+$netif = 'eth0';
 
 my @expect_seen = ();
 sub handle_expect
@@ -143,22 +166,27 @@ my %opt_spec;
     "dump"          => \$dump_opt,
     "dump-config"    => \$dump_config,
     "exiton=s"       => \@exiton,
+    "exiton-timeout=i"=> \$exiton_timeout,
+    "exiton-re=s"    => sub { my ($n, $v) = @_; push(@exiton, '-re', $v); },
     "expect=s"      => \&handle_expect,
     "expect-re=s"    => \&handle_expect,
     "expect-raw=s"   => sub { my ($n, $v) = @_; unshift(@expect_raw, eval($v)); },
+    "final-eol!"     => \$final_eol,
     "gen-only"      => \$gen_only,
     "grub|g:s"              => \$grub_config,
     "grub-preamble=s"=> \$grub_preamble,
-    "grub-prefix=s"  => \$grub_prefix,
+    "prefix|grub-prefix=s" => \$grub_prefix,
     "grub2:s"       => \$grub2_config,
     "grub2-prolog=s" => \$grub2_prolog,
     "ider"           => \$ider,
+    "interaction!"   => \$interaction,
     "iprelay=s"             => \$iprelay,
     "iso:s"         => \$iso_image,
     "kernel|k=s"     => \$kernel_opt,
     "interactive|i"  => \$interactive,
     "name=s"        => \$config_name_opt,
     "make|m:s"      => \$make,
+    "netif=s"       => \$netif,
     "no-file-gen"    => \$no_file_gen,
     "off"           => \$off_opt,
     "on"            => \$on_opt,
@@ -169,7 +197,10 @@ my %opt_spec;
     "qemu-flags|q=s" => \$qemu_flags_cmd,
     "remote-cmd=s"   => \$remote_cmd,
     "remote-expect=s"=> \$remote_expect,
+    "remote-expect-silent=s"=> sub { $remote_expect=$_[1]; $remote_expect_silent=1; },
+    "reset!"         => \$reset,
     "reset-cmd=s"    => \$reset_cmd,
+    "reset-send=s"   => \$reset_send,
     "rsync-flags=s"  => \$rsync_flags,
     "scons:s"       => \$scons,
     "scriptmod=s"    => \@scriptmod,
@@ -182,6 +213,9 @@ my %opt_spec;
     "tftp"          => \$tftp,
     "tftp-port=i"    => \$tftp_port,
     "uboot:s"       => \$uboot,
+    "no-uboot"      => sub { undef $uboot; },
+    "uboot-addr=s"   => \%uboot_addr,
+    "uboot-cmd=s"    => \$uboot_cmd,
     "uboot-init=s"   => \@uboot_init,
     "h"             => \$help,
     "help"          => \$man,
@@ -239,6 +273,16 @@ if ($ider) {
     if (!defined $amt) { die "Error: --ider requires --amt"; }
 }
 
+{
+    my %input_opts = ('--iprelay'    => \$iprelay,
+                     '--serial'     => \$serial,
+                     '--remote-cmd' => \$remote_cmd,
+                     '--amt'        => \$amt);
+    my @opts = grep(defined(${$input_opts{$_}}) , keys %input_opts);
+
+    die("novaboot: More than one target connection option: ".join(', ', @opts)) if scalar @opts > 1;
+}
+
 # Default options
 if (defined $serial) {
     $serial ||= "/dev/ttyUSB0";
@@ -252,7 +296,7 @@ my @scripts;
 my $file;
 my $EOF;
 my $last_fn = '';
-my ($modules, $variables, $generated, $continuation);
+my ($modules, $variables, $generated, $continuation) = ([], {}, []);
 my $skip_reading = defined($on_opt) || defined($off_opt);
 while (!$skip_reading && ($_ = <>)) {
     if ($ARGV ne $last_fn) { # New script
@@ -316,6 +360,17 @@ while (!$skip_reading && ($_ = <>)) {
        push @$generated, {command => $1};
        next;
     }
+    if (/^uboot(?::([0-9]+)s)? (.*)/) {        # uboot line
+       # TODO: If U-Boot supports some interactive menu, it might
+       # make sense to store uboot lines per novaboot script.
+       if ($1) {               # Command with explicit timeout
+           push @uboot_init, { command => $2,
+                               timeout => $1 };
+       } else {                # Command without explicit timeout
+           push @uboot_init, $2;
+       }
+       next;
+    }
 
     die("novaboot: Cannot parse script '$last_fn' line $.. Didn't you forget 'load' keyword?\n");
 }
@@ -364,7 +419,7 @@ sub generate_configs($$$) {
        open(my $f, '>', $fn) || die("$fn: $!");
        map { s|\brom://([^ ]*)|$rom_prefix$base$1|g; print $f "$_"; } @{$config};
        close($f);
-       print "novaboot: Created $fn\n";
+       print STDERR "novaboot: Created $fn\n";
       } elsif (exists $$g{command} && ! $no_file_gen) {
        $ENV{SRCDIR} = dirname(File::Spec->rel2abs( $filename, $invocation_dir ));
        if (exists $$g{filename}) {
@@ -496,7 +551,7 @@ sub shell_cmd_string(@)
 
 sub exec_verbose(@)
 {
-    print "novaboot: Running: ".shell_cmd_string(@_)."\n";
+    print STDERR "novaboot: Running: ".shell_cmd_string(@_)."\n";
     exec(@_);
     exit(1); # should not be reached
 }
@@ -504,19 +559,25 @@ sub exec_verbose(@)
 sub system_verbose($)
 {
     my $cmd = shift;
-    print "novaboot: Running: $cmd\n";
+    print STDERR "novaboot: Running: $cmd\n";
     my $ret = system($cmd);
     if ($ret & 0x007f) { die("Command terminated by a signal"); }
     if ($ret & 0xff00) {die("Command exit with non-zero exit code"); }
     if ($ret) { die("Command failure $ret"); }
 }
 
-## WvTest handline
+sub trim($) {
+    my ($str) = @_;
+    $str =~ s/^\s+|\s+$//g;
+    return $str
+}
+
+## WvTest headline
 
 if (exists $variables->{WVDESC}) {
-    print "Testing \"$variables->{WVDESC}\" in $last_fn:\n";
+    print STDERR "Testing \"$variables->{WVDESC}\" in $last_fn:\n";
 } elsif ($last_fn =~ /\.wv$/) {
-    print "Testing \"all\" in $last_fn:\n";
+    print STDERR "Testing \"all\" in $last_fn:\n";
 }
 
 ## Connect to the target and check whether it is not occupied
@@ -540,9 +601,9 @@ if (defined $iprelay) {
     my $paddr   = sockaddr_in($port, inet_aton($addr));
     my $proto   = getprotobyname('tcp');
     socket($IPRELAY, PF_INET, SOCK_STREAM, $proto)  || die "socket: $!";
-    print "novaboot: Connecting to IP relay... ";
+    print STDERR "novaboot: Connecting to IP relay... ";
     connect($IPRELAY, $paddr)    || die "connect: $!";
-    print "done\n";
+    print STDERR "done\n";
     $exp = Expect->init(\*$IPRELAY);
     $exp->log_stdout(1);
 
@@ -611,7 +672,7 @@ elsif ($serial) {
     $exp = Expect->init(\*$CONN);
 }
 elsif ($remote_cmd) {
-    print "novaboot: Running: $remote_cmd\n";
+    print STDERR "novaboot: Running: $remote_cmd\n";
     $exp = Expect->spawn($remote_cmd);
 }
 elsif (defined $amt) {
@@ -709,7 +770,7 @@ END
     };
 
     my $cmd = "amtterm -u $amt_user -p $amt_password $amt_host $amt_port";
-    print "novaboot: Running: $cmd\n" =~ s/\Q$amt_password\E/???/r;
+    print STDERR "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";
 
@@ -717,7 +778,16 @@ END
 
 
 if ($remote_expect) {
-    $exp->expect(10, $remote_expect) || die "Expect for '$remote_expect' timed out";
+    $exp || die("No serial line connection");
+    my $log = $exp->log_stdout;
+    if (defined $remote_expect_silent) {
+       $exp->log_stdout(0);
+    }
+    $exp->expect(180, $remote_expect) || die "Expect for '$remote_expect' timed out";
+    if (defined $remote_expect_silent) {
+       $exp->log_stdout($log);
+       print $exp->after() if $log;
+    }
 }
 
 if (defined $reset_cmd) {
@@ -726,12 +796,19 @@ if (defined $reset_cmd) {
     };
 }
 
+if (defined $reset_send) {
+    $target_reset = sub {
+       $reset_send =~ s/\\n/\n/g;
+       $exp->send($reset_send);
+    };
+}
+
 if (defined $on_opt && defined $target_power_on) {
     &$target_power_on();
     exit;
 }
 if (defined $off_opt && defined $target_power_off) {
-    print "novaboot: Switching the target off...\n";
+    print STDERR "novaboot: Switching the target off...\n";
     &$target_power_off();
     exit;
 }
@@ -739,12 +816,15 @@ if (defined $off_opt && defined $target_power_off) {
 $builddir ||= dirname(File::Spec->rel2abs( ${$scripts[0]}{filename})) if scalar @scripts;
 if (defined $builddir) {
     chdir($builddir) or die "Can't change directory to $builddir: $!";
-    print "novaboot: Entering directory `$builddir'\n";
+    print STDERR "novaboot: Entering directory `$builddir'\n";
+} else {
+    $builddir = $invocation_dir;
 }
 
 ## File generation phase
 my (%files_iso, $menu_iso, $filename);
 my $config_name = '';
+my $prefix = '';
 
 foreach my $script (@scripts) {
     $filename = $$script{filename};
@@ -758,12 +838,14 @@ foreach my $script (@scripts) {
     if (exists $variables->{BUILDDIR}) {
        $builddir = File::Spec->rel2abs($variables->{BUILDDIR});
        chdir($builddir) or die "Can't change directory to $builddir: $!";
-       print "novaboot: Entering directory `$builddir'\n";
+       print STDERR "novaboot: Entering directory `$builddir'\n";
     }
 
-    my $prefix;
-    ($prefix = $grub_prefix) =~ s/\$NAME/$config_name/ if defined $grub_prefix;
-    $prefix ||= $builddir;
+    if ($grub_prefix) {
+       $prefix = $grub_prefix;
+       $prefix =~ s/\$NAME/$config_name/;
+       $prefix =~ s/\$BUILDDIR/$builddir/;
+    }
     # TODO: use $grub_prefix as first parameter if some switch is given
     generate_configs('', $generated, $filename);
 
@@ -796,10 +878,12 @@ foreach my $script (@scripts) {
        map({ my $file = (split)[0]; die "$file: $!" if ! -f $file; } @$modules);
        my $istty = -t STDOUT && ($ENV{'TERM'} || 'dumb') ne 'dumb';
        my $progress = $istty ? "--progress" : "";
-       system_verbose("rsync $progress -RLp $rsync_flags $files $real_server");
-       if ($server =~ m|/\$NAME$| && $concat) {
-           my $cmd = join("; ", map { "( cd $path/.. && cat */$_ > $_ )" } @bootloader_configs);
-           system_verbose($hostname ? "ssh $hostname '$cmd'" : $cmd);
+       if ($files) {
+           system_verbose("rsync $progress -RLp $rsync_flags $files $real_server");
+           if ($server =~ m|/\$NAME$| && $concat) {
+               my $cmd = join("; ", map { "( cd $path/.. && cat */$_ > $_ )" } @bootloader_configs);
+               system_verbose($hostname ? "ssh $hostname '$cmd'" : $cmd);
+           }
        }
     }
 
@@ -856,13 +940,7 @@ if (scalar(@scripts) > 1 && ( defined $dhcp_tftp || defined $serial || defined $
 }
 
 if ($variables->{WVTEST_TIMEOUT}) {
-    print "wvtest: timeout ", $variables->{WVTEST_TIMEOUT}, "\n";
-}
-
-sub trim($) {
-    my ($str) = @_;
-    $str =~ s/^\s+|\s+$//g;
-    return $str
+    print STDERR "wvtest: timeout ", $variables->{WVTEST_TIMEOUT}, "\n";
 }
 
 ### Start in Qemu
@@ -901,7 +979,7 @@ if (defined $qemu) {
     }
     push(@qemu_flags,  qw(-serial stdio)); # Redirect serial output (for collecting test restuls)
     unshift(@qemu_flags, ('-name', $config_name));
-    print "novaboot: Running: ".shell_cmd_string($qemu, @qemu_flags)."\n";
+    print STDERR "novaboot: Running: ".shell_cmd_string($qemu, @qemu_flags)."\n";
     $exp = Expect->spawn(($qemu, @qemu_flags)) || die("exec() failed: $!");
 }
 
@@ -917,7 +995,7 @@ if (defined $dhcp_tftp)
     system_verbose('mkdir -p tftpboot');
     generate_grub_config("tftpboot/os-menu.lst", $config_name, "(nd)", \@$modules, "timeout 0");
     open(my $fh, '>', 'dhcpd.conf');
-    my $mac = `cat /sys/class/net/eth0/address`;
+    my $mac = `cat /sys/class/net/$netif/address`;
     chomp $mac;
     print $fh "subnet 10.23.23.0 netmask 255.255.255.0 {
                      range 10.23.23.10 10.23.23.100;
@@ -929,8 +1007,8 @@ host server {
        fixed-address 10.23.23.1;
 }";
     close($fh);
-    system_verbose("sudo ip a add 10.23.23.1/24 dev eth0;
-           sudo ip l set dev eth0 up;
+    system_verbose("sudo ip a add 10.23.23.1/24 dev $netif;
+           sudo ip l set dev $netif up;
            sudo touch dhcpd.leases");
 
     # We run servers by forking ourselves, because the servers end up
@@ -957,7 +1035,7 @@ if (defined $dhcp_tftp || defined $tftp) {
 ### AMT IDE-R
 if (defined $ider) {
     my $ider_cmd= "amtider -c $iso_image -u $amt_user -p $amt_password $amt_host $amt_port"  ;
-    print "novaboot: Running: $ider_cmd\n" =~ s/\Q$amt_password\E/???/r;
+    print STDERR "novaboot: Running: $ider_cmd\n" =~ s/\Q$amt_password\E/???/r;
     my $ider_pid = fork();
     if ($ider_pid == 0) {
        exec($ider_cmd);
@@ -970,90 +1048,138 @@ if (defined $ider) {
 
 ### Reset target (IP relay, AMT, ...)
 
-if (defined $target_reset) {
-    print "novaboot: Reseting the test box... ";
+if (defined $target_reset && $reset) {
+    print STDERR "novaboot: Reseting the test box... ";
     &$target_reset();
-    print "done\n";
+    print STDERR "done\n";
+    if (defined $exp) {
+       # We don't want to output anything printed by the target
+       # before reset so we clear the buffers now. This is, however,
+       # not ideal because we may loose some data that were sent
+       # after the reset. If this is a problem, one should reset and
+       # connect to serial line in atomic manner. For example, if
+       # supported by hardware, use --remote-cmd 'sterm -d ...' and
+       # do not use separate --reset-cmd.
+       my $log = $exp->log_stdout;
+       $exp->log_stdout(0);
+       $exp->expect(0); # Read data from target
+       $exp->clear_accum();    # Clear the read data
+       $exp->log_stdout($log);
+    }
 }
 
 ### U-boot conversation
 if (defined $uboot) {
     my $uboot_prompt = $uboot || '=> ';
-    print "novaboot: Waiting for uBoot prompt...\n";
+    print STDERR "novaboot: Waiting for U-Boot prompt...\n";
+    $exp || die("No serial line connection");
     $exp->log_stdout(1);
     #$exp->exp_internal(1);
     $exp->expect(20,
                 [qr/Hit any key to stop autoboot:/, sub { $exp->send("\n"); exp_continue; }],
-                $uboot_prompt) || die "No uBoot prompt deteceted";
-    foreach my $cmd (@uboot_init) {
+                $uboot_prompt) || die "No U-Boot prompt deteceted";
+    foreach my $cmdspec (@uboot_init) {
+       my ($cmd, $timeout);
+       if (ref($cmdspec) eq "HASH") {
+           $cmd = $cmdspec->{command};
+           $timeout = $cmdspec->{timeout};
+       } else {
+           $cmd = $cmdspec;
+           $timeout = 10;
+       }
+       if ($cmd =~ /\$NB_MYIP/) {
+           my $ip = (grep /inet /, `ip addr show $netif`)[0] || die "Problem determining our IP address";
+           $ip =~ s/\s*inet ([0-9.]*).*/$1/;
+           $cmd =~ s/\$NB_MYIP/$ip/g;
+       }
+       if ($cmd =~ /\$NB_PREFIX/) {
+           my $p = $prefix;
+           $p =~ s|/*$||;
+           $cmd =~ s/\$NB_PREFIX/$p/g;
+       }
+       chomp($cmd);
        $exp->send("$cmd\n");
-       $exp->expect(10, $uboot_prompt) || die "uBoot prompt timeout";
+
+       my ($matched_pattern_position, $error,
+           $successfully_matching_string,
+           $before_match, $after_match) =
+               $exp->expect($timeout, $uboot_prompt);
+       die "No U-Boot prompt: $error" if $error;
+       #print "\n>>>>$before_match<<<<\n";
     }
 
-    # Boot the system if there are some load lines in the script
-    if (scalar(@$modules) > 0) {
+    # Load files if there are some load lines in the script
+    if (scalar(@$modules) > 0  && !$variables->{NO_BOOT}) {
        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; }],
-                    $uboot_prompt) || die "Kernel load failed";
+       if (defined $kbin) {
+           die "No '--uboot-addr kernel' given" unless $uboot_addr{kernel};
+           $exp->send("tftpboot $uboot_addr{kernel} $prefix$kbin\n");
+           $exp->expect(10,
+                        [qr/##/, sub { exp_continue; }],
+                        $uboot_prompt) || die "Kernel load timeout";
+       }
        if (defined $dtb) {
-           $dtb_addr = '7f0000';
-           $exp->send("tftp $dtb_addr $dtb\n");
+           die "No '--uboot-addr fdt' given" unless $uboot_addr{fdt};
+           $exp->send("tftpboot $uboot_addr{fdt} $prefix$dtb\n");
            $exp->expect(10,
-                        [qr/#/, sub { exp_continue; }],
-                        $uboot_prompt) || die "Device tree load failed";
+                        [qr/##/, sub { exp_continue; }],
+                        $uboot_prompt) || die "Device tree load timeout";
        }
        if (defined $initrd) {
-           $initrd_addr = 'b00000';
-           $exp->send("tftp $initrd_addr $initrd\n");
+           die "No '--uboot-addr ramdisk' given" unless $uboot_addr{ramdisk};
+           $exp->send("tftpboot $uboot_addr{ramdisk} $prefix$initrd\n");
            $exp->expect(10,
-                        [qr/#/, sub { exp_continue; }],
-                        $uboot_prompt) || die "Initrd load failed";
+                        [qr/##/, sub { exp_continue; }],
+                        $uboot_prompt) || die "Initrd load timeout";
+       } else {
+           $uboot_addr{ramdisk} = '-';
        }
-       $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";
+
+       $kcmd //= '';
+       $exp->send("setenv bootargs $kcmd\n");
+       $exp->expect(5, $uboot_prompt)  || die "U-Boot prompt timeout";
+
+    }
+    $uboot_cmd //= $variables->{UBOOT_CMD} // 'bootm $kernel_addr $ramdisk_addr $fdt_addr';
+    if (!$variables->{NO_BOOT} && $uboot_cmd ne '') {
+       $uboot_cmd =~ s/\$kernel_addr/$uboot_addr{kernel}/g;
+       $uboot_cmd =~ s/\$ramdisk_addr/$uboot_addr{ramdisk}/g;
+       $uboot_cmd =~ s/\$fdt_addr/$uboot_addr{fdt}/g;
+
+       $exp->send($uboot_cmd . "\n");
+       $exp->expect(5, "\n")  || die "U-Boot command timeout";
     }
 }
 
 ### Serial line interaction
-if (defined $exp) {
+if ($interaction && defined $exp) {
     # Serial line of the target is available
     my $interrupt = 'Ctrl-C';
     if ($interactive && !@exiton) {
        $interrupt = '"~~."';
     }
-    my $note = (-t STDIN) ? '' : '- only target->host ';
-    print "novaboot: Serial line interaction $note(press $interrupt to interrupt)...\n";
+    print STDERR "novaboot: Serial line interaction (press $interrupt to interrupt)...\n";
     $exp->log_stdout(1);
     if (@exiton) {
-       $exp->expect(undef, @expect_raw, @exiton);
+       $exp->expect($exiton_timeout, @expect_raw, @exiton) || die("exiton timeout");
     } else {
        my @inputs = ($exp);
-       if (-t STDIN) { # Set up bi-directional communication if we run on terminal
-           my $infile = new IO::File;
-           $infile->IO::File::fdopen(*STDIN,'r');
-           my $in_object = Expect->exp_init($infile);
-           $in_object->set_group($exp);
-
-           if ($interactive) {
-               $in_object->set_seq('~~\.', sub { print "novaboot: Escape sequence detected\r\n"; undef; });
-               $in_object->manual_stty(0);       # Use raw terminal mode
-           } else {
-               $in_object->manual_stty(1);       # Do not modify terminal settings
-           }
-           push(@inputs, $in_object);
+       my $infile = new IO::File;
+       $infile->IO::File::fdopen(*STDIN,'r');
+       my $in_object = Expect->exp_init($infile);
+       $in_object->set_group($exp);
+
+       if ($interactive) {
+           $in_object->set_seq('~~\.', sub { print STDERR "novaboot: Escape sequence detected\r\n"; undef; });
+           $in_object->manual_stty(0);   # Use raw terminal mode
+       } else {
+           $in_object->manual_stty(1);   # Do not modify terminal settings
        }
+       push(@inputs, $in_object);
        #use Data::Dumper;
        #print Dumper(\@expect_raw);
        $exp->expect(undef, @expect_raw) if @expect_raw;
@@ -1066,11 +1192,16 @@ if (defined $dhcp_tftp || defined $tftp) {
     die("novaboot: This should kill servers on background\n");
 }
 
+# Always finish novaboot output with newline
+print "\n" if $final_eol;
+
 ## Documentation
 
+=encoding utf8
 =head1 NAME
 
-novaboot - A tool for booting various operating systems on various hardware or in qemu
+novaboot - Boots a locally compiled operating system on a remote
+target or in qemu
 
 =head1 SYNOPSIS
 
@@ -1082,108 +1213,151 @@ B<./script> [option]...
 
 =head1 DESCRIPTION
 
-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.
-
-For example, with C<novaboot> you can:
+Novaboot makes booting of a locally compiled operating system (OS)
+(e.g. NOVA or Linux) on remote targets as simple as running a program
+locally. It automates things like copying OS images to a TFTP server,
+generation of bootloader configuration files, resetting of target
+hardware or redirection of target's serial line to stdin/out. Novaboot
+is highly configurable and makes it easy to boot a single image on
+different targets or different images on a single target.
+
+Novaboot operation is controlled by configuration files, 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">). 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.
+
+Novaboot uses configuration files to, among other things, define
+command line options needed for different targets. Users typically use
+only the B<-t>/B<--target> command line option to select the target.
+Internally, this option expands to the pre-configured options.
+Configuration files are searched at multiple places, which allows to
+have per-system, per-user or per-project configurations. Configuration
+file syntax is described in section L</"CONFIGURATION FILES">.
+
+Simple examples of using C<novaboot>:
 
 =over 3
 
 =item 1.
 
-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 F<script>.
+Run an OS in Qemu. This can be specified with the B<--qemu> option.
+Thus running
+
+ novaboot --qemu myos
+
+(or C<./myos --qemu> as described above) will run Qemu and make it
+boot the configuration specified in the F<myos> script.
 
 =item 2.
 
 Create a bootloader configuration file (currently supported
-bootloaders are GRUB, GRUB2, Pulsar and U-Boot) and copy it with all
-other files needed for booting to a remote boot server.
+bootloaders are GRUB, GRUB2, ISOLINUX, Pulsar and U-Boot) and copy it
+with all other files needed for booting to a remote boot server. Then
+use a TCP/IP-controlled relay/serial-to-TCP converter to reset the
+target and receive its serial output.
 
- ./script --server=192.168.1.1:/tftp --iprelay=192.168.1.2
+ ./myos --grub2 --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 target host and receive its
-serial output.
+Alternatively, you can put these switches to the configuration file
+and run:
+
+ ./myos --target mytarget
 
 =item 3.
 
-Run DHCP and TFTP server on developer's machine to PXE-boot the target
-host from it. E.g.
+Run DHCP and TFTP server on developer's machine to boot the target
+from it.
 
- ./script --dhcp-tftp
+ ./myos --dhcp-tftp
 
-When a PXE-bootable machine is connected via Ethernet to developer's
-machine, it will boot the configuration described in I<script>.
+This is useful when no network infrastructure is in place and
+the target is connected directly to developer's box.
 
 =item 4.
 
-Create bootable ISO images. E.g.
+Create bootable ISO image.
 
  novaboot --iso -- script1 script2
 
-The created ISO image will have GRUB bootloader installed on it and
-the boot menu will allow selecting between I<script1> and I<script2>
-configurations.
+The created ISO image will have ISOLINUX bootloader installed on it
+and the boot menu will allow selecting between I<script1> and
+I<script2> configurations.
 
 =back
 
-Note that the options needed for a specific target can be stored in a
-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
 
 Novaboot performs its work in several phases. Each phase can be
-influenced by several options, certain phases can be skipped. The list
-of phases (in the execution order) and the corresponding options
-follow.
+influenced by several command line options, certain phases can be
+skipped. The list of phases (in the execution order) is as follows.
+
+=over
+
+=item 1. L<Configuration reading|/Configuration reading phase>
+
+=item 2. L<Command line processing|/Command line processing phase>
+
+=item 3. L<Script preprocessing|/Script preprocessing phase>
+
+=item 4. L<File generation|/File generation phase>
+
+=item 5. L<Target connection|/Target connection check>
+
+=item 6. L<File deployment|/File deployment phase>
+
+=item 7. L<Target power-on and reset|/Target power-on and reset phase>
+
+=item 8. L<Interaction with the bootloader|/Interaction with the bootloader on the target>
+
+=item 9. L<Target interaction|/Target interaction phase>
+
+=back
+
+Each phase is described in the following sections together with the
+command line options that control it.
 
 =head2 Configuration reading phase
 
 After starting, novaboot reads configuration files. Their content is
-described in L</"CONFIGURATION FILE">. By default, configuration is
-read from two locations. First from the configuration directory and
-second from F<.novaboot> files along the path to the current
-directory. The later read files override settings from the former
-ones.
-
-Configuration directory is determined by the content of
-NOVABOOT_CONFIG_DIR environment variable defaulting to
+described in section L</"CONFIGURATION FILES">. By default,
+configuration is read from multiple locations. First from the system
+configuration directory (F</etc/novaboot.d/>), second from the user
+configuration file (F<~/.config/novaboot>) and third from F<.novaboot>
+files along the path to the current directory. Alternatively, a single
+configuration file specified with the B<-c> switch or with the
+C<NOVABOOT_CONFIG> environment variable is read. The latter read files
+override settings from the former ones.
+
+The system configuration directory is determined by the content of
+NOVABOOT_CONFIG_DIR environment variable and defaults to
 F</etc/novaboot.d>. Files in this directory with names consisting
-solely from English letters, numbers, dashes '-' and underscores '_'
+solely of English letters, numbers, dashes '-' and underscores '_'
 (note that dot '.' is not included) are read in alphabetical order.
 
-Then novaboot searches for files named F<.novaboot> starting
-from the directory of the novaboot script (or working directory, see
-bellow) and continuing upwards up to the root directory. The found
-configuration files are then read in order from the root directory
-downwards.
+Then, the user configuration file is read from
+F<$XDG_CONFIG_HOME/novaboot>. If C<$XDG_CONFIG_HOME> environemnt
+variable is not set F<~/.config/novaboot> is read instead.
+
+Finally, novaboot searches for files named F<.novaboot> starting from the
+directory of the novaboot script (or working directory, see bellow)
+and continuing upwards up to the root directory. The found
+configuration files are then read in the opposite order (i.e. from the
+root directory downwards). This allows to have, for example, a project
+specific configuration in F<~/project/.novaboot>.
+
+Note the difference between F<~/.config/novaboot> and F<~/.novaboot>.
+The former one is read always, whereas the latter only when novaboot
+script or working directory is under the C<$HOME> directory.
 
 In certain cases, the location of the novaboot script cannot be
 determined in this early phase. This happens either when the script is
-read from the standard input or when novaboot is invoked explicitly
-and options precede the script name, as in the example L</"4."> above.
-In this case the current working directory is used as a starting point
-for configuration file search instead of the novaboot script
-directory.
+read from the standard input or when novaboot is invoked explicitly as
+in the example L</"4."> above. In this case the current working
+directory is used as a starting point for configuration file search
+instead of the novaboot script directory.
 
 =over 8
 
@@ -1199,7 +1373,7 @@ Use the specified configuration file instead of the default one(s).
 
 =item --dump-config
 
-Dump the current configuration to stdout end exits. Useful as an
+Dump the current configuration to stdout end exit. Useful as an
 initial template for a configuration file.
 
 =item -h, --help
@@ -1209,9 +1383,13 @@ Print short (B<-h>) or long (B<--help>) help.
 =item -t, --target=I<target>
 
 This option serves as a user configurable shortcut for other novaboot
-options. The effect of this option is the same as the options stored
-in the C<%targets> configuration variable under key I<target>. See
-also L</"CONFIGURATION FILE">.
+options. The effect of this option is the same as specifying the
+options stored in the C<%targets> configuration variable under key
+I<target>. See also L</"CONFIGURATION FILES">.
+
+When this option is not given, novaboot tries to determine the target
+to use from either B<NOVABOOT_TARGET> environment variable or from
+B<$default_target> configuration file variable.
 
 =back
 
@@ -1226,18 +1404,20 @@ used in the later phases.
 
 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.
+command line. This option can appear multiple times.
 
 =item -b, --bender
 
-Use F<bender> chainloader. Bender scans the PCI bus for PCI serial
-ports and stores the information about them in the BIOS data area for
-use by the kernel.
+Use L<bender|https://github.com/TUD-OS/morbo/blob/master/standalone/bender.c>
+chainloader. Bender scans the PCI bus for PCI serial ports and stores
+the information about them in the BIOS data area for use by the
+kernel.
 
 =item --chainloader=I<chainloader>
 
-Chainloader that is loaded before the kernel and other files specified
-in the novaboot script. E.g. 'bin/boot/bender promisc'.
+Specifies a chainloader that is loaded before the kernel and other
+files specified in the novaboot script. E.g. 'bin/boot/bender
+promisc'.
 
 =item --dump
 
@@ -1298,22 +1478,30 @@ Specifies the I<preable> that is at the beginning of the generated
 GRUB or GRUB2 config files. This is useful for specifying GRUB's
 timeout.
 
-=item --grub-prefix=I<prefix>
+=item --prefix=I<prefix>
 
-Specifies I<prefix> that is put in front of every file name in GRUB's
-F<menu.lst>. The default value is the absolute path to the build directory.
+Specifies I<prefix> (e.g. F</srv/tftp>) that is put in front of every
+file name in generated bootloader configuration files (or in U-Boot
+commands).
 
 If the I<prefix> contains string $NAME, it will be replaced with the
 name of the novaboot script (see also B<--name>).
 
+If the I<prefix> contains string $BUILDDIR, it will be replaced with
+the build directory (see also B<--build-dir>).
+
+=item --grub-prefix
+
+Alias for B<--prefix>.
+
 =item --grub2[=I<filename>]
 
-Generate GRUB2 menuentry in I<filename>. If I<filename> is not
-specified F<grub.cfg> is used. The content of the menuentry can be
-customized with B<--grub-preable>, B<--grub2-prolog> or
+Generate GRUB2 menu entry in I<filename>. If I<filename> is not
+specified F<grub.cfg> is used. The content of the menu entry can be
+customized with B<--grub-preamble>, B<--grub2-prolog> or
 B<--grub_prefix> options.
 
-In order to use the the generated menuentry on your development
+In order to use the the generated menu entry on your development
 machine that uses GRUB2, append the following snippet to
 F</etc/grub.d/40_custom> file and regenerate your grub configuration,
 i.e. run update-grub on Debian/Ubuntu.
@@ -1324,8 +1512,7 @@ i.e. run update-grub on Debian/Ubuntu.
 
 =item --grub2-prolog=I<prolog>
 
-Specifies text I<preable> that is put at the beginning of the entry
-GRUB2 entry.
+Specifies text that is put at the beginning of the GRUB2 menu entry.
 
 =item -m, --make[=make command]
 
@@ -1382,14 +1569,6 @@ 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 --ider
-
-Use Intel AMT technology for IDE redirection. This allows the target
-machine to boot from nonvaboot created ISO image.
-
-The experimental I<amtider> utility needed by this option can be
-obtained from https://github.com/wentasah/amtterm.
-
 =item --iprelay=I<addr[:port]>
 
 Use TCP/IP relay and serial port to access the target's serial port
@@ -1419,9 +1598,15 @@ example C<ssh server 'cu -l /dev/ttyS0'>.
 
 =item --remote-expect=I<string>
 
-Wait for reception of I<string> after establishing the the remote
-connection before continuing.
+Wait for reception of I<string> after establishing the remote
+connection.
 
+=item --remote-expect-silent=I<string>
+
+The same as B<--remote-expect> except that the remote output is not
+echoed to stdout while waiting for the I<string>. Everything after the
+matched string is printed to stdout, so you may want to include line
+end characters in the I<string> as well.
 
 =back
 
@@ -1463,6 +1648,13 @@ to allow running the necessary commands without asking for password.
 
 Port to run the TFTP server on. Implies B<--tftp>.
 
+=item --netif=I<network interface>
+
+Network interface used to deploy files to the target. Default value is
+I<eth0>. This influences the configuration of the DHCP server started
+by B<--dhcp-tftp> and the value that B<$NB_MYIP> get replaced with in
+U-Boot conversation.
+
 =item --iso[=filename]
 
 Generates the ISO image that boots NOVA system via GRUB. If no filename
@@ -1471,11 +1663,15 @@ of the novaboot script (see also B<--name>).
 
 =item --server[=[[user@]server:]path]
 
-Copy all files needed for booting to another location (implies B<-g>
-unless B<--grub2> is given). The files will be copied (by B<rsync>
-tool) to the directory I<path>. If the I<path> contains string $NAME,
-it will be replaced with the name of the novaboot script (see also
-B<--name>).
+Copy all files needed for booting to another location. The files will
+be copied (by B<rsync> tool) to the directory I<path>. If the I<path>
+contains string $NAME, it will be replaced with the name of the
+novaboot script (see also B<--name>).
+
+=item --rsync-flags=I<flags>
+
+Specifies which I<flags> are appended to F<rsync> command line when
+copying files as a result of I<--server> option.
 
 =item --concat
 
@@ -1486,15 +1682,23 @@ with $NAME part removed. The content of the file is created by
 concatenating all files of the same name from all subdirectories of
 I<path-wo-name> found on the "server".
 
-=item --rsync-flags=I<flags>
+=item --ider
 
-Specifies which I<flags> are appended to F<rsync> command line when
-copying files as a result of I<--server> option.
+Use Intel AMT technology for IDE redirection. This allows the target
+machine to boot from novaboot created ISO image. Implies B<--iso>.
+
+The experimental C<amtider> utility needed by this option can be
+obtained from https://github.com/wentasah/amtterm.
 
 =back
 
 =head2 Target power-on and reset phase
 
+At this point, the target is reset (or switched on/off). There is
+several ways how this can be accomplished. Resetting a physical target
+can currently be accomplished by the following options: B<--amt>,
+B<--iprelay>, B<--reset-cmd> and B<--reset-send>.
+
 =over 8
 
 =item --on, --off
@@ -1522,6 +1726,15 @@ Replace the default qemu flags (QEMU_FLAGS variable or C<-cpu coreduo
 
 Command that resets the target.
 
+=item --reset-send=I<string>
+
+Reset the target by sending the given I<string> to the remote serial
+line. "\n" sequences are replaced with newline character.
+
+=item --no-reset, --reset
+
+Disable/enable resetting of the target.
+
 =back
 
 =head2 Interaction with the bootloader on the target
@@ -1530,18 +1743,49 @@ Command that resets the target.
 
 =item --uboot[=I<prompt>]
 
-Interact with uBoot bootloader to boot the thing described in the
+Interact with U-Boot bootloader to boot the thing described in the
 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 --no-uboot
+
+Disable U-Boot interaction previously enabled with B<--uboot>.
+
 =item --uboot-init
 
 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>.
 
+If the command contains string I<$NB_MYIP> then this string is
+replaced by IPv4 address of eth0 interface (see also B<--netif>).
+Similarly I<$NB_PREFIX> is replaced with prefix given by B<--prefix>.
+
+See also C<uboot> keyword in L</"NOVABOOT SCRIPT SYNTAX">).
+
+=item --uboot-addr I<name>=I<address>
+
+Load address of U-Boot's C<tftpboot> command for loading I<name>,
+where name is one of I<kernel>, I<ramdisk> or I<fdt> (flattened device
+tree).
+
+The default addresses are ${I<name>_addr_r}, i.e. U-Boot environment
+variables used by convention for this purpose.
+
+=item --uboot-cmd=I<command>
+
+Specifies U-Boot command used to execute the OS. If the command
+contains strings C<$kernel_addr>, C<$ramdisk_addr>, C<$fdt_addr>,
+these are replaced with the addresses configured with B<--uboot-addr>.
+
+The default value is
+
+    bootm $kernel_addr $ramdisk_addr $fdt_addr
+
+or the C<UBOOT_CMD> variable if defined in the novaboot script.
+
 =back
 
 =head2 Target interaction phase
@@ -1555,13 +1799,24 @@ interactive work with the target.
 =item --exiton=I<string>
 
 When I<string> is sent by the target, novaboot exits. This option can
-be specified multiple times.
+be specified multiple times, in which case novaboot exits whenever
+either of the specified strings is sent.
 
 If I<string> is C<-re>, then the next B<--exiton>'s I<string> is
 treated as regular expression. For example:
 
     --exiton -re --exiton 'error:.*failed'
 
+=item --exiton-re=I<regex>
+
+The same as --exiton -re --exiton I<regex>.
+
+=item --exiton-timeout=I<seconds>
+
+By default B<--exiton> waits for the string match forever. When this
+option is specified, "exiton" timeouts after the specifies number of
+seconds and novaboot returns non-zero exit code.
+
 =item -i, --interactive
 
 Setup things for interactive use of target. Your terminal will be
@@ -1571,6 +1826,11 @@ 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 --no-interaction, --interaction
+
+Skip resp. force target interaction phase. When skipped, novaboot exits
+immediately when boot is initiated.
+
 =item --expect=I<string>
 
 When I<string> is received from the target, send the string specified
@@ -1603,6 +1863,14 @@ Similar to B<--send> but continue expecting more input.
 
 Example: C<--expect='Continue?' --sendcont='yes\n'>
 
+=item --final-eol, --no-final-eol
+
+By default, B<novaboot> always prints an end-of-line character at the
+end of its execution in order to ensure that the output of programs
+started after novaboot appears at the beginning of the line. When this
+is not desired B<--no-final-eol> option can be used to override this
+behavior.
+
 =back
 
 =head1 NOVABOOT SCRIPT SYNTAX
@@ -1640,6 +1908,15 @@ 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.
 
+Lines starting with C<uboot> represent U-Boot commands that are sent
+to the target if B<--uboot> option is given. Having a U-Boot line in
+the novaboot script is the same as passing an equivalent
+B<--uboot-init> option to novaboot. The C<uboot> keyword can be
+suffixed with timeout specification. The syntax is C<uboot:Ns>, where
+C<N> is the whole number of seconds. If the U-Boot command prompt does
+not appear before the timeout, novaboot fails. The default timeout is
+10 seconds.
+
 Example (Linux):
 
   #!/usr/bin/env novaboot
@@ -1694,6 +1971,13 @@ 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 NO_BOOT
+
+If this variable is 1, the system is not booted. This is currently
+only implemented for U-Boot bootloader where it is useful for
+interacting with the bootloader without booting the system - e.g. for
+flashing.
+
 =item QEMU
 
 Use a specific qemu binary (can be overridden with B<-Q>) and flags
@@ -1705,9 +1989,13 @@ QEMU_FLAGS.
 
 Use specific qemu flags (can be overridden with B<-q>).
 
+=item UBOOT_CMD
+
+See L</--uboot-cmd>.
+
 =item WVDESC
 
-Description of the wvtest-compliant program.
+Description of the WvTest-compliant program.
 
 =item WVTEST_TIMEOUT
 
@@ -1718,17 +2006,19 @@ intermediate output.
 
 =back
 
-=head1 CONFIGURATION FILE
+=head1 CONFIGURATION FILES
 
 Novaboot can read its configuration from one or more files. By
-default, novaboot looks for files named F<.novaboot> as described in
+default, novaboot looks for files in F</etc/novaboot.d>, file
+F<~/.config/novaboot> and files named F<.novaboot> as described in
 L</Configuration reading phase>. Alternatively, configuration file
 location can be 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 overridden by environment variables
-(see below) or by command line switches.
+NOVABOOT_CONFIG environment variable. The configuration file has Perl
+syntax (i.e. it is better to put C<1;> as the last line) 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 overridden by environment variables (see below) or by command
+line switches.
 
 Supported configuration variables include:
 
@@ -1742,7 +2032,8 @@ file.
 =item $default_target
 
 Default target (see below) to use when no target is explicitly
-specified on command line with the B<--target> option.
+specified with the B<--target> command line option or
+B<NOVABOOT_TARGET> environment variable.
 
 =item %targets
 
@@ -1754,8 +2045,8 @@ command line options. For instance, if the configuration file contains:
 
 then the following two commands are equivalent:
 
- ./script --server=boot:/tftproot --serial=/dev/ttyUSB0 --grub
- ./script -t mybox
+ ./myos --server=boot:/tftproot --serial=/dev/ttyUSB0 --grub
+ ./myos -t mybox
 
 =back
 
@@ -1778,12 +2069,29 @@ one(s).
 Name of the novaboot configuration directory. When not specified
 F</etc/novaboot.d> is used.
 
+=item NOVABOOT_TARGET
+
+Name of the novaboot target to use. This overrides the value of
+B<$default_target> from the configuration file and can be overriden
+with the B<--target> command line option.
+
 =item NOVABOOT_BENDER
 
-Defining this variable has the same meaning as B<--bender> option.
+Defining this variable has the same effect as using B<--bender>
+option.
 
 =back
 
 =head1 AUTHORS
 
 Michal Sojka <sojka@os.inf.tu-dresden.de>
+
+Latest novaboot version can be found at
+L<https://github.com/wentasah/novaboot>.
+
+=cut
+
+# LocalWords:  novaboot Novaboot NOVABOOT TFTP PXE DHCP filename stty
+# LocalWords:  chainloader stdout Qemu qemu preprocessing ISOLINUX bootable
+# LocalWords:  config subprocesses sudo sudoers tftp dhcp IDE stdin
+# LocalWords:  subdirectories TTY whitespace heredoc POSIX WvTest