[virt-v2v: 4/4] Pull in upstream patches to remove echoe dependence

Matthew Booth mdbooth at fedoraproject.org
Wed May 11 16:39:35 UTC 2011


commit 55697cb1ebd419b29bed0c47b4e4141040fce8e8
Author: Matthew Booth <mbooth at redhat.com>
Date:   Wed May 11 17:36:18 2011 +0100

    Pull in upstream patches to remove echoe dependence

 virt-v2v-0.8.1-00-44eb9021-modified.patch | 9296 +++++++++++++++++++++++++++++
 virt-v2v-0.8.1-01-e34a8c09.patch          |   57 +
 virt-v2v-0.8.1-02-fadb1929.patch          |  111 +
 virt-v2v.spec                             |   20 +-
 4 files changed, 9478 insertions(+), 6 deletions(-)
---
diff --git a/virt-v2v-0.8.1-00-44eb9021-modified.patch b/virt-v2v-0.8.1-00-44eb9021-modified.patch
new file mode 100644
index 0000000..5f0b250
--- /dev/null
+++ b/virt-v2v-0.8.1-00-44eb9021-modified.patch
@@ -0,0 +1,9296 @@
+diff -ruN virt-v2v-v0.8.1/Build.PL virt-v2v-v0.8.1.new/Build.PL
+--- virt-v2v-v0.8.1/Build.PL	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/Build.PL	2011-05-11 17:20:21.000000000 +0100
+@@ -26,7 +26,7 @@
+ {
+     my $self = shift;
+ 
+-    system($self->config('make'), '-C', 'p2v-image-builder') == 0
++    system($self->config('make'), '-C', 'p2v/image-builder') == 0
+         or return 1;
+ }
+ 
+@@ -243,7 +243,7 @@
+     dist_version_from => 'lib/Sys/VirtConvert.pm',
+     confdoc_files => [ 'v2v/virt-v2v.conf.pod' ],
+     install_path => { 'locale' => '/usr/local/share/locale' },
+-    script_files => [ 'v2v/virt-v2v.pl', 'p2v-server/virt-p2v-server.pl' ],
++    script_files => [ 'v2v/virt-v2v.pl', 'p2v/server/virt-p2v-server.pl' ],
+     meta_add => {
+         resources => {
+           license => "http://www.gnu.org/licenses/gpl.html",
+diff -ruN virt-v2v-v0.8.1/ChangeLog virt-v2v-v0.8.1.new/ChangeLog
+--- virt-v2v-v0.8.1/ChangeLog	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/ChangeLog	2011-05-11 17:20:21.000000000 +0100
+@@ -1,3 +1,33 @@
++2011-05-10  Matthew Booth <mbooth at redhat.com>
++
++        * Build.PL, MANIFEST, p2v-image-builder/Makefile, {p2v-client =>
++        p2v/client}/.gitignore, {p2v-client => p2v/client}/Manifest,
++        {p2v-client => p2v/client}/Rakefile, {p2v-client =>
++        p2v/client}/bin/virt-p2v, {p2v-client =>
++        p2v/client}/lib/virt-p2v/blockdevice.rb, {p2v-client =>
++        p2v/client}/lib/virt-p2v/connection.rb, {p2v-client =>
++        p2v/client}/lib/virt-p2v/converter.rb, {p2v-client =>
++        p2v/client}/lib/virt-p2v/gtk-queue.rb, {p2v-client =>
++        p2v/client}/lib/virt-p2v/netdevice.rb, {p2v-client =>
++        p2v/client}/lib/virt-p2v/ui/connect.rb, {p2v-client =>
++        p2v/client}/lib/virt-p2v/ui/convert.rb, {p2v-client =>
++        p2v/client}/lib/virt-p2v/ui/main.rb, {p2v-client =>
++        p2v/client}/lib/virt-p2v/ui/network.rb, {p2v-client =>
++        p2v/client}/lib/virt-p2v/ui/p2v.ui, {p2v-client =>
++        p2v/client}/lib/virt-p2v/ui/success.rb, {p2v-image-builder =>
++        p2v/image-builder}/.gitignore, p2v/image-builder/Makefile,
++        {p2v-image-builder => p2v/image-builder}/common-install.ks,
++        {p2v-image-builder => p2v/image-builder}/common-manifest-post.ks,
++        {p2v-image-builder => p2v/image-builder}/common-minimizer.ks,
++        {p2v-image-builder => p2v/image-builder}/common-pkgs.ks,
++        {p2v-image-builder => p2v/image-builder}/common-post-nochroot.ks,
++        {p2v-image-builder => p2v/image-builder}/common-post.ks,
++        {p2v-image-builder => p2v/image-builder}/virt-p2v-image-builder,
++        {p2v-image-builder => p2v/image-builder}/virt-p2v-image.ks,
++        {p2v-server => p2v/server}/run-p2v-locally, {p2v-server =>
++        p2v/server}/virt-p2v-server.pl, virt-v2v.spec.PL: Give p2v its own
++        subdirectory
++
+ 2011-04-26  Matthew Booth <mbooth at redhat.com>
+ 
+         * lib/Sys/VirtConvert.pm: Bump version to 0.8.1
+diff -ruN virt-v2v-v0.8.1/MANIFEST virt-v2v-v0.8.1.new/MANIFEST
+--- virt-v2v-v0.8.1/MANIFEST	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/MANIFEST	2011-05-11 17:20:21.000000000 +0100
+@@ -27,33 +27,33 @@
+ MANIFEST.SKIP
+ META.yml
+ metadata-format.txt
+-p2v-client/bin/virt-p2v
+-p2v-client/lib/virt-p2v/blockdevice.rb
+-p2v-client/lib/virt-p2v/connection.rb
+-p2v-client/lib/virt-p2v/converter.rb
+-p2v-client/lib/virt-p2v/gtk-queue.rb
+-p2v-client/lib/virt-p2v/netdevice.rb
+-p2v-client/lib/virt-p2v/ui/connect.rb
+-p2v-client/lib/virt-p2v/ui/convert.rb
+-p2v-client/lib/virt-p2v/ui/main.rb
+-p2v-client/lib/virt-p2v/ui/network.rb
+-p2v-client/lib/virt-p2v/ui/p2v.ui
+-p2v-client/lib/virt-p2v/ui/success.rb
+-p2v-client/Manifest
+-p2v-client/Rakefile
+-p2v-client/virt-p2v.gemspec
+-p2v-image-builder/common-install.ks
+-p2v-image-builder/common-manifest-post.ks
+-p2v-image-builder/common-minimizer.ks
+-p2v-image-builder/common-pkgs.ks
+-p2v-image-builder/common-post-nochroot.ks
+-p2v-image-builder/common-post.ks
+-p2v-image-builder/Makefile
+-p2v-image-builder/version.ks
+-p2v-image-builder/virt-p2v-image-builder
+-p2v-image-builder/virt-p2v-image.ks
+-p2v-server/run-p2v-locally
+-p2v-server/virt-p2v-server.pl
++p2v/client/bin/virt-p2v
++p2v/client/lib/virt-p2v/blockdevice.rb
++p2v/client/lib/virt-p2v/connection.rb
++p2v/client/lib/virt-p2v/converter.rb
++p2v/client/lib/virt-p2v/gtk-queue.rb
++p2v/client/lib/virt-p2v/netdevice.rb
++p2v/client/lib/virt-p2v/ui/connect.rb
++p2v/client/lib/virt-p2v/ui/convert.rb
++p2v/client/lib/virt-p2v/ui/main.rb
++p2v/client/lib/virt-p2v/ui/network.rb
++p2v/client/lib/virt-p2v/ui/p2v.ui
++p2v/client/lib/virt-p2v/ui/success.rb
++p2v/client/Manifest
++p2v/client/Rakefile
++p2v/client/virt-p2v.gemspec
++p2v/image-builder/common-install.ks
++p2v/image-builder/common-manifest-post.ks
++p2v/image-builder/common-minimizer.ks
++p2v/image-builder/common-pkgs.ks
++p2v/image-builder/common-post-nochroot.ks
++p2v/image-builder/common-post.ks
++p2v/image-builder/Makefile
++p2v/image-builder/version.ks
++p2v/image-builder/virt-p2v-image-builder
++p2v/image-builder/virt-p2v-image.ks
++p2v/server/run-p2v-locally
++p2v/server/virt-p2v-server.pl
+ po/es.po
+ po/it.po
+ po/Makefile
+diff -ruN virt-v2v-v0.8.1/p2v/client/bin/virt-p2v virt-v2v-v0.8.1.new/p2v/client/bin/virt-p2v
+--- virt-v2v-v0.8.1/p2v/client/bin/virt-p2v	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/bin/virt-p2v	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,62 @@
++#!/usr/bin/env ruby
++
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++require 'virt-p2v/ui/main'
++require 'virt-p2v/ui/network'
++require 'virt-p2v/ui/connect'
++require 'virt-p2v/ui/convert'
++require 'virt-p2v/ui/success'
++
++require 'virt-p2v/converter'
++require 'virt-p2v/netdevice'
++
++require 'gettext'
++
++include GetText
++
++bindtextdomain('virt-p2v')
++
++if Process.uid != 0
++    puts _("virt-p2v must be executed with root privileges.\n" +
++           "It is intended to be included in a custom Live image, not " +
++           "run from the command\nline.")
++    abort
++end
++
++converter = VirtP2V::Converter.new
++
++# Initialise the wizard UI
++ui = VirtP2V::UI::Main.new
++
++# Initialize wizard pages
++VirtP2V::UI::Network.init(ui)
++VirtP2V::UI::Connect.init(ui, converter)
++VirtP2V::UI::Convert.init(ui, converter)
++VirtP2V::UI::Success.init(ui)
++
++# Skip the network configuration screen if there is already an active network
++# connection
++VirtP2V::NetworkDevice.all_devices.each { |device|
++    if device.activated then
++        ui.active_page = 'server_win'
++        break
++    end
++}
++
++ui.show
++ui.main_loop
+diff -ruN virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/blockdevice.rb virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/blockdevice.rb
+--- virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/blockdevice.rb	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/blockdevice.rb	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,112 @@
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++module VirtP2V
++
++class NoSuchDeviceError < StandardError; end
++
++class FixedBlockDevice
++    @@devices = {}
++
++    def self.all_devices
++        @@devices.values
++    end
++
++    def self.[](device)
++        raise NoSuchDeviceError unless @@devices.has_key?(device)
++
++        @@devices[device]
++    end
++
++    attr_reader :device
++
++    def initialize(device)
++        @device = device
++        @@devices[device] = self
++    end
++end
++
++class RemovableBlockDevice
++    @@devices = {}
++
++    def self.all_devices
++        @@devices.values
++    end
++
++    def self.[](device)
++        raise NoSuchDeviceError unless @@devices.has_key?(device)
++
++        @@devices[device]
++    end
++
++    attr_reader :device, :type
++
++    def initialize(device, type)
++        @device = device
++        @type = type
++
++        @@devices[device] = self
++    end
++end
++
++# Detect and instantiate all fixed and removable block devices in the system
++begin
++    # Look for block devices
++    # Specifically, we look for entries in /sys/block which have a device
++    # symlink and no entries in their slaves subdirectory
++    Dir.foreach('/sys/block') { |dev|
++        next if dev == '.' || dev == '..'
++
++        # Skip if there's no device link
++        next unless File.exists?("/sys/block/#{dev}/device")
++
++        # Skip if the slaves subdirectory contains anything other than . and
++        # ..
++        begin
++            next if Dir.entries("/sys/block/#{dev}/slaves").length > 2
++        rescue Errno::ENOENT => ex
++            # This shouldn't happen, but if it did I guess it would mean
++            # there are no slave devices
++        end
++
++        # We've got a real block device. Check if it's removable or not
++        File.open("/sys/block/#{dev}/removable") { |fd|
++            removable = fd.gets.chomp
++            if removable == "0" then
++                FixedBlockDevice.new(dev)
++            else
++                # Look in device/modalias to work out what kind of removable
++                # device this is
++                type = File.open(
++                    "/sys/block/#{dev}/device/modalias") \
++                { |modalias_f|
++                    modalias = modalias_f.gets.chomp
++                    if modalias =~ /floppy/ then
++                        'floppy'
++                    elsif modalias =~ /cdrom/ then
++                        'cdrom'
++                    else
++                        # We don't know what this is, ignore it
++                    end
++                }
++
++                RemovableBlockDevice.new(dev, type) unless type.nil?
++            end
++        }
++    }
++end
++
++end
+diff -ruN virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/connection.rb virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/connection.rb
+--- virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/connection.rb	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/connection.rb	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,320 @@
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++require 'gettext'
++require 'rubygems'
++require 'net/ssh'
++require 'thread'
++require 'yaml'
++
++require 'virt-p2v/gtk-queue'
++
++module VirtP2V
++
++class Connection
++    include GetText
++
++    attr_reader :connected
++
++    class InvalidHostnameError < StandardError; end
++    class InvalidCredentialsError < StandardError; end
++    class TransportError < StandardError; end
++    class NoP2VError < StandardError; end
++    class RemoteError < StandardError; end
++    class ProtocolError < StandardError; end
++    class NotConnectedError < StandardError; end
++
++    def on_connect(&cb)
++        @connection_listeners << cb
++    end
++
++    def initialize(hostname, username, password, &cb)
++        @mutex = Mutex.new
++        @connection_listeners = []
++
++        # Always send our version number on connection
++        @connection_listeners << Proc.new { |cb|
++            self.version { |result| cb.call(result) }
++        }
++
++        run(cb) {
++            error = nil
++            begin
++                @ssh = Net::SSH.start(hostname, username, :password => password)
++            rescue SocketError, Errno::EHOSTUNREACH => ex
++                raise InvalidHostnameError
++                raise ex
++            rescue Net::SSH::AuthenticationFailed => ex
++                raise InvalidCredentialsError
++                raise ex
++            end
++
++            @buffer = ""
++            @connected = false
++
++            Gtk.queue { cb.call(true) }
++        }
++    end
++
++    def connect(&cb)
++        run(cb) {
++            @ch = @ssh.open_channel do |ch|
++                ch.exec("virt-p2v-server") do |ch, success|
++                    raise RemoteError,
++                          "could not execute a remote command" unless success
++
++                    ch.on_data do |ch, data|
++                        @buffer << data
++                    end
++
++                    # If we get anything on stderr, raise it as a RemoteError
++                    ch.on_extended_data do |ch, type, data|
++                        close
++                        raise RemoteError, data
++                    end
++
++                    # Clean up local resources if we get eof from the other end
++                    ch.on_eof do |ch|
++                        close
++                    end
++
++                    @connected = true
++                end
++
++            end
++
++            # Wait until we're connected
++            @ssh.loop do
++                !@connected
++            end
++
++            i = 0;
++            listener_result = lambda { |result|
++                if result.kind_of?(Exception)
++                    cb.call(result)
++                else
++                    i += 1
++                    if i == @connection_listeners.length
++                        cb.call(true)
++                    else
++                        Gtk.queue {
++                            @connection_listeners[i].call(listener_result)
++                        }
++                    end
++                end
++            }
++            Gtk.queue { @connection_listeners[0].call(listener_result) }
++        }
++    end
++
++    def close
++        @connected = false
++        @buffer = ""
++        @ch.close
++    end
++
++    def version(&cb)
++        raise NotConnectedError unless @connected
++
++        run(cb) {
++            @ch.send_data("VERSION 0\n")
++            result = parse_return
++
++            Gtk.queue { cb.call(result) }
++        }
++    end
++
++    def lang(lang, &cb)
++        raise NotConnectedError unless @connected
++
++        run(cb) {
++            @ch.send_data("LANG #{lang}\n")
++            result = parse_return
++
++            Gtk.queue { cb.call(result) }
++        }
++    end
++
++    def metadata(meta, &cb)
++        raise NotConnectedError unless @connected
++
++        run(cb) {
++            payload = YAML::dump(meta)
++            @ch.send_data("METADATA #{payload.length}\n");
++            @ch.send_data(payload)
++            result = parse_return
++
++            Gtk.queue { cb.call(result) }
++        }
++    end
++
++    def path(length, path, &cb)
++        raise NotConnectedError unless @connected
++
++        run(cb) {
++            @ch.send_data("PATH #{length} #{path}\n")
++            result = parse_return
++
++            Gtk.queue { cb.call(result) }
++        }
++    end
++
++    def convert(&cb)
++        raise NotConnectedError unless @connected
++
++        run(cb) {
++            @ch.send_data("CONVERT\n")
++            result = parse_return
++
++            Gtk.queue { cb.call(result) }
++        }
++    end
++
++    def list_profiles(&cb)
++        raise NotConnectedError unless @connected
++
++        run(cb) {
++            @ch.send_data("LIST_PROFILES\n")
++            result = parse_return
++
++            Gtk.queue { cb.call(result) }
++        }
++    end
++
++    def set_profile(profile, &cb)
++        raise NotConnectedError unless @connected
++
++        run(cb) {
++            @ch.send_data("SET_PROFILE #{profile}\n")
++            result = parse_return
++
++            Gtk.queue { cb.call(result) }
++        }
++    end
++
++    def container(type, &cb)
++        raise NotConnectedError unless @connected
++
++        run(cb) {
++            @ch.send_data("CONTAINER #{type}\n")
++            result = parse_return
++
++            Gtk.queue { cb.call(result) }
++        }
++    end
++
++    def send_data(io, length, progress, &completion)
++        raise NotConnectedError unless @connected
++
++        run(completion) {
++            @ch.send_data("DATA #{length}\n")
++            total = 0
++            buffer = ''
++            begin
++                # This loop is in the habit of hanging in Net::SSH when sending
++                # a chunk larger than about 2M. Putting the 1 second wait
++                # timeout here kickstarts it if it stops.
++                @ssh.loop(1) {
++                    if io.eof? || total == length then
++                        false
++                    else
++                        if @ch.remote_window_size > 0 then
++                            out = length - total
++                            out = @ch.remote_window_size \
++                                if out > @ch.remote_window_size
++
++                            io.read(out, buffer)
++                            @ch.send_data(buffer)
++
++                            total += buffer.length
++
++                            # Send a progress callback
++                            Gtk.queue { progress.call(total) }
++                        end
++
++                        true
++                    end
++                }
++            rescue => ex
++                Gtk.queue { completion.call(ex) }
++            end
++
++            result = parse_return
++
++            Gtk.queue { completion.call(result) }
++        }
++    end
++
++    private
++
++    def run(cb)
++        # Run the given block in a new thread
++        t = Thread.new {
++            begin
++                # We can't run more than 1 command simultaneously
++                @mutex.synchronize { yield }
++            rescue => ex
++                # Deliver exceptions to the caller, then re-raise them
++                Gtk.queue { cb.call(ex) }
++                raise ex
++            end
++        }
++        t.priority = 1
++    end
++
++    # Return a single line of output from the remote server
++    def readline
++        # Run the event loop until the buffer contains a newline
++        index = nil
++        @ssh.loop do
++            if !@ch.eof? then
++                index = @buffer.index("\n")
++                index.nil?
++            else
++                close
++                raise RemoteError, _('Server closed connection unexpectedly')
++            end
++        end
++
++        # Remove the line from the buffer and return it with the trailing
++        # newline removed
++        @buffer.slice!(0..index).chomp
++    end
++
++    def parse_return
++        line = readline
++        line =~ /^(OK|ERROR|LIST)(?:\s(.*))?$/ or
++            raise ProtocolError, "Invalid server response: #{line}"
++
++        return true if $~[1] == 'OK'
++        if $~[1] == 'ERROR' then
++            close
++            raise RemoteError, $~[2]
++        end
++
++        # LIST response. Get the number of items, and read that many lines
++        n = Integer($~[2])
++        ret = []
++        while n > 0 do
++            n -= 1
++            ret.push(readline)
++        end
++
++        ret
++    end
++end
++
++end
+diff -ruN virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/converter.rb virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/converter.rb
+--- virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/converter.rb	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/converter.rb	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,218 @@
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++require 'gettext'
++require 'rexml/document'
++include REXML
++
++require 'virt-p2v/netdevice'
++require 'virt-p2v/blockdevice'
++
++module VirtP2V
++
++# NIC
++# hostname
++# username
++# password
++
++# name          User entry
++# memory        Editable
++# cpus          Editable
++# arch          Detected: cpuflags contains lm (long mode)
++# features      Detected: apic, acpi, pae
++# disks         Editable, default to all
++#   device        Detected
++#   path          Detected
++#   is_block      1
++#   format        raw
++# removables    Editable, default to all
++#   device        Detected
++#   type          Detected
++# nics          Editable, default to all connected
++#   mac           Detected, option to generate new
++#   vnet          Set to nic name
++#   vnet_type     bridge
++
++class Converter
++    include GetText
++
++    attr_accessor :profile, :name, :cpus, :memory, :arch
++    attr_reader :features, :disks, :removables, :nics
++
++    attr_reader :connection
++
++    def on_connection(&cb)
++        @connection_listeners << cb
++    end
++
++    def connection=(connection)
++        @connection = connection
++        @connection_listeners.each { |cb|
++            cb.call(connection)
++        }
++    end
++
++    def convert(status, progress, &completion)
++        iterate([
++            lambda { |cb| @connection.set_profile(@profile, &cb) },
++            lambda { |cb| @connection.metadata(meta, &cb) },
++            lambda { |cb|
++                iterate(@disks.map { |dev|
++                    lambda { |cb2|
++                        disk(dev, status, progress, cb2)
++                    }
++                }, cb)
++            },
++            lambda { |cb|
++                status.call(_('Converting'))
++                @connection.convert(&cb)
++            }
++        ], completion)
++    end
++
++    private
++
++    def initialize()
++        @profile = nil
++        @connection = nil
++        @connection_listeners = []
++
++        # Initialize basic system information
++        @name = '' # There's no reasonable default for this
++
++        # Get total memory from /proc/meminfo
++        File.open('/proc/meminfo', 'r') do |fd|
++            fd.each { |line|
++                next unless line =~ /^MemTotal:\s+(\d+)\b/
++
++                @memory = Integer($~[1]) * 1024
++                break
++            }
++        end
++
++        # Get the total number of cpu threads from hwloc-info
++        hwloc = Document.new `hwloc-info --of xml`
++        @cpus = XPath.match(hwloc, "//object[@type='PU']").length
++
++        # Get cpu architecture and features from the first flags entry in
++        # /proc/cpuinfo
++        File.open('/proc/cpuinfo', 'r') do |fd|
++            fd.each { |line|
++                next unless line =~ /^flags\s*:\s(.*)$/
++
++                flags = $~[1]
++
++                # x86_64 if flags contains lm (long mode), i686 otherwise. We
++                # don't support anything else.
++                @arch = flags =~ /\blm\b/ ? 'x86_64' : 'i686'
++
++                # Pull some select features from cpu flags
++                @features = []
++                [ 'apic', 'acpi', 'pae' ].each { |f|
++                    @features << f if flags =~ /\b#{f}\b/
++                }
++                break
++            }
++        end
++
++        # Initialise empty lists for optional devices. These will be added
++        # according to the user's selection
++        @disks = []
++        @removables = []
++        @nics = []
++    end
++
++    def disk(dev, status, progress, completion)
++        path = "/dev/#{dev}"
++        # XXX: No error checking of blockdev execution
++        size = Integer(`blockdev --getsize64 #{path}`.chomp)
++        status.call(_("Transferring #{dev}"))
++        iterate([
++            lambda { |cb| @connection.path(size, path, &cb) },
++            lambda { |cb| @connection.container('RAW', &cb) },
++            lambda { |cb|
++                io = nil
++                begin
++                    io = File.new(path, 'r')
++                rescue => ex
++                    cb.call(ex)
++                end
++                pc = 0
++                @connection.send_data(io, size, lambda { |total|
++                    npc = Float(total) * 100 / size
++                    # Only update the progress if it has increased by
++                    # at least 1%
++                    if Integer(npc) > pc then
++                        pc += 1
++                        progress.call(dev, pc)
++                    end
++                }, &cb)
++            }
++        ], completion)
++    end
++
++    def iterate(stages, completion)
++        i = 0
++        cb = lambda { |result|
++            if result.kind_of?(Exception) then
++                completion.call(result)
++            else
++                i += 1
++                if i == stages.length then
++                    completion.call(true)
++                else
++                    stages[i].call(cb)
++                end
++            end
++        }
++        stages[0].call(cb)
++    end
++
++    def meta
++        {
++            'name'      => @name,
++            'cpus'      => @cpus,
++            'memory'    => @memory,
++            'arch'      => @arch,
++            'features'  => @features,
++            'disks'     => @disks.map { |device|
++                {
++                    'device'    => device,
++                    'path'      => "/dev/#{device}",
++                    'is_block'  => '1',
++                    'format'    => 'raw'
++                }
++            },
++            'removables' => @removables.map { |device|
++                removable = RemovableBlockDevice[device]
++                {
++                    'device'    => removable.device,
++                    'type'      => removable.type
++                }
++            },
++            'nics'      => @nics.map { |device|
++                nic = NetworkDevice[device]
++                {
++                    'mac'       => nic.mac,
++                    'vnet'      => nic.name,
++                    'vnet_type' => 'bridge'
++                }
++            }
++        }
++    end
++end
++
++end
+diff -ruN virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/gtk-queue.rb virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/gtk-queue.rb
+--- virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/gtk-queue.rb	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/gtk-queue.rb	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,52 @@
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++# This code is taken from:
++#   http://ruby-gnome2.sourceforge.jp/hiki.cgi?tips_threads
++# The author of the above page is given as Tal Liron
++# The above page is distributed under the terms of the GNU FDL, although I
++# consider this code to be too trivial to be copyrightable
++
++require 'gtk2'
++require 'thread'
++
++module Gtk
++    GTK_PENDING_BLOCKS = []
++    GTK_PENDING_BLOCKS_LOCK = Mutex.new
++
++    def Gtk.queue &block
++        if Thread.current == Thread.main
++            block.call
++        else
++            GTK_PENDING_BLOCKS_LOCK.synchronize do
++                GTK_PENDING_BLOCKS << block
++            end
++        end
++    end
++
++    def Gtk.main_with_queue timeout
++        Gtk.timeout_add timeout do
++            GTK_PENDING_BLOCKS_LOCK.synchronize do
++                for block in GTK_PENDING_BLOCKS
++                    block.call
++                end
++                GTK_PENDING_BLOCKS.clear
++            end
++            true
++        end
++        Gtk.main
++    end
++end
+diff -ruN virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/netdevice.rb virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/netdevice.rb
+--- virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/netdevice.rb	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/netdevice.rb	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,259 @@
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++require 'dbus'
++require 'gettext'
++
++module VirtP2V
++
++class NetworkDevice
++    include GetText
++
++    attr_reader :name, :mac, :connected, :activated, :state
++
++    # Some NetworkManager names, for convenience
++    CONNECTION      = 'org.freedesktop.NetworkManagerSettings.Connection'.freeze
++    DEVICE          = 'org.freedesktop.NetworkManager.Device'.freeze
++    NETWORKMANAGER  = 'org.freedesktop.NetworkManager'.freeze
++    PROPERTIES      = 'org.freedesktop.DBus.Properties'.freeze
++    SETTINGS        = 'org.freedesktop.NetworkManagerSettings'.freeze
++    WIRED           = 'org.freedesktop.NetworkManager.Device.Wired'.freeze
++
++    # NetworkManager device types
++    # http://projects.gnome.org/NetworkManager/developers/spec-08.html
++    TYPE_UNKNOWN  = 0
++    TYPE_ETHERNET = 1
++    TYPE_WIFI     = 2
++    TYPE_GSM      = 3
++    TYPE_CDMA     = 4
++
++    # NetworkManager device states
++    STATE_UNKNOWN         = 0
++    STATE_UNMANAGED       = 1
++    STATE_UNAVAILABLE     = 2
++    STATE_DISCONNECTED    = 3
++    STATE_PREPARE         = 4
++    STATE_CONFIG          = 5
++    STATE_NEED_AUTH       = 6
++    STATE_IP_CONFIG       = 7
++    STATE_ACTIVATED       = 8
++    STATE_FAILED          = 9
++
++    # Human readable descriptions of NetworkManager Device States
++    STATES = {
++        0 => _('Unknown').freeze,           # For completeness
++        1 => _('Unmanaged').freeze,         # For completeness
++        2 => _('No cable connected').freeze,
++        3 => _('Not connected').freeze,
++        4 => _('Preparing to connect').freeze,
++        5 => _('Configuring').freeze,
++        6 => _('Waiting for authentication').freeze,
++        7 => _('Obtaining an IP address').freeze,
++        8 => _('Connected').freeze,
++        9 => _('Connection failed').freeze
++    }.freeze
++
++    def initialize(obj, device, props)
++        device.default_iface = WIRED
++
++        @nm_obj = obj
++        @name   = props.Get(DEVICE, 'Interface')[0]
++        @mac    = props.Get(WIRED, 'HwAddress')[0]
++        state   = props.Get(WIRED, 'State')[0]
++
++        # Lookup by name
++        @@devices[@name] = self
++
++        state_updated(state)
++
++        # Register a listener for state changes
++        device.on_signal('PropertiesChanged') { |props|
++            if props.has_key?('State') then
++                state_updated(props['State'])
++
++                # Notify registered state change handlers
++                @@listeners.each { |cb| cb.call(self) }
++            end
++        }
++    end
++
++    def self.all_devices()
++        @@devices.values
++    end
++
++    def self.add_listener(cb)
++        @@listeners.push(cb)
++    end
++
++    def self.[](name)
++        @@devices[name]
++    end
++
++    def activate(auto, ip, prefix, gateway, dns)
++        # Get an IP config dependent on whether @ip_address is IPv4 or IPv6
++        ip_config = auto ? get_config_auto :
++                           ip.ipv4? ? get_config_ipv4() : get_config_ipv6()
++
++        # Create a new NetworkManager connection object
++        settings = @@nm_service.object(
++            '/org/freedesktop/NetworkManagerSettings')
++        settings.introspect()
++        settings.default_iface = SETTINGS
++
++        uuid = `uuidgen`.chomp
++        settings.AddConnection(
++            'connection' => {
++                'uuid' => uuid,
++                'id' => 'P2V',
++                'type' => '802-3-ethernet',
++                'autoconnect' => false
++            },
++            '802-3-ethernet' => {},
++            'ipv4' => ip_config['ipv4'],
++            'ipv6' => ip_config['ipv6']
++        )
++
++        # Find the connection we just created
++        # XXX: There must be a better way to get this!
++        conn = settings.ListConnections()[0].each { |i|
++            conn = @@nm_service.object(i)
++            conn.introspect
++            conn.default_iface = CONNECTION
++
++            break i if conn.GetSettings()[0]['connection']['uuid'] == uuid
++        }
++
++        nm = @@nm_service.object('/org/freedesktop/NetworkManager')
++        nm.introspect
++        nm.default_iface = NETWORKMANAGER
++        nm.ActivateConnection('org.freedesktop.NetworkManagerSystemSettings',
++                             conn, @nm_obj, '/')
++    end
++
++    private
++
++    def state_updated(state)
++        @connected = state > 2
++        @state  = STATES[state]
++
++        if state == STATE_ACTIVATED then
++            @activated = true
++        elsif state == STATE_FAILED then
++            @activated = false
++        else
++            @activated = nil
++        end
++    end
++
++    def get_config_auto
++        {
++            'ipv4' => {
++                'method' => 'auto'
++            },
++            'ipv6' => {
++                'method' => 'ignore'
++            }
++        }
++    end
++
++    def ipv4_to_nm(ipaddr)
++        ipaddr.hton().unpack("I")[0]
++    end
++
++    def get_config_ipv4
++        addresses = [[ ipv4_to_nm(@ip_address), @ip_prefix,
++                       ipv4_to_nm(@ip_gateway) ]]
++
++        dns = []
++        @ip_dns.each{ |ipaddr|
++            # Only use IPv4 DNS servers
++            next unless ipaddr.ipv4?
++            dns.push(ipv4_to_nm(ipaddr))
++        }
++
++        {
++            'ipv4' => {
++                'method' => 'manual',
++                'addresses' => [ 'aau', addresses ],
++                'dns' => [ 'au', dns ]
++            },
++            'ipv6' => {
++                'method' => 'ignore'
++            }
++        }
++    end
++
++    def ipv6_to_nm(ipaddr)
++        ipaddr.hton().unpack("c*")
++    end
++
++    def get_config_ipv6
++        dns = []
++        @ip_dns.each { |ipaddr|
++            # Only use IPv6 DNS servers
++            next unless ipaddr.ipv6?
++            dns.push(ipv6_to_nm(ipaddr))
++        }
++
++        {
++            'ipv4' => {
++                'method' => 'disabled'
++            },
++            'ipv6' => {
++                'method' => 'manual',
++                'addresses' => [ 'a(ayu)', [[
++                    ipv6_to_nm(@ip_address),
++                    @ip_prefix
++                ]] ],
++                'routes' => [ 'a(ayuayu)', [[
++                    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], 0,
++                    ipv6_to_nm(@ip_gateway), 1024
++                ]] ],
++                'dns' => [ 'aay', dns ]
++            }
++        }
++    end
++
++    # Class initialization
++    begin
++        dbus = DBus::SystemBus.instance()
++        dbus.glibize()
++        @@nm_service = dbus.service(NETWORKMANAGER)
++
++        nm = @@nm_service.object('/org/freedesktop/NetworkManager')
++        nm.introspect
++        nm.default_iface = NETWORKMANAGER
++
++        @@devices = {}
++        nm.GetDevices()[0].each { |obj|
++            device = @@nm_service.object(obj)
++            device.introspect
++
++            props = device[PROPERTIES]
++            type = props.Get(DEVICE, 'DeviceType')[0]
++
++            # We only support ethernet devices
++            next unless type == TYPE_ETHERNET
++
++            # Constructor will add it to @@devices
++            self.new(obj, device, props)
++        }
++
++        @@listeners = []
++    end
++end
++
++end #module
+diff -ruN virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/ui/connect.rb virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/ui/connect.rb
+--- virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/ui/connect.rb	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/ui/connect.rb	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,179 @@
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++require 'gettext'
++require 'gtk2'
++
++require 'virt-p2v/connection'
++
++module VirtP2V::UI::Connect
++    include GetText
++
++    UI_STATE_INVALID    = 0
++    UI_STATE_VALID      = 1
++    UI_STATE_ACTIVATING = 2
++    UI_STATE_COMPLETE   = 3
++
++    EV_HOSTNAME     = 0
++    EV_USERNAME     = 1
++    EV_PASSWORD     = 2
++    EV_BUTTON       = 3
++    EV_ACTIVATION   = 4
++
++    def self.event(event, status)
++        case event
++        when EV_HOSTNAME
++            @hostname = status
++        when EV_USERNAME
++            @username = status
++        when EV_PASSWORD
++            @password = status
++        when EV_BUTTON, EV_ACTIVATION
++            # Persistent state not required
++        else
++            raise "Unexpected event: #{event}"
++        end
++
++        valid = @hostname && @username && @password
++
++        case @state
++        when UI_STATE_INVALID
++            set_state(UI_STATE_VALID) if valid
++        when UI_STATE_VALID
++            if !valid then
++                set_state(UI_STATE_INVALID)
++            elsif event == EV_BUTTON
++                set_state(UI_STATE_ACTIVATING)
++            end
++        when UI_STATE_ACTIVATING
++            # UI is disabled, so we shouldn't be getting any events other than
++            # EV_ACTIVATION
++            raise "Unexpected event: #{event}" unless event == EV_ACTIVATION
++
++            set_state(status ? UI_STATE_COMPLETE : UI_STATE_VALID)
++        else
++            raise "Unexpected UI state: #{@state}"
++        end
++    end
++
++    def self.init(ui, converter)
++        @hostname_ui    = ui.get_object('server_hostname')
++        @username_ui    = ui.get_object('server_username')
++        @password_ui    = ui.get_object('server_password')
++        @connect_frame  = ui.get_object('connect_frame')
++        @connect_button = ui.get_object('connect_button')
++        @connect_error  = ui.get_object('connect_error')
++
++        ui.register_handler('server_hostname_changed',
++                            method(:server_hostname_changed))
++        ui.register_handler('server_username_changed',
++                            method(:server_username_changed))
++        ui.register_handler('server_password_changed',
++                            method(:server_password_changed))
++        ui.register_handler('connect_button_clicked',
++                            method(:connect_button_clicked))
++
++        @hostname = @hostname_ui.text.strip.length > 0
++        @username = @username_ui.text.strip.length > 0
++        @password = @password_ui.text.length > 0 # Allow spaces in passwords
++        @state = UI_STATE_INVALID
++
++        @ui = ui
++        @converter = converter
++    end
++
++    def self.set_state(state)
++        # Don't do anything if state hasn't changed
++        return if state == @state
++
++        case state
++        when UI_STATE_INVALID
++            @connect_frame.sensitive = true
++            @connect_button.sensitive = false
++
++            @state = UI_STATE_INVALID
++        when UI_STATE_VALID
++            @connect_frame.sensitive = true
++            @connect_button.sensitive = true
++
++            @state = UI_STATE_VALID
++        when UI_STATE_ACTIVATING
++            @connect_frame.sensitive = false
++            @connect_button.sensitive = false
++            @connect_error.text = ''
++
++            @state = UI_STATE_ACTIVATING
++        when UI_STATE_COMPLETE
++            # Activate the next page
++            @ui.active_page = 'conversion_win'
++
++            # ... then leave this one as we hope to find it if we come back here
++            set_state(UI_STATE_VALID)
++        else
++            raise "Attempt to set unexpected UI state: #{@state}"
++        end
++    end
++
++    def self.server_hostname_changed
++        event(EV_HOSTNAME, @hostname_ui.text.strip.length > 0)
++    end
++
++    def self.server_username_changed
++        event(EV_USERNAME, @username_ui.text.strip.length > 0)
++    end
++
++    def self.server_password_changed
++        event(EV_PASSWORD, @password_ui.text.length > 0)
++    end
++
++    def self.connect_button_clicked
++        event(EV_BUTTON, true)
++
++        hostname = @hostname_ui.text.strip
++        username = @username_ui.text.strip
++        password = @password_ui.text
++        connection = VirtP2V::Connection.new(hostname, username, password) \
++        { |result|
++            case result
++            when true
++                @converter.connection = connection
++                connection.connect { |result|
++                    case result
++                    when true
++                        event(EV_ACTIVATION, true)
++                    when VirtP2V::Connection::RemoteError
++                        @connect_error.text = _('Failed to start ' +
++                                                'virt-p2v-server on remote ' +
++                                                'server')
++                        event(EV_ACTIVATION, false)
++                    else
++                        @connect_error.text = result.message
++                        event(EV_ACTIVATION, false)
++                    end
++                }
++            when VirtP2V::Connection::InvalidHostnameError
++                @connect_error.text = _"Unable to connect to #{hostname}"
++                event(EV_ACTIVATION, false)
++            when VirtP2V::Connection::InvalidCredentialsError
++                @connect_error.text = _"Invalid username/password"
++                event(EV_ACTIVATION, false)
++            else
++                raise result
++            end
++        }
++    end
++
++end # module
+diff -ruN virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/ui/convert.rb virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/ui/convert.rb
+--- virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/ui/convert.rb	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/ui/convert.rb	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,422 @@
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++require 'gettext'
++require 'gtk2'
++
++require 'virt-p2v/blockdevice'
++require 'virt-p2v/netdevice'
++
++module VirtP2V::UI::Convert
++    include GetText
++
++    CONVERT_PROFILE_NAME    = 0
++
++    CONVERT_NETWORK_CONVERT = 0
++    CONVERT_NETWORK_DEVICE  = 1
++
++    CONVERT_FIXED_CONVERT   = 0
++    CONVERT_FIXED_DEVICE    = 1
++    CONVERT_FIXED_PROGRESS  = 2
++
++    CONVERT_REMOVABLE_CONVERT   = 0
++    CONVERT_REMOVABLE_DEVICE    = 1
++    CONVERT_REMOVABLE_TYPE      = 2
++
++    UI_STATE_INVALID    = 0
++    UI_STATE_VALID      = 1
++    UI_STATE_CONNECTING = 2
++    UI_STATE_CONVERTING = 3
++    UI_STATE_COMPLETE   = 4
++
++    EV_VALID        = 0
++    EV_BUTTON       = 1
++    EV_CONNECTION   = 2
++    EV_CONVERTED    = 3
++
++    def self.init(ui, converter)
++        # ListStores
++        @profiles   = ui.get_object('convert_profile_list')
++        @nics       = ui.get_object('convert_network_list')
++        @fixeds     = ui.get_object('convert_fixed_list')
++        @removables = ui.get_object('convert_removable_list')
++
++        # Widgets
++        @profile    = ui.get_object('convert_profile')
++        @name       = ui.get_object('convert_name')
++        @cpus       = ui.get_object('convert_cpus')
++        @memory     = ui.get_object('convert_memory')
++        @editable   = ui.get_object('convert_editable')
++        @button     = ui.get_object('convert_button')
++        @status     = ui.get_object('convert_status')
++
++        # Get initial values from converter
++        @name.text = converter.name
++        @cpus.text = converter.cpus.to_s
++        @memory.text = (converter.memory / 1024 / 1024).to_s
++
++        # Populate profiles on connection
++        converter.on_connection { |conn|
++            conn.on_connect { |cb|
++                conn.list_profiles { |profiles|
++                    cb.call(RuntimeError.new(_('Remote server does not ' +
++                                               'define any profiles in ' +
++                                               '/etc/virt-v2v.conf'))) \
++                        if profiles.kind_of?(Exception) or profiles.empty?
++
++                    selected = @profile.active_iter
++                    selected = selected[CONVERT_PROFILE_NAME] \
++                        unless selected.nil?
++
++                    @profiles.clear
++                    profiles.each { |i|
++                        profile = @profiles.append
++                        profile[CONVERT_PROFILE_NAME] = i
++                        @profile.active_iter = profile if i == selected
++                    }
++
++                    cb.call(true)
++                }
++            }
++        }
++
++        VirtP2V::FixedBlockDevice.all_devices.each { |dev|
++            fixed = @fixeds.append
++            fixed[CONVERT_FIXED_CONVERT]    = true
++            fixed[CONVERT_FIXED_DEVICE]     = dev.device
++            fixed[CONVERT_FIXED_PROGRESS]   = 0
++        }
++
++        VirtP2V::RemovableBlockDevice.all_devices.each { |dev|
++            rem = @removables.append
++            rem[CONVERT_REMOVABLE_CONVERT]  = true
++            rem[CONVERT_REMOVABLE_DEVICE]   = dev.device
++            rem[CONVERT_REMOVABLE_TYPE]     = dev.type
++        }
++
++        VirtP2V::NetworkDevice.all_devices.each { |dev|
++            nic = @nics.append
++            nic[CONVERT_NETWORK_CONVERT]    = dev.connected
++            nic[CONVERT_NETWORK_DEVICE]     = dev.name
++        }
++
++        # Event handlers
++        ui.register_handler('convert_profile_changed',
++                            method(:update_values))
++        ui.register_handler('convert_name_changed',
++                            method(:update_values))
++        ui.register_handler('convert_cpus_changed',
++                            method(:convert_cpus_changed))
++        ui.register_handler('convert_memory_changed',
++                            method(:convert_memory_changed))
++        ui.register_handler('convert_fixed_list_row_changed',
++                            method(:convert_fixed_list_row_changed))
++        ui.register_handler('convert_removable_list_row_changed',
++                            method(:update_values))
++        ui.register_handler('convert_network_list_row_changed',
++                            method(:update_values))
++        ui.register_handler('convert_fixed_select_toggled',
++                            method(:convert_fixed_select_toggled))
++        ui.register_handler('convert_removable_select_toggled',
++                            method(:convert_removable_select_toggled))
++        ui.register_handler('convert_network_select_toggled',
++                            method(:convert_network_select_toggled))
++        ui.register_handler('convert_button_clicked',
++                            method(:convert_button_clicked))
++
++        @state = nil
++        set_state(UI_STATE_INVALID)
++        update_values
++
++        @ui = ui
++        @converter = converter
++    end
++
++    def self.event(event, status)
++        case @state
++        when UI_STATE_INVALID
++            case event
++            when EV_VALID
++                set_state(UI_STATE_VALID) if status
++            else
++                raise "Unexpected event: #{@state} #{event}"
++            end
++        when UI_STATE_VALID
++            case event
++            when EV_VALID
++                set_state(UI_STATE_INVALID) if !status
++            when EV_BUTTON
++                if @converter.connection.connected then
++                    set_state(UI_STATE_CONVERTING)
++                    convert
++                else
++                    set_state(UI_STATE_CONNECTING)
++                    reconnect
++                end
++            else
++                raise "Unexpected event: #{@state} #{event}"
++            end
++        when UI_STATE_CONNECTING
++            case event
++            when EV_CONNECTION
++                if status then
++                    set_state(UI_STATE_CONVERTING)
++                    convert
++                else
++                    set_state(UI_STATE_VALID)
++                end
++            when EV_VALID
++                # update_values will be called when the profile list is cleared
++                # and repopulated during connection. Untidy, but ignore it.
++            else
++                raise "Unexpected event: #{@state} #{event}" \
++                    unless event == EV_CONNECTION
++            end
++        when UI_STATE_CONVERTING
++            case event
++            when EV_CONVERTED
++                if status then
++                    set_state(UI_STATE_COMPLETE)
++                else
++                    set_state(UI_STATE_VALID)
++                end
++            when EV_VALID
++                # update_values will be called when the list stores are updated.
++                # Untidy, but ignore it
++            else
++                raise "Unexpected event: #{@state} #{event}"
++            end
++        else
++            raise "Unexpected UI state: #{@state}"
++        end
++    end
++
++    def self.set_state(state)
++        # Don't do anything if state hasn't changed
++        return if state == @state
++        @state = state
++
++        case @state
++        when UI_STATE_INVALID
++            @editable.sensitive = true
++            @button.sensitive = false
++        when UI_STATE_VALID
++            @editable.sensitive = true
++            @button.sensitive = true
++        when UI_STATE_CONNECTING
++            @status.text = _'Failed to start virt-p2v-server on remote server'
++            @editable.sensitive = false
++            @button.sensitive = false
++        when UI_STATE_CONVERTING
++            @editable.sensitive = false
++            @button.sensitive = false
++        when UI_STATE_COMPLETE
++            @ui.active_page = 'success_win'
++
++            # ... then leave this one as we hope to find it if we come back here
++            set_state(UI_STATE_VALID)
++        else
++            raise "Attempt to set unexpected UI state: #{@state}"
++        end
++    end
++
++    def self.convert
++        @converter.convert(
++            # status
++            lambda { |msg|
++                @status.text = msg
++            },
++            # progress
++            lambda { |dev, progress|
++                @fixeds.each { |model, path, iter|
++                    next unless iter[CONVERT_FIXED_DEVICE] == dev
++
++                    iter[CONVERT_FIXED_PROGRESS] = progress
++                    break
++                }
++            }
++        ) { |result|
++            # N.B. Explicit test against true is required here, as result may be
++            # an Exception, which would also return true if evaluated alone
++            if result == true then
++                @status.text = ''
++                event(EV_CONVERTED, true)
++            else
++                @status.text = result.message
++                event(EV_CONVERTED, false)
++            end
++        }
++    end
++
++    def self.reconnect
++        @status.text = _('Reconnecting')
++        @converter.connection.connect { |result|
++            if result == true then
++                event(EV_CONNECTION, true)
++            else
++                @status.text =
++                    _'Failed to start virt-p2v-server on remote server'
++                event(EV_CONNECTION, false)
++            end
++        }
++    end
++
++    def self.convert_fixed_list_row_changed(model, path, iter)
++        update_values
++    end
++
++    class InvalidUIState < StandardError; end
++
++    def self.update_values
++        valid = nil
++        begin
++            # Check there's a profile selected
++            profile = @profile.active_iter
++            raise InvalidUIState if profile.nil?
++            @converter.profile = profile[CONVERT_PROFILE_NAME]
++
++            # Check there's a name set
++            name = @name.text
++            raise InvalidUIState if name.nil? || name.strip.length == 0
++            @converter.name = name
++
++            # Check cpus and memory are set and numeric
++            cpus = @cpus.text
++            raise InvalidUIState if cpus.nil?
++            cpus = Integer(cpus) rescue nil
++            raise InvalidUIState if cpus.nil?
++            @converter.cpus = cpus
++
++            memory = @memory.text
++            raise InvalidUIState if memory.nil?
++            memory = Integer(memory) rescue nil
++            raise InvalidUIState if memory.nil?
++            @converter.memory = memory * 1024 * 1024
++
++            # Check that at least 1 fixed storage device is selected
++            fixed = false
++            @converter.disks.clear
++            @fixeds.each { |model, path, iter|
++                if iter[CONVERT_FIXED_CONVERT] then
++                    fixed = true
++                    @converter.disks << iter[CONVERT_FIXED_DEVICE]
++                end
++            }
++            raise InvalidUIState unless fixed
++
++            # Populate removables and nics, although these aren't required to be
++            # selected for the ui state to be valid
++            @converter.removables.clear
++            @removables.each { |model, path, iter|
++                if iter[CONVERT_REMOVABLE_CONVERT] then
++                    @converter.removables << iter[CONVERT_REMOVABLE_DEVICE]
++                end
++            }
++            @converter.nics.clear
++            @nics.each { |model, path, iter|
++                if iter[CONVERT_NETWORK_CONVERT] then
++                    @converter.nics << iter[CONVERT_NETWORK_DEVICE]
++                end
++            }
++        rescue InvalidUIState
++            valid = false
++        end
++        valid = true if valid.nil?
++
++        event(EV_VALID, valid)
++    end
++
++    def self.valid?
++        # Check there's a profile selected
++        profile = @profile.active_iter
++        return false if profile.nil?
++
++        # Check there's a name set
++        name = @name.text
++        return false if name.nil?
++        return false unless name.strip.length > 0
++
++        # Check cpus and memory are set and numeric
++        cpus = @cpus.text
++        return false if cpus.nil?
++        cpus = Integer(cpus) rescue nil
++        return false if cpus.nil?
++
++        memory = @memory.text
++        return false if memory.nil?
++        memory = Integer(memory) rescue nil
++        return false if memory.nil?
++
++        # Check that at least 1 fixed storage device is selected
++        fixed = false
++        @fixeds.each { |model, path, iter|
++            if iter[CONVERT_FIXED_CONVERT] then
++                fixed = true
++                break
++            end
++        }
++        return false unless fixed
++
++        return true
++    end
++
++    def self.convert_cpus_changed
++        check_numeric(@cpus)
++    end
++
++    def self.convert_memory_changed
++        check_numeric(@memory)
++    end
++
++    def self.check_numeric(widget)
++        value = widget.text
++        if value.nil? ? false : begin
++            value = Integer(value)
++            value > 0
++        rescue
++            false
++        end
++        then
++            widget.secondary_icon_name = nil
++        else
++            widget.secondary_icon_name = 'gtk-dialog-warning'
++            widget.secondary_icon_tooltip_text =
++                _('Value must be an integer greater than 0')
++        end
++
++        update_values
++    end
++
++    def self.convert_fixed_select_toggled(widget, path)
++        iter = @fixeds.get_iter(path)
++        iter[CONVERT_FIXED_CONVERT] = !iter[CONVERT_FIXED_CONVERT]
++    end
++
++    def self.convert_removable_select_toggled(widget, path)
++        iter = @removables.get_iter(path)
++        iter[CONVERT_REMOVABLE_CONVERT] = !iter[CONVERT_REMOVABLE_CONVERT]
++    end
++
++    def self.convert_network_select_toggled(widget, path)
++        iter = @nics.get_iter(path)
++        iter[CONVERT_NETWORK_CONVERT] = !iter[CONVERT_NETWORK_CONVERT]
++    end
++
++    def self.convert_button_clicked
++        event(EV_BUTTON, true)
++    end
++
++end # module
+diff -ruN virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/ui/main.rb virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/ui/main.rb
+--- virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/ui/main.rb	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/ui/main.rb	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,110 @@
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++require 'gtk2'
++require 'virt-p2v/gtk-queue'
++
++module VirtP2V
++module UI
++
++class Main
++    def get_object(name)
++        o = @builder.get_object(name)
++        raise "Object #{name} not found in ui" unless o != nil
++
++        return o
++    end
++
++    def show
++        @builder.connect_signals { |signal|
++            raise "No hander for signal #{signal}" \
++                unless @signal_handlers.has_key?(signal)
++
++            @signal_handlers[signal]
++        }
++
++        # Display the main window
++        main = self.get_object('main_window')
++        main.show_all()
++    end
++
++    def register_handler(signal, handler)
++        @signal_handlers[signal] = handler
++    end
++
++    def main_loop
++        Gtk.main_with_queue 100
++    end
++
++    def active_page=(name)
++        raise "Attempt to activate non-existent page #{name}" \
++            unless @pages.has_key?(name)
++
++        page = @pages[name]
++
++        @page_vbox = self.get_object('page_vbox') unless defined? @page_vbox
++        @page_vbox.remove(@selected) if defined? @selected
++        @page_vbox.add(page)
++        @selected = page
++    end
++
++    def active_page
++        return @selected
++    end
++
++    def quit
++        Gtk.main_quit()
++    end
++
++    private
++
++    def initialize
++        @builder = Gtk::Builder.new()
++
++        # Find the UI definition in $LOAD_PATH
++        i = $LOAD_PATH.index { |path|
++            File.exists?(path + '/virt-p2v/ui/p2v.ui')
++        }
++        @builder.add_from_file($LOAD_PATH[i] + '/virt-p2v/ui/p2v.ui')
++
++        @signal_handlers = {}
++        self.register_handler('gtk_main_quit', method(:quit))
++
++        # Configure the Wizard page frame
++        # Can't change these colours from glade for some reason
++        self.get_object('title_background').
++           modify_bg(Gtk::STATE_NORMAL, Gdk::Color.parse('#86ABD9'))
++        self.get_object('page_frame').
++           modify_fg(Gtk::STATE_NORMAL, Gdk::Color.parse('#86ABD9'))
++
++        # Load all pages from glade
++        @pages = {}
++        [ 'network_win', 'server_win',
++          'conversion_win', 'success_win' ].each { |name|
++            page = self.get_object(name)
++
++            child = page.children[0]
++            page.remove(child)
++            @pages[name] = child
++        }
++
++        # Set a default first page
++        self.active_page = 'network_win'
++    end
++end
++
++end # UI
++end # VirtP2V
+diff -ruN virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/ui/network.rb virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/ui/network.rb
+--- virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/ui/network.rb	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/ui/network.rb	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,317 @@
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++require 'gettext'
++require 'gtk2'
++require 'ipaddr'
++require 'virt-p2v/netdevice'
++
++module VirtP2V::UI::Network
++    include GetText
++
++    # The indices of Device List colums, taken from glade
++    DEVCOL_NAME      = 0
++    DEVCOL_MAC       = 1
++    DEVCOL_STATUS    = 2
++    DEVCOL_AVAILABLE = 3
++
++    UI_STATE_INVALID    = 0
++    UI_STATE_VALID      = 1
++    UI_STATE_ACTIVATING = 2
++    UI_STATE_COMPLETE   = 3
++
++    EV_IP_CONFIG    = 0
++    EV_SELECTION    = 1
++    EV_BUTTON       = 2
++    EV_ACTIVATION   = 3
++
++    def self.event(event, status)
++        case event
++        when EV_IP_CONFIG
++            @ip_config = status
++        when EV_SELECTION
++            @selected = status
++        when EV_BUTTON, EV_ACTIVATION
++            # Persistent state not required
++        else
++            raise "Unexpected NetworkConfig event: #{event}"
++        end
++
++        case @state
++        when UI_STATE_INVALID
++            if @ip_config && @selected then
++                set_state(UI_STATE_VALID)
++            end
++        when UI_STATE_VALID
++            if !@ip_config || !@selected then
++                set_state(UI_STATE_INVALID)
++            elsif event == EV_BUTTON
++                set_state(UI_STATE_ACTIVATING)
++            end
++        when UI_STATE_ACTIVATING
++            # UI is disabled and we're waiting for EV_ACTIVATION, but we could
++            # also get events triggered by NetworkManager signals.
++
++            if event == EV_ACTIVATION then
++                if status then
++                    set_state(UI_STATE_COMPLETE)
++                else
++                    set_state(UI_STATE_VALID)
++                end
++            elsif !@ip_config || !@selected then
++                set_state(UI_STATE_INVALID)
++            end
++        else
++            raise "Unexpected NetworkConfig UI state: #{@state}"
++        end
++    end
++
++    def self.init(ui)
++        # Configure initial defaults
++        @manual_mode = false
++        @ip_address = nil
++        @ip_prefix = nil
++        @ip_gateway = nil
++        @ip_dns = nil
++        @state = UI_STATE_INVALID
++        @ip_config = false
++        @selected = false
++
++        @network_button     = ui.get_object('network_button')
++        @device_list_frame  = ui.get_object('device_list_frame')
++        @ipv4_config_frame  = ui.get_object('ipv4_config_frame')
++        @dl_selection       = ui.get_object('network_device_list_view').
++                              selection
++        @device_list        = ui.get_object('network_device_list')
++        @manual_ui          = ui.get_object('ip_manual')
++        @ip_address_ui      = ui.get_object('ip_address')
++        @ip_prefix_ui       = ui.get_object('ip_prefix')
++        @ip_gateway_ui      = ui.get_object('ip_gateway')
++        @ip_dns_ui          = ui.get_object('ip_dns')
++
++        ui.register_handler('network_button_clicked',
++                            method(:network_button_clicked))
++        ui.register_handler('ip_auto_toggled',
++                            method(:ip_auto_toggled))
++        ui.register_handler('ip_address_changed',
++                            method(:ip_address_changed))
++        ui.register_handler('ip_prefix_changed',
++                            method(:ip_prefix_changed))
++        ui.register_handler('ip_gateway_changed',
++                            method(:ip_gateway_changed))
++        ui.register_handler('ip_dns_changed',
++                            method(:ip_dns_changed))
++
++        check_config_valid()
++
++        # The user may only select a single device
++        @dl_selection.mode = Gtk::SELECTION_SINGLE
++
++        @dl_selection.set_select_function { |selection, model, path, current|
++            iter = model.get_iter(path)
++
++            # This is a toggle event. The new state is the opposite of the
++            # current state
++            new_state = !current
++
++            # Don't allow the user to select an unavailable device
++            if new_state then
++                # Notify the config UI if we're selecting a device
++                if iter[DEVCOL_AVAILABLE] then
++                    event(EV_SELECTION, true)
++                end
++
++                iter[DEVCOL_AVAILABLE]
++
++            # Always allow the user to unselect a device
++            else
++                # Notify the UI that we're unselecting the device
++                event(EV_SELECTION, false)
++                true
++            end
++        }
++
++        # Store a map of device names to row references
++        refs = {}
++
++        # Populate the device list with all detected network devices
++        VirtP2V::NetworkDevice.all_devices.each { |device|
++            iter = @device_list.append()
++
++            iter[DEVCOL_NAME]       = device.name
++            iter[DEVCOL_MAC]        = device.mac
++            iter[DEVCOL_STATUS]     = device.state
++            iter[DEVCOL_AVAILABLE]  = device.connected
++
++            # Store a stable reference to this row in the TreeModel
++            refs[device.name] =
++                Gtk::TreeRowReference.new(@device_list, iter.path)
++        }
++
++        # Listen for updates to device states
++        VirtP2V::NetworkDevice.add_listener( lambda { |device|
++            path = refs[device.name].path
++
++            iter = @device_list.get_iter(path)
++            iter[DEVCOL_STATUS]     = device.state
++            iter[DEVCOL_AVAILABLE]  = device.connected
++
++            # Notify the UI that a device was activated
++            event(EV_ACTIVATION, device.activated) \
++                unless device.activated.nil?
++
++            # Unselect the path if it was previously selected and is no
++            # longer available
++            if !device.connected && @dl_selection.iter_is_selected?(iter)
++            then
++                @dl_selection.unselect_all()
++                event(EV_SELECTION, false)
++            end
++        } )
++
++        @ui = ui
++    end
++
++    def self.set_state(state)
++        # Don't do anything if state hasn't changed
++        return if state == @state
++
++        case state
++        when UI_STATE_INVALID
++            @network_button.sensitive = false
++            @device_list_frame.sensitive = true
++            @ipv4_config_frame.sensitive = true
++
++            @state = UI_STATE_INVALID
++        when UI_STATE_VALID
++            @network_button.sensitive = true
++            @device_list_frame.sensitive = true
++            @ipv4_config_frame.sensitive = true
++
++            @state = UI_STATE_VALID
++        when UI_STATE_ACTIVATING
++            @network_button.sensitive = false
++            @device_list_frame.sensitive = false
++            @ipv4_config_frame.sensitive = false
++
++            @state = UI_STATE_ACTIVATING
++        when UI_STATE_COMPLETE
++            # Activate the next page
++            @ui.active_page = 'server_win'
++
++            # ... then leave this one as we hope to find it if we come back here
++            set_state(UI_STATE_VALID)
++        else
++            raise "Attempt to set unexected NetworkConfig UI state: #{@state}"
++        end
++    end
++
++    def self.network_button_clicked
++        event(EV_BUTTON, true)
++
++        iter = @dl_selection.selected
++        return if iter.nil? # Shouldn't be possible
++        name = iter[DEVCOL_NAME]
++
++        VirtP2V::NetworkDevice[name].activate(!@manual_mode, @ip_address,
++                                              @ip_prefix, @ip_gateway, @ip_dns)
++    end
++
++    def self.ip_auto_toggled
++        @manual_mode = !@manual_mode
++        @manual_ui.sensitive = @manual_mode
++
++        check_config_valid()
++    end
++
++    def self.ip_address_changed
++        @ip_address = parse_ip(@ip_address_ui)
++
++        check_config_valid()
++    end
++
++    # Check IP prefix is a positive integer
++    # We check that it's appropriate to the address class in use elsewhere
++    def self.ip_prefix_changed
++        begin
++            @ip_prefix = Integer(@ip_prefix_ui.text)
++        rescue ArgumentError => e
++            # Ignore the result if it didn't parse
++            @ip_prefix = nil
++            return
++        end
++
++        if @ip_prefix < 0 then
++            @ip_prefix = nil
++        end
++
++        check_config_valid()
++    end
++
++    def self.ip_gateway_changed
++        @ip_gateway = parse_ip(@ip_gateway_ui)
++
++        check_config_valid()
++    end
++
++    # Parse an IP address understood by IPAddr
++    def self.parse_ip(entry)
++        a = entry.text.strip
++
++        begin
++            ip = IPAddr.new(a)
++        rescue ArgumentError => e
++            # Ignore the result if it didn't parse
++            ip = nil
++        end
++
++        return ip
++    end
++
++    def self.ip_dns_changed
++        dns = @ip_dns_ui.text
++
++        @ip_dns = []
++        dns.split(/\s*,+\s*/).each { |entry|
++            begin
++                @ip_dns << IPAddr.new(entry)
++            rescue ArgumentError => e
++                @ip_dns = ()
++                break
++            end
++        }
++    end
++
++    def self.check_config_valid
++        if !@manual_mode || (!@ip_address.nil? &&
++                             !@ip_prefix.nil? &&
++                             !@ip_gateway.nil?) then
++            if @manual_mode then
++                # Check that IPv4/IPv6 is used consistently
++                if @ip_address.ipv4? then
++                    event(EV_IP_CONFIG, @ip_gateway.ipv4? && @ip_prefix < 32)
++                else
++                    event(EV_IP_CONFIG, @ip_gateway.ipv6? && @ip_prefix < 128)
++                end
++            else
++                event(EV_IP_CONFIG, true)
++            end
++        else
++            event(EV_IP_CONFIG, false)
++        end
++    end
++
++end # module
+diff -ruN virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/ui/p2v.ui virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/ui/p2v.ui
+--- virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/ui/p2v.ui	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/ui/p2v.ui	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,1031 @@
++<?xml version="1.0"?>
++<interface>
++  <requires lib="gtk+" version="2.16"/>
++  <!-- interface-naming-policy project-wide -->
++  <object class="GtkWindow" id="main_window">
++    <property name="resizable">False</property>
++    <property name="window_position">center-always</property>
++    <property name="decorated">False</property>
++    <signal name="destroy" handler="gtk_main_quit"/>
++    <child>
++      <object class="GtkAlignment" id="alignment2">
++        <property name="visible">True</property>
++        <property name="xscale">0</property>
++        <property name="yscale">0</property>
++        <child>
++          <object class="GtkFrame" id="page_frame">
++            <property name="width_request">800</property>
++            <property name="height_request">600</property>
++            <property name="visible">True</property>
++            <property name="label_xalign">0</property>
++            <property name="label_yalign">0</property>
++            <property name="shadow_type">in</property>
++            <child>
++              <object class="GtkVBox" id="page_vbox">
++                <property name="visible">True</property>
++                <property name="orientation">vertical</property>
++                <property name="spacing">2</property>
++                <child>
++                  <object class="GtkEventBox" id="title_background">
++                    <property name="visible">True</property>
++                    <child>
++                      <object class="GtkLabel" id="title_label">
++                        <property name="visible">True</property>
++                        <property name="xalign">0</property>
++                        <property name="yalign">0</property>
++                        <property name="xpad">5</property>
++                        <property name="ypad">5</property>
++                        <property name="label">&lt;span weight='bold' foreground='white' size='xx-large'&gt;virt-p2v&lt;/span&gt;</property>
++                        <property name="use_markup">True</property>
++                      </object>
++                    </child>
++                  </object>
++                  <packing>
++                    <property name="expand">False</property>
++                    <property name="position">0</property>
++                  </packing>
++                </child>
++                <child>
++                  <placeholder/>
++                </child>
++              </object>
++            </child>
++            <child type="label_item">
++              <placeholder/>
++            </child>
++          </object>
++        </child>
++      </object>
++    </child>
++  </object>
++  <object class="GtkListStore" id="network_device_list">
++    <columns>
++      <!-- column-name Name -->
++      <column type="gchararray"/>
++      <!-- column-name MAC -->
++      <column type="gchararray"/>
++      <!-- column-name Status -->
++      <column type="gchararray"/>
++      <!-- column-name Available -->
++      <column type="gboolean"/>
++    </columns>
++  </object>
++  <object class="GtkListStore" id="convert_network_list">
++    <columns>
++      <!-- column-name Convert -->
++      <column type="gboolean"/>
++      <!-- column-name Device -->
++      <column type="gchararray"/>
++    </columns>
++    <signal name="row_changed" handler="convert_network_list_row_changed"/>
++  </object>
++  <object class="GtkListStore" id="convert_fixed_list">
++    <columns>
++      <!-- column-name Convert -->
++      <column type="gboolean"/>
++      <!-- column-name Device -->
++      <column type="gchararray"/>
++      <!-- column-name Progress -->
++      <column type="gdouble"/>
++    </columns>
++    <signal name="row_changed" handler="convert_fixed_list_row_changed"/>
++  </object>
++  <object class="GtkListStore" id="convert_removable_list">
++    <columns>
++      <!-- column-name Convert -->
++      <column type="gboolean"/>
++      <!-- column-name Device -->
++      <column type="gchararray"/>
++      <!-- column-name Type -->
++      <column type="gchararray"/>
++    </columns>
++    <signal name="row_changed" handler="convert_removable_list_row_changed"/>
++  </object>
++  <object class="GtkListStore" id="convert_profile_list">
++    <columns>
++      <!-- column-name Name -->
++      <column type="gchararray"/>
++    </columns>
++  </object>
++  <object class="GtkWindow" id="network_win">
++    <property name="width_request">800</property>
++    <property name="height_request">550</property>
++    <child>
++      <object class="GtkVBox" id="vbox1">
++        <property name="visible">True</property>
++        <property name="orientation">vertical</property>
++        <child>
++          <object class="GtkLabel" id="label1">
++            <property name="visible">True</property>
++            <property name="xalign">0</property>
++            <property name="yalign">1</property>
++            <property name="ypad">11</property>
++            <property name="label" translatable="yes">Welcome to virt-p2v.</property>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="position">0</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkFrame" id="device_list_frame">
++            <property name="visible">True</property>
++            <property name="label_xalign">0</property>
++            <property name="shadow_type">out</property>
++            <child>
++              <object class="GtkScrolledWindow" id="scrolledwindow1">
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <property name="hscrollbar_policy">automatic</property>
++                <property name="vscrollbar_policy">automatic</property>
++                <child>
++                  <object class="GtkTreeView" id="network_device_list_view">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <property name="model">network_device_list</property>
++                    <property name="headers_clickable">False</property>
++                    <property name="search_column">0</property>
++                    <child>
++                      <object class="GtkTreeViewColumn" id="treeviewcolumn1">
++                        <property name="title">Device</property>
++                        <child>
++                          <object class="GtkCellRendererText" id="cellrenderertext1"/>
++                          <attributes>
++                            <attribute name="sensitive">3</attribute>
++                            <attribute name="text">0</attribute>
++                          </attributes>
++                        </child>
++                      </object>
++                    </child>
++                    <child>
++                      <object class="GtkTreeViewColumn" id="treeviewcolumn3">
++                        <property name="fixed_width">18</property>
++                        <property name="title">MAC Address</property>
++                        <child>
++                          <object class="GtkCellRendererText" id="cellrenderertext3"/>
++                          <attributes>
++                            <attribute name="sensitive">3</attribute>
++                            <attribute name="text">1</attribute>
++                          </attributes>
++                        </child>
++                      </object>
++                    </child>
++                    <child>
++                      <object class="GtkTreeViewColumn" id="treeviewcolumn2">
++                        <property name="title">Status</property>
++                        <child>
++                          <object class="GtkCellRendererText" id="cellrenderertext2"/>
++                          <attributes>
++                            <attribute name="sensitive">3</attribute>
++                            <attribute name="text">2</attribute>
++                          </attributes>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child type="label">
++              <object class="GtkLabel" id="label5">
++                <property name="visible">True</property>
++                <property name="label" translatable="yes">&lt;b&gt;Select a network device&lt;/b&gt;</property>
++                <property name="use_markup">True</property>
++              </object>
++            </child>
++          </object>
++          <packing>
++            <property name="position">1</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkFrame" id="ipv4_config_frame">
++            <property name="visible">True</property>
++            <property name="label_xalign">0</property>
++            <property name="shadow_type">in</property>
++            <child>
++              <object class="GtkAlignment" id="alignment1">
++                <property name="visible">True</property>
++                <property name="left_padding">12</property>
++                <child>
++                  <object class="GtkVBox" id="vbox2">
++                    <property name="visible">True</property>
++                    <property name="orientation">vertical</property>
++                    <child>
++                      <object class="GtkCheckButton" id="ip_auto">
++                        <property name="label" translatable="yes">Automatic configuration</property>
++                        <property name="visible">True</property>
++                        <property name="can_focus">True</property>
++                        <property name="receives_default">False</property>
++                        <property name="active">True</property>
++                        <property name="draw_indicator">True</property>
++                        <signal name="toggled" handler="ip_auto_toggled"/>
++                      </object>
++                      <packing>
++                        <property name="position">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkTable" id="ip_manual">
++                        <property name="visible">True</property>
++                        <property name="sensitive">False</property>
++                        <property name="n_rows">3</property>
++                        <property name="n_columns">2</property>
++                        <property name="column_spacing">2</property>
++                        <child>
++                          <object class="GtkLabel" id="label3">
++                            <property name="visible">True</property>
++                            <property name="xalign">0</property>
++                            <property name="label" translatable="yes">IP Address:</property>
++                          </object>
++                          <packing>
++                            <property name="x_options">GTK_FILL</property>
++                            <property name="y_options">GTK_FILL</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="label8">
++                            <property name="visible">True</property>
++                            <property name="xalign">0</property>
++                            <property name="label" translatable="yes">Gateway:</property>
++                          </object>
++                          <packing>
++                            <property name="top_attach">1</property>
++                            <property name="bottom_attach">2</property>
++                            <property name="x_options">GTK_FILL</property>
++                            <property name="y_options">GTK_FILL</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="label4">
++                            <property name="visible">True</property>
++                            <property name="xalign">0</property>
++                            <property name="label" translatable="yes">DNS Servers:</property>
++                          </object>
++                          <packing>
++                            <property name="top_attach">2</property>
++                            <property name="bottom_attach">3</property>
++                            <property name="x_options">GTK_FILL</property>
++                            <property name="y_options">GTK_FILL</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkEntry" id="ip_gateway">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="max_length">39</property>
++                            <property name="width_chars">39</property>
++                            <property name="truncate_multiline">True</property>
++                            <signal name="changed" handler="ip_gateway_changed"/>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="right_attach">2</property>
++                            <property name="top_attach">1</property>
++                            <property name="bottom_attach">2</property>
++                            <property name="y_options">GTK_FILL</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkEntry" id="ip_dns">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="width_chars">35</property>
++                            <signal name="changed" handler="ip_dns_changed"/>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="right_attach">2</property>
++                            <property name="top_attach">2</property>
++                            <property name="bottom_attach">3</property>
++                            <property name="y_options">GTK_FILL</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkHBox" id="hbox6">
++                            <property name="visible">True</property>
++                            <property name="spacing">2</property>
++                            <child>
++                              <object class="GtkEntry" id="ip_address">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="max_length">39</property>
++                                <property name="width_chars">39</property>
++                                <property name="truncate_multiline">True</property>
++                                <signal name="changed" handler="ip_address_changed"/>
++                              </object>
++                              <packing>
++                                <property name="position">0</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkLabel" id="label7">
++                                <property name="visible">True</property>
++                                <property name="xalign">0</property>
++                                <property name="label" translatable="yes">Prefix:</property>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="position">1</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkEntry" id="ip_prefix">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="max_length">2</property>
++                                <property name="width_chars">2</property>
++                                <property name="truncate_multiline">True</property>
++                                <signal name="changed" handler="ip_prefix_changed"/>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="position">2</property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="right_attach">2</property>
++                            <property name="y_options">GTK_FILL</property>
++                          </packing>
++                        </child>
++                      </object>
++                      <packing>
++                        <property name="position">1</property>
++                      </packing>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child type="label">
++              <object class="GtkLabel" id="label2">
++                <property name="visible">True</property>
++                <property name="label" translatable="yes">&lt;b&gt;IP Configuration&lt;/b&gt;</property>
++                <property name="use_markup">True</property>
++              </object>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="position">2</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkAlignment" id="alignment3">
++            <property name="visible">True</property>
++            <property name="xalign">1</property>
++            <property name="xscale">0</property>
++            <child>
++              <object class="GtkButton" id="network_button">
++                <property name="label" translatable="yes">Use these network settings</property>
++                <property name="visible">True</property>
++                <property name="sensitive">False</property>
++                <property name="can_focus">True</property>
++                <property name="receives_default">True</property>
++                <signal name="clicked" handler="network_button_clicked"/>
++              </object>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="position">3</property>
++          </packing>
++        </child>
++      </object>
++    </child>
++  </object>
++  <object class="GtkWindow" id="server_win">
++    <child>
++      <object class="GtkVBox" id="vbox3">
++        <property name="visible">True</property>
++        <property name="orientation">vertical</property>
++        <child>
++          <object class="GtkAlignment" id="alignment4">
++            <property name="visible">True</property>
++            <property name="xscale">0</property>
++            <property name="yscale">0</property>
++            <child>
++              <object class="GtkFrame" id="connect_frame">
++                <property name="visible">True</property>
++                <property name="label_xalign">0</property>
++                <property name="shadow_type">in</property>
++                <child>
++                  <object class="GtkAlignment" id="alignment9">
++                    <property name="visible">True</property>
++                    <property name="left_padding">12</property>
++                    <child>
++                      <object class="GtkVBox" id="vbox5">
++                        <property name="visible">True</property>
++                        <property name="orientation">vertical</property>
++                        <child>
++                          <object class="GtkTable" id="table1">
++                            <property name="visible">True</property>
++                            <property name="n_rows">3</property>
++                            <property name="n_columns">2</property>
++                            <property name="column_spacing">2</property>
++                            <child>
++                              <object class="GtkLabel" id="label9">
++                                <property name="visible">True</property>
++                                <property name="xalign">0</property>
++                                <property name="label" translatable="yes">Hostname:</property>
++                              </object>
++                              <packing>
++                                <property name="x_options"></property>
++                                <property name="y_options"></property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkLabel" id="label10">
++                                <property name="visible">True</property>
++                                <property name="xalign">0</property>
++                                <property name="label" translatable="yes">Username:</property>
++                              </object>
++                              <packing>
++                                <property name="top_attach">1</property>
++                                <property name="bottom_attach">2</property>
++                                <property name="x_options"></property>
++                                <property name="y_options"></property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkLabel" id="label11">
++                                <property name="visible">True</property>
++                                <property name="xalign">0</property>
++                                <property name="label" translatable="yes">Password:</property>
++                              </object>
++                              <packing>
++                                <property name="top_attach">2</property>
++                                <property name="bottom_attach">3</property>
++                                <property name="x_options"></property>
++                                <property name="y_options"></property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkEntry" id="server_hostname">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="invisible_char">&#x2022;</property>
++                                <property name="width_chars">40</property>
++                                <signal name="changed" handler="server_hostname_changed"/>
++                              </object>
++                              <packing>
++                                <property name="left_attach">1</property>
++                                <property name="right_attach">2</property>
++                                <property name="y_options"></property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkEntry" id="server_password">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="visibility">False</property>
++                                <property name="invisible_char">&#x2022;</property>
++                                <property name="width_chars">40</property>
++                                <signal name="changed" handler="server_password_changed"/>
++                              </object>
++                              <packing>
++                                <property name="left_attach">1</property>
++                                <property name="right_attach">2</property>
++                                <property name="top_attach">2</property>
++                                <property name="bottom_attach">3</property>
++                                <property name="y_options"></property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkEntry" id="server_username">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="invisible_char">&#x2022;</property>
++                                <property name="width_chars">40</property>
++                                <property name="text" translatable="yes">root</property>
++                                <signal name="changed" handler="server_username_changed"/>
++                              </object>
++                              <packing>
++                                <property name="left_attach">1</property>
++                                <property name="right_attach">2</property>
++                                <property name="top_attach">1</property>
++                                <property name="bottom_attach">2</property>
++                                <property name="y_options"></property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="position">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="connect_error">
++                            <property name="visible">True</property>
++                            <property name="xalign">0</property>
++                            <property name="yalign">0</property>
++                            <property name="xpad">8</property>
++                            <property name="ypad">8</property>
++                            <attributes>
++                              <attribute name="foreground" value="#ffff00000000"/>
++                            </attributes>
++                          </object>
++                          <packing>
++                            <property name="position">1</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++                <child type="label">
++                  <object class="GtkLabel" id="label6">
++                    <property name="visible">True</property>
++                    <property name="label" translatable="yes">&lt;b&gt;Connect to conversion server&lt;/b&gt;</property>
++                    <property name="use_markup">True</property>
++                  </object>
++                </child>
++              </object>
++            </child>
++          </object>
++          <packing>
++            <property name="position">0</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkAlignment" id="alignment5">
++            <property name="visible">True</property>
++            <property name="xalign">1</property>
++            <property name="yalign">0</property>
++            <property name="xscale">0</property>
++            <property name="yscale">0</property>
++            <child>
++              <object class="GtkButton" id="connect_button">
++                <property name="label" translatable="yes">Connect</property>
++                <property name="visible">True</property>
++                <property name="sensitive">False</property>
++                <property name="can_focus">True</property>
++                <property name="receives_default">True</property>
++                <signal name="clicked" handler="connect_button_clicked"/>
++              </object>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="position">1</property>
++          </packing>
++        </child>
++      </object>
++    </child>
++  </object>
++  <object class="GtkWindow" id="conversion_win">
++    <child>
++      <object class="GtkVBox" id="vbox4">
++        <property name="visible">True</property>
++        <property name="orientation">vertical</property>
++        <child>
++          <object class="GtkHBox" id="convert_editable">
++            <property name="visible">True</property>
++            <child>
++              <object class="GtkFrame" id="frame2">
++                <property name="visible">True</property>
++                <property name="label_xalign">0</property>
++                <property name="shadow_type">out</property>
++                <child>
++                  <object class="GtkAlignment" id="alignment6">
++                    <property name="visible">True</property>
++                    <property name="xalign">0</property>
++                    <property name="yalign">0</property>
++                    <property name="xscale">0</property>
++                    <property name="yscale">0</property>
++                    <property name="left_padding">12</property>
++                    <child>
++                      <object class="GtkTable" id="table2">
++                        <property name="visible">True</property>
++                        <property name="n_rows">4</property>
++                        <property name="n_columns">2</property>
++                        <property name="column_spacing">2</property>
++                        <child>
++                          <object class="GtkLabel" id="label14">
++                            <property name="visible">True</property>
++                            <property name="xalign">0</property>
++                            <property name="label" translatable="yes">Destination Profile:</property>
++                          </object>
++                        </child>
++                        <child>
++                          <object class="GtkComboBox" id="convert_profile">
++                            <property name="visible">True</property>
++                            <property name="model">convert_profile_list</property>
++                            <signal name="changed" handler="convert_profile_changed"/>
++                            <child>
++                              <object class="GtkCellRendererText" id="cellrenderertext8"/>
++                              <attributes>
++                                <attribute name="text">0</attribute>
++                              </attributes>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="right_attach">2</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="label16">
++                            <property name="visible">True</property>
++                            <property name="xalign">0</property>
++                            <property name="label" translatable="yes">Memory (MB):</property>
++                          </object>
++                          <packing>
++                            <property name="top_attach">3</property>
++                            <property name="bottom_attach">4</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkEntry" id="convert_memory">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="invisible_char">&#x2022;</property>
++                            <property name="truncate_multiline">True</property>
++                            <signal name="changed" handler="convert_memory_changed"/>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="right_attach">2</property>
++                            <property name="top_attach">3</property>
++                            <property name="bottom_attach">4</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="label15">
++                            <property name="visible">True</property>
++                            <property name="xalign">0</property>
++                            <property name="label" translatable="yes">Number of CPUs:</property>
++                          </object>
++                          <packing>
++                            <property name="top_attach">2</property>
++                            <property name="bottom_attach">3</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="label18">
++                            <property name="visible">True</property>
++                            <property name="xalign">0</property>
++                            <property name="label" translatable="yes">Name</property>
++                          </object>
++                          <packing>
++                            <property name="top_attach">1</property>
++                            <property name="bottom_attach">2</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkEntry" id="convert_name">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="invisible_char">&#x2022;</property>
++                            <property name="truncate_multiline">True</property>
++                            <signal name="changed" handler="convert_name_changed"/>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="right_attach">2</property>
++                            <property name="top_attach">1</property>
++                            <property name="bottom_attach">2</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkEntry" id="convert_cpus">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="invisible_char">&#x2022;</property>
++                            <property name="truncate_multiline">True</property>
++                            <signal name="changed" handler="convert_cpus_changed"/>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="right_attach">2</property>
++                            <property name="top_attach">2</property>
++                            <property name="bottom_attach">3</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++                <child type="label">
++                  <object class="GtkLabel" id="label13">
++                    <property name="visible">True</property>
++                    <property name="label" translatable="yes">&lt;b&gt;Target properties&lt;/b&gt;</property>
++                    <property name="use_markup">True</property>
++                  </object>
++                </child>
++              </object>
++              <packing>
++                <property name="expand">False</property>
++                <property name="fill">False</property>
++                <property name="position">0</property>
++              </packing>
++            </child>
++            <child>
++              <object class="GtkVBox" id="vbox6">
++                <property name="visible">True</property>
++                <property name="orientation">vertical</property>
++                <child>
++                  <object class="GtkFrame" id="frame3">
++                    <property name="visible">True</property>
++                    <property name="label_xalign">0</property>
++                    <property name="shadow_type">out</property>
++                    <child>
++                      <object class="GtkAlignment" id="alignment8">
++                        <property name="visible">True</property>
++                        <child>
++                          <object class="GtkScrolledWindow" id="scrolledwindow2">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="hscrollbar_policy">automatic</property>
++                            <property name="vscrollbar_policy">automatic</property>
++                            <child>
++                              <object class="GtkTreeView" id="treeview1">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="model">convert_fixed_list</property>
++                                <property name="headers_clickable">False</property>
++                                <property name="search_column">0</property>
++                                <child>
++                                  <object class="GtkTreeViewColumn" id="treeviewcolumn4">
++                                    <property name="title">Convert</property>
++                                    <property name="clickable">True</property>
++                                    <child>
++                                      <object class="GtkCellRendererToggle" id="convert_fixed_select">
++                                        <signal name="toggled" handler="convert_fixed_select_toggled"/>
++                                      </object>
++                                      <attributes>
++                                        <attribute name="active">0</attribute>
++                                      </attributes>
++                                    </child>
++                                  </object>
++                                </child>
++                                <child>
++                                  <object class="GtkTreeViewColumn" id="treeviewcolumn5">
++                                    <property name="title">Device</property>
++                                    <child>
++                                      <object class="GtkCellRendererText" id="cellrenderertext4"/>
++                                      <attributes>
++                                        <attribute name="text">1</attribute>
++                                      </attributes>
++                                    </child>
++                                  </object>
++                                </child>
++                                <child>
++                                  <object class="GtkTreeViewColumn" id="treeviewcolumn8">
++                                    <property name="title">Transfer Progress</property>
++                                    <property name="expand">True</property>
++                                    <child>
++                                      <object class="GtkCellRendererProgress" id="cellrendererprogress1"/>
++                                      <attributes>
++                                        <attribute name="value">2</attribute>
++                                      </attributes>
++                                    </child>
++                                  </object>
++                                </child>
++                              </object>
++                            </child>
++                          </object>
++                        </child>
++                      </object>
++                    </child>
++                    <child type="label">
++                      <object class="GtkLabel" id="label17">
++                        <property name="visible">True</property>
++                        <property name="label" translatable="yes">&lt;b&gt;Fixed Storage&lt;/b&gt;</property>
++                        <property name="use_markup">True</property>
++                      </object>
++                    </child>
++                  </object>
++                  <packing>
++                    <property name="position">0</property>
++                  </packing>
++                </child>
++                <child>
++                  <object class="GtkFrame" id="frame4">
++                    <property name="visible">True</property>
++                    <property name="label_xalign">0</property>
++                    <property name="shadow_type">out</property>
++                    <child>
++                      <object class="GtkAlignment" id="alignment11">
++                        <property name="visible">True</property>
++                        <child>
++                          <object class="GtkScrolledWindow" id="scrolledwindow4">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="hscrollbar_policy">automatic</property>
++                            <property name="vscrollbar_policy">automatic</property>
++                            <child>
++                              <object class="GtkTreeView" id="treeview3">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="model">convert_removable_list</property>
++                                <child>
++                                  <object class="GtkTreeViewColumn" id="treeviewcolumn9">
++                                    <property name="title">Convert</property>
++                                    <child>
++                                      <object class="GtkCellRendererToggle" id="convert_removable_select">
++                                        <signal name="toggled" handler="convert_removable_select_toggled"/>
++                                      </object>
++                                      <attributes>
++                                        <attribute name="active">0</attribute>
++                                      </attributes>
++                                    </child>
++                                  </object>
++                                </child>
++                                <child>
++                                  <object class="GtkTreeViewColumn" id="treeviewcolumn10">
++                                    <property name="title">Device</property>
++                                    <child>
++                                      <object class="GtkCellRendererText" id="cellrenderertext6"/>
++                                      <attributes>
++                                        <attribute name="text">1</attribute>
++                                      </attributes>
++                                    </child>
++                                  </object>
++                                </child>
++                                <child>
++                                  <object class="GtkTreeViewColumn" id="treeviewcolumn11">
++                                    <property name="title">Type</property>
++                                    <child>
++                                      <object class="GtkCellRendererText" id="cellrenderertext7"/>
++                                      <attributes>
++                                        <attribute name="text">2</attribute>
++                                      </attributes>
++                                    </child>
++                                  </object>
++                                </child>
++                              </object>
++                            </child>
++                          </object>
++                        </child>
++                      </object>
++                    </child>
++                    <child type="label">
++                      <object class="GtkLabel" id="label19">
++                        <property name="visible">True</property>
++                        <property name="label" translatable="yes">&lt;b&gt;Removable Media&lt;/b&gt;</property>
++                        <property name="use_markup">True</property>
++                      </object>
++                    </child>
++                  </object>
++                  <packing>
++                    <property name="position">1</property>
++                  </packing>
++                </child>
++                <child>
++                  <object class="GtkFrame" id="frame1">
++                    <property name="visible">True</property>
++                    <property name="label_xalign">0</property>
++                    <property name="shadow_type">out</property>
++                    <child>
++                      <object class="GtkAlignment" id="alignment10">
++                        <property name="visible">True</property>
++                        <property name="xalign">1</property>
++                        <property name="yalign">1</property>
++                        <child>
++                          <object class="GtkScrolledWindow" id="scrolledwindow3">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="hscrollbar_policy">automatic</property>
++                            <property name="vscrollbar_policy">automatic</property>
++                            <child>
++                              <object class="GtkTreeView" id="treeview2">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="model">convert_network_list</property>
++                                <property name="headers_clickable">False</property>
++                                <property name="search_column">0</property>
++                                <child>
++                                  <object class="GtkTreeViewColumn" id="treeviewcolumn6">
++                                    <property name="title">Convert</property>
++                                    <child>
++                                      <object class="GtkCellRendererToggle" id="convert_network_select">
++                                        <signal name="toggled" handler="convert_network_select_toggled"/>
++                                      </object>
++                                      <attributes>
++                                        <attribute name="active">0</attribute>
++                                      </attributes>
++                                    </child>
++                                  </object>
++                                </child>
++                                <child>
++                                  <object class="GtkTreeViewColumn" id="treeviewcolumn7">
++                                    <property name="title">Device</property>
++                                    <child>
++                                      <object class="GtkCellRendererText" id="cellrenderertext5"/>
++                                      <attributes>
++                                        <attribute name="text">1</attribute>
++                                      </attributes>
++                                    </child>
++                                  </object>
++                                </child>
++                              </object>
++                            </child>
++                          </object>
++                        </child>
++                      </object>
++                    </child>
++                    <child type="label">
++                      <object class="GtkLabel" id="label12">
++                        <property name="visible">True</property>
++                        <property name="label" translatable="yes">&lt;b&gt;Network Interfaces&lt;/b&gt;</property>
++                        <property name="use_markup">True</property>
++                      </object>
++                    </child>
++                  </object>
++                  <packing>
++                    <property name="position">2</property>
++                  </packing>
++                </child>
++              </object>
++              <packing>
++                <property name="position">1</property>
++              </packing>
++            </child>
++          </object>
++          <packing>
++            <property name="position">0</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkHBox" id="hbox1">
++            <property name="visible">True</property>
++            <child>
++              <object class="GtkLabel" id="convert_status">
++                <property name="visible">True</property>
++                <property name="xalign">0</property>
++                <property name="xpad">12</property>
++                <attributes>
++                  <attribute name="foreground" value="#ffff00000000"/>
++                </attributes>
++              </object>
++              <packing>
++                <property name="position">0</property>
++              </packing>
++            </child>
++            <child>
++              <object class="GtkButton" id="convert_button">
++                <property name="label" translatable="yes">Convert</property>
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <property name="receives_default">True</property>
++                <signal name="clicked" handler="convert_button_clicked"/>
++              </object>
++              <packing>
++                <property name="expand">False</property>
++                <property name="fill">False</property>
++                <property name="position">1</property>
++              </packing>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">False</property>
++            <property name="position">1</property>
++          </packing>
++        </child>
++      </object>
++    </child>
++  </object>
++  <object class="GtkWindow" id="success_win">
++    <child>
++      <object class="GtkVBox" id="vbox7">
++        <property name="visible">True</property>
++        <property name="orientation">vertical</property>
++        <child>
++          <object class="GtkLabel" id="label20">
++            <property name="visible">True</property>
++            <property name="label" translatable="yes">A guest has been successfully created on the target server.
++
++Remove the temporary boot device from this machine and press 'Reboot' to continue.</property>
++            <property name="justify">center</property>
++          </object>
++          <packing>
++            <property name="position">0</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkAlignment" id="alignment7">
++            <property name="visible">True</property>
++            <property name="xscale">0.25</property>
++            <property name="yscale">0.25</property>
++            <child>
++              <object class="GtkButton" id="reboot_button">
++                <property name="label" translatable="yes">Reboot</property>
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <property name="receives_default">True</property>
++                <signal name="clicked" handler="reboot_button_clicked"/>
++              </object>
++            </child>
++          </object>
++          <packing>
++            <property name="position">1</property>
++          </packing>
++        </child>
++      </object>
++    </child>
++  </object>
++</interface>
+diff -ruN virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/ui/success.rb virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/ui/success.rb
+--- virt-v2v-v0.8.1/p2v/client/lib/virt-p2v/ui/success.rb	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/lib/virt-p2v/ui/success.rb	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,33 @@
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++require 'gettext'
++
++module VirtP2V::UI::Success
++    include GetText
++
++    def self.init(ui)
++        ui.register_handler('reboot_button_clicked',
++                            method(:reboot_button_clicked))
++
++        @ui = ui
++    end
++
++    def self.reboot_button_clicked
++        @ui.quit
++    end
++
++end # module
+diff -ruN virt-v2v-v0.8.1/p2v/client/Manifest virt-v2v-v0.8.1.new/p2v/client/Manifest
+--- virt-v2v-v0.8.1/p2v/client/Manifest	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/Manifest	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,15 @@
++Rakefile
++bin/virt-p2v
++lib/virt-p2v/blockdevice.rb
++lib/virt-p2v/connection.rb
++lib/virt-p2v/converter.rb
++lib/virt-p2v/gtk-queue.rb
++lib/virt-p2v/netdevice.rb
++lib/virt-p2v/ui/connect.rb
++lib/virt-p2v/ui/convert.rb
++lib/virt-p2v/ui/main.rb
++lib/virt-p2v/ui/network.rb
++lib/virt-p2v/ui/p2v.ui
++lib/virt-p2v/ui/success.rb
++virt-p2v.gemspec
++Manifest
+diff -ruN virt-v2v-v0.8.1/p2v/client/Rakefile virt-v2v-v0.8.1.new/p2v/client/Rakefile
+--- virt-v2v-v0.8.1/p2v/client/Rakefile	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/client/Rakefile	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,37 @@
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++require 'rubygems'
++require 'echoe'
++
++Echoe.new("virt-p2v") do |p|
++  p.project     = "Virt P2V"
++  p.version     = `../../Build version`
++  p.author      = "Matthew Booth"
++  p.summary     = "Send a machine's storage and metadata to virt-p2v-server"
++  p.description = <<EOF
++virt-p2v is a client which connects to a virt-p2v-server and transfer's the host
++machine's storage and metadata. virt-p2v is intended to be run from a live
++image, so it is unlikely you want to install it.
++EOF
++  p.url         = "http://libguestfs.org"
++  p.email       = "libguestfs at redhat.com"
++  p.runtime_dependencies = [
++      'gtk2',
++      'gettext',
++      'net-ssh'
++  ]
++end
+diff -ruN virt-v2v-v0.8.1/p2v/image-builder/common-install.ks virt-v2v-v0.8.1.new/p2v/image-builder/common-install.ks
+--- virt-v2v-v0.8.1/p2v/image-builder/common-install.ks	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/image-builder/common-install.ks	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,54 @@
++lang C
++keyboard us
++timezone --utc UTC
++auth --useshadow --enablemd5
++selinux --disabled
++firewall --disabled
++# TODO: the sizing of the image needs to be more dynamic
++part / --size 1024 --fstype ext2
++services --enabled=NetworkManager --disabled=auditd
++bootloader --timeout=30
++rootpw --iscrypted $1$tQiZwocX$ghhurQEm56p/HqgN.XEtk1
++
++# add missing scsi modules to initramfs
++device 3w-9xxx
++device 3w-sas
++device 3w-xxxx
++device a100u2w
++device aacraid
++device aic79xx
++device aic94xx
++device arcmsr
++device atp870u
++device be2iscsi
++device bfa
++device BusLogic
++device cxgb3i
++device dc395x
++device fnic
++device gdth
++device hpsa
++device hptiop
++device imm
++device initio
++device ips
++device libosd
++device libsas
++device libsrp
++device lpfc
++device megaraid
++device megaraid_mbox
++device megaraid_mm
++device megaraid_sas
++device mpt2sas
++device mvsas
++device osd
++device osst
++device pm8001
++device pmcraid
++device qla1280
++device qla2xxx
++device qla4xxx
++device qlogicfas408
++device stex
++device tmscsim
+diff -ruN virt-v2v-v0.8.1/p2v/image-builder/common-manifest-post.ks virt-v2v-v0.8.1.new/p2v/image-builder/common-manifest-post.ks
+--- virt-v2v-v0.8.1/p2v/image-builder/common-manifest-post.ks	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/image-builder/common-manifest-post.ks	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,36 @@
++%post
++echo -n "Creating manifest"
++# Create post-image processing manifests
++rpm -qa --qf '%{name}-%{version}-%{release}.%{arch} (%{SIGGPG:pgpsig})\n' | \
++    sort > /manifest-rpm.txt
++rpm -qa --qf '%{sourcerpm}\n' | sort -u > /manifest-srpm.txt
++# collect all included licenses rhbz#601927
++rpm -qa --qf '%{license}\n' | sort -u > /manifest-license.txt
++# dependencies
++rpm -qa | xargs -n1 rpm -e --test 2> /manifest-deps.txt
++echo -n "."
++find / -xdev -print -exec rpm -qf {} \; > /manifest-owns.txt
++rpm -qa --qf '%{NAME}\t%{VERSION}\t%{RELEASE}\t%{BUILDTIME}\n' | \
++    sort > /rpm-qa.txt
++echo -n "."
++
++du -akx --exclude=/var/cache/yum / > /manifest-file.txt
++du -x --exclude=/var/cache/yum / > /manifest-dir.txt
++echo -n "."
++bzip2 /manifest-deps.txt /manifest-owns.txt /manifest-file.txt /manifest-dir.txt
++echo -n "."
++
++%end
++
++%post --nochroot
++# Move manifests to ISO
++mv $INSTALL_ROOT/manifest-* $LIVE_ROOT/isolinux
++echo "done"
++
++# only works on x86, x86_64
++if [ "$(uname -i)" = "i386" -o "$(uname -i)" = "x86_64" ]; then
++    if [ ! -d $LIVE_ROOT/LiveOS ]; then mkdir -p $LIVE_ROOT/LiveOS ; fi
++    cp /usr/bin/livecd-iso-to-disk $LIVE_ROOT/LiveOS
++    cp /usr/bin/livecd-iso-to-pxeboot $LIVE_ROOT/LiveOS
++fi
++%end
+diff -ruN virt-v2v-v0.8.1/p2v/image-builder/common-minimizer.ks virt-v2v-v0.8.1.new/p2v/image-builder/common-minimizer.ks
+--- virt-v2v-v0.8.1/p2v/image-builder/common-minimizer.ks	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/image-builder/common-minimizer.ks	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,239 @@
++# This file is only relatively lightly modified from the version copied from
++# oVirt, and certainly contains much which is irrelevant to this image. I have,
++# however, removed some obviously extraneous entries and added a few additional
++# entries.
++#
++# Matthew Booth <mbooth at redhat.com> - 18/4/2011
++
++%post --nochroot --interpreter image-minimizer
++# lokkit is just an install-time dependency; we can remove
++# it afterwards, which we do here
++droprpm system-config-*
++droprpm libsemanage-python
++droprpm python-libs
++droprpm python
++
++droprpm mkinitrd
++droprpm isomd5sum
++droprpm dmraid
++droprpm checkpolicy
++droprpm make
++droprpm policycoreutils-python
++droprpm setools-libs-python
++droprpm setools-libs
++
++droprpm gamin
++droprpm pm-utils
++droprpm kbd
++droprpm usermode
++droprpm vbetool
++droprpm ConsoleKit
++droprpm hdparm
++droprpm efibootmgr
++droprpm linux-atm-libs
++droprpm mtools
++droprpm syslinux
++droprpm wireless-tools
++droprpm radeontool
++droprpm libicu
++droprpm gnupg2
++droprpm fedora-release-notes
++droprpm fedora-logos
++
++# cronie pulls in exim (sendmail) which pulls in all kinds of perl deps
++droprpm exim
++droprpm perl*
++droprpm postfix
++droprpm mysql*
++
++droprpm sysklogd
++
++# unneeded rhn deps
++droprpm yum*
++
++# pam complains when this is missing
++keeprpm ConsoleKit-libs
++
++# kernel modules minimization
++
++# filesystems
++drop /lib/modules/*/kernel/fs
++keep /lib/modules/*/kernel/fs/ext*
++keep /lib/modules/*/kernel/fs/jbd*
++keep /lib/modules/*/kernel/fs/btrfs
++keep /lib/modules/*/kernel/fs/fat
++keep /lib/modules/*/kernel/fs/nfs
++keep /lib/modules/*/kernel/fs/nfs_common
++keep /lib/modules/*/kernel/fs/fscache
++keep /lib/modules/*/kernel/fs/lockd
++keep /lib/modules/*/kernel/fs/nls/nls_utf8.ko
++# autofs4     configfs  exportfs *fat     *jbd    mbcache.ko  nls       xfs
++#*btrfs       cramfs   *ext2     *fscache *jbd2  *nfs         squashfs
++# cachefiles  dlm      *ext3      fuse     jffs2 *nfs_common  ubifs
++# cifs        ecryptfs *ext4      gfs2    *lockd  nfsd        udf
++
++# network
++drop /lib/modules/*/kernel/net
++keep /lib/modules/*/kernel/net/802*
++keep /lib/modules/*/kernel/net/bridge
++keep /lib/modules/*/kernel/net/core
++keep /lib/modules/*/kernel/net/ipv*
++keep /lib/modules/*/kernel/net/key
++keep /lib/modules/*/kernel/net/llc
++keep /lib/modules/*/kernel/net/netfilter
++keep /lib/modules/*/kernel/net/rds
++keep /lib/modules/*/kernel/net/sctp
++keep /lib/modules/*/kernel/net/sunrpc
++#*802    atm        can   ieee802154 *key      *netfilter  rfkill *sunrpc  xfrm
++#*8021q  bluetooth *core *ipv4       *llc       phonet     sched   wimax
++# 9p    *bridge     dccp *ipv6        mac80211 *rds       *sctp    wireless
++
++drop /lib/modules/*/kernel/sound
++
++# drivers
++drop /lib/modules/*/kernel/drivers
++keep /lib/modules/*/kernel/drivers/ata
++keep /lib/modules/*/kernel/drivers/block
++keep /lib/modules/*/kernel/drivers/cdrom
++keep /lib/modules/*/kernel/drivers/char
++keep /lib/modules/*/kernel/drivers/cpufreq
++keep /lib/modules/*/kernel/drivers/dca
++keep /lib/modules/*/kernel/drivers/dma
++keep /lib/modules/*/kernel/drivers/edac
++keep /lib/modules/*/kernel/drivers/firmware
++keep /lib/modules/*/kernel/drivers/idle
++keep /lib/modules/*/kernel/drivers/infiniband
++keep /lib/modules/*/kernel/drivers/md
++keep /lib/modules/*/kernel/drivers/message
++keep /lib/modules/*/kernel/drivers/net
++drop /lib/modules/*/kernel/drivers/net/pcmcia
++drop /lib/modules/*/kernel/drivers/net/wireless
++drop /lib/modules/*/kernel/drivers/net/ppp*
++keep /lib/modules/*/kernel/drivers/pci
++keep /lib/modules/*/kernel/drivers/scsi
++keep /lib/modules/*/kernel/drivers/staging/ramzswap
++keep /lib/modules/*/kernel/drivers/uio
++keep /lib/modules/*/kernel/drivers/usb
++drop /lib/modules/*/kernel/drivers/usb/atm
++drop /lib/modules/*/kernel/drivers/usb/class
++drop /lib/modules/*/kernel/drivers/usb/image
++drop /lib/modules/*/kernel/drivers/usb/misc
++drop /lib/modules/*/kernel/drivers/usb/serial
++keep /lib/modules/*/kernel/drivers/vhost
++keep /lib/modules/*/kernel/drivers/virtio
++
++# acpi       *cpufreq   hid         leds      mtd      ?regulator  uwb
++#*ata         crypto   ?hwmon      *md       *net*      rtc       *vhost
++# atm        *dca      ?i2c         media    ?parport  *scsi*      video
++# auxdisplay *dma      *idle        memstick *pci      ?serial    *virtio
++#*block      *edac      ieee802154 *message   pcmcia   ?ssb        watchdog
++# bluetooth   firewire *infiniband ?mfd       platform *staging    xen
++#*cdrom      *firmware  input       misc     ?power    ?uio
++#*char*      ?gpu       isdn        mmc      ?pps      *usb
++
++drop /usr/share/zoneinfo
++keep /usr/share/zoneinfo/UTC
++
++drop /etc/alsa
++drop /usr/share/alsa
++drop /usr/share/awk
++drop /usr/share/vim
++drop /usr/share/anaconda
++drop /usr/share/backgrounds
++drop /usr/share/wallpapers
++drop /usr/share/kde-settings
++drop /usr/share/gnome-background-properties
++drop /usr/share/dracut
++drop /usr/share/plymouth
++drop /usr/share/setuptool
++drop /usr/share/hwdata/MonitorsDB
++drop /usr/share/hwdata/oui.txt
++drop /usr/share/hwdata/videoaliases
++drop /usr/share/hwdata/videodrivers
++drop /usr/share/firstboot
++drop /usr/share/lua
++drop /usr/share/kde4
++drop /usr/share/pixmaps
++drop /usr/share/icons
++drop /usr/share/fedora-release
++drop /usr/share/tabset
++
++drop /usr/share/tc
++drop /usr/share/emacs
++drop /usr/share/info
++drop /usr/src
++drop /usr/etc
++drop /usr/games
++drop /usr/include
++drop /usr/local
++drop /usr/sbin/dell*
++keep /usr/sbin/build-locale-archive
++drop /usr/sbin/glibc_post_upgrade.*
++drop /usr/lib*/tc
++drop /usr/lib*/tls
++drop /usr/lib*/sse2
++drop /usr/lib*/pkgconfig
++drop /usr/lib*/nss
++drop /usr/lib*/games
++drop /usr/lib*/alsa-lib
++drop /usr/lib*/krb5
++drop /usr/lib*/hal
++drop /usr/lib*/gio
++
++# syslinux
++drop /usr/share/syslinux
++# glibc-common locales
++drop /usr/lib/locale
++keep /usr/lib/locale/usr/share/locale/en_US
++# openssh
++drop /usr/bin/sftp
++drop /usr/bin/slogin
++drop /usr/bin/ssh-add
++drop /usr/bin/ssh-agent
++drop /usr/bin/ssh-keyscan
++# docs
++drop /usr/share/omf
++drop /usr/share/gnome
++drop /usr/share/doc
++keep /usr/share/doc/*-firmware-*
++drop /usr/share/locale/
++keep /usr/share/locale/en_US
++drop /usr/share/man
++drop /usr/share/i18n
++drop /boot/*
++drop /var/lib/builder
++
++drop /usr/lib*/libboost*
++keep /usr/lib*/libboost_program_options.so*
++keep /usr/lib*/libboost_filesystem.so*
++keep /usr/lib*/libboost_thread-mt.so*
++keep /usr/lib*/libboost_system.so*
++drop /usr/kerberos
++keep /usr/kerberos/bin/kinit
++keep /usr/kerberos/bin/klist
++drop /lib/firmware
++keep /lib/firmware/3com
++keep /lib/firmware/acenic
++keep /lib/firmware/adaptec
++keep /lib/firmware/advansys
++keep /lib/firmware/bnx2
++keep /lib/firmware/cxgb3
++keep /lib/firmware/e100
++keep /lib/firmware/myricom
++keep /lib/firmware/ql*
++keep /lib/firmware/sun
++keep /lib/firmware/tehuti
++keep /lib/firmware/tigon
++drop /lib/kbd/consolefonts
++drop /etc/pki/tls
++drop /etc/pki/java
++drop /etc/pki/nssdb
++drop /etc/pki/rpm-gpg
++%end
++
++%post
++echo "Removing python source files"
++find / -name '*.py' -exec rm -f {} \;
++find / -name '*.pyo' -exec rm -f {} \;
++
++%end
+diff -ruN virt-v2v-v0.8.1/p2v/image-builder/common-pkgs.ks virt-v2v-v0.8.1.new/p2v/image-builder/common-pkgs.ks
+--- virt-v2v-v0.8.1/p2v/image-builder/common-pkgs.ks	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/image-builder/common-pkgs.ks	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,48 @@
++# Direct requirements
++rubygem-virt-p2v
++bitstream-vera-sans-fonts
++xorg-x11-xinit
++xorg-x11-drivers
++xorg-x11-server-Xorg
++
++# Boot requirements
++device-mapper
++
++# Required for livecd creation
++passwd
++rpm
++/usr/sbin/lokkit
++
++# Remove unnecessary packages
++-audit-libs-python
++-ustr
++-authconfig
++-wireless-tools
++-setserial
++-prelink
++-newt-python
++-newt
++-libselinux-python
++-kbd
++-usermode
++-fedora-release
++-fedora-release-notes
++-dmraid
++-gzip
++-less
++-which
++-parted
++-tar
++-libuser
++-mtools
++-cpio
++-yum
++-numactl # Pulls in perl dependency
++-perl
++
++# qlogic firmware
++ql2100-firmware
++ql2200-firmware
++ql23xx-firmware
++ql2400-firmware
++ql2500-firmware
+diff -ruN virt-v2v-v0.8.1/p2v/image-builder/common-post.ks virt-v2v-v0.8.1.new/p2v/image-builder/common-post.ks
+--- virt-v2v-v0.8.1/p2v/image-builder/common-post.ks	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/image-builder/common-post.ks	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,43 @@
++# -*-Shell-script-*-
++echo "Starting Kickstart Post"
++PATH=/sbin:/usr/sbin:/bin:/usr/bin
++export PATH
++
++# cleanup rpmdb to allow non-matching host and chroot RPM versions
++rm -f /var/lib/rpm/__db*
++
++echo "Creating shadow files"
++# because we aren't installing authconfig, we aren't setting up shadow
++# and gshadow properly.  Do it by hand here
++pwconv
++grpconv
++
++echo "Forcing C locale"
++# force logins (via ssh, etc) to use C locale, since we remove locales
++cat >> /etc/profile << \EOF
++# force our locale to C since we don't have locale stuff'
++export LC_ALL=C LANG=C
++EOF
++
++# remove errors from /sbin/dhclient-script
++DHSCRIPT=/sbin/dhclient-script
++sed -i 's/mv /cp -p /g'  $DHSCRIPT
++sed -i '/rm -f.*${interface}/d' $DHSCRIPT
++sed -i '/rm -f \/etc\/localtime/d' $DHSCRIPT
++sed -i '/rm -f \/etc\/ntp.conf/d' $DHSCRIPT
++sed -i '/rm -f \/etc\/yp.conf/d' $DHSCRIPT
++
++# Lock root account
++#passwd -l root
++
++#strip out all unncesssary locales
++localedef --list-archive | grep -v -i -E 'en_US.utf8' |xargs localedef --delete-from-archive
++mv /usr/lib/locale/locale-archive /usr/lib/locale/locale-archive.tmpl
++/usr/sbin/build-locale-archive
++
++# Run virt-p2v
++cat >> /etc/rc.local <<EOF
++export HOME=/root # rubygem Net::SSH needs this
++/usr/bin/xinit /usr/bin/virt-p2v > /root/virt-p2v.log 2>&1
++poweroff
++EOF
+diff -ruN virt-v2v-v0.8.1/p2v/image-builder/common-post-nochroot.ks virt-v2v-v0.8.1.new/p2v/image-builder/common-post-nochroot.ks
+--- virt-v2v-v0.8.1/p2v/image-builder/common-post-nochroot.ks	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/image-builder/common-post-nochroot.ks	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,60 @@
++%include version.ks
++
++PRODUCT='Virt P2V'
++PRODUCT_SHORT='virt-p2v'
++PACKAGE='virt-p2v'
++RELEASE=${RELEASE:-devel.`date +%Y%m%d%H%M%S`}
++
++echo "Customizing boot menu"
++sed -i -e '
++# Put product information at the top of the file
++1 {
++    i '"say $PRODUCT $VERSION ($RELEASE)"'
++    i '"menu title $PRODUCT_SHORT $VERSION ($RELEASE)"'
++}
++
++# Remove any existing menu title
++/^menu title .*/d
++
++# Remove quiet bootparam
++#s/ quiet//
++
++# Disable selinux entirely. Required, as we dont install an SELinux policy.
++/^\s*append\s/ s/\s*$/ selinux=0/
++
++# Remove Verify and Boot option
++/label check0/{N;N;N;d;}
++
++# Set the default timeout to 15 seconds
++s/^timeout .*/timeout 15/
++' $LIVE_ROOT/isolinux/isolinux.cfg
++
++# TODO: Replace the splash screen with something P2V appropriate
++#cp $INSTALL_ROOT//syslinux-vesa-splash.jpg $LIVE_ROOT/isolinux/splash.jpg
++
++# store image version info in the ISO
++cat > $LIVE_ROOT/isolinux/version <<EOF
++PRODUCT='$PRODUCT'
++PRODUCT_SHORT='${PRODUCT_SHORT}'
++PRODUCT_CODE=$PRODUCT_CODE
++RECIPE_SHA256=$RECIPE_SHA256
++RECIPE_RPM=$RECIPE_RPM
++PACKAGE=$PACKAGE
++VERSION=$VERSION
++RELEASE=$RELEASE
++EOF
++
++# overwrite user visible banners with the image versioning info
++cat > $INSTALL_ROOT/etc/$PACKAGE-release <<EOF
++$PRODUCT release $VERSION ($RELEASE)
++EOF
++ln -snf $PACKAGE-release $INSTALL_ROOT/etc/redhat-release
++ln -snf $PACKAGE-release $INSTALL_ROOT/etc/system-release
++cp $INSTALL_ROOT/etc/$PACKAGE-release $INSTALL_ROOT/etc/issue
++echo "Kernel \r on an \m (\l)" >> $INSTALL_ROOT/etc/issue
++cp $INSTALL_ROOT/etc/issue $INSTALL_ROOT/etc/issue.net
++
++# replace initramfs if regenerated
++if [ -f "$INSTALL_ROOT/initrd0.img" ]; then
++  mv -v "$INSTALL_ROOT/initrd0.img" "$LIVE_ROOT/isolinux/initrd0.img"
++fi
+diff -ruN virt-v2v-v0.8.1/p2v/image-builder/Makefile virt-v2v-v0.8.1.new/p2v/image-builder/Makefile
+--- virt-v2v-v0.8.1/p2v/image-builder/Makefile	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/image-builder/Makefile	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,2 @@
++version.ks: ../../Build
++	echo VERSION=`../../Build version` > version.ks
+diff -ruN virt-v2v-v0.8.1/p2v/image-builder/version.ks virt-v2v-v0.8.1.new/p2v/image-builder/version.ks
+--- virt-v2v-v0.8.1/p2v/image-builder/version.ks	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/image-builder/version.ks	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1 @@
++VERSION=0.8.1
+diff -ruN virt-v2v-v0.8.1/p2v/image-builder/virt-p2v-image-builder virt-v2v-v0.8.1.new/p2v/image-builder/virt-p2v-image-builder
+--- virt-v2v-v0.8.1/p2v/image-builder/virt-p2v-image-builder	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/image-builder/virt-p2v-image-builder	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,188 @@
++#!/bin/bash
++
++# Copyright (C) 2010-2011, Red Hat, Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; version 2 of the License.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
++# MA  02110-1301, USA.  A copy of the GNU General Public License is
++# also available at http://www.gnu.org/copyleft/gpl.html.
++
++# Requires: sudo livecd-creator, sudo setenforce, ksflatten
++
++# Based on oVirt's node-creator
++
++# Current fedora data
++cur_rawhide=16
++cur_devel=15
++
++me=$(basename "$0")
++warn() { printf '%s: %s\n' "$me" "$*" >&2; }
++die() { warn "$*"; exit 1; }
++usage() {
++cat <<EOF
++usage: $me <options>
++
++Build a virt-p2v bootable image.
++
++OPTIONS:
++  -a    Additional yum repository. Can be specified multiple times.
++  -c    Yum cache directory.
++  -d    Directory containing virt-p2v-image.ks.
++  -f    Specific Fedora mirror to use if building a Fedora image.
++  -l    Boot image label.
++  -r    Primary yum repository.
++  -u    Updates yum repository.
++  -h    Show this message.
++EOF
++}
++
++onlyonce() {
++    warn "-$1 may only be specified once"
++    usage
++    exit 1
++}
++
++while getopts "a:d:f:hl:r:u:w:" OPTION
++do
++    case $OPTION in
++        a)
++            n_elems=${#extra_repos[*]}
++            extra_repos[$n_elems]="$OPTARG"
++            ;;
++        c)
++            [ -n "$cachedir" ] && onlyonce $OPTION
++            cachedir="$OPTARG"
++            ;;
++        d)
++            [ -n "$datadir" ] && onlyonce $OPTION
++            datadir="$OPTARG"
++            ;;
++        f)
++            [ -n "$fedora_url" ] && onlyonce $OPTION
++            fedora_url="$OPTARG"
++            ;;
++        l)
++            [ -n "$label" ] && onlyonce $OPTION
++            label="$OPTARG"
++            ;;
++        r)
++            [ -n "$repo" ] && onlyonce $OPTION
++            repo="$OPTARG"
++            ;;
++        u)
++            [ -n "$updates" ] && onlyonce $OPTION
++            updates="$OPTARG"
++            ;;
++        h)
++            usage
++            exit 0
++            ;;
++        ?)
++            usage
++            exit 1
++            ;;
++    esac
++done
++
++# Split out here for simple editing with sed during installation
++DEFAULT_DATADIR=.
++
++# Option defaults
++datadir="${datadir:-$DEFAULT_DATADIR}"
++cachedir="${cachedir:-/var/tmp/p2v-image-builder.$USER}"
++label="${label:-Virt-P2V}"
++
++arch=$(rpm --eval '%{_arch}')
++kstmp=$(mktemp --tmpdir p2v-image-builder.XXXXXXXX)
++
++if pgrep -xl nscd; then
++    die "Please stop nscd first"
++fi
++
++rm -f "$kstmp"
++# combine recipe includes
++ksflatten --config "$datadir/virt-p2v-image.ks" --output "$kstmp"
++# XXX broken ksflatten leaves %include
++sed -i 's/^%include /#&/' "$kstmp"
++
++if [ -z "$repo" ]; then
++    # Set defaults for Fedora if this is a fedora system
++    fedora=$(rpm --eval '%{fedora}' |grep [0-9])
++
++    mirrorlist="http://mirrors.fedoraproject.org/mirrorlist"
++
++    case "$fedora" in
++    $curr_rawhide)
++        if [ -z "$fedora_url" ]; then
++            repo="--mirrorlist=$mirrorlist?repo=rawhide&arch=$arch"
++        else
++            repo="--baseurl=$fedora_url/development/rawhide/$arch/os"
++        fi
++        ;;
++    $cur_devel)
++        if [ -z "$fedora_url" ]; then
++            repo="--mirrorlist=$mirrorlist?repo=fedora-$fedora&arch=$arch"
++        else
++            repo="--baseurl=$fedora_url/development/$fedora/$arch/os"
++        fi
++        ;;
++    ?*)
++        if [ -z "$fedora_url" ]; then
++            repo="--mirrorlist=$mirrorlist?repo=fedora-$fedora&arch=$arch"
++            updates="--mirrorlist=$mirrorlist?repo=updates-released-f${fedora}&arch=$arch"
++        else
++            repo="--baseurl=$fedora_url/releases/$fedora/Everything/$arch/os"
++            updates="--baseurl=$fedora_url/updates/$fedora/$arch"
++        fi
++    esac
++else
++    repo="--baseurl=$repo"
++    [ -n "$updates" ] && updates="--baseurl=$updates"
++fi
++
++if [ -n "$repo" ]; then
++    echo "repo --name=base $repo" >> "$kstmp"
++else
++    die "No repository specified, and no default available."
++fi
++if [ -n "$updates" ]; then
++    echo "repo --name=updates $updates" >> "$kstmp"
++fi
++i=0
++for extra in "${extra_repos[@]}"; do
++    ((i++))
++    [ -d "$extra" ] && extra="file://$extra"
++    echo "repo --name=extra$i --baseurl=$extra" >> "$kstmp"
++done
++
++selinux_enforcing=$(/usr/sbin/getenforce)
++case "$selinux_enforcing" in
++    Enforcing) sudo /usr/sbin/setenforce Permissive ;;
++    Permissive) ;;
++    *) if grep -q '^selinux --disabled' "$kstmp";
++           then
++               warn "WARNING: SELinux disabled in kickstart"
++           else
++               die "ERROR: SELinux enabled in kickstart, \
++               but disabled on the build machine"
++       fi ;;
++esac
++
++mkdir -p $cachedir
++sudo livecd-creator -c "$kstmp" -f "$label" --cache="$cachedir"
++
++# Clean up
++rm -f $kstmp
++if [ "$selinux_enforcing" = Enforcing ]; then
++    sudo /usr/sbin/setenforce Enforcing
++fi
+diff -ruN virt-v2v-v0.8.1/p2v/image-builder/virt-p2v-image.ks virt-v2v-v0.8.1.new/p2v/image-builder/virt-p2v-image.ks
+--- virt-v2v-v0.8.1/p2v/image-builder/virt-p2v-image.ks	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/image-builder/virt-p2v-image.ks	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,19 @@
++# virt-p2v Node image recipe
++
++%include common-install.ks
++
++%packages --excludedocs --nobase
++%include common-pkgs.ks
++%end
++
++%post
++%include common-post.ks
++%end
++
++%include common-minimizer.ks
++
++%post --nochroot
++%include common-post-nochroot.ks
++%end
++
++%include common-manifest-post.ks
+diff -ruN virt-v2v-v0.8.1/p2v/server/run-p2v-locally virt-v2v-v0.8.1.new/p2v/server/run-p2v-locally
+--- virt-v2v-v0.8.1/p2v/server/run-p2v-locally	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/server/run-p2v-locally	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,52 @@
++#!/bin/sh
++# virt-p2v
++# Copyright (C) 2010 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++# This script sets up the environment so you can run virt-v2v in place
++# without needing to do 'make install' first.
++#
++# Use it like this:
++#   ./run-p2v-locally
++#
++# It requires the environment variable VIRTV2V_ROOT to be set. If using
++# libguestfs from source, LIBGUESTFS_ROOT must also be set.
++
++if [ -z "$VIRTV2V_ROOT" ]; then
++    echo "VIRTV2V_ROOT must be set"
++    exit 1
++fi
++
++if [ -z "$PERL5LIB" ]; then
++    PERL5LIB="$VIRTV2V_ROOT/blib/lib"
++else
++    PERL5LIB="$VIRTV2V_ROOT/blib/lib:$PERL5LIB"
++fi
++
++if [ ! -z "$LIBGUESTFS_ROOT" ]; then
++    if [ -z "$LD_LIBRARY_PATH" ]; then
++        LD_LIBRARY_PATH="$LIBGUESTFS_ROOT/src/.libs"
++    else
++        LD_LIBRARY_PATH="$LIBGUESTFS_ROOT/src/.libs:$LD_LIBRARY_PATH"
++    fi
++
++    LIBGUESTFS_PATH="$LIBGUESTFS_ROOT/appliance"
++    PERL5LIB="$LIBGUESTFS_ROOT/perl/blib/lib:$LIBGUESTFS_ROOT/perl/blib/arch:$PERL5LIB"
++fi
++
++export PERL5LIB LD_LIBRARY_PATH LIBGUESTFS_PATH
++
++exec perl "$VIRTV2V_ROOT/p2v-server/virt-p2v-server.pl" "$@"
+diff -ruN virt-v2v-v0.8.1/p2v/server/virt-p2v-server.pl virt-v2v-v0.8.1.new/p2v/server/virt-p2v-server.pl
+--- virt-v2v-v0.8.1/p2v/server/virt-p2v-server.pl	1970-01-01 01:00:00.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v/server/virt-p2v-server.pl	2011-05-11 17:20:21.000000000 +0100
+@@ -0,0 +1,505 @@
++#!/usr/bin/perl
++# virt-p2v-server
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++use warnings;
++use strict;
++
++use IO::Handle;
++use YAML::Any;
++
++use Locale::TextDomain 'virt-v2v';
++
++use Sys::Guestfs;
++
++use Sys::VirtConvert;
++use Sys::VirtConvert::Config;
++use Sys::VirtConvert::Converter;
++use Sys::VirtConvert::Connection::LibVirtTarget;
++use Sys::VirtConvert::Connection::RHEVTarget;
++use Sys::VirtConvert::GuestfsHandle;
++use Sys::VirtConvert::Util qw(:DEFAULT logmsg_init logmsg_level);
++
++=encoding utf8
++
++=head1 NAME
++
++virt-p2v-server - Receive data from virt-p2v
++
++=head1 DESCRIPTION
++
++virt-p2v-server is invoked over SSH by virt-p2v. It is not intended to be run
++manually.
++
++=cut
++
++# SIGPIPE will cause an untidy exit of the perl process, without calling
++# destructors. We don't rely on it anywhere, as we check for errors when reading
++# from or writing to a pipe.
++$SIG{'PIPE'} = 'IGNORE';
++
++# The protocol version we support
++use constant VERSION => 0;
++
++# Message types
++use constant MSG_VERSION        => 'VERSION';
++use constant MSG_LANG           => 'LANG';
++use constant MSG_METADATA       => 'METADATA';
++use constant MSG_PATH           => 'PATH';
++use constant MSG_CONVERT        => 'CONVERT';
++use constant MSG_LIST_PROFILES  => 'LIST_PROFILES';
++use constant MSG_SET_PROFILE    => 'SET_PROFILE';
++use constant MSG_CONTAINER      => 'CONTAINER';
++use constant MSG_DATA           => 'DATA';
++
++# Container types
++use constant CONT_RAW => 'RAW';
++
++# Global state
++my $config;
++my $meta;
++my $target;
++
++# Initialize logging
++logmsg_init('syslog');
++#logmsg_level(DEBUG);
++
++logmsg NOTICE, __x("{program} started.", program => 'p2v-server');
++
++# Wrap everything in a big eval to catch any die(). N.B. $SIG{__DIE__} is no
++# good for this, as it catches every die(), even those inside an eval
++eval {
++    # Set the umask to a reasonable default
++    umask(0022);
++
++    # Don't buffer output
++    # While perl will use line buffering when STDOUT is connected to a tty, when
++    # not connected to a tty, for example when invoked directly over ssh, it
++    # will use a regular, large output buffer. This results in messages being
++    # held in the buffer indefinitely.
++    STDOUT->autoflush(1);
++
++    # Read the config file
++    eval {
++        $config = Sys::VirtConvert::Config->new('/etc/virt-v2v.conf');
++    };
++    v2vdie $@ if $@;
++
++    my $msg;
++    while ($msg = p2v_receive()) {
++        my $type = $msg->{type};
++
++        # VERSION n
++        if ($type eq MSG_VERSION) {
++            my $version = $msg->{args}[0];
++            if ($version <= VERSION) {
++                p2v_return_ok();
++            }
++
++            else {
++                err_and_die(__x('This version of virt-p2v-server does not '.
++                                'support protocol version {version}.',
++                                version => $version));
++            }
++        }
++
++        # LANG lang
++        elsif ($type eq MSG_LANG) {
++            $ENV{LANG} = $msg->{args}[0];
++            p2v_return_ok();
++        }
++
++        # METADATA length
++        #  length bytes of YAML
++        elsif ($type eq MSG_METADATA) {
++            my $yaml = p2v_read($msg->{args}[0]);
++            eval { $meta = Load($yaml); };
++            err_and_die('Error parsing metadata: '.$@) if $@;
++
++            p2v_return_ok();
++        }
++
++        # PATH length path
++        #   N.B. path could theoretically include spaces
++        elsif ($type eq MSG_PATH) {
++            my $length = $msg->{args}[0];
++
++            my $path = join(' ', @{$msg->{args}}[1..$#{$msg->{args}}]);
++            receive_path($path, $length);
++        }
++
++        # CONVERT
++        elsif ($type eq MSG_CONVERT) {
++            convert();
++        }
++
++        # LIST_PROFILES
++        elsif ($type eq MSG_LIST_PROFILES) {
++            p2v_return_list($config->list_profiles());
++        }
++
++        # SET_PROFILE profile
++        elsif ($type eq MSG_SET_PROFILE) {
++            set_profile($msg->{args}[0]);
++        }
++
++        else {
++            unexpected_msg($type);
++        }
++    }
++};
++logmsg FATAL, $@ if $@;
++
++exit(0);
++
++# Receive an image file
++sub receive_path
++{
++    my ($path, $length) = @_;
++
++    err_and_die('PATH without prior SET_PROFILE command')
++        unless defined($target);
++    err_and_die('PATH without prior METADATA command')
++        unless defined($meta);
++
++    my ($disk) = grep { $_->{path} eq $path } @{$meta->{disks}};
++    err_and_die("$path not found in metadata") unless defined($disk);
++
++    # Construct a volume name based on the path and hostname
++    my $name = $meta->{name}.'-'.$disk->{device};
++    $name =~ s,/,_,g;       # e.g. cciss devices have a directory structure
++
++    my $sopts = $config->get_storage_opts();
++
++    my $convert = 0;
++    my $format;
++    my $sparse;
++
++    # Default to raw. Conversion required for anything else.
++    if (!exists($sopts->{format}) || $sopts->{format} eq 'raw') {
++        $format = 'raw';
++    } else {
++        $format = $sopts->{format};
++        $convert = 1;
++    }
++
++    # Default to non-sparse
++    my $allocation = $sopts->{allocation};
++    if (!defined($allocation) || $allocation eq 'preallocated') {
++        $sparse = 0;
++    } elsif ($allocation eq 'sparse') {
++        $sparse = 1;
++    } else {
++        err_and_die(__x('Invalid allocation policy {policy} in profile.',
++                        policy => $allocation));
++    }
++
++    # Create the target volume
++    my $vol;
++    eval {
++        $vol = $target->create_volume(
++            $name,
++            $format,
++            $length,
++            $sparse
++        );
++    };
++    err_and_die($@) if $@;
++    p2v_return_ok();
++
++    # Receive an initial container
++    my $msg = p2v_receive();
++    unexpected_msg($msg->{type}) unless $msg->{type} eq MSG_CONTAINER;
++
++    # We only support RAW container
++    my $ctype = $msg->{args}[0];
++    err_and_die("Received unknown container type: $ctype")
++        unless $ctype eq CONT_RAW;
++    p2v_return_ok();
++
++    # Update the disk entry with the new volume details
++    $disk->{local_path} = $vol->get_local_path();
++    $disk->{path} = $vol->get_path();
++    $disk->{is_block} = $vol->is_block();
++
++    my $writer = $vol->get_write_stream($convert);
++
++    # Receive volume data in chunks
++    my $received = 0;
++    while ($received < $length) {
++        my $data = p2v_receive();
++
++        unexpected_msg($data->command) unless $data->{type} eq MSG_DATA;
++
++        # Read the data message in chunks of up to 4M
++        my $remaining = $data->{args}[0];
++        while ($remaining > 0) {
++            my $chunk = $remaining > 4*1024*1024 ? 4*1024*1024 : $remaining;
++            my $buf = p2v_read($chunk);
++
++            $received += $chunk;
++            $remaining -= $chunk;
++
++            eval { $writer->write($buf); };
++            err_and_die($@) if $@;
++        }
++
++        p2v_return_ok();
++    }
++}
++
++# Use the specified profile
++sub set_profile
++{
++    my ($profile) = @_;
++
++    # Check the profile is in our list
++    my $found = 0;
++    for my $i ($config->list_profiles()) {
++        if ($i eq $profile) {
++            $found = 1;
++            last;
++        }
++    }
++    err_and_die(__x('Invalid profile: {profile}', profile => $profile))
++        unless ($found);
++
++    $config->use_profile($profile);
++
++    my $storage = $config->get_storage();
++    my $method = $config->get_method();
++    if ($method eq 'libvirt') {
++        $target = new Sys::VirtConvert::Connection::LibVirtTarget
++            ('qemu:///system', $storage);
++    } elsif ($method eq 'rhev') {
++        $target = new Sys::VirtConvert::Connection::RHEVTarget($storage);
++    } else {
++        err_and_die(__x('Profile {profile} specifies invalid method {method}.',
++                        profile => $profile, method => $method));
++    }
++
++    p2v_return_ok();
++}
++
++sub convert
++{
++    err_and_die('CONVERT without prior SET_PROFILE command')
++        unless (defined($target));
++
++    err_and_die('CONVERT without prior METADATA command')
++        unless defined($meta);
++
++    my @localpaths = map { $_->{local_path} } @{$meta->{disks}};
++
++    my $g;
++    eval {
++        my $transferiso = $config->get_transfer_iso();
++
++        $g = new Sys::VirtConvert::GuestfsHandle(
++            \@localpaths,
++            $transferiso,
++            $target->isa('Sys::VirtConvert::Connection::RHEVTarget')
++        );
++
++        my $transferdev;
++        if (defined($transferiso)) {
++            my @devices = $g->list_devices();
++            $transferdev = pop(@devices);
++        }
++
++        my $root = inspect_guest($g, $transferdev);
++        my $guestcaps =
++            Sys::VirtConvert::Converter->convert($g, $config, $root, $meta);
++        $target->create_guest($g, $root, $meta, $config, $guestcaps,
++                              $meta->{name});
++
++        if($guestcaps->{block} eq 'virtio' && $guestcaps->{net} eq 'virtio') {
++            logmsg NOTICE, __x('{name} configured with virtio drivers.',
++                               name => $meta->{name});
++        } elsif ($guestcaps->{block} eq 'virtio') {
++            logmsg NOTICE, __x('{name} configured with virtio storage only.',
++                               name => $meta->{name});
++        } elsif ($guestcaps->{net} eq 'virtio') {
++            logmsg NOTICE, __x('{name} configured with virtio networking only.',
++                               name => $meta->{name});
++        } else {
++            logmsg NOTICE, __x('{name} configured without virtio drivers.',
++                               name => $meta->{name});
++        }
++    };
++
++    # If any of the above commands result in failure, we need to ensure that
++    # the guestfs qemu process is cleaned up before further cleanup. Failure to
++    # do this can result in failure to umount RHEV export's temporary mount
++    # point.
++    if ($@) {
++        my $err = $@;
++        $g->close();
++
++        # We trust the error was already logged
++        p2v_return_err($err);
++        die($@);
++    }
++
++    p2v_return_ok();
++}
++
++sub unexpected_msg
++{
++    err_and_die('Received unexpected command: '.shift);
++}
++
++sub err_and_die
++{
++    my $err = shift;
++    p2v_return_err($err);
++    v2vdie $err;
++}
++
++END {
++    my $err = $?;
++
++    logmsg NOTICE, __x("{program} exited.", program => 'p2v-server');
++
++    # die() sets $? to 255, which is untidy.
++    $? = $err == 255 ? 1 : $err;
++}
++
++# Perform guest inspection using the libguestfs core inspection API.
++# Returns the root device of the os to be converted.
++sub inspect_guest
++{
++    my $g = shift;
++    my $transferdev = shift;
++
++    # Get list of roots, sorted
++    my @roots = $g->inspect_os();
++
++    # Filter out the transfer device from the results of inspect_os
++    # There's a libguestfs bug (fixed upstream) which meant the transfer ISO
++    # could be erroneously detected as an unknown Windows OS. As we know what it
++    # is, we can filter out the transfer device here. Even when the fix is
++    # released this is reasonable belt & braces.
++    @roots = grep(!/^\Q$transferdev\E$/, @roots);
++
++    @roots = sort @roots;
++
++    # Only work on single-root operating systems.
++    v2vdie __('No root device found in this operating system image.')
++        if @roots == 0;
++
++    v2vdie __('Multiboot operating systems are not supported.')
++        if @roots > 1;
++
++    return $roots[0];
++}
++
++sub p2v_receive
++{
++    my $in = <>;
++    v2vdie __('Client closed connection unexpectedly') unless defined($in);
++
++    # Messages consist of the message type followed by 0 or more arguments,
++    # terminated by a newline
++    chomp($in);
++    $in =~ /^([A-Z_]+)( .+)?$/ or err_and_die("Received invalid message: $in");
++
++    my %msg;
++    $msg{type} = $1;
++    if (defined($2)) {
++        my @args = split(' ', $2);
++        $msg{args} =  \@args;
++    } else {
++        $msg{args} = [];
++    }
++
++    logmsg DEBUG, __x('Received: {command} {args}',
++                      command => $msg{type},
++                      args => join(' ', @{$msg{args}}));
++
++    return \%msg;
++}
++
++sub p2v_read
++{
++    my ($length) = @_;
++
++    my $buf;
++    my $total = 0;
++
++    while($total < $length) {
++        my $in = read(STDIN, $buf, $length, $total)
++            or err_and_die(__x('Error receiving data: {error}', error => $@));
++        logmsg DEBUG, "Read $in bytes";
++        $total += $in;
++    }
++
++    return $buf;
++}
++
++sub p2v_return_ok
++{
++    my $msg = "OK";
++    logmsg DEBUG, __x('Sent: {msg}', msg => $msg);
++    print $msg,"\n";
++}
++
++sub p2v_return_list
++{
++    my @values = @_;
++
++    my $msg = 'LIST '.scalar(@values);
++    foreach my $value (@values) {
++        $msg .= "\n$value";
++    }
++    logmsg DEBUG, __x('Sent: {msg}', msg => $msg);
++    print $msg,"\n";
++}
++
++sub p2v_return_err
++{
++    my $msg = 'ERROR '.shift;
++    logmsg DEBUG, __x('Sent: {msg}', msg => $msg);
++    print $msg,"\n";
++}
++
++=head1 SEE ALSO
++
++L<virt-v2v(1)>,
++L<http://libguestfs.org/>.
++
++=head1 AUTHOR
++
++Matthew Booth <mbooth at redhat.com>
++
++=head1 COPYRIGHT
++
++Copyright (C) 2011 Red Hat Inc.
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation; either version 2 of the License, or
++(at your option) any later version.
++
++This program is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with this program; if not, write to the Free Software
++Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+diff -ruN virt-v2v-v0.8.1/p2v-client/bin/virt-p2v virt-v2v-v0.8.1.new/p2v-client/bin/virt-p2v
+--- virt-v2v-v0.8.1/p2v-client/bin/virt-p2v	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/bin/virt-p2v	1970-01-01 01:00:00.000000000 +0100
+@@ -1,62 +0,0 @@
+-#!/usr/bin/env ruby
+-
+-# Copyright (C) 2011 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-require 'virt-p2v/ui/main'
+-require 'virt-p2v/ui/network'
+-require 'virt-p2v/ui/connect'
+-require 'virt-p2v/ui/convert'
+-require 'virt-p2v/ui/success'
+-
+-require 'virt-p2v/converter'
+-require 'virt-p2v/netdevice'
+-
+-require 'gettext'
+-
+-include GetText
+-
+-bindtextdomain('virt-p2v')
+-
+-if Process.uid != 0
+-    puts _("virt-p2v must be executed with root privileges.\n" +
+-           "It is intended to be included in a custom Live image, not " +
+-           "run from the command\nline.")
+-    abort
+-end
+-
+-converter = VirtP2V::Converter.new
+-
+-# Initialise the wizard UI
+-ui = VirtP2V::UI::Main.new
+-
+-# Initialize wizard pages
+-VirtP2V::UI::Network.init(ui)
+-VirtP2V::UI::Connect.init(ui, converter)
+-VirtP2V::UI::Convert.init(ui, converter)
+-VirtP2V::UI::Success.init(ui)
+-
+-# Skip the network configuration screen if there is already an active network
+-# connection
+-VirtP2V::NetworkDevice.all_devices.each { |device|
+-    if device.activated then
+-        ui.active_page = 'server_win'
+-        break
+-    end
+-}
+-
+-ui.show
+-ui.main_loop
+diff -ruN virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/blockdevice.rb virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/blockdevice.rb
+--- virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/blockdevice.rb	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/blockdevice.rb	1970-01-01 01:00:00.000000000 +0100
+@@ -1,112 +0,0 @@
+-# Copyright (C) 2011 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-module VirtP2V
+-
+-class NoSuchDeviceError < StandardError; end
+-
+-class FixedBlockDevice
+-    @@devices = {}
+-
+-    def self.all_devices
+-        @@devices.values
+-    end
+-
+-    def self.[](device)
+-        raise NoSuchDeviceError unless @@devices.has_key?(device)
+-
+-        @@devices[device]
+-    end
+-
+-    attr_reader :device
+-
+-    def initialize(device)
+-        @device = device
+-        @@devices[device] = self
+-    end
+-end
+-
+-class RemovableBlockDevice
+-    @@devices = {}
+-
+-    def self.all_devices
+-        @@devices.values
+-    end
+-
+-    def self.[](device)
+-        raise NoSuchDeviceError unless @@devices.has_key?(device)
+-
+-        @@devices[device]
+-    end
+-
+-    attr_reader :device, :type
+-
+-    def initialize(device, type)
+-        @device = device
+-        @type = type
+-
+-        @@devices[device] = self
+-    end
+-end
+-
+-# Detect and instantiate all fixed and removable block devices in the system
+-begin
+-    # Look for block devices
+-    # Specifically, we look for entries in /sys/block which have a device
+-    # symlink and no entries in their slaves subdirectory
+-    Dir.foreach('/sys/block') { |dev|
+-        next if dev == '.' || dev == '..'
+-
+-        # Skip if there's no device link
+-        next unless File.exists?("/sys/block/#{dev}/device")
+-
+-        # Skip if the slaves subdirectory contains anything other than . and
+-        # ..
+-        begin
+-            next if Dir.entries("/sys/block/#{dev}/slaves").length > 2
+-        rescue Errno::ENOENT => ex
+-            # This shouldn't happen, but if it did I guess it would mean
+-            # there are no slave devices
+-        end
+-
+-        # We've got a real block device. Check if it's removable or not
+-        File.open("/sys/block/#{dev}/removable") { |fd|
+-            removable = fd.gets.chomp
+-            if removable == "0" then
+-                FixedBlockDevice.new(dev)
+-            else
+-                # Look in device/modalias to work out what kind of removable
+-                # device this is
+-                type = File.open(
+-                    "/sys/block/#{dev}/device/modalias") \
+-                { |modalias_f|
+-                    modalias = modalias_f.gets.chomp
+-                    if modalias =~ /floppy/ then
+-                        'floppy'
+-                    elsif modalias =~ /cdrom/ then
+-                        'cdrom'
+-                    else
+-                        # We don't know what this is, ignore it
+-                    end
+-                }
+-
+-                RemovableBlockDevice.new(dev, type) unless type.nil?
+-            end
+-        }
+-    }
+-end
+-
+-end
+diff -ruN virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/connection.rb virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/connection.rb
+--- virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/connection.rb	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/connection.rb	1970-01-01 01:00:00.000000000 +0100
+@@ -1,320 +0,0 @@
+-# Copyright (C) 2011 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-require 'gettext'
+-require 'rubygems'
+-require 'net/ssh'
+-require 'thread'
+-require 'yaml'
+-
+-require 'virt-p2v/gtk-queue'
+-
+-module VirtP2V
+-
+-class Connection
+-    include GetText
+-
+-    attr_reader :connected
+-
+-    class InvalidHostnameError < StandardError; end
+-    class InvalidCredentialsError < StandardError; end
+-    class TransportError < StandardError; end
+-    class NoP2VError < StandardError; end
+-    class RemoteError < StandardError; end
+-    class ProtocolError < StandardError; end
+-    class NotConnectedError < StandardError; end
+-
+-    def on_connect(&cb)
+-        @connection_listeners << cb
+-    end
+-
+-    def initialize(hostname, username, password, &cb)
+-        @mutex = Mutex.new
+-        @connection_listeners = []
+-
+-        # Always send our version number on connection
+-        @connection_listeners << Proc.new { |cb|
+-            self.version { |result| cb.call(result) }
+-        }
+-
+-        run(cb) {
+-            error = nil
+-            begin
+-                @ssh = Net::SSH.start(hostname, username, :password => password)
+-            rescue SocketError, Errno::EHOSTUNREACH => ex
+-                raise InvalidHostnameError
+-                raise ex
+-            rescue Net::SSH::AuthenticationFailed => ex
+-                raise InvalidCredentialsError
+-                raise ex
+-            end
+-
+-            @buffer = ""
+-            @connected = false
+-
+-            Gtk.queue { cb.call(true) }
+-        }
+-    end
+-
+-    def connect(&cb)
+-        run(cb) {
+-            @ch = @ssh.open_channel do |ch|
+-                ch.exec("virt-p2v-server") do |ch, success|
+-                    raise RemoteError,
+-                          "could not execute a remote command" unless success
+-
+-                    ch.on_data do |ch, data|
+-                        @buffer << data
+-                    end
+-
+-                    # If we get anything on stderr, raise it as a RemoteError
+-                    ch.on_extended_data do |ch, type, data|
+-                        close
+-                        raise RemoteError, data
+-                    end
+-
+-                    # Clean up local resources if we get eof from the other end
+-                    ch.on_eof do |ch|
+-                        close
+-                    end
+-
+-                    @connected = true
+-                end
+-
+-            end
+-
+-            # Wait until we're connected
+-            @ssh.loop do
+-                !@connected
+-            end
+-
+-            i = 0;
+-            listener_result = lambda { |result|
+-                if result.kind_of?(Exception)
+-                    cb.call(result)
+-                else
+-                    i += 1
+-                    if i == @connection_listeners.length
+-                        cb.call(true)
+-                    else
+-                        Gtk.queue {
+-                            @connection_listeners[i].call(listener_result)
+-                        }
+-                    end
+-                end
+-            }
+-            Gtk.queue { @connection_listeners[0].call(listener_result) }
+-        }
+-    end
+-
+-    def close
+-        @connected = false
+-        @buffer = ""
+-        @ch.close
+-    end
+-
+-    def version(&cb)
+-        raise NotConnectedError unless @connected
+-
+-        run(cb) {
+-            @ch.send_data("VERSION 0\n")
+-            result = parse_return
+-
+-            Gtk.queue { cb.call(result) }
+-        }
+-    end
+-
+-    def lang(lang, &cb)
+-        raise NotConnectedError unless @connected
+-
+-        run(cb) {
+-            @ch.send_data("LANG #{lang}\n")
+-            result = parse_return
+-
+-            Gtk.queue { cb.call(result) }
+-        }
+-    end
+-
+-    def metadata(meta, &cb)
+-        raise NotConnectedError unless @connected
+-
+-        run(cb) {
+-            payload = YAML::dump(meta)
+-            @ch.send_data("METADATA #{payload.length}\n");
+-            @ch.send_data(payload)
+-            result = parse_return
+-
+-            Gtk.queue { cb.call(result) }
+-        }
+-    end
+-
+-    def path(length, path, &cb)
+-        raise NotConnectedError unless @connected
+-
+-        run(cb) {
+-            @ch.send_data("PATH #{length} #{path}\n")
+-            result = parse_return
+-
+-            Gtk.queue { cb.call(result) }
+-        }
+-    end
+-
+-    def convert(&cb)
+-        raise NotConnectedError unless @connected
+-
+-        run(cb) {
+-            @ch.send_data("CONVERT\n")
+-            result = parse_return
+-
+-            Gtk.queue { cb.call(result) }
+-        }
+-    end
+-
+-    def list_profiles(&cb)
+-        raise NotConnectedError unless @connected
+-
+-        run(cb) {
+-            @ch.send_data("LIST_PROFILES\n")
+-            result = parse_return
+-
+-            Gtk.queue { cb.call(result) }
+-        }
+-    end
+-
+-    def set_profile(profile, &cb)
+-        raise NotConnectedError unless @connected
+-
+-        run(cb) {
+-            @ch.send_data("SET_PROFILE #{profile}\n")
+-            result = parse_return
+-
+-            Gtk.queue { cb.call(result) }
+-        }
+-    end
+-
+-    def container(type, &cb)
+-        raise NotConnectedError unless @connected
+-
+-        run(cb) {
+-            @ch.send_data("CONTAINER #{type}\n")
+-            result = parse_return
+-
+-            Gtk.queue { cb.call(result) }
+-        }
+-    end
+-
+-    def send_data(io, length, progress, &completion)
+-        raise NotConnectedError unless @connected
+-
+-        run(completion) {
+-            @ch.send_data("DATA #{length}\n")
+-            total = 0
+-            buffer = ''
+-            begin
+-                # This loop is in the habit of hanging in Net::SSH when sending
+-                # a chunk larger than about 2M. Putting the 1 second wait
+-                # timeout here kickstarts it if it stops.
+-                @ssh.loop(1) {
+-                    if io.eof? || total == length then
+-                        false
+-                    else
+-                        if @ch.remote_window_size > 0 then
+-                            out = length - total
+-                            out = @ch.remote_window_size \
+-                                if out > @ch.remote_window_size
+-
+-                            io.read(out, buffer)
+-                            @ch.send_data(buffer)
+-
+-                            total += buffer.length
+-
+-                            # Send a progress callback
+-                            Gtk.queue { progress.call(total) }
+-                        end
+-
+-                        true
+-                    end
+-                }
+-            rescue => ex
+-                Gtk.queue { completion.call(ex) }
+-            end
+-
+-            result = parse_return
+-
+-            Gtk.queue { completion.call(result) }
+-        }
+-    end
+-
+-    private
+-
+-    def run(cb)
+-        # Run the given block in a new thread
+-        t = Thread.new {
+-            begin
+-                # We can't run more than 1 command simultaneously
+-                @mutex.synchronize { yield }
+-            rescue => ex
+-                # Deliver exceptions to the caller, then re-raise them
+-                Gtk.queue { cb.call(ex) }
+-                raise ex
+-            end
+-        }
+-        t.priority = 1
+-    end
+-
+-    # Return a single line of output from the remote server
+-    def readline
+-        # Run the event loop until the buffer contains a newline
+-        index = nil
+-        @ssh.loop do
+-            if !@ch.eof? then
+-                index = @buffer.index("\n")
+-                index.nil?
+-            else
+-                close
+-                raise RemoteError, _('Server closed connection unexpectedly')
+-            end
+-        end
+-
+-        # Remove the line from the buffer and return it with the trailing
+-        # newline removed
+-        @buffer.slice!(0..index).chomp
+-    end
+-
+-    def parse_return
+-        line = readline
+-        line =~ /^(OK|ERROR|LIST)(?:\s(.*))?$/ or
+-            raise ProtocolError, "Invalid server response: #{line}"
+-
+-        return true if $~[1] == 'OK'
+-        if $~[1] == 'ERROR' then
+-            close
+-            raise RemoteError, $~[2]
+-        end
+-
+-        # LIST response. Get the number of items, and read that many lines
+-        n = Integer($~[2])
+-        ret = []
+-        while n > 0 do
+-            n -= 1
+-            ret.push(readline)
+-        end
+-
+-        ret
+-    end
+-end
+-
+-end
+diff -ruN virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/converter.rb virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/converter.rb
+--- virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/converter.rb	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/converter.rb	1970-01-01 01:00:00.000000000 +0100
+@@ -1,218 +0,0 @@
+-# Copyright (C) 2011 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-require 'gettext'
+-require 'rexml/document'
+-include REXML
+-
+-require 'virt-p2v/netdevice'
+-require 'virt-p2v/blockdevice'
+-
+-module VirtP2V
+-
+-# NIC
+-# hostname
+-# username
+-# password
+-
+-# name          User entry
+-# memory        Editable
+-# cpus          Editable
+-# arch          Detected: cpuflags contains lm (long mode)
+-# features      Detected: apic, acpi, pae
+-# disks         Editable, default to all
+-#   device        Detected
+-#   path          Detected
+-#   is_block      1
+-#   format        raw
+-# removables    Editable, default to all
+-#   device        Detected
+-#   type          Detected
+-# nics          Editable, default to all connected
+-#   mac           Detected, option to generate new
+-#   vnet          Set to nic name
+-#   vnet_type     bridge
+-
+-class Converter
+-    include GetText
+-
+-    attr_accessor :profile, :name, :cpus, :memory, :arch
+-    attr_reader :features, :disks, :removables, :nics
+-
+-    attr_reader :connection
+-
+-    def on_connection(&cb)
+-        @connection_listeners << cb
+-    end
+-
+-    def connection=(connection)
+-        @connection = connection
+-        @connection_listeners.each { |cb|
+-            cb.call(connection)
+-        }
+-    end
+-
+-    def convert(status, progress, &completion)
+-        iterate([
+-            lambda { |cb| @connection.set_profile(@profile, &cb) },
+-            lambda { |cb| @connection.metadata(meta, &cb) },
+-            lambda { |cb|
+-                iterate(@disks.map { |dev|
+-                    lambda { |cb2|
+-                        disk(dev, status, progress, cb2)
+-                    }
+-                }, cb)
+-            },
+-            lambda { |cb|
+-                status.call(_('Converting'))
+-                @connection.convert(&cb)
+-            }
+-        ], completion)
+-    end
+-
+-    private
+-
+-    def initialize()
+-        @profile = nil
+-        @connection = nil
+-        @connection_listeners = []
+-
+-        # Initialize basic system information
+-        @name = '' # There's no reasonable default for this
+-
+-        # Get total memory from /proc/meminfo
+-        File.open('/proc/meminfo', 'r') do |fd|
+-            fd.each { |line|
+-                next unless line =~ /^MemTotal:\s+(\d+)\b/
+-
+-                @memory = Integer($~[1]) * 1024
+-                break
+-            }
+-        end
+-
+-        # Get the total number of cpu threads from hwloc-info
+-        hwloc = Document.new `hwloc-info --of xml`
+-        @cpus = XPath.match(hwloc, "//object[@type='PU']").length
+-
+-        # Get cpu architecture and features from the first flags entry in
+-        # /proc/cpuinfo
+-        File.open('/proc/cpuinfo', 'r') do |fd|
+-            fd.each { |line|
+-                next unless line =~ /^flags\s*:\s(.*)$/
+-
+-                flags = $~[1]
+-
+-                # x86_64 if flags contains lm (long mode), i686 otherwise. We
+-                # don't support anything else.
+-                @arch = flags =~ /\blm\b/ ? 'x86_64' : 'i686'
+-
+-                # Pull some select features from cpu flags
+-                @features = []
+-                [ 'apic', 'acpi', 'pae' ].each { |f|
+-                    @features << f if flags =~ /\b#{f}\b/
+-                }
+-                break
+-            }
+-        end
+-
+-        # Initialise empty lists for optional devices. These will be added
+-        # according to the user's selection
+-        @disks = []
+-        @removables = []
+-        @nics = []
+-    end
+-
+-    def disk(dev, status, progress, completion)
+-        path = "/dev/#{dev}"
+-        # XXX: No error checking of blockdev execution
+-        size = Integer(`blockdev --getsize64 #{path}`.chomp)
+-        status.call(_("Transferring #{dev}"))
+-        iterate([
+-            lambda { |cb| @connection.path(size, path, &cb) },
+-            lambda { |cb| @connection.container('RAW', &cb) },
+-            lambda { |cb|
+-                io = nil
+-                begin
+-                    io = File.new(path, 'r')
+-                rescue => ex
+-                    cb.call(ex)
+-                end
+-                pc = 0
+-                @connection.send_data(io, size, lambda { |total|
+-                    npc = Float(total) * 100 / size
+-                    # Only update the progress if it has increased by
+-                    # at least 1%
+-                    if Integer(npc) > pc then
+-                        pc += 1
+-                        progress.call(dev, pc)
+-                    end
+-                }, &cb)
+-            }
+-        ], completion)
+-    end
+-
+-    def iterate(stages, completion)
+-        i = 0
+-        cb = lambda { |result|
+-            if result.kind_of?(Exception) then
+-                completion.call(result)
+-            else
+-                i += 1
+-                if i == stages.length then
+-                    completion.call(true)
+-                else
+-                    stages[i].call(cb)
+-                end
+-            end
+-        }
+-        stages[0].call(cb)
+-    end
+-
+-    def meta
+-        {
+-            'name'      => @name,
+-            'cpus'      => @cpus,
+-            'memory'    => @memory,
+-            'arch'      => @arch,
+-            'features'  => @features,
+-            'disks'     => @disks.map { |device|
+-                {
+-                    'device'    => device,
+-                    'path'      => "/dev/#{device}",
+-                    'is_block'  => '1',
+-                    'format'    => 'raw'
+-                }
+-            },
+-            'removables' => @removables.map { |device|
+-                removable = RemovableBlockDevice[device]
+-                {
+-                    'device'    => removable.device,
+-                    'type'      => removable.type
+-                }
+-            },
+-            'nics'      => @nics.map { |device|
+-                nic = NetworkDevice[device]
+-                {
+-                    'mac'       => nic.mac,
+-                    'vnet'      => nic.name,
+-                    'vnet_type' => 'bridge'
+-                }
+-            }
+-        }
+-    end
+-end
+-
+-end
+diff -ruN virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/gtk-queue.rb virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/gtk-queue.rb
+--- virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/gtk-queue.rb	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/gtk-queue.rb	1970-01-01 01:00:00.000000000 +0100
+@@ -1,52 +0,0 @@
+-# Copyright (C) 2011 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-# This code is taken from:
+-#   http://ruby-gnome2.sourceforge.jp/hiki.cgi?tips_threads
+-# The author of the above page is given as Tal Liron
+-# The above page is distributed under the terms of the GNU FDL, although I
+-# consider this code to be too trivial to be copyrightable
+-
+-require 'gtk2'
+-require 'thread'
+-
+-module Gtk
+-    GTK_PENDING_BLOCKS = []
+-    GTK_PENDING_BLOCKS_LOCK = Mutex.new
+-
+-    def Gtk.queue &block
+-        if Thread.current == Thread.main
+-            block.call
+-        else
+-            GTK_PENDING_BLOCKS_LOCK.synchronize do
+-                GTK_PENDING_BLOCKS << block
+-            end
+-        end
+-    end
+-
+-    def Gtk.main_with_queue timeout
+-        Gtk.timeout_add timeout do
+-            GTK_PENDING_BLOCKS_LOCK.synchronize do
+-                for block in GTK_PENDING_BLOCKS
+-                    block.call
+-                end
+-                GTK_PENDING_BLOCKS.clear
+-            end
+-            true
+-        end
+-        Gtk.main
+-    end
+-end
+diff -ruN virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/netdevice.rb virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/netdevice.rb
+--- virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/netdevice.rb	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/netdevice.rb	1970-01-01 01:00:00.000000000 +0100
+@@ -1,259 +0,0 @@
+-# Copyright (C) 2011 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-require 'dbus'
+-require 'gettext'
+-
+-module VirtP2V
+-
+-class NetworkDevice
+-    include GetText
+-
+-    attr_reader :name, :mac, :connected, :activated, :state
+-
+-    # Some NetworkManager names, for convenience
+-    CONNECTION      = 'org.freedesktop.NetworkManagerSettings.Connection'.freeze
+-    DEVICE          = 'org.freedesktop.NetworkManager.Device'.freeze
+-    NETWORKMANAGER  = 'org.freedesktop.NetworkManager'.freeze
+-    PROPERTIES      = 'org.freedesktop.DBus.Properties'.freeze
+-    SETTINGS        = 'org.freedesktop.NetworkManagerSettings'.freeze
+-    WIRED           = 'org.freedesktop.NetworkManager.Device.Wired'.freeze
+-
+-    # NetworkManager device types
+-    # http://projects.gnome.org/NetworkManager/developers/spec-08.html
+-    TYPE_UNKNOWN  = 0
+-    TYPE_ETHERNET = 1
+-    TYPE_WIFI     = 2
+-    TYPE_GSM      = 3
+-    TYPE_CDMA     = 4
+-
+-    # NetworkManager device states
+-    STATE_UNKNOWN         = 0
+-    STATE_UNMANAGED       = 1
+-    STATE_UNAVAILABLE     = 2
+-    STATE_DISCONNECTED    = 3
+-    STATE_PREPARE         = 4
+-    STATE_CONFIG          = 5
+-    STATE_NEED_AUTH       = 6
+-    STATE_IP_CONFIG       = 7
+-    STATE_ACTIVATED       = 8
+-    STATE_FAILED          = 9
+-
+-    # Human readable descriptions of NetworkManager Device States
+-    STATES = {
+-        0 => _('Unknown').freeze,           # For completeness
+-        1 => _('Unmanaged').freeze,         # For completeness
+-        2 => _('No cable connected').freeze,
+-        3 => _('Not connected').freeze,
+-        4 => _('Preparing to connect').freeze,
+-        5 => _('Configuring').freeze,
+-        6 => _('Waiting for authentication').freeze,
+-        7 => _('Obtaining an IP address').freeze,
+-        8 => _('Connected').freeze,
+-        9 => _('Connection failed').freeze
+-    }.freeze
+-
+-    def initialize(obj, device, props)
+-        device.default_iface = WIRED
+-
+-        @nm_obj = obj
+-        @name   = props.Get(DEVICE, 'Interface')[0]
+-        @mac    = props.Get(WIRED, 'HwAddress')[0]
+-        state   = props.Get(WIRED, 'State')[0]
+-
+-        # Lookup by name
+-        @@devices[@name] = self
+-
+-        state_updated(state)
+-
+-        # Register a listener for state changes
+-        device.on_signal('PropertiesChanged') { |props|
+-            if props.has_key?('State') then
+-                state_updated(props['State'])
+-
+-                # Notify registered state change handlers
+-                @@listeners.each { |cb| cb.call(self) }
+-            end
+-        }
+-    end
+-
+-    def self.all_devices()
+-        @@devices.values
+-    end
+-
+-    def self.add_listener(cb)
+-        @@listeners.push(cb)
+-    end
+-
+-    def self.[](name)
+-        @@devices[name]
+-    end
+-
+-    def activate(auto, ip, prefix, gateway, dns)
+-        # Get an IP config dependent on whether @ip_address is IPv4 or IPv6
+-        ip_config = auto ? get_config_auto :
+-                           ip.ipv4? ? get_config_ipv4() : get_config_ipv6()
+-
+-        # Create a new NetworkManager connection object
+-        settings = @@nm_service.object(
+-            '/org/freedesktop/NetworkManagerSettings')
+-        settings.introspect()
+-        settings.default_iface = SETTINGS
+-
+-        uuid = `uuidgen`.chomp
+-        settings.AddConnection(
+-            'connection' => {
+-                'uuid' => uuid,
+-                'id' => 'P2V',
+-                'type' => '802-3-ethernet',
+-                'autoconnect' => false
+-            },
+-            '802-3-ethernet' => {},
+-            'ipv4' => ip_config['ipv4'],
+-            'ipv6' => ip_config['ipv6']
+-        )
+-
+-        # Find the connection we just created
+-        # XXX: There must be a better way to get this!
+-        conn = settings.ListConnections()[0].each { |i|
+-            conn = @@nm_service.object(i)
+-            conn.introspect
+-            conn.default_iface = CONNECTION
+-
+-            break i if conn.GetSettings()[0]['connection']['uuid'] == uuid
+-        }
+-
+-        nm = @@nm_service.object('/org/freedesktop/NetworkManager')
+-        nm.introspect
+-        nm.default_iface = NETWORKMANAGER
+-        nm.ActivateConnection('org.freedesktop.NetworkManagerSystemSettings',
+-                             conn, @nm_obj, '/')
+-    end
+-
+-    private
+-
+-    def state_updated(state)
+-        @connected = state > 2
+-        @state  = STATES[state]
+-
+-        if state == STATE_ACTIVATED then
+-            @activated = true
+-        elsif state == STATE_FAILED then
+-            @activated = false
+-        else
+-            @activated = nil
+-        end
+-    end
+-
+-    def get_config_auto
+-        {
+-            'ipv4' => {
+-                'method' => 'auto'
+-            },
+-            'ipv6' => {
+-                'method' => 'ignore'
+-            }
+-        }
+-    end
+-
+-    def ipv4_to_nm(ipaddr)
+-        ipaddr.hton().unpack("I")[0]
+-    end
+-
+-    def get_config_ipv4
+-        addresses = [[ ipv4_to_nm(@ip_address), @ip_prefix,
+-                       ipv4_to_nm(@ip_gateway) ]]
+-
+-        dns = []
+-        @ip_dns.each{ |ipaddr|
+-            # Only use IPv4 DNS servers
+-            next unless ipaddr.ipv4?
+-            dns.push(ipv4_to_nm(ipaddr))
+-        }
+-
+-        {
+-            'ipv4' => {
+-                'method' => 'manual',
+-                'addresses' => [ 'aau', addresses ],
+-                'dns' => [ 'au', dns ]
+-            },
+-            'ipv6' => {
+-                'method' => 'ignore'
+-            }
+-        }
+-    end
+-
+-    def ipv6_to_nm(ipaddr)
+-        ipaddr.hton().unpack("c*")
+-    end
+-
+-    def get_config_ipv6
+-        dns = []
+-        @ip_dns.each { |ipaddr|
+-            # Only use IPv6 DNS servers
+-            next unless ipaddr.ipv6?
+-            dns.push(ipv6_to_nm(ipaddr))
+-        }
+-
+-        {
+-            'ipv4' => {
+-                'method' => 'disabled'
+-            },
+-            'ipv6' => {
+-                'method' => 'manual',
+-                'addresses' => [ 'a(ayu)', [[
+-                    ipv6_to_nm(@ip_address),
+-                    @ip_prefix
+-                ]] ],
+-                'routes' => [ 'a(ayuayu)', [[
+-                    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], 0,
+-                    ipv6_to_nm(@ip_gateway), 1024
+-                ]] ],
+-                'dns' => [ 'aay', dns ]
+-            }
+-        }
+-    end
+-
+-    # Class initialization
+-    begin
+-        dbus = DBus::SystemBus.instance()
+-        dbus.glibize()
+-        @@nm_service = dbus.service(NETWORKMANAGER)
+-
+-        nm = @@nm_service.object('/org/freedesktop/NetworkManager')
+-        nm.introspect
+-        nm.default_iface = NETWORKMANAGER
+-
+-        @@devices = {}
+-        nm.GetDevices()[0].each { |obj|
+-            device = @@nm_service.object(obj)
+-            device.introspect
+-
+-            props = device[PROPERTIES]
+-            type = props.Get(DEVICE, 'DeviceType')[0]
+-
+-            # We only support ethernet devices
+-            next unless type == TYPE_ETHERNET
+-
+-            # Constructor will add it to @@devices
+-            self.new(obj, device, props)
+-        }
+-
+-        @@listeners = []
+-    end
+-end
+-
+-end #module
+diff -ruN virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/ui/connect.rb virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/ui/connect.rb
+--- virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/ui/connect.rb	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/ui/connect.rb	1970-01-01 01:00:00.000000000 +0100
+@@ -1,179 +0,0 @@
+-# Copyright (C) 2011 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-require 'gettext'
+-require 'gtk2'
+-
+-require 'virt-p2v/connection'
+-
+-module VirtP2V::UI::Connect
+-    include GetText
+-
+-    UI_STATE_INVALID    = 0
+-    UI_STATE_VALID      = 1
+-    UI_STATE_ACTIVATING = 2
+-    UI_STATE_COMPLETE   = 3
+-
+-    EV_HOSTNAME     = 0
+-    EV_USERNAME     = 1
+-    EV_PASSWORD     = 2
+-    EV_BUTTON       = 3
+-    EV_ACTIVATION   = 4
+-
+-    def self.event(event, status)
+-        case event
+-        when EV_HOSTNAME
+-            @hostname = status
+-        when EV_USERNAME
+-            @username = status
+-        when EV_PASSWORD
+-            @password = status
+-        when EV_BUTTON, EV_ACTIVATION
+-            # Persistent state not required
+-        else
+-            raise "Unexpected event: #{event}"
+-        end
+-
+-        valid = @hostname && @username && @password
+-
+-        case @state
+-        when UI_STATE_INVALID
+-            set_state(UI_STATE_VALID) if valid
+-        when UI_STATE_VALID
+-            if !valid then
+-                set_state(UI_STATE_INVALID)
+-            elsif event == EV_BUTTON
+-                set_state(UI_STATE_ACTIVATING)
+-            end
+-        when UI_STATE_ACTIVATING
+-            # UI is disabled, so we shouldn't be getting any events other than
+-            # EV_ACTIVATION
+-            raise "Unexpected event: #{event}" unless event == EV_ACTIVATION
+-
+-            set_state(status ? UI_STATE_COMPLETE : UI_STATE_VALID)
+-        else
+-            raise "Unexpected UI state: #{@state}"
+-        end
+-    end
+-
+-    def self.init(ui, converter)
+-        @hostname_ui    = ui.get_object('server_hostname')
+-        @username_ui    = ui.get_object('server_username')
+-        @password_ui    = ui.get_object('server_password')
+-        @connect_frame  = ui.get_object('connect_frame')
+-        @connect_button = ui.get_object('connect_button')
+-        @connect_error  = ui.get_object('connect_error')
+-
+-        ui.register_handler('server_hostname_changed',
+-                            method(:server_hostname_changed))
+-        ui.register_handler('server_username_changed',
+-                            method(:server_username_changed))
+-        ui.register_handler('server_password_changed',
+-                            method(:server_password_changed))
+-        ui.register_handler('connect_button_clicked',
+-                            method(:connect_button_clicked))
+-
+-        @hostname = @hostname_ui.text.strip.length > 0
+-        @username = @username_ui.text.strip.length > 0
+-        @password = @password_ui.text.length > 0 # Allow spaces in passwords
+-        @state = UI_STATE_INVALID
+-
+-        @ui = ui
+-        @converter = converter
+-    end
+-
+-    def self.set_state(state)
+-        # Don't do anything if state hasn't changed
+-        return if state == @state
+-
+-        case state
+-        when UI_STATE_INVALID
+-            @connect_frame.sensitive = true
+-            @connect_button.sensitive = false
+-
+-            @state = UI_STATE_INVALID
+-        when UI_STATE_VALID
+-            @connect_frame.sensitive = true
+-            @connect_button.sensitive = true
+-
+-            @state = UI_STATE_VALID
+-        when UI_STATE_ACTIVATING
+-            @connect_frame.sensitive = false
+-            @connect_button.sensitive = false
+-            @connect_error.text = ''
+-
+-            @state = UI_STATE_ACTIVATING
+-        when UI_STATE_COMPLETE
+-            # Activate the next page
+-            @ui.active_page = 'conversion_win'
+-
+-            # ... then leave this one as we hope to find it if we come back here
+-            set_state(UI_STATE_VALID)
+-        else
+-            raise "Attempt to set unexpected UI state: #{@state}"
+-        end
+-    end
+-
+-    def self.server_hostname_changed
+-        event(EV_HOSTNAME, @hostname_ui.text.strip.length > 0)
+-    end
+-
+-    def self.server_username_changed
+-        event(EV_USERNAME, @username_ui.text.strip.length > 0)
+-    end
+-
+-    def self.server_password_changed
+-        event(EV_PASSWORD, @password_ui.text.length > 0)
+-    end
+-
+-    def self.connect_button_clicked
+-        event(EV_BUTTON, true)
+-
+-        hostname = @hostname_ui.text.strip
+-        username = @username_ui.text.strip
+-        password = @password_ui.text
+-        connection = VirtP2V::Connection.new(hostname, username, password) \
+-        { |result|
+-            case result
+-            when true
+-                @converter.connection = connection
+-                connection.connect { |result|
+-                    case result
+-                    when true
+-                        event(EV_ACTIVATION, true)
+-                    when VirtP2V::Connection::RemoteError
+-                        @connect_error.text = _('Failed to start ' +
+-                                                'virt-p2v-server on remote ' +
+-                                                'server')
+-                        event(EV_ACTIVATION, false)
+-                    else
+-                        @connect_error.text = result.message
+-                        event(EV_ACTIVATION, false)
+-                    end
+-                }
+-            when VirtP2V::Connection::InvalidHostnameError
+-                @connect_error.text = _"Unable to connect to #{hostname}"
+-                event(EV_ACTIVATION, false)
+-            when VirtP2V::Connection::InvalidCredentialsError
+-                @connect_error.text = _"Invalid username/password"
+-                event(EV_ACTIVATION, false)
+-            else
+-                raise result
+-            end
+-        }
+-    end
+-
+-end # module
+diff -ruN virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/ui/convert.rb virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/ui/convert.rb
+--- virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/ui/convert.rb	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/ui/convert.rb	1970-01-01 01:00:00.000000000 +0100
+@@ -1,422 +0,0 @@
+-# Copyright (C) 2011 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-require 'gettext'
+-require 'gtk2'
+-
+-require 'virt-p2v/blockdevice'
+-require 'virt-p2v/netdevice'
+-
+-module VirtP2V::UI::Convert
+-    include GetText
+-
+-    CONVERT_PROFILE_NAME    = 0
+-
+-    CONVERT_NETWORK_CONVERT = 0
+-    CONVERT_NETWORK_DEVICE  = 1
+-
+-    CONVERT_FIXED_CONVERT   = 0
+-    CONVERT_FIXED_DEVICE    = 1
+-    CONVERT_FIXED_PROGRESS  = 2
+-
+-    CONVERT_REMOVABLE_CONVERT   = 0
+-    CONVERT_REMOVABLE_DEVICE    = 1
+-    CONVERT_REMOVABLE_TYPE      = 2
+-
+-    UI_STATE_INVALID    = 0
+-    UI_STATE_VALID      = 1
+-    UI_STATE_CONNECTING = 2
+-    UI_STATE_CONVERTING = 3
+-    UI_STATE_COMPLETE   = 4
+-
+-    EV_VALID        = 0
+-    EV_BUTTON       = 1
+-    EV_CONNECTION   = 2
+-    EV_CONVERTED    = 3
+-
+-    def self.init(ui, converter)
+-        # ListStores
+-        @profiles   = ui.get_object('convert_profile_list')
+-        @nics       = ui.get_object('convert_network_list')
+-        @fixeds     = ui.get_object('convert_fixed_list')
+-        @removables = ui.get_object('convert_removable_list')
+-
+-        # Widgets
+-        @profile    = ui.get_object('convert_profile')
+-        @name       = ui.get_object('convert_name')
+-        @cpus       = ui.get_object('convert_cpus')
+-        @memory     = ui.get_object('convert_memory')
+-        @editable   = ui.get_object('convert_editable')
+-        @button     = ui.get_object('convert_button')
+-        @status     = ui.get_object('convert_status')
+-
+-        # Get initial values from converter
+-        @name.text = converter.name
+-        @cpus.text = converter.cpus.to_s
+-        @memory.text = (converter.memory / 1024 / 1024).to_s
+-
+-        # Populate profiles on connection
+-        converter.on_connection { |conn|
+-            conn.on_connect { |cb|
+-                conn.list_profiles { |profiles|
+-                    cb.call(RuntimeError.new(_('Remote server does not ' +
+-                                               'define any profiles in ' +
+-                                               '/etc/virt-v2v.conf'))) \
+-                        if profiles.kind_of?(Exception) or profiles.empty?
+-
+-                    selected = @profile.active_iter
+-                    selected = selected[CONVERT_PROFILE_NAME] \
+-                        unless selected.nil?
+-
+-                    @profiles.clear
+-                    profiles.each { |i|
+-                        profile = @profiles.append
+-                        profile[CONVERT_PROFILE_NAME] = i
+-                        @profile.active_iter = profile if i == selected
+-                    }
+-
+-                    cb.call(true)
+-                }
+-            }
+-        }
+-
+-        VirtP2V::FixedBlockDevice.all_devices.each { |dev|
+-            fixed = @fixeds.append
+-            fixed[CONVERT_FIXED_CONVERT]    = true
+-            fixed[CONVERT_FIXED_DEVICE]     = dev.device
+-            fixed[CONVERT_FIXED_PROGRESS]   = 0
+-        }
+-
+-        VirtP2V::RemovableBlockDevice.all_devices.each { |dev|
+-            rem = @removables.append
+-            rem[CONVERT_REMOVABLE_CONVERT]  = true
+-            rem[CONVERT_REMOVABLE_DEVICE]   = dev.device
+-            rem[CONVERT_REMOVABLE_TYPE]     = dev.type
+-        }
+-
+-        VirtP2V::NetworkDevice.all_devices.each { |dev|
+-            nic = @nics.append
+-            nic[CONVERT_NETWORK_CONVERT]    = dev.connected
+-            nic[CONVERT_NETWORK_DEVICE]     = dev.name
+-        }
+-
+-        # Event handlers
+-        ui.register_handler('convert_profile_changed',
+-                            method(:update_values))
+-        ui.register_handler('convert_name_changed',
+-                            method(:update_values))
+-        ui.register_handler('convert_cpus_changed',
+-                            method(:convert_cpus_changed))
+-        ui.register_handler('convert_memory_changed',
+-                            method(:convert_memory_changed))
+-        ui.register_handler('convert_fixed_list_row_changed',
+-                            method(:convert_fixed_list_row_changed))
+-        ui.register_handler('convert_removable_list_row_changed',
+-                            method(:update_values))
+-        ui.register_handler('convert_network_list_row_changed',
+-                            method(:update_values))
+-        ui.register_handler('convert_fixed_select_toggled',
+-                            method(:convert_fixed_select_toggled))
+-        ui.register_handler('convert_removable_select_toggled',
+-                            method(:convert_removable_select_toggled))
+-        ui.register_handler('convert_network_select_toggled',
+-                            method(:convert_network_select_toggled))
+-        ui.register_handler('convert_button_clicked',
+-                            method(:convert_button_clicked))
+-
+-        @state = nil
+-        set_state(UI_STATE_INVALID)
+-        update_values
+-
+-        @ui = ui
+-        @converter = converter
+-    end
+-
+-    def self.event(event, status)
+-        case @state
+-        when UI_STATE_INVALID
+-            case event
+-            when EV_VALID
+-                set_state(UI_STATE_VALID) if status
+-            else
+-                raise "Unexpected event: #{@state} #{event}"
+-            end
+-        when UI_STATE_VALID
+-            case event
+-            when EV_VALID
+-                set_state(UI_STATE_INVALID) if !status
+-            when EV_BUTTON
+-                if @converter.connection.connected then
+-                    set_state(UI_STATE_CONVERTING)
+-                    convert
+-                else
+-                    set_state(UI_STATE_CONNECTING)
+-                    reconnect
+-                end
+-            else
+-                raise "Unexpected event: #{@state} #{event}"
+-            end
+-        when UI_STATE_CONNECTING
+-            case event
+-            when EV_CONNECTION
+-                if status then
+-                    set_state(UI_STATE_CONVERTING)
+-                    convert
+-                else
+-                    set_state(UI_STATE_VALID)
+-                end
+-            when EV_VALID
+-                # update_values will be called when the profile list is cleared
+-                # and repopulated during connection. Untidy, but ignore it.
+-            else
+-                raise "Unexpected event: #{@state} #{event}" \
+-                    unless event == EV_CONNECTION
+-            end
+-        when UI_STATE_CONVERTING
+-            case event
+-            when EV_CONVERTED
+-                if status then
+-                    set_state(UI_STATE_COMPLETE)
+-                else
+-                    set_state(UI_STATE_VALID)
+-                end
+-            when EV_VALID
+-                # update_values will be called when the list stores are updated.
+-                # Untidy, but ignore it
+-            else
+-                raise "Unexpected event: #{@state} #{event}"
+-            end
+-        else
+-            raise "Unexpected UI state: #{@state}"
+-        end
+-    end
+-
+-    def self.set_state(state)
+-        # Don't do anything if state hasn't changed
+-        return if state == @state
+-        @state = state
+-
+-        case @state
+-        when UI_STATE_INVALID
+-            @editable.sensitive = true
+-            @button.sensitive = false
+-        when UI_STATE_VALID
+-            @editable.sensitive = true
+-            @button.sensitive = true
+-        when UI_STATE_CONNECTING
+-            @status.text = _'Failed to start virt-p2v-server on remote server'
+-            @editable.sensitive = false
+-            @button.sensitive = false
+-        when UI_STATE_CONVERTING
+-            @editable.sensitive = false
+-            @button.sensitive = false
+-        when UI_STATE_COMPLETE
+-            @ui.active_page = 'success_win'
+-
+-            # ... then leave this one as we hope to find it if we come back here
+-            set_state(UI_STATE_VALID)
+-        else
+-            raise "Attempt to set unexpected UI state: #{@state}"
+-        end
+-    end
+-
+-    def self.convert
+-        @converter.convert(
+-            # status
+-            lambda { |msg|
+-                @status.text = msg
+-            },
+-            # progress
+-            lambda { |dev, progress|
+-                @fixeds.each { |model, path, iter|
+-                    next unless iter[CONVERT_FIXED_DEVICE] == dev
+-
+-                    iter[CONVERT_FIXED_PROGRESS] = progress
+-                    break
+-                }
+-            }
+-        ) { |result|
+-            # N.B. Explicit test against true is required here, as result may be
+-            # an Exception, which would also return true if evaluated alone
+-            if result == true then
+-                @status.text = ''
+-                event(EV_CONVERTED, true)
+-            else
+-                @status.text = result.message
+-                event(EV_CONVERTED, false)
+-            end
+-        }
+-    end
+-
+-    def self.reconnect
+-        @status.text = _('Reconnecting')
+-        @converter.connection.connect { |result|
+-            if result == true then
+-                event(EV_CONNECTION, true)
+-            else
+-                @status.text =
+-                    _'Failed to start virt-p2v-server on remote server'
+-                event(EV_CONNECTION, false)
+-            end
+-        }
+-    end
+-
+-    def self.convert_fixed_list_row_changed(model, path, iter)
+-        update_values
+-    end
+-
+-    class InvalidUIState < StandardError; end
+-
+-    def self.update_values
+-        valid = nil
+-        begin
+-            # Check there's a profile selected
+-            profile = @profile.active_iter
+-            raise InvalidUIState if profile.nil?
+-            @converter.profile = profile[CONVERT_PROFILE_NAME]
+-
+-            # Check there's a name set
+-            name = @name.text
+-            raise InvalidUIState if name.nil? || name.strip.length == 0
+-            @converter.name = name
+-
+-            # Check cpus and memory are set and numeric
+-            cpus = @cpus.text
+-            raise InvalidUIState if cpus.nil?
+-            cpus = Integer(cpus) rescue nil
+-            raise InvalidUIState if cpus.nil?
+-            @converter.cpus = cpus
+-
+-            memory = @memory.text
+-            raise InvalidUIState if memory.nil?
+-            memory = Integer(memory) rescue nil
+-            raise InvalidUIState if memory.nil?
+-            @converter.memory = memory * 1024 * 1024
+-
+-            # Check that at least 1 fixed storage device is selected
+-            fixed = false
+-            @converter.disks.clear
+-            @fixeds.each { |model, path, iter|
+-                if iter[CONVERT_FIXED_CONVERT] then
+-                    fixed = true
+-                    @converter.disks << iter[CONVERT_FIXED_DEVICE]
+-                end
+-            }
+-            raise InvalidUIState unless fixed
+-
+-            # Populate removables and nics, although these aren't required to be
+-            # selected for the ui state to be valid
+-            @converter.removables.clear
+-            @removables.each { |model, path, iter|
+-                if iter[CONVERT_REMOVABLE_CONVERT] then
+-                    @converter.removables << iter[CONVERT_REMOVABLE_DEVICE]
+-                end
+-            }
+-            @converter.nics.clear
+-            @nics.each { |model, path, iter|
+-                if iter[CONVERT_NETWORK_CONVERT] then
+-                    @converter.nics << iter[CONVERT_NETWORK_DEVICE]
+-                end
+-            }
+-        rescue InvalidUIState
+-            valid = false
+-        end
+-        valid = true if valid.nil?
+-
+-        event(EV_VALID, valid)
+-    end
+-
+-    def self.valid?
+-        # Check there's a profile selected
+-        profile = @profile.active_iter
+-        return false if profile.nil?
+-
+-        # Check there's a name set
+-        name = @name.text
+-        return false if name.nil?
+-        return false unless name.strip.length > 0
+-
+-        # Check cpus and memory are set and numeric
+-        cpus = @cpus.text
+-        return false if cpus.nil?
+-        cpus = Integer(cpus) rescue nil
+-        return false if cpus.nil?
+-
+-        memory = @memory.text
+-        return false if memory.nil?
+-        memory = Integer(memory) rescue nil
+-        return false if memory.nil?
+-
+-        # Check that at least 1 fixed storage device is selected
+-        fixed = false
+-        @fixeds.each { |model, path, iter|
+-            if iter[CONVERT_FIXED_CONVERT] then
+-                fixed = true
+-                break
+-            end
+-        }
+-        return false unless fixed
+-
+-        return true
+-    end
+-
+-    def self.convert_cpus_changed
+-        check_numeric(@cpus)
+-    end
+-
+-    def self.convert_memory_changed
+-        check_numeric(@memory)
+-    end
+-
+-    def self.check_numeric(widget)
+-        value = widget.text
+-        if value.nil? ? false : begin
+-            value = Integer(value)
+-            value > 0
+-        rescue
+-            false
+-        end
+-        then
+-            widget.secondary_icon_name = nil
+-        else
+-            widget.secondary_icon_name = 'gtk-dialog-warning'
+-            widget.secondary_icon_tooltip_text =
+-                _('Value must be an integer greater than 0')
+-        end
+-
+-        update_values
+-    end
+-
+-    def self.convert_fixed_select_toggled(widget, path)
+-        iter = @fixeds.get_iter(path)
+-        iter[CONVERT_FIXED_CONVERT] = !iter[CONVERT_FIXED_CONVERT]
+-    end
+-
+-    def self.convert_removable_select_toggled(widget, path)
+-        iter = @removables.get_iter(path)
+-        iter[CONVERT_REMOVABLE_CONVERT] = !iter[CONVERT_REMOVABLE_CONVERT]
+-    end
+-
+-    def self.convert_network_select_toggled(widget, path)
+-        iter = @nics.get_iter(path)
+-        iter[CONVERT_NETWORK_CONVERT] = !iter[CONVERT_NETWORK_CONVERT]
+-    end
+-
+-    def self.convert_button_clicked
+-        event(EV_BUTTON, true)
+-    end
+-
+-end # module
+diff -ruN virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/ui/main.rb virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/ui/main.rb
+--- virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/ui/main.rb	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/ui/main.rb	1970-01-01 01:00:00.000000000 +0100
+@@ -1,110 +0,0 @@
+-# Copyright (C) 2011 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-require 'gtk2'
+-require 'virt-p2v/gtk-queue'
+-
+-module VirtP2V
+-module UI
+-
+-class Main
+-    def get_object(name)
+-        o = @builder.get_object(name)
+-        raise "Object #{name} not found in ui" unless o != nil
+-
+-        return o
+-    end
+-
+-    def show
+-        @builder.connect_signals { |signal|
+-            raise "No hander for signal #{signal}" \
+-                unless @signal_handlers.has_key?(signal)
+-
+-            @signal_handlers[signal]
+-        }
+-
+-        # Display the main window
+-        main = self.get_object('main_window')
+-        main.show_all()
+-    end
+-
+-    def register_handler(signal, handler)
+-        @signal_handlers[signal] = handler
+-    end
+-
+-    def main_loop
+-        Gtk.main_with_queue 100
+-    end
+-
+-    def active_page=(name)
+-        raise "Attempt to activate non-existent page #{name}" \
+-            unless @pages.has_key?(name)
+-
+-        page = @pages[name]
+-
+-        @page_vbox = self.get_object('page_vbox') unless defined? @page_vbox
+-        @page_vbox.remove(@selected) if defined? @selected
+-        @page_vbox.add(page)
+-        @selected = page
+-    end
+-
+-    def active_page
+-        return @selected
+-    end
+-
+-    def quit
+-        Gtk.main_quit()
+-    end
+-
+-    private
+-
+-    def initialize
+-        @builder = Gtk::Builder.new()
+-
+-        # Find the UI definition in $LOAD_PATH
+-        i = $LOAD_PATH.index { |path|
+-            File.exists?(path + '/virt-p2v/ui/p2v.ui')
+-        }
+-        @builder.add_from_file($LOAD_PATH[i] + '/virt-p2v/ui/p2v.ui')
+-
+-        @signal_handlers = {}
+-        self.register_handler('gtk_main_quit', method(:quit))
+-
+-        # Configure the Wizard page frame
+-        # Can't change these colours from glade for some reason
+-        self.get_object('title_background').
+-           modify_bg(Gtk::STATE_NORMAL, Gdk::Color.parse('#86ABD9'))
+-        self.get_object('page_frame').
+-           modify_fg(Gtk::STATE_NORMAL, Gdk::Color.parse('#86ABD9'))
+-
+-        # Load all pages from glade
+-        @pages = {}
+-        [ 'network_win', 'server_win',
+-          'conversion_win', 'success_win' ].each { |name|
+-            page = self.get_object(name)
+-
+-            child = page.children[0]
+-            page.remove(child)
+-            @pages[name] = child
+-        }
+-
+-        # Set a default first page
+-        self.active_page = 'network_win'
+-    end
+-end
+-
+-end # UI
+-end # VirtP2V
+diff -ruN virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/ui/network.rb virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/ui/network.rb
+--- virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/ui/network.rb	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/ui/network.rb	1970-01-01 01:00:00.000000000 +0100
+@@ -1,317 +0,0 @@
+-# Copyright (C) 2011 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-require 'gettext'
+-require 'gtk2'
+-require 'ipaddr'
+-require 'virt-p2v/netdevice'
+-
+-module VirtP2V::UI::Network
+-    include GetText
+-
+-    # The indices of Device List colums, taken from glade
+-    DEVCOL_NAME      = 0
+-    DEVCOL_MAC       = 1
+-    DEVCOL_STATUS    = 2
+-    DEVCOL_AVAILABLE = 3
+-
+-    UI_STATE_INVALID    = 0
+-    UI_STATE_VALID      = 1
+-    UI_STATE_ACTIVATING = 2
+-    UI_STATE_COMPLETE   = 3
+-
+-    EV_IP_CONFIG    = 0
+-    EV_SELECTION    = 1
+-    EV_BUTTON       = 2
+-    EV_ACTIVATION   = 3
+-
+-    def self.event(event, status)
+-        case event
+-        when EV_IP_CONFIG
+-            @ip_config = status
+-        when EV_SELECTION
+-            @selected = status
+-        when EV_BUTTON, EV_ACTIVATION
+-            # Persistent state not required
+-        else
+-            raise "Unexpected NetworkConfig event: #{event}"
+-        end
+-
+-        case @state
+-        when UI_STATE_INVALID
+-            if @ip_config && @selected then
+-                set_state(UI_STATE_VALID)
+-            end
+-        when UI_STATE_VALID
+-            if !@ip_config || !@selected then
+-                set_state(UI_STATE_INVALID)
+-            elsif event == EV_BUTTON
+-                set_state(UI_STATE_ACTIVATING)
+-            end
+-        when UI_STATE_ACTIVATING
+-            # UI is disabled and we're waiting for EV_ACTIVATION, but we could
+-            # also get events triggered by NetworkManager signals.
+-
+-            if event == EV_ACTIVATION then
+-                if status then
+-                    set_state(UI_STATE_COMPLETE)
+-                else
+-                    set_state(UI_STATE_VALID)
+-                end
+-            elsif !@ip_config || !@selected then
+-                set_state(UI_STATE_INVALID)
+-            end
+-        else
+-            raise "Unexpected NetworkConfig UI state: #{@state}"
+-        end
+-    end
+-
+-    def self.init(ui)
+-        # Configure initial defaults
+-        @manual_mode = false
+-        @ip_address = nil
+-        @ip_prefix = nil
+-        @ip_gateway = nil
+-        @ip_dns = nil
+-        @state = UI_STATE_INVALID
+-        @ip_config = false
+-        @selected = false
+-
+-        @network_button     = ui.get_object('network_button')
+-        @device_list_frame  = ui.get_object('device_list_frame')
+-        @ipv4_config_frame  = ui.get_object('ipv4_config_frame')
+-        @dl_selection       = ui.get_object('network_device_list_view').
+-                              selection
+-        @device_list        = ui.get_object('network_device_list')
+-        @manual_ui          = ui.get_object('ip_manual')
+-        @ip_address_ui      = ui.get_object('ip_address')
+-        @ip_prefix_ui       = ui.get_object('ip_prefix')
+-        @ip_gateway_ui      = ui.get_object('ip_gateway')
+-        @ip_dns_ui          = ui.get_object('ip_dns')
+-
+-        ui.register_handler('network_button_clicked',
+-                            method(:network_button_clicked))
+-        ui.register_handler('ip_auto_toggled',
+-                            method(:ip_auto_toggled))
+-        ui.register_handler('ip_address_changed',
+-                            method(:ip_address_changed))
+-        ui.register_handler('ip_prefix_changed',
+-                            method(:ip_prefix_changed))
+-        ui.register_handler('ip_gateway_changed',
+-                            method(:ip_gateway_changed))
+-        ui.register_handler('ip_dns_changed',
+-                            method(:ip_dns_changed))
+-
+-        check_config_valid()
+-
+-        # The user may only select a single device
+-        @dl_selection.mode = Gtk::SELECTION_SINGLE
+-
+-        @dl_selection.set_select_function { |selection, model, path, current|
+-            iter = model.get_iter(path)
+-
+-            # This is a toggle event. The new state is the opposite of the
+-            # current state
+-            new_state = !current
+-
+-            # Don't allow the user to select an unavailable device
+-            if new_state then
+-                # Notify the config UI if we're selecting a device
+-                if iter[DEVCOL_AVAILABLE] then
+-                    event(EV_SELECTION, true)
+-                end
+-
+-                iter[DEVCOL_AVAILABLE]
+-
+-            # Always allow the user to unselect a device
+-            else
+-                # Notify the UI that we're unselecting the device
+-                event(EV_SELECTION, false)
+-                true
+-            end
+-        }
+-
+-        # Store a map of device names to row references
+-        refs = {}
+-
+-        # Populate the device list with all detected network devices
+-        VirtP2V::NetworkDevice.all_devices.each { |device|
+-            iter = @device_list.append()
+-
+-            iter[DEVCOL_NAME]       = device.name
+-            iter[DEVCOL_MAC]        = device.mac
+-            iter[DEVCOL_STATUS]     = device.state
+-            iter[DEVCOL_AVAILABLE]  = device.connected
+-
+-            # Store a stable reference to this row in the TreeModel
+-            refs[device.name] =
+-                Gtk::TreeRowReference.new(@device_list, iter.path)
+-        }
+-
+-        # Listen for updates to device states
+-        VirtP2V::NetworkDevice.add_listener( lambda { |device|
+-            path = refs[device.name].path
+-
+-            iter = @device_list.get_iter(path)
+-            iter[DEVCOL_STATUS]     = device.state
+-            iter[DEVCOL_AVAILABLE]  = device.connected
+-
+-            # Notify the UI that a device was activated
+-            event(EV_ACTIVATION, device.activated) \
+-                unless device.activated.nil?
+-
+-            # Unselect the path if it was previously selected and is no
+-            # longer available
+-            if !device.connected && @dl_selection.iter_is_selected?(iter)
+-            then
+-                @dl_selection.unselect_all()
+-                event(EV_SELECTION, false)
+-            end
+-        } )
+-
+-        @ui = ui
+-    end
+-
+-    def self.set_state(state)
+-        # Don't do anything if state hasn't changed
+-        return if state == @state
+-
+-        case state
+-        when UI_STATE_INVALID
+-            @network_button.sensitive = false
+-            @device_list_frame.sensitive = true
+-            @ipv4_config_frame.sensitive = true
+-
+-            @state = UI_STATE_INVALID
+-        when UI_STATE_VALID
+-            @network_button.sensitive = true
+-            @device_list_frame.sensitive = true
+-            @ipv4_config_frame.sensitive = true
+-
+-            @state = UI_STATE_VALID
+-        when UI_STATE_ACTIVATING
+-            @network_button.sensitive = false
+-            @device_list_frame.sensitive = false
+-            @ipv4_config_frame.sensitive = false
+-
+-            @state = UI_STATE_ACTIVATING
+-        when UI_STATE_COMPLETE
+-            # Activate the next page
+-            @ui.active_page = 'server_win'
+-
+-            # ... then leave this one as we hope to find it if we come back here
+-            set_state(UI_STATE_VALID)
+-        else
+-            raise "Attempt to set unexected NetworkConfig UI state: #{@state}"
+-        end
+-    end
+-
+-    def self.network_button_clicked
+-        event(EV_BUTTON, true)
+-
+-        iter = @dl_selection.selected
+-        return if iter.nil? # Shouldn't be possible
+-        name = iter[DEVCOL_NAME]
+-
+-        VirtP2V::NetworkDevice[name].activate(!@manual_mode, @ip_address,
+-                                              @ip_prefix, @ip_gateway, @ip_dns)
+-    end
+-
+-    def self.ip_auto_toggled
+-        @manual_mode = !@manual_mode
+-        @manual_ui.sensitive = @manual_mode
+-
+-        check_config_valid()
+-    end
+-
+-    def self.ip_address_changed
+-        @ip_address = parse_ip(@ip_address_ui)
+-
+-        check_config_valid()
+-    end
+-
+-    # Check IP prefix is a positive integer
+-    # We check that it's appropriate to the address class in use elsewhere
+-    def self.ip_prefix_changed
+-        begin
+-            @ip_prefix = Integer(@ip_prefix_ui.text)
+-        rescue ArgumentError => e
+-            # Ignore the result if it didn't parse
+-            @ip_prefix = nil
+-            return
+-        end
+-
+-        if @ip_prefix < 0 then
+-            @ip_prefix = nil
+-        end
+-
+-        check_config_valid()
+-    end
+-
+-    def self.ip_gateway_changed
+-        @ip_gateway = parse_ip(@ip_gateway_ui)
+-
+-        check_config_valid()
+-    end
+-
+-    # Parse an IP address understood by IPAddr
+-    def self.parse_ip(entry)
+-        a = entry.text.strip
+-
+-        begin
+-            ip = IPAddr.new(a)
+-        rescue ArgumentError => e
+-            # Ignore the result if it didn't parse
+-            ip = nil
+-        end
+-
+-        return ip
+-    end
+-
+-    def self.ip_dns_changed
+-        dns = @ip_dns_ui.text
+-
+-        @ip_dns = []
+-        dns.split(/\s*,+\s*/).each { |entry|
+-            begin
+-                @ip_dns << IPAddr.new(entry)
+-            rescue ArgumentError => e
+-                @ip_dns = ()
+-                break
+-            end
+-        }
+-    end
+-
+-    def self.check_config_valid
+-        if !@manual_mode || (!@ip_address.nil? &&
+-                             !@ip_prefix.nil? &&
+-                             !@ip_gateway.nil?) then
+-            if @manual_mode then
+-                # Check that IPv4/IPv6 is used consistently
+-                if @ip_address.ipv4? then
+-                    event(EV_IP_CONFIG, @ip_gateway.ipv4? && @ip_prefix < 32)
+-                else
+-                    event(EV_IP_CONFIG, @ip_gateway.ipv6? && @ip_prefix < 128)
+-                end
+-            else
+-                event(EV_IP_CONFIG, true)
+-            end
+-        else
+-            event(EV_IP_CONFIG, false)
+-        end
+-    end
+-
+-end # module
+diff -ruN virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/ui/p2v.ui virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/ui/p2v.ui
+--- virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/ui/p2v.ui	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/ui/p2v.ui	1970-01-01 01:00:00.000000000 +0100
+@@ -1,1031 +0,0 @@
+-<?xml version="1.0"?>
+-<interface>
+-  <requires lib="gtk+" version="2.16"/>
+-  <!-- interface-naming-policy project-wide -->
+-  <object class="GtkWindow" id="main_window">
+-    <property name="resizable">False</property>
+-    <property name="window_position">center-always</property>
+-    <property name="decorated">False</property>
+-    <signal name="destroy" handler="gtk_main_quit"/>
+-    <child>
+-      <object class="GtkAlignment" id="alignment2">
+-        <property name="visible">True</property>
+-        <property name="xscale">0</property>
+-        <property name="yscale">0</property>
+-        <child>
+-          <object class="GtkFrame" id="page_frame">
+-            <property name="width_request">800</property>
+-            <property name="height_request">600</property>
+-            <property name="visible">True</property>
+-            <property name="label_xalign">0</property>
+-            <property name="label_yalign">0</property>
+-            <property name="shadow_type">in</property>
+-            <child>
+-              <object class="GtkVBox" id="page_vbox">
+-                <property name="visible">True</property>
+-                <property name="orientation">vertical</property>
+-                <property name="spacing">2</property>
+-                <child>
+-                  <object class="GtkEventBox" id="title_background">
+-                    <property name="visible">True</property>
+-                    <child>
+-                      <object class="GtkLabel" id="title_label">
+-                        <property name="visible">True</property>
+-                        <property name="xalign">0</property>
+-                        <property name="yalign">0</property>
+-                        <property name="xpad">5</property>
+-                        <property name="ypad">5</property>
+-                        <property name="label">&lt;span weight='bold' foreground='white' size='xx-large'&gt;virt-p2v&lt;/span&gt;</property>
+-                        <property name="use_markup">True</property>
+-                      </object>
+-                    </child>
+-                  </object>
+-                  <packing>
+-                    <property name="expand">False</property>
+-                    <property name="position">0</property>
+-                  </packing>
+-                </child>
+-                <child>
+-                  <placeholder/>
+-                </child>
+-              </object>
+-            </child>
+-            <child type="label_item">
+-              <placeholder/>
+-            </child>
+-          </object>
+-        </child>
+-      </object>
+-    </child>
+-  </object>
+-  <object class="GtkListStore" id="network_device_list">
+-    <columns>
+-      <!-- column-name Name -->
+-      <column type="gchararray"/>
+-      <!-- column-name MAC -->
+-      <column type="gchararray"/>
+-      <!-- column-name Status -->
+-      <column type="gchararray"/>
+-      <!-- column-name Available -->
+-      <column type="gboolean"/>
+-    </columns>
+-  </object>
+-  <object class="GtkListStore" id="convert_network_list">
+-    <columns>
+-      <!-- column-name Convert -->
+-      <column type="gboolean"/>
+-      <!-- column-name Device -->
+-      <column type="gchararray"/>
+-    </columns>
+-    <signal name="row_changed" handler="convert_network_list_row_changed"/>
+-  </object>
+-  <object class="GtkListStore" id="convert_fixed_list">
+-    <columns>
+-      <!-- column-name Convert -->
+-      <column type="gboolean"/>
+-      <!-- column-name Device -->
+-      <column type="gchararray"/>
+-      <!-- column-name Progress -->
+-      <column type="gdouble"/>
+-    </columns>
+-    <signal name="row_changed" handler="convert_fixed_list_row_changed"/>
+-  </object>
+-  <object class="GtkListStore" id="convert_removable_list">
+-    <columns>
+-      <!-- column-name Convert -->
+-      <column type="gboolean"/>
+-      <!-- column-name Device -->
+-      <column type="gchararray"/>
+-      <!-- column-name Type -->
+-      <column type="gchararray"/>
+-    </columns>
+-    <signal name="row_changed" handler="convert_removable_list_row_changed"/>
+-  </object>
+-  <object class="GtkListStore" id="convert_profile_list">
+-    <columns>
+-      <!-- column-name Name -->
+-      <column type="gchararray"/>
+-    </columns>
+-  </object>
+-  <object class="GtkWindow" id="network_win">
+-    <property name="width_request">800</property>
+-    <property name="height_request">550</property>
+-    <child>
+-      <object class="GtkVBox" id="vbox1">
+-        <property name="visible">True</property>
+-        <property name="orientation">vertical</property>
+-        <child>
+-          <object class="GtkLabel" id="label1">
+-            <property name="visible">True</property>
+-            <property name="xalign">0</property>
+-            <property name="yalign">1</property>
+-            <property name="ypad">11</property>
+-            <property name="label" translatable="yes">Welcome to virt-p2v.</property>
+-          </object>
+-          <packing>
+-            <property name="expand">False</property>
+-            <property name="position">0</property>
+-          </packing>
+-        </child>
+-        <child>
+-          <object class="GtkFrame" id="device_list_frame">
+-            <property name="visible">True</property>
+-            <property name="label_xalign">0</property>
+-            <property name="shadow_type">out</property>
+-            <child>
+-              <object class="GtkScrolledWindow" id="scrolledwindow1">
+-                <property name="visible">True</property>
+-                <property name="can_focus">True</property>
+-                <property name="hscrollbar_policy">automatic</property>
+-                <property name="vscrollbar_policy">automatic</property>
+-                <child>
+-                  <object class="GtkTreeView" id="network_device_list_view">
+-                    <property name="visible">True</property>
+-                    <property name="can_focus">True</property>
+-                    <property name="model">network_device_list</property>
+-                    <property name="headers_clickable">False</property>
+-                    <property name="search_column">0</property>
+-                    <child>
+-                      <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+-                        <property name="title">Device</property>
+-                        <child>
+-                          <object class="GtkCellRendererText" id="cellrenderertext1"/>
+-                          <attributes>
+-                            <attribute name="sensitive">3</attribute>
+-                            <attribute name="text">0</attribute>
+-                          </attributes>
+-                        </child>
+-                      </object>
+-                    </child>
+-                    <child>
+-                      <object class="GtkTreeViewColumn" id="treeviewcolumn3">
+-                        <property name="fixed_width">18</property>
+-                        <property name="title">MAC Address</property>
+-                        <child>
+-                          <object class="GtkCellRendererText" id="cellrenderertext3"/>
+-                          <attributes>
+-                            <attribute name="sensitive">3</attribute>
+-                            <attribute name="text">1</attribute>
+-                          </attributes>
+-                        </child>
+-                      </object>
+-                    </child>
+-                    <child>
+-                      <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+-                        <property name="title">Status</property>
+-                        <child>
+-                          <object class="GtkCellRendererText" id="cellrenderertext2"/>
+-                          <attributes>
+-                            <attribute name="sensitive">3</attribute>
+-                            <attribute name="text">2</attribute>
+-                          </attributes>
+-                        </child>
+-                      </object>
+-                    </child>
+-                  </object>
+-                </child>
+-              </object>
+-            </child>
+-            <child type="label">
+-              <object class="GtkLabel" id="label5">
+-                <property name="visible">True</property>
+-                <property name="label" translatable="yes">&lt;b&gt;Select a network device&lt;/b&gt;</property>
+-                <property name="use_markup">True</property>
+-              </object>
+-            </child>
+-          </object>
+-          <packing>
+-            <property name="position">1</property>
+-          </packing>
+-        </child>
+-        <child>
+-          <object class="GtkFrame" id="ipv4_config_frame">
+-            <property name="visible">True</property>
+-            <property name="label_xalign">0</property>
+-            <property name="shadow_type">in</property>
+-            <child>
+-              <object class="GtkAlignment" id="alignment1">
+-                <property name="visible">True</property>
+-                <property name="left_padding">12</property>
+-                <child>
+-                  <object class="GtkVBox" id="vbox2">
+-                    <property name="visible">True</property>
+-                    <property name="orientation">vertical</property>
+-                    <child>
+-                      <object class="GtkCheckButton" id="ip_auto">
+-                        <property name="label" translatable="yes">Automatic configuration</property>
+-                        <property name="visible">True</property>
+-                        <property name="can_focus">True</property>
+-                        <property name="receives_default">False</property>
+-                        <property name="active">True</property>
+-                        <property name="draw_indicator">True</property>
+-                        <signal name="toggled" handler="ip_auto_toggled"/>
+-                      </object>
+-                      <packing>
+-                        <property name="position">0</property>
+-                      </packing>
+-                    </child>
+-                    <child>
+-                      <object class="GtkTable" id="ip_manual">
+-                        <property name="visible">True</property>
+-                        <property name="sensitive">False</property>
+-                        <property name="n_rows">3</property>
+-                        <property name="n_columns">2</property>
+-                        <property name="column_spacing">2</property>
+-                        <child>
+-                          <object class="GtkLabel" id="label3">
+-                            <property name="visible">True</property>
+-                            <property name="xalign">0</property>
+-                            <property name="label" translatable="yes">IP Address:</property>
+-                          </object>
+-                          <packing>
+-                            <property name="x_options">GTK_FILL</property>
+-                            <property name="y_options">GTK_FILL</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+-                          <object class="GtkLabel" id="label8">
+-                            <property name="visible">True</property>
+-                            <property name="xalign">0</property>
+-                            <property name="label" translatable="yes">Gateway:</property>
+-                          </object>
+-                          <packing>
+-                            <property name="top_attach">1</property>
+-                            <property name="bottom_attach">2</property>
+-                            <property name="x_options">GTK_FILL</property>
+-                            <property name="y_options">GTK_FILL</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+-                          <object class="GtkLabel" id="label4">
+-                            <property name="visible">True</property>
+-                            <property name="xalign">0</property>
+-                            <property name="label" translatable="yes">DNS Servers:</property>
+-                          </object>
+-                          <packing>
+-                            <property name="top_attach">2</property>
+-                            <property name="bottom_attach">3</property>
+-                            <property name="x_options">GTK_FILL</property>
+-                            <property name="y_options">GTK_FILL</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+-                          <object class="GtkEntry" id="ip_gateway">
+-                            <property name="visible">True</property>
+-                            <property name="can_focus">True</property>
+-                            <property name="max_length">39</property>
+-                            <property name="width_chars">39</property>
+-                            <property name="truncate_multiline">True</property>
+-                            <signal name="changed" handler="ip_gateway_changed"/>
+-                          </object>
+-                          <packing>
+-                            <property name="left_attach">1</property>
+-                            <property name="right_attach">2</property>
+-                            <property name="top_attach">1</property>
+-                            <property name="bottom_attach">2</property>
+-                            <property name="y_options">GTK_FILL</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+-                          <object class="GtkEntry" id="ip_dns">
+-                            <property name="visible">True</property>
+-                            <property name="can_focus">True</property>
+-                            <property name="width_chars">35</property>
+-                            <signal name="changed" handler="ip_dns_changed"/>
+-                          </object>
+-                          <packing>
+-                            <property name="left_attach">1</property>
+-                            <property name="right_attach">2</property>
+-                            <property name="top_attach">2</property>
+-                            <property name="bottom_attach">3</property>
+-                            <property name="y_options">GTK_FILL</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+-                          <object class="GtkHBox" id="hbox6">
+-                            <property name="visible">True</property>
+-                            <property name="spacing">2</property>
+-                            <child>
+-                              <object class="GtkEntry" id="ip_address">
+-                                <property name="visible">True</property>
+-                                <property name="can_focus">True</property>
+-                                <property name="max_length">39</property>
+-                                <property name="width_chars">39</property>
+-                                <property name="truncate_multiline">True</property>
+-                                <signal name="changed" handler="ip_address_changed"/>
+-                              </object>
+-                              <packing>
+-                                <property name="position">0</property>
+-                              </packing>
+-                            </child>
+-                            <child>
+-                              <object class="GtkLabel" id="label7">
+-                                <property name="visible">True</property>
+-                                <property name="xalign">0</property>
+-                                <property name="label" translatable="yes">Prefix:</property>
+-                              </object>
+-                              <packing>
+-                                <property name="expand">False</property>
+-                                <property name="position">1</property>
+-                              </packing>
+-                            </child>
+-                            <child>
+-                              <object class="GtkEntry" id="ip_prefix">
+-                                <property name="visible">True</property>
+-                                <property name="can_focus">True</property>
+-                                <property name="max_length">2</property>
+-                                <property name="width_chars">2</property>
+-                                <property name="truncate_multiline">True</property>
+-                                <signal name="changed" handler="ip_prefix_changed"/>
+-                              </object>
+-                              <packing>
+-                                <property name="expand">False</property>
+-                                <property name="position">2</property>
+-                              </packing>
+-                            </child>
+-                          </object>
+-                          <packing>
+-                            <property name="left_attach">1</property>
+-                            <property name="right_attach">2</property>
+-                            <property name="y_options">GTK_FILL</property>
+-                          </packing>
+-                        </child>
+-                      </object>
+-                      <packing>
+-                        <property name="position">1</property>
+-                      </packing>
+-                    </child>
+-                  </object>
+-                </child>
+-              </object>
+-            </child>
+-            <child type="label">
+-              <object class="GtkLabel" id="label2">
+-                <property name="visible">True</property>
+-                <property name="label" translatable="yes">&lt;b&gt;IP Configuration&lt;/b&gt;</property>
+-                <property name="use_markup">True</property>
+-              </object>
+-            </child>
+-          </object>
+-          <packing>
+-            <property name="expand">False</property>
+-            <property name="position">2</property>
+-          </packing>
+-        </child>
+-        <child>
+-          <object class="GtkAlignment" id="alignment3">
+-            <property name="visible">True</property>
+-            <property name="xalign">1</property>
+-            <property name="xscale">0</property>
+-            <child>
+-              <object class="GtkButton" id="network_button">
+-                <property name="label" translatable="yes">Use these network settings</property>
+-                <property name="visible">True</property>
+-                <property name="sensitive">False</property>
+-                <property name="can_focus">True</property>
+-                <property name="receives_default">True</property>
+-                <signal name="clicked" handler="network_button_clicked"/>
+-              </object>
+-            </child>
+-          </object>
+-          <packing>
+-            <property name="expand">False</property>
+-            <property name="position">3</property>
+-          </packing>
+-        </child>
+-      </object>
+-    </child>
+-  </object>
+-  <object class="GtkWindow" id="server_win">
+-    <child>
+-      <object class="GtkVBox" id="vbox3">
+-        <property name="visible">True</property>
+-        <property name="orientation">vertical</property>
+-        <child>
+-          <object class="GtkAlignment" id="alignment4">
+-            <property name="visible">True</property>
+-            <property name="xscale">0</property>
+-            <property name="yscale">0</property>
+-            <child>
+-              <object class="GtkFrame" id="connect_frame">
+-                <property name="visible">True</property>
+-                <property name="label_xalign">0</property>
+-                <property name="shadow_type">in</property>
+-                <child>
+-                  <object class="GtkAlignment" id="alignment9">
+-                    <property name="visible">True</property>
+-                    <property name="left_padding">12</property>
+-                    <child>
+-                      <object class="GtkVBox" id="vbox5">
+-                        <property name="visible">True</property>
+-                        <property name="orientation">vertical</property>
+-                        <child>
+-                          <object class="GtkTable" id="table1">
+-                            <property name="visible">True</property>
+-                            <property name="n_rows">3</property>
+-                            <property name="n_columns">2</property>
+-                            <property name="column_spacing">2</property>
+-                            <child>
+-                              <object class="GtkLabel" id="label9">
+-                                <property name="visible">True</property>
+-                                <property name="xalign">0</property>
+-                                <property name="label" translatable="yes">Hostname:</property>
+-                              </object>
+-                              <packing>
+-                                <property name="x_options"></property>
+-                                <property name="y_options"></property>
+-                              </packing>
+-                            </child>
+-                            <child>
+-                              <object class="GtkLabel" id="label10">
+-                                <property name="visible">True</property>
+-                                <property name="xalign">0</property>
+-                                <property name="label" translatable="yes">Username:</property>
+-                              </object>
+-                              <packing>
+-                                <property name="top_attach">1</property>
+-                                <property name="bottom_attach">2</property>
+-                                <property name="x_options"></property>
+-                                <property name="y_options"></property>
+-                              </packing>
+-                            </child>
+-                            <child>
+-                              <object class="GtkLabel" id="label11">
+-                                <property name="visible">True</property>
+-                                <property name="xalign">0</property>
+-                                <property name="label" translatable="yes">Password:</property>
+-                              </object>
+-                              <packing>
+-                                <property name="top_attach">2</property>
+-                                <property name="bottom_attach">3</property>
+-                                <property name="x_options"></property>
+-                                <property name="y_options"></property>
+-                              </packing>
+-                            </child>
+-                            <child>
+-                              <object class="GtkEntry" id="server_hostname">
+-                                <property name="visible">True</property>
+-                                <property name="can_focus">True</property>
+-                                <property name="invisible_char">&#x2022;</property>
+-                                <property name="width_chars">40</property>
+-                                <signal name="changed" handler="server_hostname_changed"/>
+-                              </object>
+-                              <packing>
+-                                <property name="left_attach">1</property>
+-                                <property name="right_attach">2</property>
+-                                <property name="y_options"></property>
+-                              </packing>
+-                            </child>
+-                            <child>
+-                              <object class="GtkEntry" id="server_password">
+-                                <property name="visible">True</property>
+-                                <property name="can_focus">True</property>
+-                                <property name="visibility">False</property>
+-                                <property name="invisible_char">&#x2022;</property>
+-                                <property name="width_chars">40</property>
+-                                <signal name="changed" handler="server_password_changed"/>
+-                              </object>
+-                              <packing>
+-                                <property name="left_attach">1</property>
+-                                <property name="right_attach">2</property>
+-                                <property name="top_attach">2</property>
+-                                <property name="bottom_attach">3</property>
+-                                <property name="y_options"></property>
+-                              </packing>
+-                            </child>
+-                            <child>
+-                              <object class="GtkEntry" id="server_username">
+-                                <property name="visible">True</property>
+-                                <property name="can_focus">True</property>
+-                                <property name="invisible_char">&#x2022;</property>
+-                                <property name="width_chars">40</property>
+-                                <property name="text" translatable="yes">root</property>
+-                                <signal name="changed" handler="server_username_changed"/>
+-                              </object>
+-                              <packing>
+-                                <property name="left_attach">1</property>
+-                                <property name="right_attach">2</property>
+-                                <property name="top_attach">1</property>
+-                                <property name="bottom_attach">2</property>
+-                                <property name="y_options"></property>
+-                              </packing>
+-                            </child>
+-                          </object>
+-                          <packing>
+-                            <property name="expand">False</property>
+-                            <property name="position">0</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+-                          <object class="GtkLabel" id="connect_error">
+-                            <property name="visible">True</property>
+-                            <property name="xalign">0</property>
+-                            <property name="yalign">0</property>
+-                            <property name="xpad">8</property>
+-                            <property name="ypad">8</property>
+-                            <attributes>
+-                              <attribute name="foreground" value="#ffff00000000"/>
+-                            </attributes>
+-                          </object>
+-                          <packing>
+-                            <property name="position">1</property>
+-                          </packing>
+-                        </child>
+-                      </object>
+-                    </child>
+-                  </object>
+-                </child>
+-                <child type="label">
+-                  <object class="GtkLabel" id="label6">
+-                    <property name="visible">True</property>
+-                    <property name="label" translatable="yes">&lt;b&gt;Connect to conversion server&lt;/b&gt;</property>
+-                    <property name="use_markup">True</property>
+-                  </object>
+-                </child>
+-              </object>
+-            </child>
+-          </object>
+-          <packing>
+-            <property name="position">0</property>
+-          </packing>
+-        </child>
+-        <child>
+-          <object class="GtkAlignment" id="alignment5">
+-            <property name="visible">True</property>
+-            <property name="xalign">1</property>
+-            <property name="yalign">0</property>
+-            <property name="xscale">0</property>
+-            <property name="yscale">0</property>
+-            <child>
+-              <object class="GtkButton" id="connect_button">
+-                <property name="label" translatable="yes">Connect</property>
+-                <property name="visible">True</property>
+-                <property name="sensitive">False</property>
+-                <property name="can_focus">True</property>
+-                <property name="receives_default">True</property>
+-                <signal name="clicked" handler="connect_button_clicked"/>
+-              </object>
+-            </child>
+-          </object>
+-          <packing>
+-            <property name="expand">False</property>
+-            <property name="position">1</property>
+-          </packing>
+-        </child>
+-      </object>
+-    </child>
+-  </object>
+-  <object class="GtkWindow" id="conversion_win">
+-    <child>
+-      <object class="GtkVBox" id="vbox4">
+-        <property name="visible">True</property>
+-        <property name="orientation">vertical</property>
+-        <child>
+-          <object class="GtkHBox" id="convert_editable">
+-            <property name="visible">True</property>
+-            <child>
+-              <object class="GtkFrame" id="frame2">
+-                <property name="visible">True</property>
+-                <property name="label_xalign">0</property>
+-                <property name="shadow_type">out</property>
+-                <child>
+-                  <object class="GtkAlignment" id="alignment6">
+-                    <property name="visible">True</property>
+-                    <property name="xalign">0</property>
+-                    <property name="yalign">0</property>
+-                    <property name="xscale">0</property>
+-                    <property name="yscale">0</property>
+-                    <property name="left_padding">12</property>
+-                    <child>
+-                      <object class="GtkTable" id="table2">
+-                        <property name="visible">True</property>
+-                        <property name="n_rows">4</property>
+-                        <property name="n_columns">2</property>
+-                        <property name="column_spacing">2</property>
+-                        <child>
+-                          <object class="GtkLabel" id="label14">
+-                            <property name="visible">True</property>
+-                            <property name="xalign">0</property>
+-                            <property name="label" translatable="yes">Destination Profile:</property>
+-                          </object>
+-                        </child>
+-                        <child>
+-                          <object class="GtkComboBox" id="convert_profile">
+-                            <property name="visible">True</property>
+-                            <property name="model">convert_profile_list</property>
+-                            <signal name="changed" handler="convert_profile_changed"/>
+-                            <child>
+-                              <object class="GtkCellRendererText" id="cellrenderertext8"/>
+-                              <attributes>
+-                                <attribute name="text">0</attribute>
+-                              </attributes>
+-                            </child>
+-                          </object>
+-                          <packing>
+-                            <property name="left_attach">1</property>
+-                            <property name="right_attach">2</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+-                          <object class="GtkLabel" id="label16">
+-                            <property name="visible">True</property>
+-                            <property name="xalign">0</property>
+-                            <property name="label" translatable="yes">Memory (MB):</property>
+-                          </object>
+-                          <packing>
+-                            <property name="top_attach">3</property>
+-                            <property name="bottom_attach">4</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+-                          <object class="GtkEntry" id="convert_memory">
+-                            <property name="visible">True</property>
+-                            <property name="can_focus">True</property>
+-                            <property name="invisible_char">&#x2022;</property>
+-                            <property name="truncate_multiline">True</property>
+-                            <signal name="changed" handler="convert_memory_changed"/>
+-                          </object>
+-                          <packing>
+-                            <property name="left_attach">1</property>
+-                            <property name="right_attach">2</property>
+-                            <property name="top_attach">3</property>
+-                            <property name="bottom_attach">4</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+-                          <object class="GtkLabel" id="label15">
+-                            <property name="visible">True</property>
+-                            <property name="xalign">0</property>
+-                            <property name="label" translatable="yes">Number of CPUs:</property>
+-                          </object>
+-                          <packing>
+-                            <property name="top_attach">2</property>
+-                            <property name="bottom_attach">3</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+-                          <object class="GtkLabel" id="label18">
+-                            <property name="visible">True</property>
+-                            <property name="xalign">0</property>
+-                            <property name="label" translatable="yes">Name</property>
+-                          </object>
+-                          <packing>
+-                            <property name="top_attach">1</property>
+-                            <property name="bottom_attach">2</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+-                          <object class="GtkEntry" id="convert_name">
+-                            <property name="visible">True</property>
+-                            <property name="can_focus">True</property>
+-                            <property name="invisible_char">&#x2022;</property>
+-                            <property name="truncate_multiline">True</property>
+-                            <signal name="changed" handler="convert_name_changed"/>
+-                          </object>
+-                          <packing>
+-                            <property name="left_attach">1</property>
+-                            <property name="right_attach">2</property>
+-                            <property name="top_attach">1</property>
+-                            <property name="bottom_attach">2</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+-                          <object class="GtkEntry" id="convert_cpus">
+-                            <property name="visible">True</property>
+-                            <property name="can_focus">True</property>
+-                            <property name="invisible_char">&#x2022;</property>
+-                            <property name="truncate_multiline">True</property>
+-                            <signal name="changed" handler="convert_cpus_changed"/>
+-                          </object>
+-                          <packing>
+-                            <property name="left_attach">1</property>
+-                            <property name="right_attach">2</property>
+-                            <property name="top_attach">2</property>
+-                            <property name="bottom_attach">3</property>
+-                          </packing>
+-                        </child>
+-                      </object>
+-                    </child>
+-                  </object>
+-                </child>
+-                <child type="label">
+-                  <object class="GtkLabel" id="label13">
+-                    <property name="visible">True</property>
+-                    <property name="label" translatable="yes">&lt;b&gt;Target properties&lt;/b&gt;</property>
+-                    <property name="use_markup">True</property>
+-                  </object>
+-                </child>
+-              </object>
+-              <packing>
+-                <property name="expand">False</property>
+-                <property name="fill">False</property>
+-                <property name="position">0</property>
+-              </packing>
+-            </child>
+-            <child>
+-              <object class="GtkVBox" id="vbox6">
+-                <property name="visible">True</property>
+-                <property name="orientation">vertical</property>
+-                <child>
+-                  <object class="GtkFrame" id="frame3">
+-                    <property name="visible">True</property>
+-                    <property name="label_xalign">0</property>
+-                    <property name="shadow_type">out</property>
+-                    <child>
+-                      <object class="GtkAlignment" id="alignment8">
+-                        <property name="visible">True</property>
+-                        <child>
+-                          <object class="GtkScrolledWindow" id="scrolledwindow2">
+-                            <property name="visible">True</property>
+-                            <property name="can_focus">True</property>
+-                            <property name="hscrollbar_policy">automatic</property>
+-                            <property name="vscrollbar_policy">automatic</property>
+-                            <child>
+-                              <object class="GtkTreeView" id="treeview1">
+-                                <property name="visible">True</property>
+-                                <property name="can_focus">True</property>
+-                                <property name="model">convert_fixed_list</property>
+-                                <property name="headers_clickable">False</property>
+-                                <property name="search_column">0</property>
+-                                <child>
+-                                  <object class="GtkTreeViewColumn" id="treeviewcolumn4">
+-                                    <property name="title">Convert</property>
+-                                    <property name="clickable">True</property>
+-                                    <child>
+-                                      <object class="GtkCellRendererToggle" id="convert_fixed_select">
+-                                        <signal name="toggled" handler="convert_fixed_select_toggled"/>
+-                                      </object>
+-                                      <attributes>
+-                                        <attribute name="active">0</attribute>
+-                                      </attributes>
+-                                    </child>
+-                                  </object>
+-                                </child>
+-                                <child>
+-                                  <object class="GtkTreeViewColumn" id="treeviewcolumn5">
+-                                    <property name="title">Device</property>
+-                                    <child>
+-                                      <object class="GtkCellRendererText" id="cellrenderertext4"/>
+-                                      <attributes>
+-                                        <attribute name="text">1</attribute>
+-                                      </attributes>
+-                                    </child>
+-                                  </object>
+-                                </child>
+-                                <child>
+-                                  <object class="GtkTreeViewColumn" id="treeviewcolumn8">
+-                                    <property name="title">Transfer Progress</property>
+-                                    <property name="expand">True</property>
+-                                    <child>
+-                                      <object class="GtkCellRendererProgress" id="cellrendererprogress1"/>
+-                                      <attributes>
+-                                        <attribute name="value">2</attribute>
+-                                      </attributes>
+-                                    </child>
+-                                  </object>
+-                                </child>
+-                              </object>
+-                            </child>
+-                          </object>
+-                        </child>
+-                      </object>
+-                    </child>
+-                    <child type="label">
+-                      <object class="GtkLabel" id="label17">
+-                        <property name="visible">True</property>
+-                        <property name="label" translatable="yes">&lt;b&gt;Fixed Storage&lt;/b&gt;</property>
+-                        <property name="use_markup">True</property>
+-                      </object>
+-                    </child>
+-                  </object>
+-                  <packing>
+-                    <property name="position">0</property>
+-                  </packing>
+-                </child>
+-                <child>
+-                  <object class="GtkFrame" id="frame4">
+-                    <property name="visible">True</property>
+-                    <property name="label_xalign">0</property>
+-                    <property name="shadow_type">out</property>
+-                    <child>
+-                      <object class="GtkAlignment" id="alignment11">
+-                        <property name="visible">True</property>
+-                        <child>
+-                          <object class="GtkScrolledWindow" id="scrolledwindow4">
+-                            <property name="visible">True</property>
+-                            <property name="can_focus">True</property>
+-                            <property name="hscrollbar_policy">automatic</property>
+-                            <property name="vscrollbar_policy">automatic</property>
+-                            <child>
+-                              <object class="GtkTreeView" id="treeview3">
+-                                <property name="visible">True</property>
+-                                <property name="can_focus">True</property>
+-                                <property name="model">convert_removable_list</property>
+-                                <child>
+-                                  <object class="GtkTreeViewColumn" id="treeviewcolumn9">
+-                                    <property name="title">Convert</property>
+-                                    <child>
+-                                      <object class="GtkCellRendererToggle" id="convert_removable_select">
+-                                        <signal name="toggled" handler="convert_removable_select_toggled"/>
+-                                      </object>
+-                                      <attributes>
+-                                        <attribute name="active">0</attribute>
+-                                      </attributes>
+-                                    </child>
+-                                  </object>
+-                                </child>
+-                                <child>
+-                                  <object class="GtkTreeViewColumn" id="treeviewcolumn10">
+-                                    <property name="title">Device</property>
+-                                    <child>
+-                                      <object class="GtkCellRendererText" id="cellrenderertext6"/>
+-                                      <attributes>
+-                                        <attribute name="text">1</attribute>
+-                                      </attributes>
+-                                    </child>
+-                                  </object>
+-                                </child>
+-                                <child>
+-                                  <object class="GtkTreeViewColumn" id="treeviewcolumn11">
+-                                    <property name="title">Type</property>
+-                                    <child>
+-                                      <object class="GtkCellRendererText" id="cellrenderertext7"/>
+-                                      <attributes>
+-                                        <attribute name="text">2</attribute>
+-                                      </attributes>
+-                                    </child>
+-                                  </object>
+-                                </child>
+-                              </object>
+-                            </child>
+-                          </object>
+-                        </child>
+-                      </object>
+-                    </child>
+-                    <child type="label">
+-                      <object class="GtkLabel" id="label19">
+-                        <property name="visible">True</property>
+-                        <property name="label" translatable="yes">&lt;b&gt;Removable Media&lt;/b&gt;</property>
+-                        <property name="use_markup">True</property>
+-                      </object>
+-                    </child>
+-                  </object>
+-                  <packing>
+-                    <property name="position">1</property>
+-                  </packing>
+-                </child>
+-                <child>
+-                  <object class="GtkFrame" id="frame1">
+-                    <property name="visible">True</property>
+-                    <property name="label_xalign">0</property>
+-                    <property name="shadow_type">out</property>
+-                    <child>
+-                      <object class="GtkAlignment" id="alignment10">
+-                        <property name="visible">True</property>
+-                        <property name="xalign">1</property>
+-                        <property name="yalign">1</property>
+-                        <child>
+-                          <object class="GtkScrolledWindow" id="scrolledwindow3">
+-                            <property name="visible">True</property>
+-                            <property name="can_focus">True</property>
+-                            <property name="hscrollbar_policy">automatic</property>
+-                            <property name="vscrollbar_policy">automatic</property>
+-                            <child>
+-                              <object class="GtkTreeView" id="treeview2">
+-                                <property name="visible">True</property>
+-                                <property name="can_focus">True</property>
+-                                <property name="model">convert_network_list</property>
+-                                <property name="headers_clickable">False</property>
+-                                <property name="search_column">0</property>
+-                                <child>
+-                                  <object class="GtkTreeViewColumn" id="treeviewcolumn6">
+-                                    <property name="title">Convert</property>
+-                                    <child>
+-                                      <object class="GtkCellRendererToggle" id="convert_network_select">
+-                                        <signal name="toggled" handler="convert_network_select_toggled"/>
+-                                      </object>
+-                                      <attributes>
+-                                        <attribute name="active">0</attribute>
+-                                      </attributes>
+-                                    </child>
+-                                  </object>
+-                                </child>
+-                                <child>
+-                                  <object class="GtkTreeViewColumn" id="treeviewcolumn7">
+-                                    <property name="title">Device</property>
+-                                    <child>
+-                                      <object class="GtkCellRendererText" id="cellrenderertext5"/>
+-                                      <attributes>
+-                                        <attribute name="text">1</attribute>
+-                                      </attributes>
+-                                    </child>
+-                                  </object>
+-                                </child>
+-                              </object>
+-                            </child>
+-                          </object>
+-                        </child>
+-                      </object>
+-                    </child>
+-                    <child type="label">
+-                      <object class="GtkLabel" id="label12">
+-                        <property name="visible">True</property>
+-                        <property name="label" translatable="yes">&lt;b&gt;Network Interfaces&lt;/b&gt;</property>
+-                        <property name="use_markup">True</property>
+-                      </object>
+-                    </child>
+-                  </object>
+-                  <packing>
+-                    <property name="position">2</property>
+-                  </packing>
+-                </child>
+-              </object>
+-              <packing>
+-                <property name="position">1</property>
+-              </packing>
+-            </child>
+-          </object>
+-          <packing>
+-            <property name="position">0</property>
+-          </packing>
+-        </child>
+-        <child>
+-          <object class="GtkHBox" id="hbox1">
+-            <property name="visible">True</property>
+-            <child>
+-              <object class="GtkLabel" id="convert_status">
+-                <property name="visible">True</property>
+-                <property name="xalign">0</property>
+-                <property name="xpad">12</property>
+-                <attributes>
+-                  <attribute name="foreground" value="#ffff00000000"/>
+-                </attributes>
+-              </object>
+-              <packing>
+-                <property name="position">0</property>
+-              </packing>
+-            </child>
+-            <child>
+-              <object class="GtkButton" id="convert_button">
+-                <property name="label" translatable="yes">Convert</property>
+-                <property name="visible">True</property>
+-                <property name="can_focus">True</property>
+-                <property name="receives_default">True</property>
+-                <signal name="clicked" handler="convert_button_clicked"/>
+-              </object>
+-              <packing>
+-                <property name="expand">False</property>
+-                <property name="fill">False</property>
+-                <property name="position">1</property>
+-              </packing>
+-            </child>
+-          </object>
+-          <packing>
+-            <property name="expand">False</property>
+-            <property name="fill">False</property>
+-            <property name="position">1</property>
+-          </packing>
+-        </child>
+-      </object>
+-    </child>
+-  </object>
+-  <object class="GtkWindow" id="success_win">
+-    <child>
+-      <object class="GtkVBox" id="vbox7">
+-        <property name="visible">True</property>
+-        <property name="orientation">vertical</property>
+-        <child>
+-          <object class="GtkLabel" id="label20">
+-            <property name="visible">True</property>
+-            <property name="label" translatable="yes">A guest has been successfully created on the target server.
+-
+-Remove the temporary boot device from this machine and press 'Reboot' to continue.</property>
+-            <property name="justify">center</property>
+-          </object>
+-          <packing>
+-            <property name="position">0</property>
+-          </packing>
+-        </child>
+-        <child>
+-          <object class="GtkAlignment" id="alignment7">
+-            <property name="visible">True</property>
+-            <property name="xscale">0.25</property>
+-            <property name="yscale">0.25</property>
+-            <child>
+-              <object class="GtkButton" id="reboot_button">
+-                <property name="label" translatable="yes">Reboot</property>
+-                <property name="visible">True</property>
+-                <property name="can_focus">True</property>
+-                <property name="receives_default">True</property>
+-                <signal name="clicked" handler="reboot_button_clicked"/>
+-              </object>
+-            </child>
+-          </object>
+-          <packing>
+-            <property name="position">1</property>
+-          </packing>
+-        </child>
+-      </object>
+-    </child>
+-  </object>
+-</interface>
+diff -ruN virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/ui/success.rb virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/ui/success.rb
+--- virt-v2v-v0.8.1/p2v-client/lib/virt-p2v/ui/success.rb	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/lib/virt-p2v/ui/success.rb	1970-01-01 01:00:00.000000000 +0100
+@@ -1,33 +0,0 @@
+-# Copyright (C) 2011 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-require 'gettext'
+-
+-module VirtP2V::UI::Success
+-    include GetText
+-
+-    def self.init(ui)
+-        ui.register_handler('reboot_button_clicked',
+-                            method(:reboot_button_clicked))
+-
+-        @ui = ui
+-    end
+-
+-    def self.reboot_button_clicked
+-        @ui.quit
+-    end
+-
+-end # module
+diff -ruN virt-v2v-v0.8.1/p2v-client/Manifest virt-v2v-v0.8.1.new/p2v-client/Manifest
+--- virt-v2v-v0.8.1/p2v-client/Manifest	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/Manifest	1970-01-01 01:00:00.000000000 +0100
+@@ -1,15 +0,0 @@
+-Rakefile
+-bin/virt-p2v
+-lib/virt-p2v/blockdevice.rb
+-lib/virt-p2v/connection.rb
+-lib/virt-p2v/converter.rb
+-lib/virt-p2v/gtk-queue.rb
+-lib/virt-p2v/netdevice.rb
+-lib/virt-p2v/ui/connect.rb
+-lib/virt-p2v/ui/convert.rb
+-lib/virt-p2v/ui/main.rb
+-lib/virt-p2v/ui/network.rb
+-lib/virt-p2v/ui/p2v.ui
+-lib/virt-p2v/ui/success.rb
+-virt-p2v.gemspec
+-Manifest
+diff -ruN virt-v2v-v0.8.1/p2v-client/Rakefile virt-v2v-v0.8.1.new/p2v-client/Rakefile
+--- virt-v2v-v0.8.1/p2v-client/Rakefile	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/Rakefile	1970-01-01 01:00:00.000000000 +0100
+@@ -1,37 +0,0 @@
+-# Copyright (C) 2011 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-require 'rubygems'
+-require 'echoe'
+-
+-Echoe.new("virt-p2v") do |p|
+-  p.project     = "Virt P2V"
+-  p.version     = `../Build version`
+-  p.author      = "Matthew Booth"
+-  p.summary     = "Send a machine's storage and metadata to virt-p2v-server"
+-  p.description = <<EOF
+-virt-p2v is a client which connects to a virt-p2v-server and transfer's the host
+-machine's storage and metadata. virt-p2v is intended to be run from a live
+-image, so it is unlikely you want to install it.
+-EOF
+-  p.url         = "http://libguestfs.org"
+-  p.email       = "libguestfs at redhat.com"
+-  p.runtime_dependencies = [
+-      'gtk2',
+-      'gettext',
+-      'net-ssh'
+-  ]
+-end
+diff -ruN virt-v2v-v0.8.1/p2v-client/virt-p2v.gemspec virt-v2v-v0.8.1.new/p2v-client/virt-p2v.gemspec
+--- virt-v2v-v0.8.1/p2v-client/virt-p2v.gemspec	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-client/virt-p2v.gemspec	1970-01-01 01:00:00.000000000 +0100
+@@ -1,44 +0,0 @@
+-# -*- encoding: utf-8 -*-
+-
+-Gem::Specification.new do |s|
+-  s.name = %q{virt-p2v}
+-  s.version = "0.7.1"
+-
+-  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
+-  s.authors = ["Matthew Booth"]
+-  s.date = %q{2011-04-15}
+-  s.default_executable = %q{virt-p2v}
+-  s.description = %q{virt-p2v is a client which connects to a virt-p2v-server and transfer's the host
+-machine's storage and metadata. virt-p2v is intended to be run from a live
+-image, so it is unlikely you want to install it.
+-}
+-  s.email = %q{libguestfs at redhat.com}
+-  s.executables = ["virt-p2v"]
+-  s.extra_rdoc_files = ["COPYING", "bin/virt-p2v", "lib/virt-p2v/blockdevice.rb", "lib/virt-p2v/connection.rb", "lib/virt-p2v/converter.rb", "lib/virt-p2v/gtk-queue.rb", "lib/virt-p2v/netdevice.rb", "lib/virt-p2v/ui/connect.rb", "lib/virt-p2v/ui/convert.rb", "lib/virt-p2v/ui/main.rb", "lib/virt-p2v/ui/network.rb", "lib/virt-p2v/ui/p2v.ui", "lib/virt-p2v/ui/success.rb"]
+-  s.files = ["COPYING", "Rakefile", "bin/virt-p2v", "lib/virt-p2v/blockdevice.rb", "lib/virt-p2v/connection.rb", "lib/virt-p2v/converter.rb", "lib/virt-p2v/gtk-queue.rb", "lib/virt-p2v/netdevice.rb", "lib/virt-p2v/ui/connect.rb", "lib/virt-p2v/ui/convert.rb", "lib/virt-p2v/ui/main.rb", "lib/virt-p2v/ui/network.rb", "lib/virt-p2v/ui/p2v.ui", "lib/virt-p2v/ui/success.rb", "virt-p2v.gemspec", "Manifest"]
+-  s.homepage = %q{http://libguestfs.org}
+-  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Virt-p2v"]
+-  s.require_paths = ["lib"]
+-  s.rubyforge_project = %q{Virt P2V}
+-  s.rubygems_version = %q{1.3.7}
+-  s.summary = %q{Send a machine's storage and metadata to virt-p2v-server}
+-
+-  if s.respond_to? :specification_version then
+-    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+-    s.specification_version = 3
+-
+-    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
+-      s.add_runtime_dependency(%q<gtk2>, [">= 0"])
+-      s.add_runtime_dependency(%q<gettext>, [">= 0"])
+-      s.add_runtime_dependency(%q<net-ssh>, [">= 0"])
+-    else
+-      s.add_dependency(%q<gtk2>, [">= 0"])
+-      s.add_dependency(%q<gettext>, [">= 0"])
+-      s.add_dependency(%q<net-ssh>, [">= 0"])
+-    end
+-  else
+-    s.add_dependency(%q<gtk2>, [">= 0"])
+-    s.add_dependency(%q<gettext>, [">= 0"])
+-    s.add_dependency(%q<net-ssh>, [">= 0"])
+-  end
+-end
+diff -ruN virt-v2v-v0.8.1/p2v-image-builder/common-install.ks virt-v2v-v0.8.1.new/p2v-image-builder/common-install.ks
+--- virt-v2v-v0.8.1/p2v-image-builder/common-install.ks	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-image-builder/common-install.ks	1970-01-01 01:00:00.000000000 +0100
+@@ -1,54 +0,0 @@
+-lang C
+-keyboard us
+-timezone --utc UTC
+-auth --useshadow --enablemd5
+-selinux --disabled
+-firewall --disabled
+-# TODO: the sizing of the image needs to be more dynamic
+-part / --size 1024 --fstype ext2
+-services --enabled=NetworkManager --disabled=auditd
+-bootloader --timeout=30
+-rootpw --iscrypted $1$tQiZwocX$ghhurQEm56p/HqgN.XEtk1
+-
+-# add missing scsi modules to initramfs
+-device 3w-9xxx
+-device 3w-sas
+-device 3w-xxxx
+-device a100u2w
+-device aacraid
+-device aic79xx
+-device aic94xx
+-device arcmsr
+-device atp870u
+-device be2iscsi
+-device bfa
+-device BusLogic
+-device cxgb3i
+-device dc395x
+-device fnic
+-device gdth
+-device hpsa
+-device hptiop
+-device imm
+-device initio
+-device ips
+-device libosd
+-device libsas
+-device libsrp
+-device lpfc
+-device megaraid
+-device megaraid_mbox
+-device megaraid_mm
+-device megaraid_sas
+-device mpt2sas
+-device mvsas
+-device osd
+-device osst
+-device pm8001
+-device pmcraid
+-device qla1280
+-device qla2xxx
+-device qla4xxx
+-device qlogicfas408
+-device stex
+-device tmscsim
+diff -ruN virt-v2v-v0.8.1/p2v-image-builder/common-manifest-post.ks virt-v2v-v0.8.1.new/p2v-image-builder/common-manifest-post.ks
+--- virt-v2v-v0.8.1/p2v-image-builder/common-manifest-post.ks	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-image-builder/common-manifest-post.ks	1970-01-01 01:00:00.000000000 +0100
+@@ -1,36 +0,0 @@
+-%post
+-echo -n "Creating manifest"
+-# Create post-image processing manifests
+-rpm -qa --qf '%{name}-%{version}-%{release}.%{arch} (%{SIGGPG:pgpsig})\n' | \
+-    sort > /manifest-rpm.txt
+-rpm -qa --qf '%{sourcerpm}\n' | sort -u > /manifest-srpm.txt
+-# collect all included licenses rhbz#601927
+-rpm -qa --qf '%{license}\n' | sort -u > /manifest-license.txt
+-# dependencies
+-rpm -qa | xargs -n1 rpm -e --test 2> /manifest-deps.txt
+-echo -n "."
+-find / -xdev -print -exec rpm -qf {} \; > /manifest-owns.txt
+-rpm -qa --qf '%{NAME}\t%{VERSION}\t%{RELEASE}\t%{BUILDTIME}\n' | \
+-    sort > /rpm-qa.txt
+-echo -n "."
+-
+-du -akx --exclude=/var/cache/yum / > /manifest-file.txt
+-du -x --exclude=/var/cache/yum / > /manifest-dir.txt
+-echo -n "."
+-bzip2 /manifest-deps.txt /manifest-owns.txt /manifest-file.txt /manifest-dir.txt
+-echo -n "."
+-
+-%end
+-
+-%post --nochroot
+-# Move manifests to ISO
+-mv $INSTALL_ROOT/manifest-* $LIVE_ROOT/isolinux
+-echo "done"
+-
+-# only works on x86, x86_64
+-if [ "$(uname -i)" = "i386" -o "$(uname -i)" = "x86_64" ]; then
+-    if [ ! -d $LIVE_ROOT/LiveOS ]; then mkdir -p $LIVE_ROOT/LiveOS ; fi
+-    cp /usr/bin/livecd-iso-to-disk $LIVE_ROOT/LiveOS
+-    cp /usr/bin/livecd-iso-to-pxeboot $LIVE_ROOT/LiveOS
+-fi
+-%end
+diff -ruN virt-v2v-v0.8.1/p2v-image-builder/common-minimizer.ks virt-v2v-v0.8.1.new/p2v-image-builder/common-minimizer.ks
+--- virt-v2v-v0.8.1/p2v-image-builder/common-minimizer.ks	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-image-builder/common-minimizer.ks	1970-01-01 01:00:00.000000000 +0100
+@@ -1,239 +0,0 @@
+-# This file is only relatively lightly modified from the version copied from
+-# oVirt, and certainly contains much which is irrelevant to this image. I have,
+-# however, removed some obviously extraneous entries and added a few additional
+-# entries.
+-#
+-# Matthew Booth <mbooth at redhat.com> - 18/4/2011
+-
+-%post --nochroot --interpreter image-minimizer
+-# lokkit is just an install-time dependency; we can remove
+-# it afterwards, which we do here
+-droprpm system-config-*
+-droprpm libsemanage-python
+-droprpm python-libs
+-droprpm python
+-
+-droprpm mkinitrd
+-droprpm isomd5sum
+-droprpm dmraid
+-droprpm checkpolicy
+-droprpm make
+-droprpm policycoreutils-python
+-droprpm setools-libs-python
+-droprpm setools-libs
+-
+-droprpm gamin
+-droprpm pm-utils
+-droprpm kbd
+-droprpm usermode
+-droprpm vbetool
+-droprpm ConsoleKit
+-droprpm hdparm
+-droprpm efibootmgr
+-droprpm linux-atm-libs
+-droprpm mtools
+-droprpm syslinux
+-droprpm wireless-tools
+-droprpm radeontool
+-droprpm libicu
+-droprpm gnupg2
+-droprpm fedora-release-notes
+-droprpm fedora-logos
+-
+-# cronie pulls in exim (sendmail) which pulls in all kinds of perl deps
+-droprpm exim
+-droprpm perl*
+-droprpm postfix
+-droprpm mysql*
+-
+-droprpm sysklogd
+-
+-# unneeded rhn deps
+-droprpm yum*
+-
+-# pam complains when this is missing
+-keeprpm ConsoleKit-libs
+-
+-# kernel modules minimization
+-
+-# filesystems
+-drop /lib/modules/*/kernel/fs
+-keep /lib/modules/*/kernel/fs/ext*
+-keep /lib/modules/*/kernel/fs/jbd*
+-keep /lib/modules/*/kernel/fs/btrfs
+-keep /lib/modules/*/kernel/fs/fat
+-keep /lib/modules/*/kernel/fs/nfs
+-keep /lib/modules/*/kernel/fs/nfs_common
+-keep /lib/modules/*/kernel/fs/fscache
+-keep /lib/modules/*/kernel/fs/lockd
+-keep /lib/modules/*/kernel/fs/nls/nls_utf8.ko
+-# autofs4     configfs  exportfs *fat     *jbd    mbcache.ko  nls       xfs
+-#*btrfs       cramfs   *ext2     *fscache *jbd2  *nfs         squashfs
+-# cachefiles  dlm      *ext3      fuse     jffs2 *nfs_common  ubifs
+-# cifs        ecryptfs *ext4      gfs2    *lockd  nfsd        udf
+-
+-# network
+-drop /lib/modules/*/kernel/net
+-keep /lib/modules/*/kernel/net/802*
+-keep /lib/modules/*/kernel/net/bridge
+-keep /lib/modules/*/kernel/net/core
+-keep /lib/modules/*/kernel/net/ipv*
+-keep /lib/modules/*/kernel/net/key
+-keep /lib/modules/*/kernel/net/llc
+-keep /lib/modules/*/kernel/net/netfilter
+-keep /lib/modules/*/kernel/net/rds
+-keep /lib/modules/*/kernel/net/sctp
+-keep /lib/modules/*/kernel/net/sunrpc
+-#*802    atm        can   ieee802154 *key      *netfilter  rfkill *sunrpc  xfrm
+-#*8021q  bluetooth *core *ipv4       *llc       phonet     sched   wimax
+-# 9p    *bridge     dccp *ipv6        mac80211 *rds       *sctp    wireless
+-
+-drop /lib/modules/*/kernel/sound
+-
+-# drivers
+-drop /lib/modules/*/kernel/drivers
+-keep /lib/modules/*/kernel/drivers/ata
+-keep /lib/modules/*/kernel/drivers/block
+-keep /lib/modules/*/kernel/drivers/cdrom
+-keep /lib/modules/*/kernel/drivers/char
+-keep /lib/modules/*/kernel/drivers/cpufreq
+-keep /lib/modules/*/kernel/drivers/dca
+-keep /lib/modules/*/kernel/drivers/dma
+-keep /lib/modules/*/kernel/drivers/edac
+-keep /lib/modules/*/kernel/drivers/firmware
+-keep /lib/modules/*/kernel/drivers/idle
+-keep /lib/modules/*/kernel/drivers/infiniband
+-keep /lib/modules/*/kernel/drivers/md
+-keep /lib/modules/*/kernel/drivers/message
+-keep /lib/modules/*/kernel/drivers/net
+-drop /lib/modules/*/kernel/drivers/net/pcmcia
+-drop /lib/modules/*/kernel/drivers/net/wireless
+-drop /lib/modules/*/kernel/drivers/net/ppp*
+-keep /lib/modules/*/kernel/drivers/pci
+-keep /lib/modules/*/kernel/drivers/scsi
+-keep /lib/modules/*/kernel/drivers/staging/ramzswap
+-keep /lib/modules/*/kernel/drivers/uio
+-keep /lib/modules/*/kernel/drivers/usb
+-drop /lib/modules/*/kernel/drivers/usb/atm
+-drop /lib/modules/*/kernel/drivers/usb/class
+-drop /lib/modules/*/kernel/drivers/usb/image
+-drop /lib/modules/*/kernel/drivers/usb/misc
+-drop /lib/modules/*/kernel/drivers/usb/serial
+-keep /lib/modules/*/kernel/drivers/vhost
+-keep /lib/modules/*/kernel/drivers/virtio
+-
+-# acpi       *cpufreq   hid         leds      mtd      ?regulator  uwb
+-#*ata         crypto   ?hwmon      *md       *net*      rtc       *vhost
+-# atm        *dca      ?i2c         media    ?parport  *scsi*      video
+-# auxdisplay *dma      *idle        memstick *pci      ?serial    *virtio
+-#*block      *edac      ieee802154 *message   pcmcia   ?ssb        watchdog
+-# bluetooth   firewire *infiniband ?mfd       platform *staging    xen
+-#*cdrom      *firmware  input       misc     ?power    ?uio
+-#*char*      ?gpu       isdn        mmc      ?pps      *usb
+-
+-drop /usr/share/zoneinfo
+-keep /usr/share/zoneinfo/UTC
+-
+-drop /etc/alsa
+-drop /usr/share/alsa
+-drop /usr/share/awk
+-drop /usr/share/vim
+-drop /usr/share/anaconda
+-drop /usr/share/backgrounds
+-drop /usr/share/wallpapers
+-drop /usr/share/kde-settings
+-drop /usr/share/gnome-background-properties
+-drop /usr/share/dracut
+-drop /usr/share/plymouth
+-drop /usr/share/setuptool
+-drop /usr/share/hwdata/MonitorsDB
+-drop /usr/share/hwdata/oui.txt
+-drop /usr/share/hwdata/videoaliases
+-drop /usr/share/hwdata/videodrivers
+-drop /usr/share/firstboot
+-drop /usr/share/lua
+-drop /usr/share/kde4
+-drop /usr/share/pixmaps
+-drop /usr/share/icons
+-drop /usr/share/fedora-release
+-drop /usr/share/tabset
+-
+-drop /usr/share/tc
+-drop /usr/share/emacs
+-drop /usr/share/info
+-drop /usr/src
+-drop /usr/etc
+-drop /usr/games
+-drop /usr/include
+-drop /usr/local
+-drop /usr/sbin/dell*
+-keep /usr/sbin/build-locale-archive
+-drop /usr/sbin/glibc_post_upgrade.*
+-drop /usr/lib*/tc
+-drop /usr/lib*/tls
+-drop /usr/lib*/sse2
+-drop /usr/lib*/pkgconfig
+-drop /usr/lib*/nss
+-drop /usr/lib*/games
+-drop /usr/lib*/alsa-lib
+-drop /usr/lib*/krb5
+-drop /usr/lib*/hal
+-drop /usr/lib*/gio
+-
+-# syslinux
+-drop /usr/share/syslinux
+-# glibc-common locales
+-drop /usr/lib/locale
+-keep /usr/lib/locale/usr/share/locale/en_US
+-# openssh
+-drop /usr/bin/sftp
+-drop /usr/bin/slogin
+-drop /usr/bin/ssh-add
+-drop /usr/bin/ssh-agent
+-drop /usr/bin/ssh-keyscan
+-# docs
+-drop /usr/share/omf
+-drop /usr/share/gnome
+-drop /usr/share/doc
+-keep /usr/share/doc/*-firmware-*
+-drop /usr/share/locale/
+-keep /usr/share/locale/en_US
+-drop /usr/share/man
+-drop /usr/share/i18n
+-drop /boot/*
+-drop /var/lib/builder
+-
+-drop /usr/lib*/libboost*
+-keep /usr/lib*/libboost_program_options.so*
+-keep /usr/lib*/libboost_filesystem.so*
+-keep /usr/lib*/libboost_thread-mt.so*
+-keep /usr/lib*/libboost_system.so*
+-drop /usr/kerberos
+-keep /usr/kerberos/bin/kinit
+-keep /usr/kerberos/bin/klist
+-drop /lib/firmware
+-keep /lib/firmware/3com
+-keep /lib/firmware/acenic
+-keep /lib/firmware/adaptec
+-keep /lib/firmware/advansys
+-keep /lib/firmware/bnx2
+-keep /lib/firmware/cxgb3
+-keep /lib/firmware/e100
+-keep /lib/firmware/myricom
+-keep /lib/firmware/ql*
+-keep /lib/firmware/sun
+-keep /lib/firmware/tehuti
+-keep /lib/firmware/tigon
+-drop /lib/kbd/consolefonts
+-drop /etc/pki/tls
+-drop /etc/pki/java
+-drop /etc/pki/nssdb
+-drop /etc/pki/rpm-gpg
+-%end
+-
+-%post
+-echo "Removing python source files"
+-find / -name '*.py' -exec rm -f {} \;
+-find / -name '*.pyo' -exec rm -f {} \;
+-
+-%end
+diff -ruN virt-v2v-v0.8.1/p2v-image-builder/common-pkgs.ks virt-v2v-v0.8.1.new/p2v-image-builder/common-pkgs.ks
+--- virt-v2v-v0.8.1/p2v-image-builder/common-pkgs.ks	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-image-builder/common-pkgs.ks	1970-01-01 01:00:00.000000000 +0100
+@@ -1,48 +0,0 @@
+-# Direct requirements
+-rubygem-virt-p2v
+-bitstream-vera-sans-fonts
+-xorg-x11-xinit
+-xorg-x11-drivers
+-xorg-x11-server-Xorg
+-
+-# Boot requirements
+-device-mapper
+-
+-# Required for livecd creation
+-passwd
+-rpm
+-/usr/sbin/lokkit
+-
+-# Remove unnecessary packages
+--audit-libs-python
+--ustr
+--authconfig
+--wireless-tools
+--setserial
+--prelink
+--newt-python
+--newt
+--libselinux-python
+--kbd
+--usermode
+--fedora-release
+--fedora-release-notes
+--dmraid
+--gzip
+--less
+--which
+--parted
+--tar
+--libuser
+--mtools
+--cpio
+--yum
+--numactl # Pulls in perl dependency
+--perl
+-
+-# qlogic firmware
+-ql2100-firmware
+-ql2200-firmware
+-ql23xx-firmware
+-ql2400-firmware
+-ql2500-firmware
+diff -ruN virt-v2v-v0.8.1/p2v-image-builder/common-post.ks virt-v2v-v0.8.1.new/p2v-image-builder/common-post.ks
+--- virt-v2v-v0.8.1/p2v-image-builder/common-post.ks	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-image-builder/common-post.ks	1970-01-01 01:00:00.000000000 +0100
+@@ -1,43 +0,0 @@
+-# -*-Shell-script-*-
+-echo "Starting Kickstart Post"
+-PATH=/sbin:/usr/sbin:/bin:/usr/bin
+-export PATH
+-
+-# cleanup rpmdb to allow non-matching host and chroot RPM versions
+-rm -f /var/lib/rpm/__db*
+-
+-echo "Creating shadow files"
+-# because we aren't installing authconfig, we aren't setting up shadow
+-# and gshadow properly.  Do it by hand here
+-pwconv
+-grpconv
+-
+-echo "Forcing C locale"
+-# force logins (via ssh, etc) to use C locale, since we remove locales
+-cat >> /etc/profile << \EOF
+-# force our locale to C since we don't have locale stuff'
+-export LC_ALL=C LANG=C
+-EOF
+-
+-# remove errors from /sbin/dhclient-script
+-DHSCRIPT=/sbin/dhclient-script
+-sed -i 's/mv /cp -p /g'  $DHSCRIPT
+-sed -i '/rm -f.*${interface}/d' $DHSCRIPT
+-sed -i '/rm -f \/etc\/localtime/d' $DHSCRIPT
+-sed -i '/rm -f \/etc\/ntp.conf/d' $DHSCRIPT
+-sed -i '/rm -f \/etc\/yp.conf/d' $DHSCRIPT
+-
+-# Lock root account
+-#passwd -l root
+-
+-#strip out all unncesssary locales
+-localedef --list-archive | grep -v -i -E 'en_US.utf8' |xargs localedef --delete-from-archive
+-mv /usr/lib/locale/locale-archive /usr/lib/locale/locale-archive.tmpl
+-/usr/sbin/build-locale-archive
+-
+-# Run virt-p2v
+-cat >> /etc/rc.local <<EOF
+-export HOME=/root # rubygem Net::SSH needs this
+-/usr/bin/xinit /usr/bin/virt-p2v > /root/virt-p2v.log 2>&1
+-poweroff
+-EOF
+diff -ruN virt-v2v-v0.8.1/p2v-image-builder/common-post-nochroot.ks virt-v2v-v0.8.1.new/p2v-image-builder/common-post-nochroot.ks
+--- virt-v2v-v0.8.1/p2v-image-builder/common-post-nochroot.ks	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-image-builder/common-post-nochroot.ks	1970-01-01 01:00:00.000000000 +0100
+@@ -1,60 +0,0 @@
+-%include version.ks
+-
+-PRODUCT='Virt P2V'
+-PRODUCT_SHORT='virt-p2v'
+-PACKAGE='virt-p2v'
+-RELEASE=${RELEASE:-devel.`date +%Y%m%d%H%M%S`}
+-
+-echo "Customizing boot menu"
+-sed -i -e '
+-# Put product information at the top of the file
+-1 {
+-    i '"say $PRODUCT $VERSION ($RELEASE)"'
+-    i '"menu title $PRODUCT_SHORT $VERSION ($RELEASE)"'
+-}
+-
+-# Remove any existing menu title
+-/^menu title .*/d
+-
+-# Remove quiet bootparam
+-#s/ quiet//
+-
+-# Disable selinux entirely. Required, as we dont install an SELinux policy.
+-/^\s*append\s/ s/\s*$/ selinux=0/
+-
+-# Remove Verify and Boot option
+-/label check0/{N;N;N;d;}
+-
+-# Set the default timeout to 15 seconds
+-s/^timeout .*/timeout 15/
+-' $LIVE_ROOT/isolinux/isolinux.cfg
+-
+-# TODO: Replace the splash screen with something P2V appropriate
+-#cp $INSTALL_ROOT//syslinux-vesa-splash.jpg $LIVE_ROOT/isolinux/splash.jpg
+-
+-# store image version info in the ISO
+-cat > $LIVE_ROOT/isolinux/version <<EOF
+-PRODUCT='$PRODUCT'
+-PRODUCT_SHORT='${PRODUCT_SHORT}'
+-PRODUCT_CODE=$PRODUCT_CODE
+-RECIPE_SHA256=$RECIPE_SHA256
+-RECIPE_RPM=$RECIPE_RPM
+-PACKAGE=$PACKAGE
+-VERSION=$VERSION
+-RELEASE=$RELEASE
+-EOF
+-
+-# overwrite user visible banners with the image versioning info
+-cat > $INSTALL_ROOT/etc/$PACKAGE-release <<EOF
+-$PRODUCT release $VERSION ($RELEASE)
+-EOF
+-ln -snf $PACKAGE-release $INSTALL_ROOT/etc/redhat-release
+-ln -snf $PACKAGE-release $INSTALL_ROOT/etc/system-release
+-cp $INSTALL_ROOT/etc/$PACKAGE-release $INSTALL_ROOT/etc/issue
+-echo "Kernel \r on an \m (\l)" >> $INSTALL_ROOT/etc/issue
+-cp $INSTALL_ROOT/etc/issue $INSTALL_ROOT/etc/issue.net
+-
+-# replace initramfs if regenerated
+-if [ -f "$INSTALL_ROOT/initrd0.img" ]; then
+-  mv -v "$INSTALL_ROOT/initrd0.img" "$LIVE_ROOT/isolinux/initrd0.img"
+-fi
+diff -ruN virt-v2v-v0.8.1/p2v-image-builder/Makefile virt-v2v-v0.8.1.new/p2v-image-builder/Makefile
+--- virt-v2v-v0.8.1/p2v-image-builder/Makefile	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-image-builder/Makefile	1970-01-01 01:00:00.000000000 +0100
+@@ -1,2 +0,0 @@
+-version.ks: ../Build
+-	echo VERSION=`../Build version` > version.ks
+diff -ruN virt-v2v-v0.8.1/p2v-image-builder/version.ks virt-v2v-v0.8.1.new/p2v-image-builder/version.ks
+--- virt-v2v-v0.8.1/p2v-image-builder/version.ks	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-image-builder/version.ks	1970-01-01 01:00:00.000000000 +0100
+@@ -1 +0,0 @@
+-VERSION=0.8.1
+diff -ruN virt-v2v-v0.8.1/p2v-image-builder/virt-p2v-image-builder virt-v2v-v0.8.1.new/p2v-image-builder/virt-p2v-image-builder
+--- virt-v2v-v0.8.1/p2v-image-builder/virt-p2v-image-builder	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-image-builder/virt-p2v-image-builder	1970-01-01 01:00:00.000000000 +0100
+@@ -1,188 +0,0 @@
+-#!/bin/bash
+-
+-# Copyright (C) 2010-2011, Red Hat, Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; version 2 of the License.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+-# MA  02110-1301, USA.  A copy of the GNU General Public License is
+-# also available at http://www.gnu.org/copyleft/gpl.html.
+-
+-# Requires: sudo livecd-creator, sudo setenforce, ksflatten
+-
+-# Based on oVirt's node-creator
+-
+-# Current fedora data
+-cur_rawhide=16
+-cur_devel=15
+-
+-me=$(basename "$0")
+-warn() { printf '%s: %s\n' "$me" "$*" >&2; }
+-die() { warn "$*"; exit 1; }
+-usage() {
+-cat <<EOF
+-usage: $me <options>
+-
+-Build a virt-p2v bootable image.
+-
+-OPTIONS:
+-  -a    Additional yum repository. Can be specified multiple times.
+-  -c    Yum cache directory.
+-  -d    Directory containing virt-p2v-image.ks.
+-  -f    Specific Fedora mirror to use if building a Fedora image.
+-  -l    Boot image label.
+-  -r    Primary yum repository.
+-  -u    Updates yum repository.
+-  -h    Show this message.
+-EOF
+-}
+-
+-onlyonce() {
+-    warn "-$1 may only be specified once"
+-    usage
+-    exit 1
+-}
+-
+-while getopts "a:d:f:hl:r:u:w:" OPTION
+-do
+-    case $OPTION in
+-        a)
+-            n_elems=${#extra_repos[*]}
+-            extra_repos[$n_elems]="$OPTARG"
+-            ;;
+-        c)
+-            [ -n "$cachedir" ] && onlyonce $OPTION
+-            cachedir="$OPTARG"
+-            ;;
+-        d)
+-            [ -n "$datadir" ] && onlyonce $OPTION
+-            datadir="$OPTARG"
+-            ;;
+-        f)
+-            [ -n "$fedora_url" ] && onlyonce $OPTION
+-            fedora_url="$OPTARG"
+-            ;;
+-        l)
+-            [ -n "$label" ] && onlyonce $OPTION
+-            label="$OPTARG"
+-            ;;
+-        r)
+-            [ -n "$repo" ] && onlyonce $OPTION
+-            repo="$OPTARG"
+-            ;;
+-        u)
+-            [ -n "$updates" ] && onlyonce $OPTION
+-            updates="$OPTARG"
+-            ;;
+-        h)
+-            usage
+-            exit 0
+-            ;;
+-        ?)
+-            usage
+-            exit 1
+-            ;;
+-    esac
+-done
+-
+-# Split out here for simple editing with sed during installation
+-DEFAULT_DATADIR=.
+-
+-# Option defaults
+-datadir="${datadir:-$DEFAULT_DATADIR}"
+-cachedir="${cachedir:-/var/tmp/p2v-image-builder.$USER}"
+-label="${label:-Virt-P2V}"
+-
+-arch=$(rpm --eval '%{_arch}')
+-kstmp=$(mktemp --tmpdir p2v-image-builder.XXXXXXXX)
+-
+-if pgrep -xl nscd; then
+-    die "Please stop nscd first"
+-fi
+-
+-rm -f "$kstmp"
+-# combine recipe includes
+-ksflatten --config "$datadir/virt-p2v-image.ks" --output "$kstmp"
+-# XXX broken ksflatten leaves %include
+-sed -i 's/^%include /#&/' "$kstmp"
+-
+-if [ -z "$repo" ]; then
+-    # Set defaults for Fedora if this is a fedora system
+-    fedora=$(rpm --eval '%{fedora}' |grep [0-9])
+-
+-    mirrorlist="http://mirrors.fedoraproject.org/mirrorlist"
+-
+-    case "$fedora" in
+-    $curr_rawhide)
+-        if [ -z "$fedora_url" ]; then
+-            repo="--mirrorlist=$mirrorlist?repo=rawhide&arch=$arch"
+-        else
+-            repo="--baseurl=$fedora_url/development/rawhide/$arch/os"
+-        fi
+-        ;;
+-    $cur_devel)
+-        if [ -z "$fedora_url" ]; then
+-            repo="--mirrorlist=$mirrorlist?repo=fedora-$fedora&arch=$arch"
+-        else
+-            repo="--baseurl=$fedora_url/development/$fedora/$arch/os"
+-        fi
+-        ;;
+-    ?*)
+-        if [ -z "$fedora_url" ]; then
+-            repo="--mirrorlist=$mirrorlist?repo=fedora-$fedora&arch=$arch"
+-            updates="--mirrorlist=$mirrorlist?repo=updates-released-f${fedora}&arch=$arch"
+-        else
+-            repo="--baseurl=$fedora_url/releases/$fedora/Everything/$arch/os"
+-            updates="--baseurl=$fedora_url/updates/$fedora/$arch"
+-        fi
+-    esac
+-else
+-    repo="--baseurl=$repo"
+-    [ -n "$updates" ] && updates="--baseurl=$updates"
+-fi
+-
+-if [ -n "$repo" ]; then
+-    echo "repo --name=base $repo" >> "$kstmp"
+-else
+-    die "No repository specified, and no default available."
+-fi
+-if [ -n "$updates" ]; then
+-    echo "repo --name=updates $updates" >> "$kstmp"
+-fi
+-i=0
+-for extra in "${extra_repos[@]}"; do
+-    ((i++))
+-    [ -d "$extra" ] && extra="file://$extra"
+-    echo "repo --name=extra$i --baseurl=$extra" >> "$kstmp"
+-done
+-
+-selinux_enforcing=$(/usr/sbin/getenforce)
+-case "$selinux_enforcing" in
+-    Enforcing) sudo /usr/sbin/setenforce Permissive ;;
+-    Permissive) ;;
+-    *) if grep -q '^selinux --disabled' "$kstmp";
+-           then
+-               warn "WARNING: SELinux disabled in kickstart"
+-           else
+-               die "ERROR: SELinux enabled in kickstart, \
+-               but disabled on the build machine"
+-       fi ;;
+-esac
+-
+-mkdir -p $cachedir
+-sudo livecd-creator -c "$kstmp" -f "$label" --cache="$cachedir"
+-
+-# Clean up
+-rm -f $kstmp
+-if [ "$selinux_enforcing" = Enforcing ]; then
+-    sudo /usr/sbin/setenforce Enforcing
+-fi
+diff -ruN virt-v2v-v0.8.1/p2v-image-builder/virt-p2v-image.ks virt-v2v-v0.8.1.new/p2v-image-builder/virt-p2v-image.ks
+--- virt-v2v-v0.8.1/p2v-image-builder/virt-p2v-image.ks	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-image-builder/virt-p2v-image.ks	1970-01-01 01:00:00.000000000 +0100
+@@ -1,19 +0,0 @@
+-# virt-p2v Node image recipe
+-
+-%include common-install.ks
+-
+-%packages --excludedocs --nobase
+-%include common-pkgs.ks
+-%end
+-
+-%post
+-%include common-post.ks
+-%end
+-
+-%include common-minimizer.ks
+-
+-%post --nochroot
+-%include common-post-nochroot.ks
+-%end
+-
+-%include common-manifest-post.ks
+diff -ruN virt-v2v-v0.8.1/p2v-server/run-p2v-locally virt-v2v-v0.8.1.new/p2v-server/run-p2v-locally
+--- virt-v2v-v0.8.1/p2v-server/run-p2v-locally	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-server/run-p2v-locally	1970-01-01 01:00:00.000000000 +0100
+@@ -1,52 +0,0 @@
+-#!/bin/sh
+-# virt-p2v
+-# Copyright (C) 2010 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-# This script sets up the environment so you can run virt-v2v in place
+-# without needing to do 'make install' first.
+-#
+-# Use it like this:
+-#   ./run-p2v-locally
+-#
+-# It requires the environment variable VIRTV2V_ROOT to be set. If using
+-# libguestfs from source, LIBGUESTFS_ROOT must also be set.
+-
+-if [ -z "$VIRTV2V_ROOT" ]; then
+-    echo "VIRTV2V_ROOT must be set"
+-    exit 1
+-fi
+-
+-if [ -z "$PERL5LIB" ]; then
+-    PERL5LIB="$VIRTV2V_ROOT/blib/lib"
+-else
+-    PERL5LIB="$VIRTV2V_ROOT/blib/lib:$PERL5LIB"
+-fi
+-
+-if [ ! -z "$LIBGUESTFS_ROOT" ]; then
+-    if [ -z "$LD_LIBRARY_PATH" ]; then
+-        LD_LIBRARY_PATH="$LIBGUESTFS_ROOT/src/.libs"
+-    else
+-        LD_LIBRARY_PATH="$LIBGUESTFS_ROOT/src/.libs:$LD_LIBRARY_PATH"
+-    fi
+-
+-    LIBGUESTFS_PATH="$LIBGUESTFS_ROOT/appliance"
+-    PERL5LIB="$LIBGUESTFS_ROOT/perl/blib/lib:$LIBGUESTFS_ROOT/perl/blib/arch:$PERL5LIB"
+-fi
+-
+-export PERL5LIB LD_LIBRARY_PATH LIBGUESTFS_PATH
+-
+-exec perl "$VIRTV2V_ROOT/p2v-server/virt-p2v-server.pl" "$@"
+diff -ruN virt-v2v-v0.8.1/p2v-server/virt-p2v-server.pl virt-v2v-v0.8.1.new/p2v-server/virt-p2v-server.pl
+--- virt-v2v-v0.8.1/p2v-server/virt-p2v-server.pl	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/p2v-server/virt-p2v-server.pl	1970-01-01 01:00:00.000000000 +0100
+@@ -1,505 +0,0 @@
+-#!/usr/bin/perl
+-# virt-p2v-server
+-# Copyright (C) 2011 Red Hat Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-use warnings;
+-use strict;
+-
+-use IO::Handle;
+-use YAML::Any;
+-
+-use Locale::TextDomain 'virt-v2v';
+-
+-use Sys::Guestfs;
+-
+-use Sys::VirtConvert;
+-use Sys::VirtConvert::Config;
+-use Sys::VirtConvert::Converter;
+-use Sys::VirtConvert::Connection::LibVirtTarget;
+-use Sys::VirtConvert::Connection::RHEVTarget;
+-use Sys::VirtConvert::GuestfsHandle;
+-use Sys::VirtConvert::Util qw(:DEFAULT logmsg_init logmsg_level);
+-
+-=encoding utf8
+-
+-=head1 NAME
+-
+-virt-p2v-server - Receive data from virt-p2v
+-
+-=head1 DESCRIPTION
+-
+-virt-p2v-server is invoked over SSH by virt-p2v. It is not intended to be run
+-manually.
+-
+-=cut
+-
+-# SIGPIPE will cause an untidy exit of the perl process, without calling
+-# destructors. We don't rely on it anywhere, as we check for errors when reading
+-# from or writing to a pipe.
+-$SIG{'PIPE'} = 'IGNORE';
+-
+-# The protocol version we support
+-use constant VERSION => 0;
+-
+-# Message types
+-use constant MSG_VERSION        => 'VERSION';
+-use constant MSG_LANG           => 'LANG';
+-use constant MSG_METADATA       => 'METADATA';
+-use constant MSG_PATH           => 'PATH';
+-use constant MSG_CONVERT        => 'CONVERT';
+-use constant MSG_LIST_PROFILES  => 'LIST_PROFILES';
+-use constant MSG_SET_PROFILE    => 'SET_PROFILE';
+-use constant MSG_CONTAINER      => 'CONTAINER';
+-use constant MSG_DATA           => 'DATA';
+-
+-# Container types
+-use constant CONT_RAW => 'RAW';
+-
+-# Global state
+-my $config;
+-my $meta;
+-my $target;
+-
+-# Initialize logging
+-logmsg_init('syslog');
+-#logmsg_level(DEBUG);
+-
+-logmsg NOTICE, __x("{program} started.", program => 'p2v-server');
+-
+-# Wrap everything in a big eval to catch any die(). N.B. $SIG{__DIE__} is no
+-# good for this, as it catches every die(), even those inside an eval
+-eval {
+-    # Set the umask to a reasonable default
+-    umask(0022);
+-
+-    # Don't buffer output
+-    # While perl will use line buffering when STDOUT is connected to a tty, when
+-    # not connected to a tty, for example when invoked directly over ssh, it
+-    # will use a regular, large output buffer. This results in messages being
+-    # held in the buffer indefinitely.
+-    STDOUT->autoflush(1);
+-
+-    # Read the config file
+-    eval {
+-        $config = Sys::VirtConvert::Config->new('/etc/virt-v2v.conf');
+-    };
+-    v2vdie $@ if $@;
+-
+-    my $msg;
+-    while ($msg = p2v_receive()) {
+-        my $type = $msg->{type};
+-
+-        # VERSION n
+-        if ($type eq MSG_VERSION) {
+-            my $version = $msg->{args}[0];
+-            if ($version <= VERSION) {
+-                p2v_return_ok();
+-            }
+-
+-            else {
+-                err_and_die(__x('This version of virt-p2v-server does not '.
+-                                'support protocol version {version}.',
+-                                version => $version));
+-            }
+-        }
+-
+-        # LANG lang
+-        elsif ($type eq MSG_LANG) {
+-            $ENV{LANG} = $msg->{args}[0];
+-            p2v_return_ok();
+-        }
+-
+-        # METADATA length
+-        #  length bytes of YAML
+-        elsif ($type eq MSG_METADATA) {
+-            my $yaml = p2v_read($msg->{args}[0]);
+-            eval { $meta = Load($yaml); };
+-            err_and_die('Error parsing metadata: '.$@) if $@;
+-
+-            p2v_return_ok();
+-        }
+-
+-        # PATH length path
+-        #   N.B. path could theoretically include spaces
+-        elsif ($type eq MSG_PATH) {
+-            my $length = $msg->{args}[0];
+-
+-            my $path = join(' ', @{$msg->{args}}[1..$#{$msg->{args}}]);
+-            receive_path($path, $length);
+-        }
+-
+-        # CONVERT
+-        elsif ($type eq MSG_CONVERT) {
+-            convert();
+-        }
+-
+-        # LIST_PROFILES
+-        elsif ($type eq MSG_LIST_PROFILES) {
+-            p2v_return_list($config->list_profiles());
+-        }
+-
+-        # SET_PROFILE profile
+-        elsif ($type eq MSG_SET_PROFILE) {
+-            set_profile($msg->{args}[0]);
+-        }
+-
+-        else {
+-            unexpected_msg($type);
+-        }
+-    }
+-};
+-logmsg FATAL, $@ if $@;
+-
+-exit(0);
+-
+-# Receive an image file
+-sub receive_path
+-{
+-    my ($path, $length) = @_;
+-
+-    err_and_die('PATH without prior SET_PROFILE command')
+-        unless defined($target);
+-    err_and_die('PATH without prior METADATA command')
+-        unless defined($meta);
+-
+-    my ($disk) = grep { $_->{path} eq $path } @{$meta->{disks}};
+-    err_and_die("$path not found in metadata") unless defined($disk);
+-
+-    # Construct a volume name based on the path and hostname
+-    my $name = $meta->{name}.'-'.$disk->{device};
+-    $name =~ s,/,_,g;       # e.g. cciss devices have a directory structure
+-
+-    my $sopts = $config->get_storage_opts();
+-
+-    my $convert = 0;
+-    my $format;
+-    my $sparse;
+-
+-    # Default to raw. Conversion required for anything else.
+-    if (!exists($sopts->{format}) || $sopts->{format} eq 'raw') {
+-        $format = 'raw';
+-    } else {
+-        $format = $sopts->{format};
+-        $convert = 1;
+-    }
+-
+-    # Default to non-sparse
+-    my $allocation = $sopts->{allocation};
+-    if (!defined($allocation) || $allocation eq 'preallocated') {
+-        $sparse = 0;
+-    } elsif ($allocation eq 'sparse') {
+-        $sparse = 1;
+-    } else {
+-        err_and_die(__x('Invalid allocation policy {policy} in profile.',
+-                        policy => $allocation));
+-    }
+-
+-    # Create the target volume
+-    my $vol;
+-    eval {
+-        $vol = $target->create_volume(
+-            $name,
+-            $format,
+-            $length,
+-            $sparse
+-        );
+-    };
+-    err_and_die($@) if $@;
+-    p2v_return_ok();
+-
+-    # Receive an initial container
+-    my $msg = p2v_receive();
+-    unexpected_msg($msg->{type}) unless $msg->{type} eq MSG_CONTAINER;
+-
+-    # We only support RAW container
+-    my $ctype = $msg->{args}[0];
+-    err_and_die("Received unknown container type: $ctype")
+-        unless $ctype eq CONT_RAW;
+-    p2v_return_ok();
+-
+-    # Update the disk entry with the new volume details
+-    $disk->{local_path} = $vol->get_local_path();
+-    $disk->{path} = $vol->get_path();
+-    $disk->{is_block} = $vol->is_block();
+-
+-    my $writer = $vol->get_write_stream($convert);
+-
+-    # Receive volume data in chunks
+-    my $received = 0;
+-    while ($received < $length) {
+-        my $data = p2v_receive();
+-
+-        unexpected_msg($data->command) unless $data->{type} eq MSG_DATA;
+-
+-        # Read the data message in chunks of up to 4M
+-        my $remaining = $data->{args}[0];
+-        while ($remaining > 0) {
+-            my $chunk = $remaining > 4*1024*1024 ? 4*1024*1024 : $remaining;
+-            my $buf = p2v_read($chunk);
+-
+-            $received += $chunk;
+-            $remaining -= $chunk;
+-
+-            eval { $writer->write($buf); };
+-            err_and_die($@) if $@;
+-        }
+-
+-        p2v_return_ok();
+-    }
+-}
+-
+-# Use the specified profile
+-sub set_profile
+-{
+-    my ($profile) = @_;
+-
+-    # Check the profile is in our list
+-    my $found = 0;
+-    for my $i ($config->list_profiles()) {
+-        if ($i eq $profile) {
+-            $found = 1;
+-            last;
+-        }
+-    }
+-    err_and_die(__x('Invalid profile: {profile}', profile => $profile))
+-        unless ($found);
+-
+-    $config->use_profile($profile);
+-
+-    my $storage = $config->get_storage();
+-    my $method = $config->get_method();
+-    if ($method eq 'libvirt') {
+-        $target = new Sys::VirtConvert::Connection::LibVirtTarget
+-            ('qemu:///system', $storage);
+-    } elsif ($method eq 'rhev') {
+-        $target = new Sys::VirtConvert::Connection::RHEVTarget($storage);
+-    } else {
+-        err_and_die(__x('Profile {profile} specifies invalid method {method}.',
+-                        profile => $profile, method => $method));
+-    }
+-
+-    p2v_return_ok();
+-}
+-
+-sub convert
+-{
+-    err_and_die('CONVERT without prior SET_PROFILE command')
+-        unless (defined($target));
+-
+-    err_and_die('CONVERT without prior METADATA command')
+-        unless defined($meta);
+-
+-    my @localpaths = map { $_->{local_path} } @{$meta->{disks}};
+-
+-    my $g;
+-    eval {
+-        my $transferiso = $config->get_transfer_iso();
+-
+-        $g = new Sys::VirtConvert::GuestfsHandle(
+-            \@localpaths,
+-            $transferiso,
+-            $target->isa('Sys::VirtConvert::Connection::RHEVTarget')
+-        );
+-
+-        my $transferdev;
+-        if (defined($transferiso)) {
+-            my @devices = $g->list_devices();
+-            $transferdev = pop(@devices);
+-        }
+-
+-        my $root = inspect_guest($g, $transferdev);
+-        my $guestcaps =
+-            Sys::VirtConvert::Converter->convert($g, $config, $root, $meta);
+-        $target->create_guest($g, $root, $meta, $config, $guestcaps,
+-                              $meta->{name});
+-
+-        if($guestcaps->{block} eq 'virtio' && $guestcaps->{net} eq 'virtio') {
+-            logmsg NOTICE, __x('{name} configured with virtio drivers.',
+-                               name => $meta->{name});
+-        } elsif ($guestcaps->{block} eq 'virtio') {
+-            logmsg NOTICE, __x('{name} configured with virtio storage only.',
+-                               name => $meta->{name});
+-        } elsif ($guestcaps->{net} eq 'virtio') {
+-            logmsg NOTICE, __x('{name} configured with virtio networking only.',
+-                               name => $meta->{name});
+-        } else {
+-            logmsg NOTICE, __x('{name} configured without virtio drivers.',
+-                               name => $meta->{name});
+-        }
+-    };
+-
+-    # If any of the above commands result in failure, we need to ensure that
+-    # the guestfs qemu process is cleaned up before further cleanup. Failure to
+-    # do this can result in failure to umount RHEV export's temporary mount
+-    # point.
+-    if ($@) {
+-        my $err = $@;
+-        $g->close();
+-
+-        # We trust the error was already logged
+-        p2v_return_err($err);
+-        die($@);
+-    }
+-
+-    p2v_return_ok();
+-}
+-
+-sub unexpected_msg
+-{
+-    err_and_die('Received unexpected command: '.shift);
+-}
+-
+-sub err_and_die
+-{
+-    my $err = shift;
+-    p2v_return_err($err);
+-    v2vdie $err;
+-}
+-
+-END {
+-    my $err = $?;
+-
+-    logmsg NOTICE, __x("{program} exited.", program => 'p2v-server');
+-
+-    # die() sets $? to 255, which is untidy.
+-    $? = $err == 255 ? 1 : $err;
+-}
+-
+-# Perform guest inspection using the libguestfs core inspection API.
+-# Returns the root device of the os to be converted.
+-sub inspect_guest
+-{
+-    my $g = shift;
+-    my $transferdev = shift;
+-
+-    # Get list of roots, sorted
+-    my @roots = $g->inspect_os();
+-
+-    # Filter out the transfer device from the results of inspect_os
+-    # There's a libguestfs bug (fixed upstream) which meant the transfer ISO
+-    # could be erroneously detected as an unknown Windows OS. As we know what it
+-    # is, we can filter out the transfer device here. Even when the fix is
+-    # released this is reasonable belt & braces.
+-    @roots = grep(!/^\Q$transferdev\E$/, @roots);
+-
+-    @roots = sort @roots;
+-
+-    # Only work on single-root operating systems.
+-    v2vdie __('No root device found in this operating system image.')
+-        if @roots == 0;
+-
+-    v2vdie __('Multiboot operating systems are not supported.')
+-        if @roots > 1;
+-
+-    return $roots[0];
+-}
+-
+-sub p2v_receive
+-{
+-    my $in = <>;
+-    v2vdie __('Client closed connection unexpectedly') unless defined($in);
+-
+-    # Messages consist of the message type followed by 0 or more arguments,
+-    # terminated by a newline
+-    chomp($in);
+-    $in =~ /^([A-Z_]+)( .+)?$/ or err_and_die("Received invalid message: $in");
+-
+-    my %msg;
+-    $msg{type} = $1;
+-    if (defined($2)) {
+-        my @args = split(' ', $2);
+-        $msg{args} =  \@args;
+-    } else {
+-        $msg{args} = [];
+-    }
+-
+-    logmsg DEBUG, __x('Received: {command} {args}',
+-                      command => $msg{type},
+-                      args => join(' ', @{$msg{args}}));
+-
+-    return \%msg;
+-}
+-
+-sub p2v_read
+-{
+-    my ($length) = @_;
+-
+-    my $buf;
+-    my $total = 0;
+-
+-    while($total < $length) {
+-        my $in = read(STDIN, $buf, $length, $total)
+-            or err_and_die(__x('Error receiving data: {error}', error => $@));
+-        logmsg DEBUG, "Read $in bytes";
+-        $total += $in;
+-    }
+-
+-    return $buf;
+-}
+-
+-sub p2v_return_ok
+-{
+-    my $msg = "OK";
+-    logmsg DEBUG, __x('Sent: {msg}', msg => $msg);
+-    print $msg,"\n";
+-}
+-
+-sub p2v_return_list
+-{
+-    my @values = @_;
+-
+-    my $msg = 'LIST '.scalar(@values);
+-    foreach my $value (@values) {
+-        $msg .= "\n$value";
+-    }
+-    logmsg DEBUG, __x('Sent: {msg}', msg => $msg);
+-    print $msg,"\n";
+-}
+-
+-sub p2v_return_err
+-{
+-    my $msg = 'ERROR '.shift;
+-    logmsg DEBUG, __x('Sent: {msg}', msg => $msg);
+-    print $msg,"\n";
+-}
+-
+-=head1 SEE ALSO
+-
+-L<virt-v2v(1)>,
+-L<http://libguestfs.org/>.
+-
+-=head1 AUTHOR
+-
+-Matthew Booth <mbooth at redhat.com>
+-
+-=head1 COPYRIGHT
+-
+-Copyright (C) 2011 Red Hat Inc.
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published by
+-the Free Software Foundation; either version 2 of the License, or
+-(at your option) any later version.
+-
+-This program is distributed in the hope that it will be useful,
+-but WITHOUT ANY WARRANTY; without even the implied warranty of
+-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-GNU General Public License for more details.
+-
+-You should have received a copy of the GNU General Public License
+-along with this program; if not, write to the Free Software
+-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+diff -ruN virt-v2v-v0.8.1/virt-v2v.spec virt-v2v-v0.8.1.new/virt-v2v.spec
+--- virt-v2v-v0.8.1/virt-v2v.spec	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/virt-v2v.spec	2011-05-11 17:20:21.000000000 +0100
+@@ -55,7 +55,6 @@
+ 
+ # virt-p2v build requirements
+ BuildRequires:  rubygem(rake)
+-BuildRequires:  rubygem(echoe)
+ 
+ Requires:  perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version))
+ 
+@@ -141,7 +140,7 @@
+ %{__perl} Build.PL
+ ./Build
+ 
+-pushd p2v-client
++pushd p2v/client
+ rake gem
+ popd
+ 
+@@ -174,7 +173,7 @@
+ mkdir -p %{buildroot}/%{gemdir}
+ 
+ gem install --local --install-dir %{buildroot}%{gemdir} \
+-            --force --rdoc p2v-client/pkg/%{gemname}-%{version}.gem
++            --force --rdoc p2v/client/pkg/%{gemname}-%{version}.gem
+ mv %{buildroot}%{gemdir}/bin/* %{buildroot}/%{_bindir}
+ find %{buildroot}%{geminstdir}/bin -type f | xargs chmod a+x
+ cp COPYING %{buildroot}/%{geminstdir}
+@@ -183,8 +182,8 @@
+ %global builderdir %{_datadir}/virt-p2v-image-builder
+ builder=%{buildroot}/%{_bindir}/virt-p2v-image-builder
+ mkdir -p %{buildroot}%{builderdir}
+-cp p2v-image-builder/*.ks %{buildroot}%{builderdir}
+-cp p2v-image-builder/virt-p2v-image-builder $builder
++cp p2v/image-builder/*.ks %{buildroot}%{builderdir}
++cp p2v/image-builder/virt-p2v-image-builder $builder
+ 
+ # Set the default data directory
+ sed -i -e 's,^DEFAULT_DATADIR=.*,DEFAULT_DATADIR=%{builderdir},' $builder
+@@ -193,7 +192,7 @@
+ %check
+ ./Build test
+ 
+-pushd p2v-client
++pushd p2v/client
+ # No tests yet
+ #rake test
+ popd
+diff -ruN virt-v2v-v0.8.1/virt-v2v.spec.PL virt-v2v-v0.8.1.new/virt-v2v.spec.PL
+--- virt-v2v-v0.8.1/virt-v2v.spec.PL	2011-04-26 20:58:33.000000000 +0100
++++ virt-v2v-v0.8.1.new/virt-v2v.spec.PL	2011-05-11 17:20:21.000000000 +0100
+@@ -165,7 +165,7 @@
+ %{__perl} Build.PL
+ ./Build
+ 
+-pushd p2v-client
++pushd p2v/client
+ rake gem
+ popd
+ 
+@@ -198,7 +198,7 @@
+ mkdir -p %{buildroot}/%{gemdir}
+ 
+ gem install --local --install-dir %{buildroot}%{gemdir} \
+-            --force --rdoc p2v-client/pkg/%{gemname}-%{version}.gem
++            --force --rdoc p2v/client/pkg/%{gemname}-%{version}.gem
+ mv %{buildroot}%{gemdir}/bin/* %{buildroot}/%{_bindir}
+ find %{buildroot}%{geminstdir}/bin -type f | xargs chmod a+x
+ cp COPYING %{buildroot}/%{geminstdir}
+@@ -207,8 +207,8 @@
+ %global builderdir %{_datadir}/virt-p2v-image-builder
+ builder=%{buildroot}/%{_bindir}/virt-p2v-image-builder
+ mkdir -p %{buildroot}%{builderdir}
+-cp p2v-image-builder/*.ks %{buildroot}%{builderdir}
+-cp p2v-image-builder/virt-p2v-image-builder $builder
++cp p2v/image-builder/*.ks %{buildroot}%{builderdir}
++cp p2v/image-builder/virt-p2v-image-builder $builder
+ 
+ # Set the default data directory
+ sed -i -e 's,^DEFAULT_DATADIR=.*,DEFAULT_DATADIR=%{builderdir},' $builder
+@@ -217,7 +217,7 @@
+ %check
+ ./Build test
+ 
+-pushd p2v-client
++pushd p2v/client
+ # No tests yet
+ #rake test
+ popd
diff --git a/virt-v2v-0.8.1-01-e34a8c09.patch b/virt-v2v-0.8.1-01-e34a8c09.patch
new file mode 100644
index 0000000..58b03a3
--- /dev/null
+++ b/virt-v2v-0.8.1-01-e34a8c09.patch
@@ -0,0 +1,57 @@
+commit e34a8c0911f53cff64f9a33d3802ac7361f3fe19
+Author: Matthew Booth <mbooth at redhat.com>
+Date:   Wed May 11 16:05:18 2011 +0100
+
+    p2v-client: Drop echoe for build
+    
+    echoe changes incompatibly from F14->F15. We're not using the vast majority of
+    its features, and it remains completely undocumented as far as I can tell. This
+    patch drops it in favour of a simple, explicit gem build task.
+
+diff --git a/p2v/client/Rakefile b/p2v/client/Rakefile
+index d190f08..23c26f5 100644
+--- a/p2v/client/Rakefile
++++ b/p2v/client/Rakefile
+@@ -14,24 +14,10 @@
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ 
+-require 'rubygems'
+-require 'echoe'
++require 'rake'
++require 'rake/gempackagetask'
+ 
+-Echoe.new("virt-p2v") do |p|
+-  p.project     = "Virt P2V"
+-  p.version     = `../../Build version`
+-  p.author      = "Matthew Booth"
+-  p.summary     = "Send a machine's storage and metadata to virt-p2v-server"
+-  p.description = <<EOF
+-virt-p2v is a client which connects to a virt-p2v-server and transfer's the host
+-machine's storage and metadata. virt-p2v is intended to be run from a live
+-image, so it is unlikely you want to install it.
+-EOF
+-  p.url         = "http://libguestfs.org"
+-  p.email       = "libguestfs at redhat.com"
+-  p.runtime_dependencies = [
+-      'gtk2',
+-      'gettext',
+-      'net-ssh'
+-  ]
+-end
++task :default => :gem
++
++load 'virt-p2v.gemspec'
++Rake::GemPackageTask.new(GEMSPEC) {}
+diff --git a/virt-v2v.spec.PL b/virt-v2v.spec.PL
+index 2249b01..6a155e2 100644
+--- a/virt-v2v.spec.PL
++++ b/virt-v2v.spec.PL
+@@ -79,7 +79,6 @@ BuildRequires:  perl-hivex >= 1.2.2
+ 
+ # virt-p2v build requirements
+ BuildRequires:  rubygem(rake)
+-BuildRequires:  rubygem(echoe)
+ 
+ Requires:  perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version))
+ 
diff --git a/virt-v2v-0.8.1-02-fadb1929.patch b/virt-v2v-0.8.1-02-fadb1929.patch
new file mode 100644
index 0000000..8fc6c4a
--- /dev/null
+++ b/virt-v2v-0.8.1-02-fadb1929.patch
@@ -0,0 +1,111 @@
+commit fadb1929b4a8447a719a34f07e5934badf694f45
+Author: Matthew Booth <mbooth at redhat.com>
+Date:   Wed May 11 16:46:37 2011 +0100
+
+    p2v-client: Add missing gemspec
+    
+    gemspec used to be auto-generated, so was explicitly ignored. It's no longer
+    auto-generated, so we need it.
+
+diff --git a/p2v/client/virt-p2v.gemspec b/p2v/client/virt-p2v.gemspec
+new file mode 100644
+index 0000000..d8edde8
+--- /dev/null
++++ b/p2v/client/virt-p2v.gemspec
+@@ -0,0 +1,96 @@
++# Copyright (C) 2011 Red Hat Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++V2V_VERSION = `../../Build version`
++abort "Failed to get version" unless $? == 0
++
++GEMSPEC = Gem::Specification.new do |s|
++    s.name = %q{virt-p2v}
++    s.version = V2V_VERSION
++
++    s.authors = ["Matthew Booth"]
++    s.date = %q{2011-05-10}
++    s.summary = %q{Send a machine's storage and metadata to virt-p2v-server}
++    s.description = %q{
++        virt-p2v is a client which connects to a virt-p2v-server and transfer's
++        the host machine's storage and metadata. virt-p2v is intended to be run
++        from a live image, so it is unlikely you want to install it.
++    }
++    s.email = %q{libguestfs at redhat.com}
++    s.homepage = %q{http://libguestfs.org}
++
++    s.default_executable = %q{virt-p2v}
++    s.executables = ["virt-p2v"]
++    s.files = [
++        "Rakefile",
++        "bin/virt-p2v",
++        "lib/virt-p2v/blockdevice.rb",
++        "lib/virt-p2v/connection.rb",
++        "lib/virt-p2v/converter.rb",
++        "lib/virt-p2v/gtk-queue.rb",
++        "lib/virt-p2v/netdevice.rb",
++        "lib/virt-p2v/ui/connect.rb",
++        "lib/virt-p2v/ui/convert.rb",
++        "lib/virt-p2v/ui/main.rb",
++        "lib/virt-p2v/ui/network.rb",
++        "lib/virt-p2v/ui/p2v.ui",
++        "lib/virt-p2v/ui/success.rb",
++        "virt-p2v.gemspec",
++        "Manifest"
++    ]
++    s.require_paths = ["lib"]
++
++    if s.respond_to? :specification_version then
++        current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
++        s.specification_version = 3
++
++        if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
++            s.add_runtime_dependency(%q<gtk2>, [">= 0"])
++            s.add_runtime_dependency(%q<gettext>, [">= 0"])
++            s.add_runtime_dependency(%q<net-ssh>, [">= 0"])
++        else
++            s.add_dependency(%q<gtk2>, [">= 0"])
++            s.add_dependency(%q<gettext>, [">= 0"])
++            s.add_dependency(%q<net-ssh>, [">= 0"])
++        end
++    else
++        s.add_dependency(%q<gtk2>, [">= 0"])
++        s.add_dependency(%q<gettext>, [">= 0"])
++        s.add_dependency(%q<net-ssh>, [">= 0"])
++    end
++
++# Source doesn't contain any rdoc
++#    s.extra_rdoc_files = [
++#        "bin/virt-p2v",
++#        "lib/virt-p2v/blockdevice.rb",
++#        "lib/virt-p2v/connection.rb",
++#        "lib/virt-p2v/converter.rb",
++#        "lib/virt-p2v/gtk-queue.rb",
++#        "lib/virt-p2v/netdevice.rb",
++#        "lib/virt-p2v/ui/connect.rb",
++#        "lib/virt-p2v/ui/convert.rb",
++#        "lib/virt-p2v/ui/main.rb",
++#        "lib/virt-p2v/ui/network.rb",
++#        "lib/virt-p2v/ui/p2v.ui",
++#        "lib/virt-p2v/ui/success.rb"
++#    ]
++#    s.rdoc_options = [
++#        "--line-numbers",
++#        "--inline-source",
++#        "--title",
++#        "Virt-p2v"
++#    ]
++end
diff --git a/virt-v2v.spec b/virt-v2v.spec
index 645e393..20f99e2 100644
--- a/virt-v2v.spec
+++ b/virt-v2v.spec
@@ -16,6 +16,10 @@ BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 #  local seq no: the order the patches should be applied in
 #  git commit:   the first 8 characters of the git commit hash
 
+Patch0:         virt-v2v-0.8.1-00-44eb9021-modified.patch
+Patch1:         virt-v2v-0.8.1-01-e34a8c09.patch
+Patch2:         virt-v2v-0.8.1-02-fadb1929.patch
+
 # Unfortunately, despite really being noarch, we have to make virt-v2v arch
 # dependent to avoid build failures on architectures where libguestfs isn't
 # available.
@@ -53,7 +57,6 @@ BuildRequires:  perl-hivex >= 1.2.2
 
 # virt-p2v build requirements
 BuildRequires:  rubygem(rake)
-BuildRequires:  rubygem(echoe)
 
 Requires:  perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version))
 
@@ -135,11 +138,16 @@ virt-p2v-image-builder is a tool to create a bootable virt-p2v live image.
 %prep
 %setup -q -n %{name}-v%{version}
 
+%patch0 -p1
+%patch1 -p1
+%patch2 -p1
+
+
 %build
 %{__perl} Build.PL
 ./Build
 
-pushd p2v-client
+pushd p2v/client
 rake gem
 popd
 
@@ -172,7 +180,7 @@ mkdir -p %{buildroot}/%{_bindir}
 mkdir -p %{buildroot}/%{gemdir}
 
 gem install --local --install-dir %{buildroot}%{gemdir} \
-            --force --rdoc p2v-client/pkg/%{gemname}-%{version}.gem
+            --force --rdoc p2v/client/pkg/%{gemname}-%{version}.gem
 mv %{buildroot}%{gemdir}/bin/* %{buildroot}/%{_bindir}
 find %{buildroot}%{geminstdir}/bin -type f | xargs chmod a+x
 cp COPYING %{buildroot}/%{geminstdir}
@@ -181,8 +189,8 @@ cp COPYING %{buildroot}/%{geminstdir}
 %global builderdir %{_datadir}/virt-p2v-image-builder
 builder=%{buildroot}/%{_bindir}/virt-p2v-image-builder
 mkdir -p %{buildroot}%{builderdir}
-cp p2v-image-builder/*.ks %{buildroot}%{builderdir}
-cp p2v-image-builder/virt-p2v-image-builder $builder
+cp p2v/image-builder/*.ks %{buildroot}%{builderdir}
+cp p2v/image-builder/virt-p2v-image-builder $builder
 
 # Set the default data directory
 sed -i -e 's,^DEFAULT_DATADIR=.*,DEFAULT_DATADIR=%{builderdir},' $builder
@@ -191,7 +199,7 @@ sed -i -e 's,^DEFAULT_DATADIR=.*,DEFAULT_DATADIR=%{builderdir},' $builder
 %check
 ./Build test
 
-pushd p2v-client
+pushd p2v/client
 # No tests yet
 #rake test
 popd


More information about the scm-commits mailing list