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;
$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',
"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;
## 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, $exiton_timeout, @expect_raw, $gen_only, $grub_config, $grub_prefix, $grub_preamble, $grub2_prolog, $grub2_config, $help, $ider, $interaction, $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, $reset_cmd, $rom_prefix, $rsync_flags, @scriptmod, $scons, $serial, $server, $stty, $tftp, $tftp_port, $uboot, %uboot_addr, $uboot_cmd, @uboot_init);
+my ($amt, @append, $bender, @chainloaders, $concat, $config_name_opt, $dhcp_tftp, $dump_opt, $dump_config, @exiton, $exiton_timeout, @expect_raw, $gen_only, $grub_config, $grub_prefix, $grub_preamble, $grub2_prolog, $grub2_config, $help, $ider, $interaction, $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, $remote_expect_silent, $reset, $reset_cmd, $rom_prefix, $rsync_flags, @scriptmod, $scons, $serial, $server, $stty, $tftp, $tftp_port, $uboot, %uboot_addr, $uboot_cmd, @uboot_init);
%uboot_addr = (
'kernel' => '${kernel_addr_r}',
"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,
"rsync-flags=s" => \$rsync_flags,
if ($remote_expect) {
$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) {
}
# Boot the system if there are some load lines in the script
- if (scalar(@$modules) > 0 && !$variables->{NO_BOOT}) {
+ if ((scalar(@$modules) > 0 && !$variables->{NO_BOOT}) ||
+ defined $uboot_cmd) {
my ($kbin, $kcmd) = split(' ', shift(@$modules), 2);
my $dtb;
@$modules = map { if (/\.dtb$/) { $dtb=$_; (); } else { $_ } } @$modules;
my $initrd = shift @$modules;
- 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 $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) {
die "No '--uboot-addr fdt' given" unless $uboot_addr{fdt};
$exp->send("tftpboot $uboot_addr{fdt} $prefix$dtb\n");
$exp->log_stdout(1);
if (@exiton) {
$exp->expect($exiton_timeout, @expect_raw, @exiton) || die("exiton timeout");
- print STDERR "\n";
} else {
my @inputs = ($exp);
my $infile = new IO::File;
die("novaboot: This should kill servers on background\n");
}
+# Always finish novaboot output with newline
+print "\n";
+
## Documentation
=head1 NAME
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 FILE">.
+file syntax is described in section L</"CONFIGURATION FILES">.
Simple examples of using C<novaboot>:
=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 myos> (or
-C<./myos> as described above) will run Qemu and make it boot the
-configuration specified in the F<myos> script.
+Run an OS in Qemu. This is can be specified with the B<--qemu> option.
+Thus running C<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.
Novaboot performs its work in several phases. Each phase can be
influenced by several command line options, certain phases can be
-skipped. The list of phases (in the execution order) and the
-corresponding options follows.
+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 section L</"CONFIGURATION FILE">. By default,
+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>
=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
=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
=back
-=head1 CONFIGURATION FILE
+=head1 CONFIGURATION FILES
Novaboot can read its configuration from one or more files. By
default, novaboot looks for files in F</etc/novaboot.d>, 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
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.