a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncC<serial-console> provides a virtual serial console for use with
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncBochs. Running C<serial-console> creates a pseudo-tty. The master
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncside of this pty is made available to the user for interaction; the
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncslave device is written to the Bochs configuration file
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync(C<bochsrc.txt>) for use by a subsequent Bochs session.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncCreate a virtual serial console for Bochs, modify C<bochsrc.txt>
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync=item C<serial-console -r ../.bochsrc -l serial.log>
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncCreate a virtual serial console for Bochs, modify C<../.bochsrc>
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncBefore starting Bochs, run C<serial-console> in a different session
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync(e.g. a different xterm window). When you subsequently start Bochs,
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncanything that the emulated machine writes to its serial port will
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncappear in the window running C<serial-console>, and anything typed in
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncthe C<serial-console> window will arrive on the emulated machine's
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncserial port.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncYou do B<not> need to rerun C<serial-console> afresh for each Bochs
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync=head1 OPTIONS
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync=item B<-l,--log FILE>
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncLog all output (i.e. everything that is printed in the
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncC<serial-console> window) to the specified file.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync=item B<-r,--rcfile FILE>
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncModify the specified bochsrc file. The file will be updated to
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsynccontain the path to the slave side of the psuedo tty that we create.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncThe original file will be restored when C<serial-console> exits. The
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncdefault is to modify the file C<bochsrc.txt> in the current directory.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncTo avoid modifying any bochsrc file, use C<--norcfile>.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncuse IO::Pty;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncuse IO::Select;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncuse File::Spec::Functions qw ( :ALL );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncuse Getopt::Long;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncuse Pod::Usage;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncuse POSIX qw ( :termios_h );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncuse warnings;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncmy $restore_file = {};
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncmy $restore_termios;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncuse constant BLOCKSIZE => 8192;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync##############################################################################
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# Parse command line options into options hash ($o)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# $o = parse_opts();
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncsub parse_opts {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync # $o is the hash that will hold the options
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync verbosity => 1,
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync # Special handlers for some options
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync my $opt_handlers = {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync verbose => sub { $o->{verbosity}++; },
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync quiet => sub { $o->{verbosity}--; },
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync help => sub { pod2usage(1); },
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync norcfile => sub { delete $o->{rcfile}; },
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync # Merge handlers into main options hash (so that Getopt::Long can find them)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync $o->{$_} = $opt_handlers->{$_} foreach keys %$opt_handlers;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync # Option specifiers for Getopt::Long
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync # Do option parsing
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync pod2usage("Error parsing command-line options") unless GetOptions (
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync $o, @optspec );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync # Clean up $o by removing the handlers
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync delete $o->{$_} foreach keys %$opt_handlers;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync##############################################################################
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# Modify bochsrc file
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncsub patch_bochsrc {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync my $active = shift;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync my $pty = shift;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync # Rename active file to backup file
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync ( my $vol, my $dir, my $file ) = splitpath ( $active );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync my $backup = catpath ( $vol, $dir, $file );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync rename $active, $backup
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync or die "Could not back up $active to $backup: $!\n";
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync # Derive line to be inserted
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync my $patch = "com1: enabled=1, mode=term, dev=$pty\n";
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync # Modify file
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync open my $old, "<$backup" or die "Could not open $backup: $!\n";
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync open my $new, ">$active" or die "Could not open $active: $!\n";
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync print $new <<"EOF";
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync##################################################
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# This file has been modified by serial-console.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# Do not modify this file; it will be erased when
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# serial-console (pid $$) exits and will be
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# replaced with the backup copy held in
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync##################################################
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync my $patched;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync while ( my $line = <$old> ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( $line =~ /^\s*\#?\s*com1:\s*\S/ ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( ! $patched ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync $line = $patch;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync $patched = 1;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync##############################################################################
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# Attach/detach message printing and terminal settings
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if $o->{verbosity} >= 1;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync print STDERR "\n\nWaiting for bochs to attach...\n"
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if $o->{verbosity} >= 1;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync##############################################################################
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# Main program
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# Catch signals
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# Create Pty, close slave side
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncprint STDERR "Slave pty is ".$pty->ttyname."\n" if $o->{verbosity} >= 1;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# Open logfile
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync open $log, ">$o->{log}" or die "Could not open $o->{log}: $!\n";
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# Set up terminal
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync $termios->setlflag ( $termios->getlflag & ~(ICANON) & ~(ECHO) );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync $termios->setiflag ( $termios->getiflag & ~(ICRNL) );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# Modify bochsrc file
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync# Start character shunt
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync # No data available but select() says we can read. This almost
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync # certainly indicates that nothing is attached to the slave.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( ( my $orig_file, my $backup_file ) = %$restore_file ) {