diff options
Diffstat (limited to 'qemu-gtk-run')
-rwxr-xr-x | qemu-gtk-run | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/qemu-gtk-run b/qemu-gtk-run new file mode 100755 index 0000000..a90c4e7 --- /dev/null +++ b/qemu-gtk-run @@ -0,0 +1,304 @@ +#!/usr/bin/perl +use warnings; +use strict; +use XML::Parser; +use Getopt::Std; +use POSIX; + +# args +my %opts; +getopts('dm', \%opts); +my $name = shift; +my $debug = defined($opts{'d'}) ? 1 : 0; +my $showmon = defined($opts{'m'}) ? 1 : 0; + +# config +my $tapup = "/etc/qemu-virbr0-ifup"; +my $tapdown = "/etc/qemu-virbr0-ifdown"; +my $mondir = $ENV{HOME} . "/.qemu-gtk"; +my $monitor = $mondir . "/" . $name; + +# vars +my ($xml, $help, $parser, @cmdline, $pid); +my $level = 0; +my $indent = 3; +my $skip_qemu = 0; +my @xml_path; +my $xml_string; + +# domain config +my %xml_elems; + +my (@disks,@nics); +my $ndisk = 0; +my $nnic = 0; + +my $usb = 0; +my $usbtablet = 0; +my $graphics = 0; +my $soundhw; + +######################################################################## +# map tables + +my %ide_table = ( + 'hda' => 'if=ide,bus=0,unit=0', + 'hdb' => 'if=ide,bus=0,unit=1', + 'hdc' => 'if=ide,bus=1,unit=0', + 'hdd' => 'if=ide,bus=1,unit=1' +); + +######################################################################## +# helper functions + +sub xml_start { + my $expat = shift; + my $element = shift; + my $path; + my %attrs; + + while (defined($_[0])) { $attrs{$_[0]} = $_[1]; shift; shift; } + push @xml_path, $element; + + printf("start: %*s%-*s | %s\n", + $level * $indent, "", + 20 - $level * $indent, $element, + join(", ", map { "$_=$attrs{$_}" } sort keys %attrs)) + if $debug; + + $path = join("-", @xml_path); + + # disks + if ($path eq "domain-devices-disk" || + $path eq "domain-devices-disk-source" || + $path eq "domain-devices-disk-target") { + for my $elem ('device', 'bus', 'dev', 'file') { + next unless defined($attrs{$elem}); + $disks[$ndisk]{"$element-$elem"} = $attrs{$elem}; + } + } + + # nics + if ($path eq "domain-devices-interface-mac" || + $path eq "domain-devices-interface-model") { + for my $elem ('address', 'type') { + next unless defined($attrs{$elem}); + $nics[$nnic]{"$element-$elem"} = $attrs{$elem}; + } + } + + # input + if ($element eq "input" && $attrs{'type'} eq "tablet") { + $usb = 1; + $usbtablet = 1; + } + + # sound + if ($element eq "sound" && defined($attrs{'model'})) { + $soundhw = $attrs{'model'}; + } + + # graphics + if ($element eq "graphics") { + $graphics = 1; + } + + undef $xml_string; + $level++; +} + +sub xml_char { + my $expat = shift; + my $string = shift; + + return unless $string =~ m/\S/; + $xml_string = $string; +} + +sub xml_end { + my $expat = shift; + my $element = shift; + my $path; + + $level--; + + if (defined($xml_string)) { + printf("/end : %*s%-*s | %s\n", + $level * $indent, "", + 20 - $level * $indent, $element, + $xml_string) + if $debug; + $xml_elems{$element} = $xml_string; + } + + $path = join("-", @xml_path); + if ($path eq "domain-devices-disk") { + $ndisk++; + } + if ($path eq "domain-devices-interface") { + $nics[$nnic]{'vlan'} = $nnic; + $nnic++; + } + + pop @xml_path; +} + + +######################################################################## +# main + +# read config +open XML, "-|", "virsh dumpxml $name"; +{ local $/; undef $/; $xml = <XML>; }; +close XML; + +# set defaults +$xml_elems{'emulator'} = "qemu"; + +# parse config +$parser = new XML::Parser(); +$parser->setHandlers(Start => \&xml_start, + Char => \&xml_char, + End => \&xml_end); +$parser->parse($xml) or die "domain config parse error"; + +# get help text +open HELP, "-|", "$xml_elems{'emulator'} --help"; +{ local $/; undef $/; $help = <HELP>; }; +close HELP; + +# build cmdline -- basic setup +print "-- \n" if $debug; +push @cmdline, $xml_elems{'emulator'}; +if (defined($xml_elems{'name'}) and $help =~ m/-name/) { + push @cmdline, "-name"; + push @cmdline, $xml_elems{'name'}; +} +if (defined($xml_elems{'uuid'}) and $help =~ m/-uuid/) { + push @cmdline, "-uuid"; + push @cmdline, $xml_elems{'uuid'}; +} +if (defined($xml_elems{'memory'})) { + push @cmdline, "-m"; + push @cmdline, $xml_elems{'memory'} / 1024; +} +if (defined($xml_elems{'vcpu'})) { + push @cmdline, "-smp"; + push @cmdline, $xml_elems{'vcpu'}; +} +if ($usb) { + push @cmdline, "-usb"; +} +if ($usbtablet) { + push @cmdline, "-usbdevice"; + push @cmdline, "tablet"; +} +if (defined($soundhw)) { + push @cmdline, "-soundhw"; + push @cmdline, $soundhw; +} + +# build cmdline -- kvm +if (POSIX::access("/dev/kvm", &POSIX::W_OK) and $help =~ m/-enable-kvm/) { + push @cmdline, "-enable-kvm"; +} + +# build cmdline -- disks +foreach my $disk (@disks) { + print "disk: " . join (", ", map { + $_ . "=" . $disk->{$_}; + } keys %{$disk}) . "\n" + if $debug; + + $disk->{'config'} = "media=" . $disk->{'disk-device'}; + $disk->{'config'} .= ",file=" . $disk->{'source-dev'} + if defined($disk->{'source-dev'}); + $disk->{'config'} .= ",file=" . $disk->{'source-file'} + if defined($disk->{'source-file'}); + + if ($disk->{'target-bus'} eq "ide") { + # handle ide + $disk->{'config'} .= "," . $ide_table{$disk->{'target-dev'}}; + } else { + # default + $disk->{'config'} .= ",if=" . $disk->{'target-bus'}; + } + + push @cmdline, "-drive"; + push @cmdline, $disk->{'config'}; +} + +# build cmdline -- nics +foreach my $nic (@nics) { + print "nic: " . join (", ", map { + $_ . "=" . $nic->{$_}; + } keys %{$nic}) . "\n" + if $debug; + + if ($< == 0) { + # root + $nic->{'netconfig'} = "tap,vlan=" . $nic->{'vlan'}; + $nic->{'netconfig'} .= ",script=" . $tapup; + $nic->{'netconfig'} .= ",downscript=" . $tapdown; + } else { + # user + $nic->{'netconfig'} = "user,vlan=" . $nic->{'vlan'}; + } + + $nic->{'nicconfig'} = "nic,vlan=" . $nic->{'vlan'}; + $nic->{'nicconfig'} .= ",macaddr=" . $nic->{'mac-address'} + if defined($nic->{'mac-address'}); + $nic->{'nicconfig'} .= ",model=" . $nic->{'model-type'} + if defined($nic->{'model-type'}); + + push @cmdline, "-net"; + push @cmdline, $nic->{'nicconfig'}; + push @cmdline, "-net"; + push @cmdline, $nic->{'netconfig'}; +} + +# build cmdline -- hardwired stuff +push @cmdline, "-monitor"; +push @cmdline, "unix:" . $monitor . ",server,nowait"; +push @cmdline, "-serial"; +push @cmdline, "unix:,server,nowait"; +if ($graphics) { + push @cmdline, "-vnc"; + push @cmdline, "127.0.0.1:0,to=128,password"; +} else { + push @cmdline, "-nographic"; +} + +# prepare +print "-- \n" if $debug; +mkdir $mondir unless -d $mondir; + +# run qemu emulator +if (-S $monitor and !system("fuser", "-s", $monitor)) { + # still running + printf "VM %s still running, reconnecting\n", $name; +} else { + unlink $monitor; + $pid = fork(); + die "fork: $!" unless defined($pid); + if (0 == $pid) { + # child + print join(", ", map { "\"$_\"" } @cmdline) . "\n" + if $debug; + exec(@cmdline); + exit(1); + } + foreach my $i (0 ... 100) { + last if -S $monitor; + sleep(0.1); + } +} + +# run qemu-gtk +@cmdline = (); +push @cmdline, "qemu-gtk"; +push @cmdline, "-m" if $showmon; +push @cmdline, "unix:" . $monitor . ",server,nowait"; +print join(", ", map { "\"$_\"" } @cmdline) . "\n" + if $debug; +exec(@cmdline); |