Hi Rich, We just talked about a new tool virt-diff which can diff files between two guest, suggested by Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> things like below, # virt-diff -Nru --guest=Guest0 --guest=Guest1 /etc/hosts Any thought about this? Another question, what do you think about implement iptables, firewall, yum, rpm, etc into libguestfs? Thanks, Wanlong Gao
On 15/05/12 09:13, Wanlong Gao wrote:
Hi Rich,
We just talked about a new tool virt-diff which can diff files between two guest, suggested by Kamezawa Hiroyuki<kamezawa.hiroyu@jp.fujitsu.com>
things like below, # virt-diff -Nru --guest=Guest0 --guest=Guest1 /etc/hosts
Any thought about this?
Sounds like a useful tool.
Another question, what do you think about implement iptables, firewall, yum, rpm, etc into libguestfs?
Can you be more specific? How exactly would libguestfs use them? Can you provide examples? Matt -- Matthew Booth, RHCA, RHCSS Red Hat Engineering, Virtualisation Team GPG ID: D33C3490 GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490
On 05/15/2012 04:33 PM, Matthew Booth wrote:
On 15/05/12 09:13, Wanlong Gao wrote:
Hi Rich,
We just talked about a new tool virt-diff which can diff files between two guest, suggested by Kamezawa Hiroyuki<kamezawa.hiroyu@jp.fujitsu.com>
things like below, # virt-diff -Nru --guest=Guest0 --guest=Guest1 /etc/hosts
Any thought about this?
Sounds like a useful tool.
Another question, what do you think about implement iptables, firewall, yum, rpm, etc into libguestfs?
Can you be more specific? How exactly would libguestfs use them? Can you provide examples?
I think the examples are like setting iptables for the Guest, showing rpm package info, setting the startup services use chkconfig, and so on. Any thought? Thanks, Wanlong Gao
Matt
On Tue, May 15, 2012 at 04:42:40PM +0800, Wanlong Gao wrote:
I think the examples are like setting iptables for the Guest, showing rpm package info, setting the startup services use chkconfig, and so on.
Any thought?
We can already get detailed package info (not just for RPMs): http://libguestfs.org/guestfs.3.html#guestfs_inspect_list_applications The rest sounds useful. This would be as separate tool, like virt-sysprep? Or perhaps as part of virt-sysprep? Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://et.redhat.com/~rjones/virt-top
On 05/15/2012 05:26 PM, Richard W.M. Jones wrote:
On Tue, May 15, 2012 at 04:42:40PM +0800, Wanlong Gao wrote:
I think the examples are like setting iptables for the Guest, showing rpm package info, setting the startup services use chkconfig, and so on.
Any thought?
We can already get detailed package info (not just for RPMs):
http://libguestfs.org/guestfs.3.html#guestfs_inspect_list_applications
The rest sounds useful. This would be as separate tool, like virt-sysprep? Or perhaps as part of virt-sysprep?
I also has no idea about the details. Thanks, Wanlong Gao
Rich.
On Tue, May 15, 2012 at 04:13:27PM +0800, Wanlong Gao wrote:
Hi Rich,
We just talked about a new tool virt-diff which can diff files between two guest, suggested by Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
things like below, # virt-diff -Nru --guest=Guest0 --guest=Guest1 /etc/hosts
Any thought about this?
Sure, sounds like a good idea.
Another question, what do you think about implement iptables, firewall, yum, rpm, etc into libguestfs?
Can you give more detail? I'm not sure what this would look like. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org
On 05/15/2012 04:41 PM, Richard W.M. Jones wrote:
On Tue, May 15, 2012 at 04:13:27PM +0800, Wanlong Gao wrote:
Hi Rich,
We just talked about a new tool virt-diff which can diff files between two guest, suggested by Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
things like below, # virt-diff -Nru --guest=Guest0 --guest=Guest1 /etc/hosts
Any thought about this?
Sure, sounds like a good idea.
What do you think about how to implement the virt-diff ? particularly for the recursive option of diff? Thanks, Wanlong Gao
Another question, what do you think about implement iptables, firewall, yum, rpm, etc into libguestfs?
Can you give more detail? I'm not sure what this would look like.
Rich.
On Tue, May 22, 2012 at 04:54:23PM +0800, Wanlong Gao wrote:
On 05/15/2012 04:41 PM, Richard W.M. Jones wrote:
On Tue, May 15, 2012 at 04:13:27PM +0800, Wanlong Gao wrote:
Hi Rich,
We just talked about a new tool virt-diff which can diff files between two guest, suggested by Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
things like below, # virt-diff -Nru --guest=Guest0 --guest=Guest1 /etc/hosts
Any thought about this?
Sure, sounds like a good idea.
What do you think about how to implement the virt-diff ? particularly for the recursive option of diff?
It depends what you want it to do! I'd definitely start with at least some notes about exactly what you want it to do. Files? Filesystems? Metadata? Partitions? Windows Regsitry? Note that you can already do some sorts of file comparison using 'virt-ls', ie: virt-ls -lR --checksum -d guest1 / > files1 virt-ls -lR --checksum -d guest2 / > files2 diff -u files1 files2 Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://et.redhat.com/~rjones/virt-top
On 05/22/2012 05:17 PM, Richard W.M. Jones wrote:
On Tue, May 22, 2012 at 04:54:23PM +0800, Wanlong Gao wrote:
On 05/15/2012 04:41 PM, Richard W.M. Jones wrote:
On Tue, May 15, 2012 at 04:13:27PM +0800, Wanlong Gao wrote:
Hi Rich,
We just talked about a new tool virt-diff which can diff files between two guest, suggested by Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
things like below, # virt-diff -Nru --guest=Guest0 --guest=Guest1 /etc/hosts
Any thought about this?
Sure, sounds like a good idea.
What do you think about how to implement the virt-diff ? particularly for the recursive option of diff?
It depends what you want it to do! I'd definitely start with at least some notes about exactly what you want it to do. Files? Filesystems? Metadata? Partitions? Windows Regsitry?
Note that you can already do some sorts of file comparison using 'virt-ls', ie:
virt-ls -lR --checksum -d guest1 / > files1 virt-ls -lR --checksum -d guest2 / > files2 diff -u files1 files2
yes, I meant files. " quoted from Kame: I think this kind of command to do comparison between 2 guests is required for private cloud system. System admin can find error setting by diff. " So, you means we can use virt-ls to list the different files list, and then use virt-cat to see the different between two single files? Thanks, Wanlong Gao
Rich.
On Tue, May 22, 2012 at 08:01:50PM +0800, Wanlong Gao wrote:
So, you means we can use virt-ls to list the different files list, and then use virt-cat to see the different between two single files?
Yes, this is what I usually do. For example: $ qemu-img create -f qcow2 -b /dev/vg_pin/F16x64 cloned-f16.img Formatting 'cloned-f16.img', fmt=qcow2 size=21474836480 backing_file='/dev/vg_pin/F16x64' encryption=off cluster_size=65536 $ qemu-kvm -hda cloned-f16.img -m 1024 [boot it, shut it down] $ virt-ls -lR -a /dev/vg_pin/F16x64 / > original.files # * $ virt-ls -lR -a cloned-f16.img / > modified.files $ diff -u original.files modified.files --- original.files 2012-05-22 13:11:00.949456251 +0100 +++ modified.files 2012-05-22 13:11:38.248133406 +0100 @@ -1651,7 +1651,7 @@ - 0644 373 /etc/rearj.cfg l 0777 14 /etc/redhat-release -> fedora-release - 0644 1787 /etc/request-key.conf -- 0644 79 /etc/resolv.conf +- 0644 74 /etc/resolv.conf l 0777 11 /etc/rmt -> ../sbin/rmt - 0644 1615 /etc/rpc d 0755 4096 /etc/rpm @@ -32090,6 +32090,7 @@ d 0775 4096 /sys d 1777 4096 /tmp d 1777 4096 /tmp/.ICE-unix +s 0777 0 /tmp/.ICE-unix/1061 s 0777 0 /tmp/.ICE-unix/1085 d 1777 4096 /tmp/.Test-unix d 1777 4096 /tmp/.X11-unix @@ -207760,7 +207761,7 @@ - 0644 28 /var/lib/AccountsService/users/rjones d 0755 4096 /var/lib/NetworkManager - 0644 87 /var/lib/NetworkManager/NetworkManager.state -- 0644 1454 /var/lib/NetworkManager/timestamps +- 0644 1502 /var/lib/NetworkManager/timestamps d 0755 4096 /var/lib/PackageKit - 0644 9216 /var/lib/PackageKit/transactions.db d 0755 4096 /var/lib/alsa [etc etc] However there are some shortcomings. It won't find differences in: - filesystem metadata - bootloaders or other information outside the regular filesystem - inside the Windows Registry (it'll just say the two binary blobs are different) Rich. * You don't need the --checksum option unless files are modified but keep the same size, in which case you have to examine the complete content of each file. Using --checksum is much slower. 'virt-ls' has other options that you may want to look at. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://et.redhat.com/~rjones/virt-df/
On 05/22/2012 08:15 PM, Richard W.M. Jones wrote:
On Tue, May 22, 2012 at 08:01:50PM +0800, Wanlong Gao wrote:
So, you means we can use virt-ls to list the different files list, and then use virt-cat to see the different between two single files?
Yes, this is what I usually do.
For example:
$ qemu-img create -f qcow2 -b /dev/vg_pin/F16x64 cloned-f16.img Formatting 'cloned-f16.img', fmt=qcow2 size=21474836480 backing_file='/dev/vg_pin/F16x64' encryption=off cluster_size=65536
$ qemu-kvm -hda cloned-f16.img -m 1024 [boot it, shut it down]
$ virt-ls -lR -a /dev/vg_pin/F16x64 / > original.files # * $ virt-ls -lR -a cloned-f16.img / > modified.files
$ diff -u original.files modified.files --- original.files 2012-05-22 13:11:00.949456251 +0100 +++ modified.files 2012-05-22 13:11:38.248133406 +0100 @@ -1651,7 +1651,7 @@ - 0644 373 /etc/rearj.cfg l 0777 14 /etc/redhat-release -> fedora-release - 0644 1787 /etc/request-key.conf -- 0644 79 /etc/resolv.conf +- 0644 74 /etc/resolv.conf l 0777 11 /etc/rmt -> ../sbin/rmt - 0644 1615 /etc/rpc d 0755 4096 /etc/rpm @@ -32090,6 +32090,7 @@ d 0775 4096 /sys d 1777 4096 /tmp d 1777 4096 /tmp/.ICE-unix +s 0777 0 /tmp/.ICE-unix/1061 s 0777 0 /tmp/.ICE-unix/1085 d 1777 4096 /tmp/.Test-unix d 1777 4096 /tmp/.X11-unix @@ -207760,7 +207761,7 @@ - 0644 28 /var/lib/AccountsService/users/rjones d 0755 4096 /var/lib/NetworkManager - 0644 87 /var/lib/NetworkManager/NetworkManager.state -- 0644 1454 /var/lib/NetworkManager/timestamps +- 0644 1502 /var/lib/NetworkManager/timestamps d 0755 4096 /var/lib/PackageKit - 0644 9216 /var/lib/PackageKit/transactions.db d 0755 4096 /var/lib/alsa
[etc etc]
However there are some shortcomings. It won't find differences in:
- filesystem metadata - bootloaders or other information outside the regular filesystem - inside the Windows Registry (it'll just say the two binary blobs are different)
Rich.
* You don't need the --checksum option unless files are modified but keep the same size, in which case you have to examine the complete content of each file. Using --checksum is much slower. 'virt-ls' has other options that you may want to look at.
Hi Rich, Kame gave me a very good detail about the use case of virt-diff example, now quoted them for you,
Anyway, in above scheme, we cannot compare the files of the same size. For example
In guest 01: # cat /etc/sysconfig/network NETWORKING=yes HOSTNAME=guest01 GATEWAY=10.124.196.1
In guest02: # cat /etc/sysconfig/network NETWORKING=yes HOSTNAME=guest02 GATEWAY=10.124.196.1
You need to diff even if you have file lists.
BTW, what we'd like to compare is the contents of file, not meta-data.
In another point of view....
In your example in mailing list, you compares 2 files.
But, now, I _think_ what users really want is a command like following.
Following command is comparing guest's file of Guest01...Guest04 with Guest00.
# virt-diff -seed Guest00 -name Guest01 -name Guest02 -name Guest03 -name Guest04 /etc/hogehoge Guest03:/etc/hogehoge is differ. diff result...
In this case, only Guest03 has a different contents of the file.
For system-admin, this means... - Guest00,01,02,04 are correct and 03 is wrong or - Guest03 is correct and Guest00,01,02,04 are wrong. or - Guest03 has different settings intentionally and he confirmed that.
This command will be very good for system-admin.
Then, any thoughts about this tool ? and more thoughts about implementing this ? We should implement a "diff" wrapper in the guestfsd, and use this API when implementing this tool or any other methods? Thanks, Wanlong Gao
On Wed, May 23, 2012 at 04:45:22PM +0800, Wanlong Gao wrote:
Kame gave me a very good detail about the use case of virt-diff example, now quoted them for you,
Anyway, in above scheme, we cannot compare the files of the same size. [...]
virt-ls can find the differences if you use the --checksum option, because this computes a checksum over the whole file content. If its just the file date which has changed, it's cheaper to use the --times option. http://libguestfs.org/virt-ls.1.html#checksum http://libguestfs.org/virt-ls.1.html#recursive_long_listing
In another point of view....
In your example in mailing list, you compares 2 files.
But, now, I _think_ what users really want is a command like following.
Following command is comparing guest's file of Guest01...Guest04 with Guest00.
# virt-diff -seed Guest00 -name Guest01 -name Guest02 -name Guest03 -name Guest04 /etc/hogehoge Guest03:/etc/hogehoge is differ. diff result...
In this case, only Guest03 has a different contents of the file.
For system-admin, this means... - Guest00,01,02,04 are correct and 03 is wrong or - Guest03 is correct and Guest00,01,02,04 are wrong. or - Guest03 has different settings intentionally and he confirmed that.
This command will be very good for system-admin.
Then, any thoughts about this tool ?
It sounds useful, but I think you could still implement this on top of virt-ls.
and more thoughts about implementing this ? We should implement a "diff" wrapper in the guestfsd, and use this API when implementing this tool or any other methods?
The problem with adding 'diff' as an operation to the daemon is that you would need to attach the disks from multiple guests to a single appliance. This is in general problematic, although we do it in some limited cases: http://libguestfs.org/guestfs-performance.1.html#reducing_the_number_of_time... If you wanted to write a separate virt-diff tool, it's probably a good idea to start with the source of virt-ls and work from there. That program already knows how to iterate over the filesystem (of a single guest), and you could build diff functionality on top of that: https://github.com/libguestfs/libguestfs/blob/0e05e9f6ce696cf2a5172eda3fe054... Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming blog: http://rwmj.wordpress.com Fedora now supports 80 OCaml packages (the OPEN alternative to F#) http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora
On 05/23/2012 05:09 PM, Richard W.M. Jones wrote:
On Wed, May 23, 2012 at 04:45:22PM +0800, Wanlong Gao wrote:
Kame gave me a very good detail about the use case of virt-diff example, now quoted them for you,
Anyway, in above scheme, we cannot compare the files of the same size. [...]
virt-ls can find the differences if you use the --checksum option, because this computes a checksum over the whole file content. If its just the file date which has changed, it's cheaper to use the --times option.
http://libguestfs.org/virt-ls.1.html#checksum http://libguestfs.org/virt-ls.1.html#recursive_long_listing
In another point of view....
In your example in mailing list, you compares 2 files.
But, now, I _think_ what users really want is a command like following.
Following command is comparing guest's file of Guest01...Guest04 with Guest00.
# virt-diff -seed Guest00 -name Guest01 -name Guest02 -name Guest03 -name Guest04 /etc/hogehoge Guest03:/etc/hogehoge is differ. diff result...
In this case, only Guest03 has a different contents of the file.
For system-admin, this means... - Guest00,01,02,04 are correct and 03 is wrong or - Guest03 is correct and Guest00,01,02,04 are wrong. or - Guest03 has different settings intentionally and he confirmed that.
This command will be very good for system-admin.
Then, any thoughts about this tool ?
It sounds useful, but I think you could still implement this on top of virt-ls.
and more thoughts about implementing this ? We should implement a "diff" wrapper in the guestfsd, and use this API when implementing this tool or any other methods?
The problem with adding 'diff' as an operation to the daemon is that you would need to attach the disks from multiple guests to a single appliance. This is in general problematic, although we do it in some limited cases:
http://libguestfs.org/guestfs-performance.1.html#reducing_the_number_of_time...
If you wanted to write a separate virt-diff tool, it's probably a good idea to start with the source of virt-ls and work from there. That program already knows how to iterate over the filesystem (of a single guest), and you could build diff functionality on top of that:
https://github.com/libguestfs/libguestfs/blob/0e05e9f6ce696cf2a5172eda3fe054...
OK, thank you very much for your opinion, I'll look into it and try to do as what you suggested. Regards, Wanlong Gao
Rich.
On 05/23/2012 05:09 PM, Richard W.M. Jones wrote:
On Wed, May 23, 2012 at 04:45:22PM +0800, Wanlong Gao wrote:
Kame gave me a very good detail about the use case of virt-diff example, now quoted them for you,
Anyway, in above scheme, we cannot compare the files of the same size. [...]
virt-ls can find the differences if you use the --checksum option, because this computes a checksum over the whole file content. If its just the file date which has changed, it's cheaper to use the --times option.
http://libguestfs.org/virt-ls.1.html#checksum http://libguestfs.org/virt-ls.1.html#recursive_long_listing
In another point of view....
In your example in mailing list, you compares 2 files.
But, now, I _think_ what users really want is a command like following.
Following command is comparing guest's file of Guest01...Guest04 with Guest00.
# virt-diff -seed Guest00 -name Guest01 -name Guest02 -name Guest03 -name Guest04 /etc/hogehoge Guest03:/etc/hogehoge is differ. diff result...
In this case, only Guest03 has a different contents of the file.
For system-admin, this means... - Guest00,01,02,04 are correct and 03 is wrong or - Guest03 is correct and Guest00,01,02,04 are wrong. or - Guest03 has different settings intentionally and he confirmed that.
This command will be very good for system-admin.
Then, any thoughts about this tool ?
It sounds useful, but I think you could still implement this on top of virt-ls.
and more thoughts about implementing this ? We should implement a "diff" wrapper in the guestfsd, and use this API when implementing this tool or any other methods?
The problem with adding 'diff' as an operation to the daemon is that you would need to attach the disks from multiple guests to a single appliance. This is in general problematic, although we do it in some limited cases:
http://libguestfs.org/guestfs-performance.1.html#reducing_the_number_of_time...
If you wanted to write a separate virt-diff tool, it's probably a good idea to start with the source of virt-ls and work from there. That program already knows how to iterate over the filesystem (of a single guest), and you could build diff functionality on top of that:
https://github.com/libguestfs/libguestfs/blob/0e05e9f6ce696cf2a5172eda3fe054...
I looked into this, now Rich, I have a more question, if we doing like virt-diff --seed Guest0 -d Guest1 -d Guest2 /etc We can mount the device of Guest0 to "/", but where the devices from Guest1 and Guest2 can be mounted? Because when doing diff, doesn't like virt-df can iterate these, but we should mount at least two devices at the same time for example the root or Guest0 and Guest1. Thanks, Wanlong Gao
Rich.
On Sun, May 27, 2012 at 02:52:59PM +0800, Wanlong Gao wrote:
I looked into this, now Rich, I have a more question, if we doing like virt-diff --seed Guest0 -d Guest1 -d Guest2 /etc We can mount the device of Guest0 to "/", but where the devices from Guest1 and Guest2 can be mounted?
The mkmountpoint call allows you to have multiple "roots": http://libguestfs.org/guestfs.3.html#guestfs_mkmountpoint *However*, this won't work for general guests, where for example two guests might have conflicting logical volumes or UUIDs which are duplicated. It's simply not possible to safely mount multiple guests in a single appliance. The solution is to use two libguestfs handles. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-p2v converts physical machines to virtual machines. Boot with a live CD or over the network (PXE) and turn machines into Xen guests. http://et.redhat.com/~rjones/virt-p2v
On 05/28/2012 03:48 PM, Richard W.M. Jones wrote:
On Sun, May 27, 2012 at 02:52:59PM +0800, Wanlong Gao wrote:
I looked into this, now Rich, I have a more question, if we doing like virt-diff --seed Guest0 -d Guest1 -d Guest2 /etc We can mount the device of Guest0 to "/", but where the devices from Guest1 and Guest2 can be mounted?
The mkmountpoint call allows you to have multiple "roots":
http://libguestfs.org/guestfs.3.html#guestfs_mkmountpoint
*However*, this won't work for general guests, where for example two guests might have conflicting logical volumes or UUIDs which are duplicated. It's simply not possible to safely mount multiple guests in a single appliance. The solution is to use two libguestfs handles.
It seems hard to launch two libguestfs handles at the same time, right? Now, many functions like inspect_mount(), inspect_do_decrypt() use the global libguestfs handle without any argument, so, when inspecting two different handles, we can't use these functions now, would you like to make them being able to handle individual libguestfs handles? And, some global values like live, read_only, etc. And, we haven't considered that we could launch more than one libguestfs handles at the same time, right? Are there some troubles doing things like this? Thanks, Wanlong Gao
Rich.
On Fri, Jun 01, 2012 at 05:11:37PM +0800, Wanlong Gao wrote:
On 05/28/2012 03:48 PM, Richard W.M. Jones wrote:
On Sun, May 27, 2012 at 02:52:59PM +0800, Wanlong Gao wrote:
I looked into this, now Rich, I have a more question, if we doing like virt-diff --seed Guest0 -d Guest1 -d Guest2 /etc We can mount the device of Guest0 to "/", but where the devices from Guest1 and Guest2 can be mounted?
The mkmountpoint call allows you to have multiple "roots":
http://libguestfs.org/guestfs.3.html#guestfs_mkmountpoint
*However*, this won't work for general guests, where for example two guests might have conflicting logical volumes or UUIDs which are duplicated. It's simply not possible to safely mount multiple guests in a single appliance. The solution is to use two libguestfs handles.
It seems hard to launch two libguestfs handles at the same time, right? Now, many functions like inspect_mount(), inspect_do_decrypt() use the global libguestfs handle without any argument, so, when inspecting two different handles, we can't use these functions now, would you like to make them being able to handle individual libguestfs handles?
Those functions are part of the guestfish shared code, and guestfish assumes there's only a single handle open (the global variable 'g'). Of course that's not a limitation of the API, just of guestfish. Certainly you could modify them so that you have to pass the handle, if that's going to help for this new virt-diff program. Or you could duplicate the code as necessary.
And, some global values like live, read_only, etc. And, we haven't considered that we could launch more than one libguestfs handles at the same time, right? Are there some troubles doing things like this?
Same thing here. All of the tools like virt-df, etc which use the guestfish shared code assume a single handle. You could change that assumption, or just copy the code and modify it in your tool, whichever makes more sense. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming blog: http://rwmj.wordpress.com Fedora now supports 80 OCaml packages (the OPEN alternative to F#) http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora
add new virt-diff tool Signed-off-by: Wanlong Gao <gaowanlong@cn.fujitsu.com> --- Hi Rich, This just a thought of virt-diff tool, I send it out ASAP to ask your opinions. Now, I just implement two guest, one SEED guest and one DIFF guest, and the patch is wholly untested. Please take patient to review. And it's hard for me to start two guest handler, if you have time, please help or just handle this work. PS, I attended the LinuxCon Japan this month, so the plan delayed. Thanks, Wanlong Gao cat/virt-diff.c | 423 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 cat/virt-diff.c diff --git a/cat/virt-diff.c b/cat/virt-diff.c new file mode 100644 index 0000000..4bd8730 --- /dev/null +++ b/cat/virt-diff.c @@ -0,0 +1,423 @@ +/* virt-diff + * Copyright (C) 2012 FUJITSU LIMITED. + * Copyright (C) 2010-2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include <unistd.h> +#include <getopt.h> +#include <fcntl.h> +#include <locale.h> +#include <assert.h> +#include <time.h> +#include <libintl.h> + +#include "human.h" +#include "progname.h" + +#include "guestfs.h" +#include "options.h" + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +/* libguestfs handle for seed. */ +static guestfs_h *sg; + +/* libguestfs handle for temp. */ +static guestfs_h *g; + +static int live = 0; +static int verbose = 0; +static int keys_from_stdin = 0; +static int echo_keys = 0; +static const char *libvirt_uri = NULL; +static int inspector = 1; + +static doing_diff = 1; + +static inline char * +diff_bad_case (char const *s) +{ + return (char *) s; +} + +static void __attribute__((noreturn)) +diff_usage (int status) +{ + if (status != EXIT_SUCCESS) { + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + } else { + fprintf (stdout, + _("%s: Show the differences between seed Guest and the others\n" + "Copyright (C) 2012 Fujitsu Limited.\n" + "Copyright (C) 2010-2012 Red Hat Inc.\n" + "Usage:\n" + "\n" + "\n" + "Options:\n" + " -a|--add image Add image\n" + " --checksum[=...] Display file checksums\n"), + program_name); + } + exit (status); +} + + +/* Simple implementation of decryption: look for any crypto_LUKS + * partitions and decrypt them, then rescan for VGs. This only works + * for Fedora whole-disk encryption. WIP to make this work for other + * encryption schemes. + */ +static void +diff_inspect_do_decrypt (guestfs_h *g) +{ + char **partitions = guestfs_list_partitions (g); + if (partitions == NULL) + exit (EXIT_FAILURE); + + int need_rescan = 0; + size_t i; + for (i = 0; partitions[i] != NULL; ++i) { + char *type = guestfs_vfs_type (g, partitions[i]); + if (type && STREQ (type, "crypto_LUKS")) { + char mapname[32]; + make_mapname (partitions[i], mapname, sizeof mapname); + + char *key = read_key (partitions[i]); + /* XXX Should we call guestfs_luks_open_ro if readonly flag + * is set? This might break 'mount_ro'. + */ + if (guestfs_luks_open (g, partitions[i], key, mapname) == -1) + exit (EXIT_FAILURE); + + free (key); + + need_rescan = 1; + } + free (type); + } + + free_strings (partitions); + + if (need_rescan) { + if (guestfs_vgscan (g) == -1) + exit (EXIT_FAILURE); + if (guestfs_vg_activate_all (g, 1) == -1) + exit (EXIT_FAILURE); + } +} + +static void +diff_inspect_mount_root (guestfs_h *g, const char *root) +{ + char **mountpoints = guestfs_inspect_get_mountpoints (g, root); + if (mountpoints == NULL) + exit (EXIT_FAILURE); + + /* Sort by key length, shortest key first, so that we end up + * mounting the filesystems in the correct order. + */ + qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *), + compare_keys_len); + + size_t i; + size_t mount_errors = 0; + for (i = 0; mountpoints[i] != NULL; i += 2) { + int r; + r = guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]); + if (r == -1) { + /* If the "/" filesystem could not be mounted, give up, else + * just count the errors and print a warning. + */ + if (STREQ (mountpoints[i], "/")) + exit (EXIT_FAILURE); + mount_errors++; + } + } + + free_strings (mountpoints); + + if (mount_errors) + fprintf (stderr, _("%s: some filesystems could not be mounted (ignored)\n"), + program_name); +} + +/* This function implements the -i option. */ +static void +diff_inspect_mount (guestfs_h *g) +{ + diff_inspect_do_decrypt (g); + + char **roots = guestfs_inspect_os (g); + if (roots == NULL) + exit (EXIT_FAILURE); + + if (roots[0] == NULL) { + fprintf (stderr, + _("%s: no operating system was found on this disk\n" + "\n" + "If using guestfish '-i' option, remove this option and instead\n" + "use the commands 'run' followed by 'list-filesystems'.\n" + "You can then mount filesystems you want by hand using the\n" + "'mount' or 'mount-ro' command.\n" + "\n" + "If using guestmount '-i', remove this option and choose the\n" + "filesystem(s) you want to see by manually adding '-m' option(s).\n" + "Use 'virt-filesystems' to see what filesystems are available.\n" + "\n" + "If using other virt tools, this disk image won't work\n" + "with these tools. Use the guestfish equivalent commands\n" + "(see the virt tool manual page).\n"), + program_name); + free_strings (roots); + exit (EXIT_FAILURE); + } + + if (roots[1] != NULL) { + fprintf (stderr, + _("%s: multi-boot operating systems are not supported\n" + "\n" + "If using guestfish '-i' option, remove this option and instead\n" + "use the commands 'run' followed by 'list-filesystems'.\n" + "You can then mount filesystems you want by hand using the\n" + "'mount' or 'mount-ro' command.\n" + "\n" + "If using guestmount '-i', remove this option and choose the\n" + "filesystem(s) you want to see by manually adding '-m' option(s).\n" + "Use 'virt-filesystems' to see what filesystems are available.\n" + "\n" + "If using other virt tools, multi-boot operating systems won't work\n" + "with these tools. Use the guestfish equivalent commands\n" + "(see the virt tool manual page).\n"), + program_name); + free_strings (roots); + exit (EXIT_FAILURE); + } + + root = roots[0]; + free (roots); + + diff_inspect_mount_root (root); +} + +int +main (int argc, int *argv[]) +{ + /* set global program name that is not polluted with libtool artifacts. */ + set_program_name (argv[0]); + bindtextdomain (PACKAGE, LOCALEBASEDIR); + textdomain (PACKAGE); + + enum { HELP_OPTION = CHAR_MAX + 1 }; + + static const char *options = "s:d:"; + static const struct option long_options[] = { + {"seed", 1, 0, 's'}, + {"domain", 1, 0, 'd'}, + {0, 0, 0, 0} + }; + + struct drv *sdrv = NULL; + struct drv *drv = NULL; + int c; + + sg = guestfs_create (); + if (sg == NULL) { + fprintf (stderr, _("guestfs_create: failed to create seed handle\n")); + exit (EXIT_FAILURE); + } + + g = guestfs_create (); + if (g == NULL) { + fprintf (stderr, _("guestfs_create: failed to create comparison handle\n")); + exit (EXIT_FAILURE); + } + + argv[0] = bad_case (program_name); + + for (;;) { + c = getopt_long (argc, argv, options, long_options, &option_index); + if (c == -1) break; + + switch (c) { + case 0: + if (STREQ (long_options[option_index].name, "seed")) { + if (sdrv) { + fprintf(stderr, _("....")); + exit (EXIT_FAILURE); + } + sdrv = calloc (1, sizeof (struct drv)); + if (!sdrv) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + sdrv->type = drv_d; + sdrv->nr_drives = -1; + sdrv->d.guest = optarg; + sdrv->next = NULL; + } else if (STREQ (long_options[option_index].name, "domain")) { + drv = calloc ("malloc"); + if (!drv) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + drv->type = drv_d; + drv->nr_drives = -1; + drv->d.guest = optarg; + drv->next = NULL; + } else { + fprintf (stderr, _("%s: unknown long option: %s (%d)\n"), + program_name, long_options[option_index].name, option_index); + exit (EXIT_FAILURE); + } + break; + + case 'd': + OPTION_d; + break; + + case 's': + if (sdrv) { + fprintf(stderr, _("....")); + exit (EXIT_FAILURE); + } + sdrv = calloc (1, sizeof (struct drv)); + if (!sdrv) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + sdrv->type = drv_d; + sdrv->nr_drives = -1; + sdrv->d.guest = optarg; + sdrv->next = NULL; + break; + + case HELP_OPTION: + usage (EXIT_SUCCESS); + + default: + usage (EXIT_FAILURE); + } + } + + if (sdrv == NULL) + usage (EXIT_FAILURE); + if (drv == NULL) + usage (EXIT_FAILURE); + + struct guestfs_add_domain_argv optargs = { + .bitmask = 0; + .libvirturi = NULL; + .readonly = 1; + .allowuuid = 1; + .readonlydisk = "read"; + }; + nr = guestfs_add_domain_argv (sg, sdrv->d.guest, &optargs); + if (r == -1) + exit (EXIT_FAILURE); + sdrv->nr_drives = nr; + nr = guestfs_add_domain_argv (g, drv->d.guest, &optargs); + if (r == -1) + exit (EXIT_FAILURE); + drv->nr_drives = nr; + + if (guestfs_launch (sg) == -1) + exit (EXIT_FAILURE); + if (guestfs_launch (g) == -1) + exit (EXIT_FAILURE); + + diff_inspect_mount (sg); + diff_inspect_mount (g); + + char stempdir = "/tmp/sGuestXXXXXX"; + char tempdir = "/tmp/GuestXXXXXX"; + char sdir[256]; + char dir[256]; + + if (mkdtemp (stempdir) == NULL) { + perror ("mkdtemp"); + exit (EXIT_FAILURE); + } + if (mkdtemp (tempdir) == NULL) { + perror ("mkdtemp"); + exit (EXIT_FAILURE); + } + + if (guestfs_mount_local (sg, stempdir, -1) == -1) + exit (EXIT_FAILURE); + if (guestfs_mount_local (g, tempdir, -1) == -1) + exit (EXIT_FAILURE); + + spid = fork (); + if (spid == -1) { + perror ("fork"); + exit (EXIT_FAILURE); + } + if (spid == 0) { + while (doing_diff) + sleep (1); + guestfs_umount_local (sg, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1); + _exit (EXIT_SUCCESS); + } + + pid = fork(); + if (pid == -1) { + perror ("fork"); + exit (EXIT_FAILURE); + } + if (pid == 0) { + while (doing_diff) + sleep (1); + guestfs_umount_local (g, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1); + _exit (EXIT_SUCCESS); + } + + if (guestfs_mount_local_run (sg) == -1) + exit (EXIT_FAILURE); + if (guestfs_mount_local_run (g) == -1) + exit (EXIT_FAILURE); + + const char *dir = argv[optind]; + char system_arg[BUFSIZ]; + sprintf (system_arg, "diff -urN %s%s %s%s", stempdir, dir, + tempdir, dir); + system(system_arg); + + waitpid (spid, NULL, 0); + waitpid (pid, NULL, 0); + + if (guestfs_umount (sg, "/") == -1) + exit (EXIT_FAILURE); + if (guestfs_umount (g, "/") == -1) + exit (EXIT_FAILURE); + + free_drives (sdrvs); + free_drives (drv); + + guestfs_close (sg); + guestfs_close (g); + + exit (EXIT_SUCCESS); +} -- 1.7.11.rc0
On 06/19/2012 05:24 PM, Wanlong Gao wrote:
add new virt-diff tool
Signed-off-by: Wanlong Gao <gaowanlong@cn.fujitsu.com> ---
Hi Rich, This just a thought of virt-diff tool, I send it out ASAP to ask your opinions.
Now, I just implement two guest, one SEED guest and one DIFF guest, and the patch is wholly untested. Please take patient to review. And it's hard for me to start two guest handler, if you have time, please help or just handle this work.
PS, I attended the LinuxCon Japan this month, so the plan delayed.
Rich, If you have time, can you look at this and give some comments? Thanks, Wanlong Gao
Thanks, Wanlong Gao
cat/virt-diff.c | 423 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 cat/virt-diff.c
diff --git a/cat/virt-diff.c b/cat/virt-diff.c new file mode 100644 index 0000000..4bd8730 --- /dev/null +++ b/cat/virt-diff.c @@ -0,0 +1,423 @@ +/* virt-diff + * Copyright (C) 2012 FUJITSU LIMITED. + * Copyright (C) 2010-2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include <unistd.h> +#include <getopt.h> +#include <fcntl.h> +#include <locale.h> +#include <assert.h> +#include <time.h> +#include <libintl.h> + +#include "human.h" +#include "progname.h" + +#include "guestfs.h" +#include "options.h" + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +/* libguestfs handle for seed. */ +static guestfs_h *sg; + +/* libguestfs handle for temp. */ +static guestfs_h *g; + +static int live = 0; +static int verbose = 0; +static int keys_from_stdin = 0; +static int echo_keys = 0; +static const char *libvirt_uri = NULL; +static int inspector = 1; + +static doing_diff = 1; + +static inline char * +diff_bad_case (char const *s) +{ + return (char *) s; +} + +static void __attribute__((noreturn)) +diff_usage (int status) +{ + if (status != EXIT_SUCCESS) { + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + } else { + fprintf (stdout, + _("%s: Show the differences between seed Guest and the others\n" + "Copyright (C) 2012 Fujitsu Limited.\n" + "Copyright (C) 2010-2012 Red Hat Inc.\n" + "Usage:\n" + "\n" + "\n" + "Options:\n" + " -a|--add image Add image\n" + " --checksum[=...] Display file checksums\n"), + program_name); + } + exit (status); +} + + +/* Simple implementation of decryption: look for any crypto_LUKS + * partitions and decrypt them, then rescan for VGs. This only works + * for Fedora whole-disk encryption. WIP to make this work for other + * encryption schemes. + */ +static void +diff_inspect_do_decrypt (guestfs_h *g) +{ + char **partitions = guestfs_list_partitions (g); + if (partitions == NULL) + exit (EXIT_FAILURE); + + int need_rescan = 0; + size_t i; + for (i = 0; partitions[i] != NULL; ++i) { + char *type = guestfs_vfs_type (g, partitions[i]); + if (type && STREQ (type, "crypto_LUKS")) { + char mapname[32]; + make_mapname (partitions[i], mapname, sizeof mapname); + + char *key = read_key (partitions[i]); + /* XXX Should we call guestfs_luks_open_ro if readonly flag + * is set? This might break 'mount_ro'. + */ + if (guestfs_luks_open (g, partitions[i], key, mapname) == -1) + exit (EXIT_FAILURE); + + free (key); + + need_rescan = 1; + } + free (type); + } + + free_strings (partitions); + + if (need_rescan) { + if (guestfs_vgscan (g) == -1) + exit (EXIT_FAILURE); + if (guestfs_vg_activate_all (g, 1) == -1) + exit (EXIT_FAILURE); + } +} + +static void +diff_inspect_mount_root (guestfs_h *g, const char *root) +{ + char **mountpoints = guestfs_inspect_get_mountpoints (g, root); + if (mountpoints == NULL) + exit (EXIT_FAILURE); + + /* Sort by key length, shortest key first, so that we end up + * mounting the filesystems in the correct order. + */ + qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *), + compare_keys_len); + + size_t i; + size_t mount_errors = 0; + for (i = 0; mountpoints[i] != NULL; i += 2) { + int r; + r = guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]); + if (r == -1) { + /* If the "/" filesystem could not be mounted, give up, else + * just count the errors and print a warning. + */ + if (STREQ (mountpoints[i], "/")) + exit (EXIT_FAILURE); + mount_errors++; + } + } + + free_strings (mountpoints); + + if (mount_errors) + fprintf (stderr, _("%s: some filesystems could not be mounted (ignored)\n"), + program_name); +} + +/* This function implements the -i option. */ +static void +diff_inspect_mount (guestfs_h *g) +{ + diff_inspect_do_decrypt (g); + + char **roots = guestfs_inspect_os (g); + if (roots == NULL) + exit (EXIT_FAILURE); + + if (roots[0] == NULL) { + fprintf (stderr, + _("%s: no operating system was found on this disk\n" + "\n" + "If using guestfish '-i' option, remove this option and instead\n" + "use the commands 'run' followed by 'list-filesystems'.\n" + "You can then mount filesystems you want by hand using the\n" + "'mount' or 'mount-ro' command.\n" + "\n" + "If using guestmount '-i', remove this option and choose the\n" + "filesystem(s) you want to see by manually adding '-m' option(s).\n" + "Use 'virt-filesystems' to see what filesystems are available.\n" + "\n" + "If using other virt tools, this disk image won't work\n" + "with these tools. Use the guestfish equivalent commands\n" + "(see the virt tool manual page).\n"), + program_name); + free_strings (roots); + exit (EXIT_FAILURE); + } + + if (roots[1] != NULL) { + fprintf (stderr, + _("%s: multi-boot operating systems are not supported\n" + "\n" + "If using guestfish '-i' option, remove this option and instead\n" + "use the commands 'run' followed by 'list-filesystems'.\n" + "You can then mount filesystems you want by hand using the\n" + "'mount' or 'mount-ro' command.\n" + "\n" + "If using guestmount '-i', remove this option and choose the\n" + "filesystem(s) you want to see by manually adding '-m' option(s).\n" + "Use 'virt-filesystems' to see what filesystems are available.\n" + "\n" + "If using other virt tools, multi-boot operating systems won't work\n" + "with these tools. Use the guestfish equivalent commands\n" + "(see the virt tool manual page).\n"), + program_name); + free_strings (roots); + exit (EXIT_FAILURE); + } + + root = roots[0]; + free (roots); + + diff_inspect_mount_root (root); +} + +int +main (int argc, int *argv[]) +{ + /* set global program name that is not polluted with libtool artifacts. */ + set_program_name (argv[0]); + bindtextdomain (PACKAGE, LOCALEBASEDIR); + textdomain (PACKAGE); + + enum { HELP_OPTION = CHAR_MAX + 1 }; + + static const char *options = "s:d:"; + static const struct option long_options[] = { + {"seed", 1, 0, 's'}, + {"domain", 1, 0, 'd'}, + {0, 0, 0, 0} + }; + + struct drv *sdrv = NULL; + struct drv *drv = NULL; + int c; + + sg = guestfs_create (); + if (sg == NULL) { + fprintf (stderr, _("guestfs_create: failed to create seed handle\n")); + exit (EXIT_FAILURE); + } + + g = guestfs_create (); + if (g == NULL) { + fprintf (stderr, _("guestfs_create: failed to create comparison handle\n")); + exit (EXIT_FAILURE); + } + + argv[0] = bad_case (program_name); + + for (;;) { + c = getopt_long (argc, argv, options, long_options, &option_index); + if (c == -1) break; + + switch (c) { + case 0: + if (STREQ (long_options[option_index].name, "seed")) { + if (sdrv) { + fprintf(stderr, _("....")); + exit (EXIT_FAILURE); + } + sdrv = calloc (1, sizeof (struct drv)); + if (!sdrv) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + sdrv->type = drv_d; + sdrv->nr_drives = -1; + sdrv->d.guest = optarg; + sdrv->next = NULL; + } else if (STREQ (long_options[option_index].name, "domain")) { + drv = calloc ("malloc"); + if (!drv) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + drv->type = drv_d; + drv->nr_drives = -1; + drv->d.guest = optarg; + drv->next = NULL; + } else { + fprintf (stderr, _("%s: unknown long option: %s (%d)\n"), + program_name, long_options[option_index].name, option_index); + exit (EXIT_FAILURE); + } + break; + + case 'd': + OPTION_d; + break; + + case 's': + if (sdrv) { + fprintf(stderr, _("....")); + exit (EXIT_FAILURE); + } + sdrv = calloc (1, sizeof (struct drv)); + if (!sdrv) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + sdrv->type = drv_d; + sdrv->nr_drives = -1; + sdrv->d.guest = optarg; + sdrv->next = NULL; + break; + + case HELP_OPTION: + usage (EXIT_SUCCESS); + + default: + usage (EXIT_FAILURE); + } + } + + if (sdrv == NULL) + usage (EXIT_FAILURE); + if (drv == NULL) + usage (EXIT_FAILURE); + + struct guestfs_add_domain_argv optargs = { + .bitmask = 0; + .libvirturi = NULL; + .readonly = 1; + .allowuuid = 1; + .readonlydisk = "read"; + }; + nr = guestfs_add_domain_argv (sg, sdrv->d.guest, &optargs); + if (r == -1) + exit (EXIT_FAILURE); + sdrv->nr_drives = nr; + nr = guestfs_add_domain_argv (g, drv->d.guest, &optargs); + if (r == -1) + exit (EXIT_FAILURE); + drv->nr_drives = nr; + + if (guestfs_launch (sg) == -1) + exit (EXIT_FAILURE); + if (guestfs_launch (g) == -1) + exit (EXIT_FAILURE); + + diff_inspect_mount (sg); + diff_inspect_mount (g); + + char stempdir = "/tmp/sGuestXXXXXX"; + char tempdir = "/tmp/GuestXXXXXX"; + char sdir[256]; + char dir[256]; + + if (mkdtemp (stempdir) == NULL) { + perror ("mkdtemp"); + exit (EXIT_FAILURE); + } + if (mkdtemp (tempdir) == NULL) { + perror ("mkdtemp"); + exit (EXIT_FAILURE); + } + + if (guestfs_mount_local (sg, stempdir, -1) == -1) + exit (EXIT_FAILURE); + if (guestfs_mount_local (g, tempdir, -1) == -1) + exit (EXIT_FAILURE); + + spid = fork (); + if (spid == -1) { + perror ("fork"); + exit (EXIT_FAILURE); + } + if (spid == 0) { + while (doing_diff) + sleep (1); + guestfs_umount_local (sg, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1); + _exit (EXIT_SUCCESS); + } + + pid = fork(); + if (pid == -1) { + perror ("fork"); + exit (EXIT_FAILURE); + } + if (pid == 0) { + while (doing_diff) + sleep (1); + guestfs_umount_local (g, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1); + _exit (EXIT_SUCCESS); + } + + if (guestfs_mount_local_run (sg) == -1) + exit (EXIT_FAILURE); + if (guestfs_mount_local_run (g) == -1) + exit (EXIT_FAILURE); + + const char *dir = argv[optind]; + char system_arg[BUFSIZ]; + sprintf (system_arg, "diff -urN %s%s %s%s", stempdir, dir, + tempdir, dir); + system(system_arg); + + waitpid (spid, NULL, 0); + waitpid (pid, NULL, 0); + + if (guestfs_umount (sg, "/") == -1) + exit (EXIT_FAILURE); + if (guestfs_umount (g, "/") == -1) + exit (EXIT_FAILURE); + + free_drives (sdrvs); + free_drives (drv); + + guestfs_close (sg); + guestfs_close (g); + + exit (EXIT_SUCCESS); +}
On Tue, Jun 19, 2012 at 05:24:26PM +0800, Wanlong Gao wrote:
add new virt-diff tool
Signed-off-by: Wanlong Gao <gaowanlong@cn.fujitsu.com> ---
Hi Rich, This just a thought of virt-diff tool, I send it out ASAP to ask your opinions.
Now, I just implement two guest, one SEED guest and one DIFF guest, and the patch is wholly untested. Please take patient to review. And it's hard for me to start two guest handler, if you have time, please help or just handle this work.
PS, I attended the LinuxCon Japan this month, so the plan delayed.
The outline of the code seems to be: * create two handles * add both disks * inspect both disks * mount-local both disks on separate temporary directories * run regular 'diff' command across the temporary directories These is a reasonable approach for code simplicity, but I guess it'll be very slow in practice.
cat/virt-diff.c | 423 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 cat/virt-diff.c
diff --git a/cat/virt-diff.c b/cat/virt-diff.c new file mode 100644 index 0000000..4bd8730 --- /dev/null +++ b/cat/virt-diff.c @@ -0,0 +1,423 @@ +/* virt-diff + * Copyright (C) 2012 FUJITSU LIMITED. + * Copyright (C) 2010-2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include <unistd.h> +#include <getopt.h> +#include <fcntl.h> +#include <locale.h> +#include <assert.h> +#include <time.h> +#include <libintl.h> + +#include "human.h" +#include "progname.h" + +#include "guestfs.h" +#include "options.h" + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +/* libguestfs handle for seed. */ +static guestfs_h *sg; + +/* libguestfs handle for temp. */ +static guestfs_h *g; + +static int live = 0; +static int verbose = 0; +static int keys_from_stdin = 0; +static int echo_keys = 0; +static const char *libvirt_uri = NULL; +static int inspector = 1; + +static doing_diff = 1; + +static inline char * +diff_bad_case (char const *s) +{ + return (char *) s; +} + +static void __attribute__((noreturn)) +diff_usage (int status) +{ + if (status != EXIT_SUCCESS) { + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + } else { + fprintf (stdout, + _("%s: Show the differences between seed Guest and the others\n" + "Copyright (C) 2012 Fujitsu Limited.\n" + "Copyright (C) 2010-2012 Red Hat Inc.\n" + "Usage:\n" + "\n" + "\n" + "Options:\n" + " -a|--add image Add image\n" + " --checksum[=...] Display file checksums\n"), + program_name); + } + exit (status); +} + + +/* Simple implementation of decryption: look for any crypto_LUKS + * partitions and decrypt them, then rescan for VGs. This only works + * for Fedora whole-disk encryption. WIP to make this work for other + * encryption schemes. + */ +static void +diff_inspect_do_decrypt (guestfs_h *g) +{ + char **partitions = guestfs_list_partitions (g); + if (partitions == NULL) + exit (EXIT_FAILURE); + + int need_rescan = 0; + size_t i; + for (i = 0; partitions[i] != NULL; ++i) { + char *type = guestfs_vfs_type (g, partitions[i]); + if (type && STREQ (type, "crypto_LUKS")) { + char mapname[32]; + make_mapname (partitions[i], mapname, sizeof mapname); + + char *key = read_key (partitions[i]); + /* XXX Should we call guestfs_luks_open_ro if readonly flag + * is set? This might break 'mount_ro'. + */ + if (guestfs_luks_open (g, partitions[i], key, mapname) == -1) + exit (EXIT_FAILURE); + + free (key); + + need_rescan = 1; + } + free (type); + } + + free_strings (partitions); + + if (need_rescan) { + if (guestfs_vgscan (g) == -1) + exit (EXIT_FAILURE); + if (guestfs_vg_activate_all (g, 1) == -1) + exit (EXIT_FAILURE); + } +} + +static void +diff_inspect_mount_root (guestfs_h *g, const char *root) +{ + char **mountpoints = guestfs_inspect_get_mountpoints (g, root); + if (mountpoints == NULL) + exit (EXIT_FAILURE); + + /* Sort by key length, shortest key first, so that we end up + * mounting the filesystems in the correct order. + */ + qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *), + compare_keys_len); + + size_t i; + size_t mount_errors = 0; + for (i = 0; mountpoints[i] != NULL; i += 2) { + int r; + r = guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]); + if (r == -1) { + /* If the "/" filesystem could not be mounted, give up, else + * just count the errors and print a warning. + */ + if (STREQ (mountpoints[i], "/")) + exit (EXIT_FAILURE); + mount_errors++; + } + } + + free_strings (mountpoints); + + if (mount_errors) + fprintf (stderr, _("%s: some filesystems could not be mounted (ignored)\n"), + program_name); +} + +/* This function implements the -i option. */ +static void +diff_inspect_mount (guestfs_h *g) +{ + diff_inspect_do_decrypt (g); + + char **roots = guestfs_inspect_os (g); + if (roots == NULL) + exit (EXIT_FAILURE); + + if (roots[0] == NULL) { + fprintf (stderr, + _("%s: no operating system was found on this disk\n" + "\n" + "If using guestfish '-i' option, remove this option and instead\n" + "use the commands 'run' followed by 'list-filesystems'.\n" + "You can then mount filesystems you want by hand using the\n" + "'mount' or 'mount-ro' command.\n" + "\n" + "If using guestmount '-i', remove this option and choose the\n" + "filesystem(s) you want to see by manually adding '-m' option(s).\n" + "Use 'virt-filesystems' to see what filesystems are available.\n" + "\n" + "If using other virt tools, this disk image won't work\n" + "with these tools. Use the guestfish equivalent commands\n" + "(see the virt tool manual page).\n"), + program_name); + free_strings (roots); + exit (EXIT_FAILURE); + } + + if (roots[1] != NULL) { + fprintf (stderr, + _("%s: multi-boot operating systems are not supported\n" + "\n" + "If using guestfish '-i' option, remove this option and instead\n" + "use the commands 'run' followed by 'list-filesystems'.\n" + "You can then mount filesystems you want by hand using the\n" + "'mount' or 'mount-ro' command.\n" + "\n" + "If using guestmount '-i', remove this option and choose the\n" + "filesystem(s) you want to see by manually adding '-m' option(s).\n" + "Use 'virt-filesystems' to see what filesystems are available.\n" + "\n" + "If using other virt tools, multi-boot operating systems won't work\n" + "with these tools. Use the guestfish equivalent commands\n" + "(see the virt tool manual page).\n"), + program_name); + free_strings (roots); + exit (EXIT_FAILURE); + } + + root = roots[0]; + free (roots); + + diff_inspect_mount_root (root); +} + +int +main (int argc, int *argv[]) +{ + /* set global program name that is not polluted with libtool artifacts. */ + set_program_name (argv[0]); + bindtextdomain (PACKAGE, LOCALEBASEDIR); + textdomain (PACKAGE); + + enum { HELP_OPTION = CHAR_MAX + 1 }; + + static const char *options = "s:d:"; + static const struct option long_options[] = { + {"seed", 1, 0, 's'}, + {"domain", 1, 0, 'd'}, + {0, 0, 0, 0} + };
Eventually you'll need to support all the other options too, or at least --help.
+ struct drv *sdrv = NULL; + struct drv *drv = NULL; + int c; + + sg = guestfs_create (); + if (sg == NULL) { + fprintf (stderr, _("guestfs_create: failed to create seed handle\n")); + exit (EXIT_FAILURE); + } + + g = guestfs_create (); + if (g == NULL) { + fprintf (stderr, _("guestfs_create: failed to create comparison handle\n")); + exit (EXIT_FAILURE); + } + + argv[0] = bad_case (program_name); + + for (;;) { + c = getopt_long (argc, argv, options, long_options, &option_index); + if (c == -1) break; + + switch (c) { + case 0: + if (STREQ (long_options[option_index].name, "seed")) { + if (sdrv) { + fprintf(stderr, _("....")); + exit (EXIT_FAILURE); + } + sdrv = calloc (1, sizeof (struct drv)); + if (!sdrv) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + sdrv->type = drv_d; + sdrv->nr_drives = -1; + sdrv->d.guest = optarg; + sdrv->next = NULL; + } else if (STREQ (long_options[option_index].name, "domain")) { + drv = calloc ("malloc"); + if (!drv) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + drv->type = drv_d; + drv->nr_drives = -1; + drv->d.guest = optarg; + drv->next = NULL; + } else { + fprintf (stderr, _("%s: unknown long option: %s (%d)\n"), + program_name, long_options[option_index].name, option_index); + exit (EXIT_FAILURE); + } + break; + + case 'd': + OPTION_d; + break; + + case 's': + if (sdrv) { + fprintf(stderr, _("....")); + exit (EXIT_FAILURE); + } + sdrv = calloc (1, sizeof (struct drv)); + if (!sdrv) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + sdrv->type = drv_d; + sdrv->nr_drives = -1; + sdrv->d.guest = optarg; + sdrv->next = NULL; + break; + + case HELP_OPTION: + usage (EXIT_SUCCESS); + + default: + usage (EXIT_FAILURE); + } + } + + if (sdrv == NULL) + usage (EXIT_FAILURE); + if (drv == NULL) + usage (EXIT_FAILURE); + + struct guestfs_add_domain_argv optargs = { + .bitmask = 0; + .libvirturi = NULL; + .readonly = 1; + .allowuuid = 1; + .readonlydisk = "read"; + }; + nr = guestfs_add_domain_argv (sg, sdrv->d.guest, &optargs); + if (r == -1) + exit (EXIT_FAILURE); + sdrv->nr_drives = nr; + nr = guestfs_add_domain_argv (g, drv->d.guest, &optargs); + if (r == -1) + exit (EXIT_FAILURE); + drv->nr_drives = nr; + + if (guestfs_launch (sg) == -1) + exit (EXIT_FAILURE); + if (guestfs_launch (g) == -1) + exit (EXIT_FAILURE); + + diff_inspect_mount (sg); + diff_inspect_mount (g); + + char stempdir = "/tmp/sGuestXXXXXX"; + char tempdir = "/tmp/GuestXXXXXX"; + char sdir[256]; + char dir[256]; + + if (mkdtemp (stempdir) == NULL) { + perror ("mkdtemp"); + exit (EXIT_FAILURE); + } + if (mkdtemp (tempdir) == NULL) { + perror ("mkdtemp"); + exit (EXIT_FAILURE); + } + + if (guestfs_mount_local (sg, stempdir, -1) == -1) + exit (EXIT_FAILURE); + if (guestfs_mount_local (g, tempdir, -1) == -1) + exit (EXIT_FAILURE); + + spid = fork (); + if (spid == -1) { + perror ("fork"); + exit (EXIT_FAILURE); + } + if (spid == 0) { + while (doing_diff) + sleep (1); + guestfs_umount_local (sg, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1); + _exit (EXIT_SUCCESS); + } + + pid = fork(); + if (pid == -1) { + perror ("fork"); + exit (EXIT_FAILURE); + } + if (pid == 0) { + while (doing_diff) + sleep (1); + guestfs_umount_local (g, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1); + _exit (EXIT_SUCCESS); + }
The doing_diff variable isn't shared between forked processes, so the child processes will simply busy-wait forever. In any case the main program never even sets doing_diff. This code is going to be far more complex in the final version.
+ if (guestfs_mount_local_run (sg) == -1) + exit (EXIT_FAILURE); + if (guestfs_mount_local_run (g) == -1) + exit (EXIT_FAILURE); + + const char *dir = argv[optind]; + char system_arg[BUFSIZ]; + sprintf (system_arg, "diff -urN %s%s %s%s", stempdir, dir, + tempdir, dir); + system(system_arg); + + waitpid (spid, NULL, 0); + waitpid (pid, NULL, 0); + + if (guestfs_umount (sg, "/") == -1) + exit (EXIT_FAILURE); + if (guestfs_umount (g, "/") == -1) + exit (EXIT_FAILURE); + + free_drives (sdrvs); + free_drives (drv); + + guestfs_close (sg); + guestfs_close (g); + + exit (EXIT_SUCCESS); +} -- 1.7.11.rc0
Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://et.redhat.com/~rjones/virt-top
On 07/02/2012 05:28 PM, Richard W.M. Jones wrote:
On Tue, Jun 19, 2012 at 05:24:26PM +0800, Wanlong Gao wrote:
add new virt-diff tool
Signed-off-by: Wanlong Gao <gaowanlong@cn.fujitsu.com> ---
Hi Rich, This just a thought of virt-diff tool, I send it out ASAP to ask your opinions.
Now, I just implement two guest, one SEED guest and one DIFF guest, and the patch is wholly untested. Please take patient to review. And it's hard for me to start two guest handler, if you have time, please help or just handle this work.
PS, I attended the LinuxCon Japan this month, so the plan delayed.
The outline of the code seems to be:
* create two handles * add both disks * inspect both disks * mount-local both disks on separate temporary directories * run regular 'diff' command across the temporary directories
These is a reasonable approach for code simplicity, but I guess it'll be very slow in practice.
If you have a better idea in mind, please teach me. Thanks, Wanlong Gao
cat/virt-diff.c | 423 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 cat/virt-diff.c
diff --git a/cat/virt-diff.c b/cat/virt-diff.c new file mode 100644 index 0000000..4bd8730 --- /dev/null +++ b/cat/virt-diff.c @@ -0,0 +1,423 @@ +/* virt-diff + * Copyright (C) 2012 FUJITSU LIMITED. + * Copyright (C) 2010-2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include <unistd.h> +#include <getopt.h> +#include <fcntl.h> +#include <locale.h> +#include <assert.h> +#include <time.h> +#include <libintl.h> + +#include "human.h" +#include "progname.h" + +#include "guestfs.h" +#include "options.h" + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +/* libguestfs handle for seed. */ +static guestfs_h *sg; + +/* libguestfs handle for temp. */ +static guestfs_h *g; + +static int live = 0; +static int verbose = 0; +static int keys_from_stdin = 0; +static int echo_keys = 0; +static const char *libvirt_uri = NULL; +static int inspector = 1; + +static doing_diff = 1; + +static inline char * +diff_bad_case (char const *s) +{ + return (char *) s; +} + +static void __attribute__((noreturn)) +diff_usage (int status) +{ + if (status != EXIT_SUCCESS) { + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + } else { + fprintf (stdout, + _("%s: Show the differences between seed Guest and the others\n" + "Copyright (C) 2012 Fujitsu Limited.\n" + "Copyright (C) 2010-2012 Red Hat Inc.\n" + "Usage:\n" + "\n" + "\n" + "Options:\n" + " -a|--add image Add image\n" + " --checksum[=...] Display file checksums\n"), + program_name); + } + exit (status); +} + + +/* Simple implementation of decryption: look for any crypto_LUKS + * partitions and decrypt them, then rescan for VGs. This only works + * for Fedora whole-disk encryption. WIP to make this work for other + * encryption schemes. + */ +static void +diff_inspect_do_decrypt (guestfs_h *g) +{ + char **partitions = guestfs_list_partitions (g); + if (partitions == NULL) + exit (EXIT_FAILURE); + + int need_rescan = 0; + size_t i; + for (i = 0; partitions[i] != NULL; ++i) { + char *type = guestfs_vfs_type (g, partitions[i]); + if (type && STREQ (type, "crypto_LUKS")) { + char mapname[32]; + make_mapname (partitions[i], mapname, sizeof mapname); + + char *key = read_key (partitions[i]); + /* XXX Should we call guestfs_luks_open_ro if readonly flag + * is set? This might break 'mount_ro'. + */ + if (guestfs_luks_open (g, partitions[i], key, mapname) == -1) + exit (EXIT_FAILURE); + + free (key); + + need_rescan = 1; + } + free (type); + } + + free_strings (partitions); + + if (need_rescan) { + if (guestfs_vgscan (g) == -1) + exit (EXIT_FAILURE); + if (guestfs_vg_activate_all (g, 1) == -1) + exit (EXIT_FAILURE); + } +} + +static void +diff_inspect_mount_root (guestfs_h *g, const char *root) +{ + char **mountpoints = guestfs_inspect_get_mountpoints (g, root); + if (mountpoints == NULL) + exit (EXIT_FAILURE); + + /* Sort by key length, shortest key first, so that we end up + * mounting the filesystems in the correct order. + */ + qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *), + compare_keys_len); + + size_t i; + size_t mount_errors = 0; + for (i = 0; mountpoints[i] != NULL; i += 2) { + int r; + r = guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]); + if (r == -1) { + /* If the "/" filesystem could not be mounted, give up, else + * just count the errors and print a warning. + */ + if (STREQ (mountpoints[i], "/")) + exit (EXIT_FAILURE); + mount_errors++; + } + } + + free_strings (mountpoints); + + if (mount_errors) + fprintf (stderr, _("%s: some filesystems could not be mounted (ignored)\n"), + program_name); +} + +/* This function implements the -i option. */ +static void +diff_inspect_mount (guestfs_h *g) +{ + diff_inspect_do_decrypt (g); + + char **roots = guestfs_inspect_os (g); + if (roots == NULL) + exit (EXIT_FAILURE); + + if (roots[0] == NULL) { + fprintf (stderr, + _("%s: no operating system was found on this disk\n" + "\n" + "If using guestfish '-i' option, remove this option and instead\n" + "use the commands 'run' followed by 'list-filesystems'.\n" + "You can then mount filesystems you want by hand using the\n" + "'mount' or 'mount-ro' command.\n" + "\n" + "If using guestmount '-i', remove this option and choose the\n" + "filesystem(s) you want to see by manually adding '-m' option(s).\n" + "Use 'virt-filesystems' to see what filesystems are available.\n" + "\n" + "If using other virt tools, this disk image won't work\n" + "with these tools. Use the guestfish equivalent commands\n" + "(see the virt tool manual page).\n"), + program_name); + free_strings (roots); + exit (EXIT_FAILURE); + } + + if (roots[1] != NULL) { + fprintf (stderr, + _("%s: multi-boot operating systems are not supported\n" + "\n" + "If using guestfish '-i' option, remove this option and instead\n" + "use the commands 'run' followed by 'list-filesystems'.\n" + "You can then mount filesystems you want by hand using the\n" + "'mount' or 'mount-ro' command.\n" + "\n" + "If using guestmount '-i', remove this option and choose the\n" + "filesystem(s) you want to see by manually adding '-m' option(s).\n" + "Use 'virt-filesystems' to see what filesystems are available.\n" + "\n" + "If using other virt tools, multi-boot operating systems won't work\n" + "with these tools. Use the guestfish equivalent commands\n" + "(see the virt tool manual page).\n"), + program_name); + free_strings (roots); + exit (EXIT_FAILURE); + } + + root = roots[0]; + free (roots); + + diff_inspect_mount_root (root); +} + +int +main (int argc, int *argv[]) +{ + /* set global program name that is not polluted with libtool artifacts. */ + set_program_name (argv[0]); + bindtextdomain (PACKAGE, LOCALEBASEDIR); + textdomain (PACKAGE); + + enum { HELP_OPTION = CHAR_MAX + 1 }; + + static const char *options = "s:d:"; + static const struct option long_options[] = { + {"seed", 1, 0, 's'}, + {"domain", 1, 0, 'd'}, + {0, 0, 0, 0} + };
Eventually you'll need to support all the other options too, or at least --help.
+ struct drv *sdrv = NULL; + struct drv *drv = NULL; + int c; + + sg = guestfs_create (); + if (sg == NULL) { + fprintf (stderr, _("guestfs_create: failed to create seed handle\n")); + exit (EXIT_FAILURE); + } + + g = guestfs_create (); + if (g == NULL) { + fprintf (stderr, _("guestfs_create: failed to create comparison handle\n")); + exit (EXIT_FAILURE); + } + + argv[0] = bad_case (program_name); + + for (;;) { + c = getopt_long (argc, argv, options, long_options, &option_index); + if (c == -1) break; + + switch (c) { + case 0: + if (STREQ (long_options[option_index].name, "seed")) { + if (sdrv) { + fprintf(stderr, _("....")); + exit (EXIT_FAILURE); + } + sdrv = calloc (1, sizeof (struct drv)); + if (!sdrv) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + sdrv->type = drv_d; + sdrv->nr_drives = -1; + sdrv->d.guest = optarg; + sdrv->next = NULL; + } else if (STREQ (long_options[option_index].name, "domain")) { + drv = calloc ("malloc"); + if (!drv) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + drv->type = drv_d; + drv->nr_drives = -1; + drv->d.guest = optarg; + drv->next = NULL; + } else { + fprintf (stderr, _("%s: unknown long option: %s (%d)\n"), + program_name, long_options[option_index].name, option_index); + exit (EXIT_FAILURE); + } + break; + + case 'd': + OPTION_d; + break; + + case 's': + if (sdrv) { + fprintf(stderr, _("....")); + exit (EXIT_FAILURE); + } + sdrv = calloc (1, sizeof (struct drv)); + if (!sdrv) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + sdrv->type = drv_d; + sdrv->nr_drives = -1; + sdrv->d.guest = optarg; + sdrv->next = NULL; + break; + + case HELP_OPTION: + usage (EXIT_SUCCESS); + + default: + usage (EXIT_FAILURE); + } + } + + if (sdrv == NULL) + usage (EXIT_FAILURE); + if (drv == NULL) + usage (EXIT_FAILURE); + + struct guestfs_add_domain_argv optargs = { + .bitmask = 0; + .libvirturi = NULL; + .readonly = 1; + .allowuuid = 1; + .readonlydisk = "read"; + }; + nr = guestfs_add_domain_argv (sg, sdrv->d.guest, &optargs); + if (r == -1) + exit (EXIT_FAILURE); + sdrv->nr_drives = nr; + nr = guestfs_add_domain_argv (g, drv->d.guest, &optargs); + if (r == -1) + exit (EXIT_FAILURE); + drv->nr_drives = nr; + + if (guestfs_launch (sg) == -1) + exit (EXIT_FAILURE); + if (guestfs_launch (g) == -1) + exit (EXIT_FAILURE); + + diff_inspect_mount (sg); + diff_inspect_mount (g); + + char stempdir = "/tmp/sGuestXXXXXX"; + char tempdir = "/tmp/GuestXXXXXX"; + char sdir[256]; + char dir[256]; + + if (mkdtemp (stempdir) == NULL) { + perror ("mkdtemp"); + exit (EXIT_FAILURE); + } + if (mkdtemp (tempdir) == NULL) { + perror ("mkdtemp"); + exit (EXIT_FAILURE); + } + + if (guestfs_mount_local (sg, stempdir, -1) == -1) + exit (EXIT_FAILURE); + if (guestfs_mount_local (g, tempdir, -1) == -1) + exit (EXIT_FAILURE); + + spid = fork (); + if (spid == -1) { + perror ("fork"); + exit (EXIT_FAILURE); + } + if (spid == 0) { + while (doing_diff) + sleep (1); + guestfs_umount_local (sg, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1); + _exit (EXIT_SUCCESS); + } + + pid = fork(); + if (pid == -1) { + perror ("fork"); + exit (EXIT_FAILURE); + } + if (pid == 0) { + while (doing_diff) + sleep (1); + guestfs_umount_local (g, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1); + _exit (EXIT_SUCCESS); + }
The doing_diff variable isn't shared between forked processes, so the child processes will simply busy-wait forever. In any case the main program never even sets doing_diff.
This code is going to be far more complex in the final version.
+ if (guestfs_mount_local_run (sg) == -1) + exit (EXIT_FAILURE); + if (guestfs_mount_local_run (g) == -1) + exit (EXIT_FAILURE); + + const char *dir = argv[optind]; + char system_arg[BUFSIZ]; + sprintf (system_arg, "diff -urN %s%s %s%s", stempdir, dir, + tempdir, dir); + system(system_arg); + + waitpid (spid, NULL, 0); + waitpid (pid, NULL, 0); + + if (guestfs_umount (sg, "/") == -1) + exit (EXIT_FAILURE); + if (guestfs_umount (g, "/") == -1) + exit (EXIT_FAILURE); + + free_drives (sdrvs); + free_drives (drv); + + guestfs_close (sg); + guestfs_close (g); + + exit (EXIT_SUCCESS); +} -- 1.7.11.rc0
Rich.
On Mon, Jul 02, 2012 at 07:34:12PM +0800, Wanlong Gao wrote:
On 07/02/2012 05:28 PM, Richard W.M. Jones wrote:
The outline of the code seems to be:
* create two handles * add both disks * inspect both disks * mount-local both disks on separate temporary directories * run regular 'diff' command across the temporary directories
These is a reasonable approach for code simplicity, but I guess it'll be very slow in practice.
If you have a better idea in mind, please teach me.
Thinking about this longer, I think the mount-local approach will be fine. If it's too slow and someone is motivated, it can always be optimized later. The larger issue is the patch as written cannot work ... Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://et.redhat.com/~rjones/virt-top
participants (3)
-
Matthew Booth -
Richard W.M. Jones -
Wanlong Gao