* To establish the connection to the root shell in the guest, let the
guest connect to a Unix domain socket on the host rather than the other way around. The former is a QEMU feature (guestfwd to a socket) while the latter requires a patch (which we can now get rid of). svn path=/nixos/branches/boot-order/; revision=22331
This commit is contained in:
parent
7eb7e8d732
commit
363806e89b
|
@ -2,7 +2,6 @@ package Machine;
|
|||
|
||||
use strict;
|
||||
use threads;
|
||||
use Thread::Queue;
|
||||
use Socket;
|
||||
use IO::Handle;
|
||||
use POSIX qw(dup2);
|
||||
|
@ -51,7 +50,6 @@ sub new {
|
|||
booted => 0,
|
||||
pid => 0,
|
||||
connected => 0,
|
||||
connectedQueue => Thread::Queue->new(),
|
||||
socket => undef,
|
||||
stateDir => "$tmpDir/$name",
|
||||
monitor => undef,
|
||||
|
@ -101,6 +99,14 @@ sub start {
|
|||
bind($monitorS, sockaddr_un($monitorPath)) or die "cannot bind monitor socket: $!";
|
||||
listen($monitorS, 1) or die;
|
||||
|
||||
# Create a Unix domain socket to which the root shell in the guest will connect.
|
||||
my $shellPath = $self->{stateDir} . "/shell";
|
||||
unlink $shellPath;
|
||||
my $shellS;
|
||||
socket($shellS, PF_UNIX, SOCK_STREAM, 0) or die;
|
||||
bind($shellS, sockaddr_un($shellPath)) or die "cannot bind shell socket: $!";
|
||||
listen($shellS, 1) or die;
|
||||
|
||||
# Start the VM.
|
||||
my $pid = fork();
|
||||
die if $pid == -1;
|
||||
|
@ -108,13 +114,15 @@ sub start {
|
|||
if ($pid == 0) {
|
||||
close $serialP;
|
||||
close $monitorS;
|
||||
close $shellS;
|
||||
open NUL, "</dev/null" or die;
|
||||
dup2(fileno(NUL), fileno(STDIN));
|
||||
dup2(fileno($serialC), fileno(STDOUT));
|
||||
dup2(fileno($serialC), fileno(STDERR));
|
||||
$ENV{TMPDIR} = $self->{stateDir};
|
||||
$ENV{USE_TMPDIR} = 1;
|
||||
$ENV{QEMU_OPTS} = "-nographic -no-reboot -redir tcp:65535::514 -monitor unix:./monitor";
|
||||
$ENV{QEMU_OPTS} = "-nographic -no-reboot -monitor unix:./monitor -chardev socket,id=shell,path=./shell";
|
||||
$ENV{QEMU_NET_OPTS} = "guestfwd=tcp:10.0.2.6:23-chardev:shell";
|
||||
$ENV{QEMU_KERNEL_PARAMS} = "hostTmpDir=$ENV{TMPDIR}";
|
||||
chdir $self->{stateDir} or die;
|
||||
exec $self->{startCommand};
|
||||
|
@ -132,16 +140,20 @@ sub start {
|
|||
chomp;
|
||||
s/\r$//;
|
||||
print STDERR $self->name, "# $_\n";
|
||||
$self->{connectedQueue}->enqueue(1) if $_ eq "===UP===";
|
||||
}
|
||||
# If the child dies, wake up connect().
|
||||
$self->{connectedQueue}->enqueue(1);
|
||||
}
|
||||
|
||||
# Wait until QEMU connects to the monitor.
|
||||
eval {
|
||||
local $SIG{CHLD} = sub { die "QEMU died prematurely\n"; };
|
||||
|
||||
# Wait until QEMU connects to the monitor.
|
||||
accept($self->{monitor}, $monitorS) or die;
|
||||
|
||||
# Wait until QEMU connects to the root shell socket. QEMU
|
||||
# does so immediately; this doesn't mean that the root shell
|
||||
# has connected yet inside the guest.
|
||||
accept($self->{socket}, $shellS) or die;
|
||||
$self->{socket}->autoflush(1);
|
||||
};
|
||||
die "$@" if $@;
|
||||
|
||||
|
@ -197,27 +209,9 @@ sub connect {
|
|||
|
||||
$self->start;
|
||||
|
||||
# Wait until the processQemuOutput thread signals that the machine
|
||||
# is up.
|
||||
retry sub {
|
||||
return 1 if $self->{connectedQueue}->dequeue_nb();
|
||||
};
|
||||
|
||||
retry sub {
|
||||
$self->log("trying to connect");
|
||||
my $socket = new IO::Handle;
|
||||
$self->{socket} = $socket;
|
||||
socket($socket, PF_UNIX, SOCK_STREAM, 0) or die;
|
||||
connect($socket, sockaddr_un($self->{stateDir} . "/65535.socket")) or die;
|
||||
$socket->autoflush(1);
|
||||
print $socket "echo hello\n" or next;
|
||||
flush $socket;
|
||||
my $line = readline($socket);
|
||||
chomp $line;
|
||||
return 1 if $line eq "hello";
|
||||
};
|
||||
|
||||
$self->log("connected");
|
||||
my $line = readline $self->{socket} or die;
|
||||
$self->log("connected to guest root shell");
|
||||
|
||||
$self->{connected} = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,3 @@ END {
|
|||
|
||||
|
||||
runTests;
|
||||
|
||||
|
||||
print STDERR "DONE\n";
|
||||
|
|
|
@ -13,6 +13,7 @@ let
|
|||
''
|
||||
#! ${pkgs.perl}/bin/perl
|
||||
$SIG{CHLD} = 'DEFAULT';
|
||||
print "\n";
|
||||
exec "/bin/sh";
|
||||
'';
|
||||
|
||||
|
@ -25,12 +26,6 @@ in
|
|||
jobs.backdoor =
|
||||
{ startOn = "started network-interfaces";
|
||||
|
||||
preStart =
|
||||
''
|
||||
echo "guest running" > /dev/ttyS0
|
||||
echo "===UP===" > dev/ttyS0
|
||||
'';
|
||||
|
||||
script =
|
||||
''
|
||||
export USER=root
|
||||
|
@ -39,7 +34,8 @@ in
|
|||
export GCOV_PREFIX=/tmp/coverage-data
|
||||
source /etc/profile
|
||||
cd /tmp
|
||||
exec ${pkgs.socat}/bin/socat tcp-listen:514,fork exec:${rootShell} 2> /dev/ttyS0
|
||||
echo "connecting to host..." > /dev/ttyS0
|
||||
exec ${pkgs.socat}/bin/socat tcp:10.0.2.6:23 exec:${rootShell} 2> /dev/ttyS0
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ let
|
|||
-m ${toString config.virtualisation.memorySize} \
|
||||
-net nic,vlan=0,model=virtio \
|
||||
-chardev socket,id=samba,path=./samba \
|
||||
-net user,vlan=0,guestfwd=tcp:10.0.2.4:139-chardev:samba \
|
||||
-net user,vlan=0,guestfwd=tcp:10.0.2.4:139-chardev:samba''${QEMU_NET_OPTS:+,$QEMU_NET_OPTS} \
|
||||
-drive file=$NIX_DISK_IMAGE,if=virtio,boot=on,cache=writeback,werror=report \
|
||||
-kernel ${config.system.build.toplevel}/kernel \
|
||||
-initrd ${config.system.build.toplevel}/initrd \
|
||||
|
|
Loading…
Reference in a new issue