diff options
Diffstat (limited to '')
-rwxr-xr-x | src/VBox/Devices/PC/ipxe/contrib/vm/serial-console | 278 | ||||
-rw-r--r-- | src/VBox/Devices/PC/ipxe/contrib/vm/serial-console.1 | 190 |
2 files changed, 468 insertions, 0 deletions
diff --git a/src/VBox/Devices/PC/ipxe/contrib/vm/serial-console b/src/VBox/Devices/PC/ipxe/contrib/vm/serial-console new file mode 100755 index 00000000..5d09876e --- /dev/null +++ b/src/VBox/Devices/PC/ipxe/contrib/vm/serial-console @@ -0,0 +1,278 @@ +#!/usr/bin/perl -w + +=head1 NAME + +serial-console + +=head1 SYNOPSIS + +serial-console [options] + +Options: + + -h,--help Display brief help message + -v,--verbose Increase verbosity + -q,--quiet Decrease verbosity + -l,--log FILE Log output to file + -r,--rcfile FILE Modify specified bochsrc file + +=head1 DESCRIPTION + +C<serial-console> provides a virtual serial console for use with +Bochs. Running C<serial-console> creates a pseudo-tty. The master +side of this pty is made available to the user for interaction; the +slave device is written to the Bochs configuration file +(C<bochsrc.txt>) for use by a subsequent Bochs session. + +=head1 EXAMPLES + +=over 4 + +=item C<serial-console> + +Create a virtual serial console for Bochs, modify C<bochsrc.txt> +appropriately. + +=item C<serial-console -r ../.bochsrc -l serial.log> + +Create a virtual serial console for Bochs, modify C<../.bochsrc> +appropriately, log output to C<serial.log>. + +=back + +=head1 INVOCATION + +Before starting Bochs, run C<serial-console> in a different session +(e.g. a different xterm window). When you subsequently start Bochs, +anything that the emulated machine writes to its serial port will +appear in the window running C<serial-console>, and anything typed in +the C<serial-console> window will arrive on the emulated machine's +serial port. + +You do B<not> need to rerun C<serial-console> afresh for each Bochs +session. + +=head1 OPTIONS + +=over 4 + +=item B<-l,--log FILE> + +Log all output (i.e. everything that is printed in the +C<serial-console> window) to the specified file. + +=item B<-r,--rcfile FILE> + +Modify the specified bochsrc file. The file will be updated to +contain the path to the slave side of the psuedo tty that we create. +The original file will be restored when C<serial-console> exits. The +default is to modify the file C<bochsrc.txt> in the current directory. + +To avoid modifying any bochsrc file, use C<--norcfile>. + +=back + +=cut + +use IO::Pty; +use IO::Select; +use File::Spec::Functions qw ( :ALL ); +use Getopt::Long; +use Pod::Usage; +use POSIX qw ( :termios_h ); +use strict; +use warnings; + +my $o; +my $restore_file = {}; +my $restore_termios; +use constant BLOCKSIZE => 8192; + +############################################################################## +# +# Parse command line options into options hash ($o) +# +# $o = parse_opts(); + +sub parse_opts { + # $o is the hash that will hold the options + my $o = { + verbosity => 1, + rcfile => 'bochsrc.txt', + }; + # Special handlers for some options + my $opt_handlers = { + verbose => sub { $o->{verbosity}++; }, + quiet => sub { $o->{verbosity}--; }, + help => sub { pod2usage(1); }, + norcfile => sub { delete $o->{rcfile}; }, + }; + # Merge handlers into main options hash (so that Getopt::Long can find them) + $o->{$_} = $opt_handlers->{$_} foreach keys %$opt_handlers; + # Option specifiers for Getopt::Long + my @optspec = ( 'help|h|?', + 'quiet|q+', + 'verbose|v+', + 'log|l=s', + 'rcfile|r=s', + 'norcfile', + ); + # Do option parsing + Getopt::Long::Configure ( 'bundling' ); + pod2usage("Error parsing command-line options") unless GetOptions ( + $o, @optspec ); + # Clean up $o by removing the handlers + delete $o->{$_} foreach keys %$opt_handlers; + return $o; +} + +############################################################################## +# +# Modify bochsrc file + +sub patch_bochsrc { + my $active = shift; + my $pty = shift; + + # Rename active file to backup file + ( my $vol, my $dir, my $file ) = splitpath ( $active ); + $file = '.'.$file.".serial-console"; + my $backup = catpath ( $vol, $dir, $file ); + rename $active, $backup + or die "Could not back up $active to $backup: $!\n"; + + # Derive line to be inserted + my $patch = "com1: enabled=1, mode=term, dev=$pty\n"; + + # Modify file + open my $old, "<$backup" or die "Could not open $backup: $!\n"; + open my $new, ">$active" or die "Could not open $active: $!\n"; + print $new <<"EOF"; +################################################## +# +# This file has been modified by serial-console. +# +# Do not modify this file; it will be erased when +# serial-console (pid $$) exits and will be +# replaced with the backup copy held in +# $backup. +# +################################################## + + +EOF + my $patched; + while ( my $line = <$old> ) { + if ( $line =~ /^\s*\#?\s*com1:\s*\S/ ) { + if ( ! $patched ) { + $line = $patch; + $patched = 1; + } else { + $line = '# '.$line unless $line =~ /^\s*\#/; + } + } + print $new $line; + } + print $new $patch unless $patched; + close $old; + close $new; + + return $backup; +} + +############################################################################## +# +# Attach/detach message printing and terminal settings + +sub bochs_attached { + print STDERR "Bochs attached.\n\n\n" + if $o->{verbosity} >= 1; +} + +sub bochs_detached { + print STDERR "\n\nWaiting for bochs to attach...\n" + if $o->{verbosity} >= 1; +} + +############################################################################## +# +# Main program + +$o = parse_opts(); +pod2usage(1) if @ARGV; + +# Catch signals +my $sigdie = sub { die "Exiting via signal\n"; }; +$SIG{INT} = $sigdie; + +# Create Pty, close slave side +my $pty = IO::Pty->new(); +$pty->close_slave(); +$pty->set_raw(); +print STDERR "Slave pty is ".$pty->ttyname."\n" if $o->{verbosity} >= 1; + +# Open logfile +my $log; +if ( $o->{log} ) { + open $log, ">$o->{log}" or die "Could not open $o->{log}: $!\n"; +} + +# Set up terminal +my $termios; +if ( -t STDIN ) { + $termios = POSIX::Termios->new; + $restore_termios = POSIX::Termios->new; + $termios->getattr ( fileno(STDIN) ); + $restore_termios->getattr ( fileno(STDIN) ); + $termios->setlflag ( $termios->getlflag & ~(ICANON) & ~(ECHO) ); + $termios->setiflag ( $termios->getiflag & ~(ICRNL) ); + $termios->setattr ( fileno(STDIN), TCSANOW ); +} + +# Modify bochsrc file +$restore_file = { $o->{rcfile} => + patch_bochsrc ( $o->{rcfile}, $pty->ttyname ) } + if $o->{rcfile}; + +# Start character shunt +my $attached = 1; +my $select = IO::Select->new ( \*STDIN, $pty ); +while ( 1 ) { + my %can_read = map { $_ => 1 } + $select->can_read ( $attached ? undef : 1 ); + if ( $can_read{\*STDIN} ) { + sysread ( STDIN, my $data, BLOCKSIZE ) + or die "Cannot read from STDIN: $!\n"; + $pty->syswrite ( $data ); + } + if ( $can_read{$pty} ) { + if ( $pty->sysread ( my $data, BLOCKSIZE ) ) { + # Actual data available + bochs_attached() if $attached == 0; + $attached = 1; + syswrite ( STDOUT, $data ); + $log->syswrite ( $data ) if $log; + } else { + # No data available but select() says we can read. This almost + # certainly indicates that nothing is attached to the slave. + bochs_detached() if $attached == 1; + $attached = 0; + sleep ( 1 ); + } + } else { + bochs_attached() if $attached == 0; + $attached = 1; + } +} + +END { + # Restore bochsrc file if applicable + if ( ( my $orig_file, my $backup_file ) = %$restore_file ) { + unlink $orig_file; + rename $backup_file, $orig_file; + } + # Restore terminal settings if applicable + if ( $restore_termios ) { + $restore_termios->setattr ( fileno(STDIN), TCSANOW ); + } +} diff --git a/src/VBox/Devices/PC/ipxe/contrib/vm/serial-console.1 b/src/VBox/Devices/PC/ipxe/contrib/vm/serial-console.1 new file mode 100644 index 00000000..6d19a7d9 --- /dev/null +++ b/src/VBox/Devices/PC/ipxe/contrib/vm/serial-console.1 @@ -0,0 +1,190 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "SERIAL-CONSOLE 1" +.TH SERIAL-CONSOLE 1 "2010-09-22" "perl v5.10.1" "User Contributed Perl Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +serial\-console +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +serial-console [options] +.PP +Options: +.PP +.Vb 5 +\& \-h,\-\-help Display brief help message +\& \-v,\-\-verbose Increase verbosity +\& \-q,\-\-quiet Decrease verbosity +\& \-l,\-\-log FILE Log output to file +\& \-r,\-\-rcfile FILE Modify specified bochsrc file +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\f(CW\*(C`serial\-console\*(C'\fR provides a virtual serial console for use with +Bochs. Running \f(CW\*(C`serial\-console\*(C'\fR creates a pseudo-tty. The master +side of this pty is made available to the user for interaction; the +slave device is written to the Bochs configuration file +(\f(CW\*(C`bochsrc.txt\*(C'\fR) for use by a subsequent Bochs session. +.SH "EXAMPLES" +.IX Header "EXAMPLES" +.ie n .IP """serial\-console""" 4 +.el .IP "\f(CWserial\-console\fR" 4 +.IX Item "serial-console" +Create a virtual serial console for Bochs, modify \f(CW\*(C`bochsrc.txt\*(C'\fR +appropriately. +.ie n .IP """serial\-console \-r ../.bochsrc \-l serial.log""" 4 +.el .IP "\f(CWserial\-console \-r ../.bochsrc \-l serial.log\fR" 4 +.IX Item "serial-console -r ../.bochsrc -l serial.log" +Create a virtual serial console for Bochs, modify \f(CW\*(C`../.bochsrc\*(C'\fR +appropriately, log output to \f(CW\*(C`serial.log\*(C'\fR. +.SH "INVOCATION" +.IX Header "INVOCATION" +Before starting Bochs, run \f(CW\*(C`serial\-console\*(C'\fR in a different session +(e.g. a different xterm window). When you subsequently start Bochs, +anything that the emulated machine writes to its serial port will +appear in the window running \f(CW\*(C`serial\-console\*(C'\fR, and anything typed in +the \f(CW\*(C`serial\-console\*(C'\fR window will arrive on the emulated machine's +serial port. +.PP +You do \fBnot\fR need to rerun \f(CW\*(C`serial\-console\*(C'\fR afresh for each Bochs +session. +.SH "OPTIONS" +.IX Header "OPTIONS" +.IP "\fB\-l,\-\-log \s-1FILE\s0\fR" 4 +.IX Item "-l,--log FILE" +Log all output (i.e. everything that is printed in the +\&\f(CW\*(C`serial\-console\*(C'\fR window) to the specified file. +.IP "\fB\-r,\-\-rcfile \s-1FILE\s0\fR" 4 +.IX Item "-r,--rcfile FILE" +Modify the specified bochsrc file. The file will be updated to +contain the path to the slave side of the psuedo tty that we create. +The original file will be restored when \f(CW\*(C`serial\-console\*(C'\fR exits. The +default is to modify the file \f(CW\*(C`bochsrc.txt\*(C'\fR in the current directory. +.Sp +To avoid modifying any bochsrc file, use \f(CW\*(C`\-\-norcfile\*(C'\fR. |