VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/ipxe/contrib/vm/serial-console@ 87942

Last change on this file since 87942 was 47928, checked in by vboxsync, 12 years ago

Devices/PC: export iPXE to OSE

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
File size: 7.0 KB
Line 
1#!/usr/bin/perl -w
2
3=head1 NAME
4
5serial-console
6
7=head1 SYNOPSIS
8
9serial-console [options]
10
11Options:
12
13 -h,--help Display brief help message
14 -v,--verbose Increase verbosity
15 -q,--quiet Decrease verbosity
16 -l,--log FILE Log output to file
17 -r,--rcfile FILE Modify specified bochsrc file
18
19=head1 DESCRIPTION
20
21C<serial-console> provides a virtual serial console for use with
22Bochs. Running C<serial-console> creates a pseudo-tty. The master
23side of this pty is made available to the user for interaction; the
24slave device is written to the Bochs configuration file
25(C<bochsrc.txt>) for use by a subsequent Bochs session.
26
27=head1 EXAMPLES
28
29=over 4
30
31=item C<serial-console>
32
33Create a virtual serial console for Bochs, modify C<bochsrc.txt>
34appropriately.
35
36=item C<serial-console -r ../.bochsrc -l serial.log>
37
38Create a virtual serial console for Bochs, modify C<../.bochsrc>
39appropriately, log output to C<serial.log>.
40
41=back
42
43=head1 INVOCATION
44
45Before starting Bochs, run C<serial-console> in a different session
46(e.g. a different xterm window). When you subsequently start Bochs,
47anything that the emulated machine writes to its serial port will
48appear in the window running C<serial-console>, and anything typed in
49the C<serial-console> window will arrive on the emulated machine's
50serial port.
51
52You do B<not> need to rerun C<serial-console> afresh for each Bochs
53session.
54
55=head1 OPTIONS
56
57=over 4
58
59=item B<-l,--log FILE>
60
61Log all output (i.e. everything that is printed in the
62C<serial-console> window) to the specified file.
63
64=item B<-r,--rcfile FILE>
65
66Modify the specified bochsrc file. The file will be updated to
67contain the path to the slave side of the psuedo tty that we create.
68The original file will be restored when C<serial-console> exits. The
69default is to modify the file C<bochsrc.txt> in the current directory.
70
71To avoid modifying any bochsrc file, use C<--norcfile>.
72
73=back
74
75=cut
76
77use IO::Pty;
78use IO::Select;
79use File::Spec::Functions qw ( :ALL );
80use Getopt::Long;
81use Pod::Usage;
82use POSIX qw ( :termios_h );
83use strict;
84use warnings;
85
86my $o;
87my $restore_file = {};
88my $restore_termios;
89use constant BLOCKSIZE => 8192;
90
91##############################################################################
92#
93# Parse command line options into options hash ($o)
94#
95# $o = parse_opts();
96
97sub parse_opts {
98 # $o is the hash that will hold the options
99 my $o = {
100 verbosity => 1,
101 rcfile => 'bochsrc.txt',
102 };
103 # Special handlers for some options
104 my $opt_handlers = {
105 verbose => sub { $o->{verbosity}++; },
106 quiet => sub { $o->{verbosity}--; },
107 help => sub { pod2usage(1); },
108 norcfile => sub { delete $o->{rcfile}; },
109 };
110 # Merge handlers into main options hash (so that Getopt::Long can find them)
111 $o->{$_} = $opt_handlers->{$_} foreach keys %$opt_handlers;
112 # Option specifiers for Getopt::Long
113 my @optspec = ( 'help|h|?',
114 'quiet|q+',
115 'verbose|v+',
116 'log|l=s',
117 'rcfile|r=s',
118 'norcfile',
119 );
120 # Do option parsing
121 Getopt::Long::Configure ( 'bundling' );
122 pod2usage("Error parsing command-line options") unless GetOptions (
123 $o, @optspec );
124 # Clean up $o by removing the handlers
125 delete $o->{$_} foreach keys %$opt_handlers;
126 return $o;
127}
128
129##############################################################################
130#
131# Modify bochsrc file
132
133sub patch_bochsrc {
134 my $active = shift;
135 my $pty = shift;
136
137 # Rename active file to backup file
138 ( my $vol, my $dir, my $file ) = splitpath ( $active );
139 $file = '.'.$file.".serial-console";
140 my $backup = catpath ( $vol, $dir, $file );
141 rename $active, $backup
142 or die "Could not back up $active to $backup: $!\n";
143
144 # Derive line to be inserted
145 my $patch = "com1: enabled=1, mode=term, dev=$pty\n";
146
147 # Modify file
148 open my $old, "<$backup" or die "Could not open $backup: $!\n";
149 open my $new, ">$active" or die "Could not open $active: $!\n";
150 print $new <<"EOF";
151##################################################
152#
153# This file has been modified by serial-console.
154#
155# Do not modify this file; it will be erased when
156# serial-console (pid $$) exits and will be
157# replaced with the backup copy held in
158# $backup.
159#
160##################################################
161
162
163EOF
164 my $patched;
165 while ( my $line = <$old> ) {
166 if ( $line =~ /^\s*\#?\s*com1:\s*\S/ ) {
167 if ( ! $patched ) {
168 $line = $patch;
169 $patched = 1;
170 } else {
171 $line = '# '.$line unless $line =~ /^\s*\#/;
172 }
173 }
174 print $new $line;
175 }
176 print $new $patch unless $patched;
177 close $old;
178 close $new;
179
180 return $backup;
181}
182
183##############################################################################
184#
185# Attach/detach message printing and terminal settings
186
187sub bochs_attached {
188 print STDERR "Bochs attached.\n\n\n"
189 if $o->{verbosity} >= 1;
190}
191
192sub bochs_detached {
193 print STDERR "\n\nWaiting for bochs to attach...\n"
194 if $o->{verbosity} >= 1;
195}
196
197##############################################################################
198#
199# Main program
200
201$o = parse_opts();
202pod2usage(1) if @ARGV;
203
204# Catch signals
205my $sigdie = sub { die "Exiting via signal\n"; };
206$SIG{INT} = $sigdie;
207
208# Create Pty, close slave side
209my $pty = IO::Pty->new();
210$pty->close_slave();
211$pty->set_raw();
212print STDERR "Slave pty is ".$pty->ttyname."\n" if $o->{verbosity} >= 1;
213
214# Open logfile
215my $log;
216if ( $o->{log} ) {
217 open $log, ">$o->{log}" or die "Could not open $o->{log}: $!\n";
218}
219
220# Set up terminal
221my $termios;
222if ( -t STDIN ) {
223 $termios = POSIX::Termios->new;
224 $restore_termios = POSIX::Termios->new;
225 $termios->getattr ( fileno(STDIN) );
226 $restore_termios->getattr ( fileno(STDIN) );
227 $termios->setlflag ( $termios->getlflag & ~(ICANON) & ~(ECHO) );
228 $termios->setiflag ( $termios->getiflag & ~(ICRNL) );
229 $termios->setattr ( fileno(STDIN), TCSANOW );
230}
231
232# Modify bochsrc file
233$restore_file = { $o->{rcfile} =>
234 patch_bochsrc ( $o->{rcfile}, $pty->ttyname ) }
235 if $o->{rcfile};
236
237# Start character shunt
238my $attached = 1;
239my $select = IO::Select->new ( \*STDIN, $pty );
240while ( 1 ) {
241 my %can_read = map { $_ => 1 }
242 $select->can_read ( $attached ? undef : 1 );
243 if ( $can_read{\*STDIN} ) {
244 sysread ( STDIN, my $data, BLOCKSIZE )
245 or die "Cannot read from STDIN: $!\n";
246 $pty->syswrite ( $data );
247 }
248 if ( $can_read{$pty} ) {
249 if ( $pty->sysread ( my $data, BLOCKSIZE ) ) {
250 # Actual data available
251 bochs_attached() if $attached == 0;
252 $attached = 1;
253 syswrite ( STDOUT, $data );
254 $log->syswrite ( $data ) if $log;
255 } else {
256 # No data available but select() says we can read. This almost
257 # certainly indicates that nothing is attached to the slave.
258 bochs_detached() if $attached == 1;
259 $attached = 0;
260 sleep ( 1 );
261 }
262 } else {
263 bochs_attached() if $attached == 0;
264 $attached = 1;
265 }
266}
267
268END {
269 # Restore bochsrc file if applicable
270 if ( ( my $orig_file, my $backup_file ) = %$restore_file ) {
271 unlink $orig_file;
272 rename $backup_file, $orig_file;
273 }
274 # Restore terminal settings if applicable
275 if ( $restore_termios ) {
276 $restore_termios->setattr ( fileno(STDIN), TCSANOW );
277 }
278}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette