mirror of https://github.com/fspc/gbootroot.git
Browse Source
IO::Tty modules. It will make creating an interactive window very easy. Now I just have to get a UML kernel working consistently.master
freesource
24 years ago
1 changed files with 215 additions and 0 deletions
@ -0,0 +1,215 @@ |
|||||
|
package UML; |
||||
|
|
||||
|
use Expect; |
||||
|
use IO::File; |
||||
|
use strict; |
||||
|
|
||||
|
sub new { |
||||
|
my $proto = shift; |
||||
|
my $class = ref($proto) || $proto; |
||||
|
my $me = { kernel => 'linux', |
||||
|
arguments => '', |
||||
|
login_prompt => 'login:', |
||||
|
login => 'root', |
||||
|
password_prompt => 'Password:', |
||||
|
password => 'root', |
||||
|
prompt => 'darkstar:.*#', |
||||
|
halt => 'halt', |
||||
|
expect_handle => undef }; |
||||
|
|
||||
|
while(@_){ |
||||
|
my $arg = shift; |
||||
|
if($arg eq 'kernel'){ |
||||
|
$me->{kernel} = shift; |
||||
|
} |
||||
|
elsif($arg eq 'arguments'){ |
||||
|
$me->{arguments} = shift; |
||||
|
} |
||||
|
elsif($arg eq 'login_prompt'){ |
||||
|
$me->{login_prompt} = shift; |
||||
|
} |
||||
|
elsif($arg eq 'login'){ |
||||
|
$me->{login} = shift; |
||||
|
} |
||||
|
elsif($arg eq 'password_prompt'){ |
||||
|
$me->{password_prompt} = shift; |
||||
|
} |
||||
|
elsif($arg eq 'password'){ |
||||
|
$me->{password} = shift; |
||||
|
} |
||||
|
elsif($arg eq 'prompt'){ |
||||
|
$me->{prompt} = shift; |
||||
|
} |
||||
|
elsif($arg eq 'halt'){ |
||||
|
$me->{halt} = shift; |
||||
|
} |
||||
|
else { |
||||
|
die "UML::new : Unknown argument - $arg"; |
||||
|
} |
||||
|
} |
||||
|
bless($me, $class); |
||||
|
return $me; |
||||
|
} |
||||
|
|
||||
|
sub boot { |
||||
|
my $me = shift; |
||||
|
my $log_file = shift; |
||||
|
my $log; |
||||
|
|
||||
|
if(defined($me->{expect_handle})){ |
||||
|
warn "UML::boot : already booted"; |
||||
|
return; |
||||
|
} |
||||
|
my $cmd = "$me->{kernel} $me->{arguments}"; |
||||
|
$me->{expect_handle} = Expect->spawn($cmd); |
||||
|
if(defined($log_file)){ |
||||
|
$log = $me->open_log($log_file); |
||||
|
$me->{expect_handle}->log_stdout(0); |
||||
|
} |
||||
|
$me->{expect_handle}->expect(undef, "$me->{login_prompt}"); |
||||
|
$me->{expect_handle}->print("$me->{login}\n"); |
||||
|
$me->{expect_handle}->expect(undef, "$me->{password_prompt}"); |
||||
|
$me->{expect_handle}->print("$me->{password}\n"); |
||||
|
$me->{expect_handle}->expect(undef, "-re", "$me->{prompt}"); |
||||
|
return($log); |
||||
|
} |
||||
|
|
||||
|
sub command { |
||||
|
my $me = shift; |
||||
|
my $cmd = shift; |
||||
|
my %globals = ( "Kernel panic" => "", "$me->{prompt}" => "-re" ); |
||||
|
my @expects = ( @_ ); |
||||
|
my @strings = (); |
||||
|
|
||||
|
foreach my $key (keys(%globals)){ |
||||
|
$globals{$key} eq "-re" and push @expects, "-re"; |
||||
|
push @expects, $key; |
||||
|
} |
||||
|
foreach my $str (@expects){ |
||||
|
$str ne "-re" and push @strings, $str; |
||||
|
} |
||||
|
$me->{expect_handle}->print("$cmd\n"); |
||||
|
my @match = $me->{expect_handle}->expect(undef, @expects); |
||||
|
defined $match[0] and $match[0]--; |
||||
|
if(defined($match[1])){ |
||||
|
die "Expect error : $match[1]"; |
||||
|
} |
||||
|
elsif(defined($globals{$strings[$match[0]]})){ |
||||
|
$strings[$match[0]] eq "Kernel panic" and die "panic"; |
||||
|
return(undef); |
||||
|
} |
||||
|
else { |
||||
|
$me->{expect_handle}->expect(undef, "-re", "$me->{prompt}"); |
||||
|
return($match[0]); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
sub open_log { |
||||
|
my $me = shift; |
||||
|
my $file = shift; |
||||
|
my $fh = new IO::File "$file"; |
||||
|
my $have_logs = $me->{expect_handle}->set_group(); |
||||
|
my @logs; |
||||
|
|
||||
|
if(!defined($have_logs)){ |
||||
|
@logs = (); |
||||
|
} |
||||
|
else { |
||||
|
@logs = $me->{expect_handle}->set_group(); |
||||
|
} |
||||
|
if(defined($fh)){ |
||||
|
my $log = Expect->exp_init(\*$fh); |
||||
|
push @logs, $log; |
||||
|
$me->{expect_handle}->set_group(@logs); |
||||
|
return $log; |
||||
|
} |
||||
|
return undef; |
||||
|
} |
||||
|
|
||||
|
sub close_log { |
||||
|
my $me = shift; |
||||
|
my $log = shift; |
||||
|
my @logs = $me->{expect_handle}->set_group(); |
||||
|
|
||||
|
foreach my $i (0..$#logs){ |
||||
|
if($logs[$i] == $log){ |
||||
|
splice @logs, $i, 1; |
||||
|
$log->hard_close(); |
||||
|
} |
||||
|
} |
||||
|
if(!@logs){ |
||||
|
my $fh = new IO::File "> /dev/null"; |
||||
|
push @logs, Expect->exp_init(\*$fh); |
||||
|
} |
||||
|
$me->{expect_handle}->set_group(@logs); |
||||
|
} |
||||
|
|
||||
|
sub halt { |
||||
|
my $me = shift; |
||||
|
|
||||
|
$me->{expect_handle}->print("$me->{halt}\n"); |
||||
|
$me->{expect_handle}->expect(undef); |
||||
|
} |
||||
|
|
||||
|
sub kill { |
||||
|
my $me = shift; |
||||
|
|
||||
|
$me->{expect_handle}->hard_close(); |
||||
|
} |
||||
|
|
||||
|
1; |
||||
|
|
||||
|
=head1 NAME |
||||
|
|
||||
|
UML - class to control User-mode Linux |
||||
|
|
||||
|
=head1 SYNOPSIS |
||||
|
|
||||
|
use UML; |
||||
|
|
||||
|
################# |
||||
|
# class methods # |
||||
|
################# |
||||
|
$uml = UML->new(kernel => $path_to_kernel, # default "linux" |
||||
|
arguments => $kernel_arguments, # "" |
||||
|
login_prompt => $login_prompt, # "login:" |
||||
|
login => $account_name, # "root" |
||||
|
password_prompt => $password_prompt, # "Password:" |
||||
|
password => $account_password, # "root" |
||||
|
prompt => $shell_prompt_re, # "darkstar:.*#" |
||||
|
halt => $halt_command); # "halt" |
||||
|
$uml->boot(); |
||||
|
$uml->command($command_string); |
||||
|
$uml->halt(); |
||||
|
|
||||
|
####################### |
||||
|
# object data methods # |
||||
|
####################### |
||||
|
|
||||
|
######################## |
||||
|
# other object methods # |
||||
|
######################## |
||||
|
|
||||
|
=head1 DESCRIPTION |
||||
|
|
||||
|
The UML class is used to control the execution of a user-mode kernel. |
||||
|
All of the arguments to UML::new are optional and will be defaulted if |
||||
|
not present. The arguments and their values are as follows: |
||||
|
kernel - the filename of the kernel executable |
||||
|
arguments - a string containing the kernel command line |
||||
|
login_prompt - a string matching the login prompt |
||||
|
login - the account to log in to |
||||
|
password_prompt - a string matching the password prompt |
||||
|
password - the account's password |
||||
|
prompt - a regular expression matching the shell prompt |
||||
|
halt - the command used to halt the virtual machine |
||||
|
|
||||
|
Once constructed, the UML object may be booted. UML::boot() will |
||||
|
return after it has successfully logged in. |
||||
|
|
||||
|
Then, UML::command may be called as many times as desired. It will |
||||
|
return when the command has finished and the next shell prompt has |
||||
|
been seen. |
||||
|
|
||||
|
When the testing is finished, UML::halt() is called to shut the |
||||
|
virtual machine down. |
Loading…
Reference in new issue