Autotools help needed
by Maros Zatko
Hi folks!
I'm trying to convince autotools to allow me to include fish.c in a C
file containing a bunch of unit tests. In order to do that I need to
convince it add include path (-I../) to gcc for that particular file
(test-quoting.c originally, but dash seems to make troubles as well).
I came up with this (snippet from Makefile.am):
bin_TESTS = testquoting
testquoting_CFLAGS = -I../
TESTS = testquoting
And it does not work (snippet of make check output):
gcc -std=gnu99 -std=gnu99 -g -O2 testquoting.c -o testquoting
In file included from testquoting.c:4:0:
fish.c:19:20: fatal error: config.h: No such file or directory
#include <config.h>
Could you please share your thoughts on this?
The motivation to include fish.c is storage type (static) of functions
of interest.
thanks,
- m
10 years, 1 month
[PATCH 0/5] use augeas for /etc/shadow
by Pino Toscano
Hi,
currently /etc/shadow is edited manually when needed (i.e. when setting
the password for an user), and it is not changed when removing users.
Import the upstream shadow.aug (currently in their development serie,
but not part of any released version yet), and use it only when the
augeas version is less than a potential 1.2.1 (covering also the case
when the new version is just 1.3.0).
Pino Toscano (5):
daemon: make aug_close cleanup available for all
daemon: add a way to check for the version of augeas
appliance: daemon: import and use upstream shadow lens
sysprep: remove (now obsolete) comment about /etc/shadow lens
customize: use augeas to change passwords
appliance/Makefile.am | 3 +-
appliance/guestfs_shadow.aug | 72 ++++++++++++++++
customize/password.ml | 64 +++++++-------
daemon/augeas.c | 137 +++++++++++++++++++++++++++++-
daemon/daemon.h | 19 ++++-
daemon/guestfsd.c | 11 +++
daemon/lvm-filter.c | 16 ----
sysprep/sysprep_operation_user_account.ml | 4 -
8 files changed, 268 insertions(+), 58 deletions(-)
create mode 100644 appliance/guestfs_shadow.aug
--
1.9.3
10 years, 1 month
[PATCH] customize: fix locking accounts with passwords
by Pino Toscano
When setting the password for a locked account, make sure to still write
the password after the "!!" marker, otherwise the account will have no
password.
---
customize/password.ml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/customize/password.ml b/customize/password.ml
index d76ebea..84af0c3 100644
--- a/customize/password.ml
+++ b/customize/password.ml
@@ -109,13 +109,13 @@ let rec set_linux_passwords ~prog ?password_crypto g root passwords =
match selector with
| { pw_locked = locked;
pw_password = Password password } ->
- if locked then "!!" else "" ^ encrypt password crypto
+ (if locked then "!!" else "") ^ encrypt password crypto
| { pw_locked = locked;
pw_password = Random_password } ->
let password = make_random_password () in
printf (f_"Setting random password of %s to %s\n%!")
user password;
- if locked then "!!" else "" ^ encrypt password crypto
+ (if locked then "!!" else "") ^ encrypt password crypto
| { pw_locked = true; pw_password = Disabled_password } -> "!!*"
| { pw_locked = false; pw_password = Disabled_password } -> "*" in
user ^ ":" ^ pwfield ^ rest
--
1.9.3
10 years, 1 month
[PATCH] v2v: adding input -i ova
by Shahar Havivi
Adding ability for v2v to get Vmware ova file as an input.
Signed-off-by: Shahar Havivi <shaharh(a)redhat.com>
---
po/POTFILES-ml | 1 +
v2v/Makefile.am | 3 +
v2v/cmdline.ml | 12 ++-
v2v/input_ova.ml | 220 +++++++++++++++++++++++++++++++++++++++++++++++++
v2v/input_ova.mli | 22 +++++
v2v/test-v2v-i-ova.ovf | 147 +++++++++++++++++++++++++++++++++
v2v/test-v2v-i-ova.sh | 73 ++++++++++++++++
v2v/virt-v2v.pod | 14 +++-
8 files changed, 489 insertions(+), 3 deletions(-)
create mode 100644 v2v/input_ova.ml
create mode 100644 v2v/input_ova.mli
create mode 100644 v2v/test-v2v-i-ova.ovf
create mode 100755 v2v/test-v2v-i-ova.sh
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index 53a7bfb..4b33dd9 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -90,6 +90,7 @@ v2v/domainxml.ml
v2v/input_disk.ml
v2v/input_libvirt.ml
v2v/input_libvirtxml.ml
+v2v/input_ova.ml
v2v/lib_esx.ml
v2v/lib_linux.ml
v2v/modules_list.ml
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index b74325e..ae65046 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -38,6 +38,7 @@ SOURCES_MLI = \
lib_linux.mli \
modules_list.mli \
output_glance.mli \
+ input_ova.mli \
output_libvirt.mli \
output_local.mli \
output_RHEV.mli \
@@ -57,6 +58,7 @@ SOURCES_ML = \
input_disk.ml \
input_libvirtxml.ml \
input_libvirt.ml \
+ input_ova.ml \
convert_linux.ml \
convert_windows.ml \
output_glance.ml \
@@ -195,6 +197,7 @@ TESTS_ENVIRONMENT = $(top_builddir)/run --test
if ENABLE_APPLIANCE
TESTS = \
+ test-v2v-i-ova.sh \
test-v2v-i-disk.sh \
test-v2v-machine-readable.sh \
test-v2v-networks-and-bridges.sh \
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
index 6a72aeb..affe36f 100644
--- a/v2v/cmdline.ml
+++ b/v2v/cmdline.ml
@@ -54,6 +54,7 @@ let parse_cmdline () =
| "disk" | "local" -> input_mode := `Disk
| "libvirt" -> input_mode := `Libvirt
| "libvirtxml" -> input_mode := `LibvirtXML
+ | "ova" -> input_mode := `OVA
| s ->
error (f_"unknown -i option: %s") s
in
@@ -241,7 +242,16 @@ read the man page virt-v2v(1).
| [filename] -> filename
| _ ->
error (f_"expecting a libvirt XML file name on the command line") in
- Input_libvirtxml.input_libvirtxml verbose filename in
+ Input_libvirtxml.input_libvirtxml verbose filename
+
+ | `OVA ->
+ (* -i ova: Expecting an ova filename (tar file). *)
+ let filename =
+ match args with
+ | [filename] -> filename
+ | _ ->
+ error (f_"expecting an OVA file name on the command line") in
+ Input_ova.input_ova verbose filename in
(* Parse the output mode. *)
let output =
diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml
new file mode 100644
index 0000000..2737718
--- /dev/null
+++ b/v2v/input_ova.ml
@@ -0,0 +1,220 @@
+(* virt-v2v
+ * Copyright (C) 2009-2014 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.
+ *)
+
+open Printf
+
+open Common_gettext.Gettext
+open Common_utils
+
+open Types
+open Utils
+
+class input_ova verbose ova =
+ let tmpdir =
+ let base_dir = (new Guestfs.guestfs ())#get_cachedir () in
+ let t = Mkdtemp.temp_dir ~base_dir "ova." "" in
+ rmdir_on_exit t;
+ t in
+object
+ inherit input verbose
+
+ method as_options = "-i ova " ^ ova
+
+ method source () =
+
+ (* extract ova (tar) file *)
+ let cmd = sprintf "tar -xf %s -C %s" (quote ova) (quote tmpdir) in
+
+ if Sys.command cmd <> 0 then
+ error (f_"error running command: %s") cmd;
+
+ let files = Sys.readdir tmpdir in
+ let mf = ref "" in
+ let ovf = ref "" in
+ (* search for the ovf file *)
+ Array.iter (fun file ->
+ if Filename.check_suffix file ".ovf" then
+ ovf := file
+ else if Filename.check_suffix file ".mf" then
+ mf := file
+ ) files;
+
+ (* verify sha1 from manifest file *)
+ let mf = tmpdir // !mf in
+ let rex = Str.regexp "SHA1(\\(.*\\))= \\(.*?\\)\r\\?$" in
+ let lines = read_whole_file mf in
+ let lines = string_nsplit "\n" lines in
+ List.iter (
+ fun line ->
+ if Str.string_match rex line 0 then
+ let file = Str.matched_group 1 line in
+ let sha1 = Str.matched_group 2 line in
+ let cmd = sprintf "sha1sum %s" (quote (tmpdir // file)) in
+ let out = external_command ~prog cmd in
+ (match out with
+ | [] -> error (f_"no output from sha1sum command, see previous errors")
+ | [line] ->
+ let hash, _ = string_split " " line in
+ if hash <> sha1 then
+ error (f_"Checksum of %s does not match manifest sha1 %s") file sha1;
+ | _::_ -> error (f_"cannot parse output of sha1sum command")
+ );
+ ) lines;
+
+ (* parse the ovf file *)
+ let xml = read_whole_file (tmpdir // !ovf) in
+ let doc = Xml.parse_memory xml in
+ let xpathctx = Xml.xpath_new_context doc in
+ Xml.xpath_register_ns xpathctx "ovf" "http://schemas.dmtf.org/ovf/envelope/1";
+ Xml.xpath_register_ns xpathctx "rasd" "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationS...";
+ Xml.xpath_register_ns xpathctx "vssd" "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettin...";
+
+ let xpath_to_string expr default =
+ let obj = Xml.xpath_eval_expression xpathctx expr in
+ if Xml.xpathobj_nr_nodes obj < 1 then default
+ else (
+ let node = Xml.xpathobj_node doc obj 0 in
+ Xml.node_as_string node
+ )
+ and xpath_to_int expr default =
+ let obj = Xml.xpath_eval_expression xpathctx expr in
+ if Xml.xpathobj_nr_nodes obj < 1 then default
+ else (
+ let node = Xml.xpathobj_node doc obj 0 in
+ let str = Xml.node_as_string node in
+ try int_of_string str
+ with Failure "int_of_string" ->
+ error (f_"expecting XML expression to return an integer (expression: %s)")
+ expr
+ )
+ in
+
+ let disks = ref [] in
+ let removables = ref [] in
+
+ (* resources hard-disk, CD-ROMs and floppy *)
+ let add_resource id =
+ let expr = sprintf "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType/text()=%d]" id in
+ let obj = Xml.xpath_eval_expression xpathctx expr in
+ let nr_nodes = Xml.xpathobj_nr_nodes obj in
+ for i = 0 to nr_nodes-1 do
+ let n = Xml.xpathobj_node doc obj i in
+ Xml.xpathctx_set_current_context xpathctx n;
+ let address = xpath_to_int "rasd:AddressOnParent/text()" 0 in
+ let parent_id = xpath_to_int "rasd:Parent/text()" 0 in
+ (* prob the parent controller *)
+ let expr = sprintf "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:InstanceId/text()=%d]/rasd:ResourceType/text()" parent_id in
+ let controller = xpath_to_int expr 0 in
+ (* 6: iscsi controller, 5: ide. assueming scsi or ide *)
+ let target_dev =
+ match controller with
+ | 6 -> "sd"
+ | 0 | 5 | _ -> "hd" in
+ (*FIXME in floppy should be 'fd'??? *)
+
+ let target_dev = sprintf "%s%c" target_dev (Char.chr(48+address)) in
+
+ (* add disk(17)/removables to its collections *)
+ if id = 17 then (
+ Xml.xpathctx_set_current_context xpathctx n;
+ let file_id = xpath_to_string "rasd:HostResource/text()" "" in
+ let rex = Str.regexp "^ovf:/disk/\\(.*\\)" in
+ if Str.string_match rex file_id 0 then (
+ let file_id = Str.matched_group 1 file_id in
+ let expr = sprintf "/ovf:Envelope/ovf:DiskSection/ovf:Disk[@ovf:diskId='%s']/@ovf:fileRef" file_id in
+ let file_ref = xpath_to_string expr "" in
+ if file_ref == "" then error (f_"Error parsing disk fileRef");
+ let expr = sprintf "/ovf:Envelope/ovf:References/ovf:File[@ovf:id='%s']/@ovf:href" file_ref in
+ let file_name = xpath_to_string expr "" in
+ let disk = { s_qemu_uri=(tmpdir // file_name); s_format=Some "vmdk"; s_target_dev=Some target_dev } in
+ disks := disk :: !disks;
+ ) else
+ error (f_"could not parse disk rasd:HostResource from OVF document");
+ )
+ else (
+ (* 14: Floppy 15: CD 16: CDROM*)
+ let typ =
+ match id with
+ | 14 -> `Floppy
+ | 15 | 16 -> `CDROM
+ | _ -> assert false in
+ let disk = { s_removable_type = typ; s_removable_target_dev = Some target_dev } in
+ removables := disk :: !removables;
+ )
+ done;
+ in
+
+ (* search for vm name *)
+ let name = xpath_to_string "/ovf:Envelope/ovf:VirtualSystem/ovf:Name/text()" "" in
+ if name = "" then
+ error (f_"could not parse ovf:Name from OVF document");
+
+ (* search for memory *)
+ let memory = xpath_to_int "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType/text()=4]/rasd:VirtualQuantity/text()" (1024 * 1024) in
+ let memory = Int64.of_int (memory * 1024 * 1024) in
+
+ (* search for cpu *)
+ let cpu = xpath_to_int "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType/text()=3]/rasd:VirtualQuantity/text()" 1 in
+
+ (* search for floopy *)
+ add_resource 14;
+
+ (* search for cd *)
+ add_resource 15;
+
+ (* search for cdrom *)
+ add_resource 16;
+
+ (* search for hard-disk *)
+ add_resource 17;
+
+ (* serch for networks ResourceType: 10*)
+ let nics = ref [] in
+ let obj = Xml.xpath_eval_expression xpathctx "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType/text()=10]" in
+ let nr_nodes = Xml.xpathobj_nr_nodes obj in
+ for i = 0 to nr_nodes-1 do
+ let n = Xml.xpathobj_node doc obj i in
+ Xml.xpathctx_set_current_context xpathctx n;
+ let vnet = xpath_to_string "rasd:ElementName/text()" (sprintf"eth%d" i) in
+ let nic = {
+ s_mac = None;
+ s_vnet = vnet;
+ s_vnet_orig = vnet;
+ s_vnet_type = Network;
+ } in
+ nics := nic :: !nics
+ done;
+
+ let source = {
+ s_dom_type = "vmware";
+ s_name = name;
+ s_orig_name = name;
+ s_memory = memory;
+ s_vcpu = cpu;
+ s_arch = "x86_64"; (* XXX: no architucture in ovf, this entry will be overritten at os inspection via libguestfs *)
+ s_features = []; (* FIXME: *)
+ s_display = None; (* FIXME: *)
+ s_disks = !disks;
+ s_removables = !removables;
+ s_nics = !nics;
+ } in
+ source
+end
+
+let input_ova = new input_ova
+let () = Modules_list.register_input_module "ova"
diff --git a/v2v/input_ova.mli b/v2v/input_ova.mli
new file mode 100644
index 0000000..d4c347e
--- /dev/null
+++ b/v2v/input_ova.mli
@@ -0,0 +1,22 @@
+(* virt-v2v
+ * Copyright (C) 2009-2014 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.
+ *)
+
+(** [-i ova] source. *)
+
+val input_ova : bool -> string -> Types.input
+(** [input_ova filename] sets up an input from vmware ova file. *)
diff --git a/v2v/test-v2v-i-ova.ovf b/v2v/test-v2v-i-ova.ovf
new file mode 100644
index 0000000..a950645
--- /dev/null
+++ b/v2v/test-v2v-i-ova.ovf
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Envelope vmw:buildId="build-1623387" xmlns="http://schemas.dmtf.org/ovf/envelope/1" xmlns:cim="http://schemas.dmtf.org/wbem/wscim/1/common" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationS..." xmlns:vmw="http://www.vmware.com/schema/ovf" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettin..." xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <References>
+ <File ovf:href="test-ova.vmdk" ovf:id="file1" ovf:size="349405696" />
+ </References>
+ <DiskSection>
+ <Info>Virtual disk information</Info>
+ <Disk ovf:capacity="32" ovf:capacityAllocationUnits="byte * 2^30" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="1008926720" />
+ </DiskSection>
+ <NetworkSection>
+ <Info>The list of logical networks</Info>
+ <Network ovf:name="VM Network">
+ <Description>The VM Network network</Description>
+ </Network>
+ </NetworkSection>
+ <VirtualSystem ovf:id="TestOva">
+ <Info>A virtual machine</Info>
+ <Name>TestOva</Name>
+ <OperatingSystemSection ovf:id="74" vmw:osType="windows7_64Guest">
+ <Info>The kind of installed guest operating system</Info>
+ </OperatingSystemSection>
+ <VirtualHardwareSection>
+ <Info>Virtual hardware requirements</Info>
+ <System>
+ <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
+ <vssd:InstanceID>0</vssd:InstanceID>
+ <vssd:VirtualSystemIdentifier>TestOva</vssd:VirtualSystemIdentifier>
+ <vssd:VirtualSystemType>vmx-08</vssd:VirtualSystemType>
+ </System>
+ <Item>
+ <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>
+ <rasd:Description>Number of Virtual CPUs</rasd:Description>
+ <rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>
+ <rasd:InstanceID>1</rasd:InstanceID>
+ <rasd:ResourceType>3</rasd:ResourceType>
+ <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
+ </Item>
+ <Item>
+ <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>
+ <rasd:Description>Memory Size</rasd:Description>
+ <rasd:ElementName>2048MB of memory</rasd:ElementName>
+ <rasd:InstanceID>2</rasd:InstanceID>
+ <rasd:ResourceType>4</rasd:ResourceType>
+ <rasd:VirtualQuantity>2048</rasd:VirtualQuantity>
+ </Item>
+ <Item>
+ <rasd:Address>0</rasd:Address>
+ <rasd:Description>SCSI Controller</rasd:Description>
+ <rasd:ElementName>SCSI Controller 0</rasd:ElementName>
+ <rasd:InstanceID>3</rasd:InstanceID>
+ <rasd:ResourceSubType>lsilogicsas</rasd:ResourceSubType>
+ <rasd:ResourceType>6</rasd:ResourceType>
+ <vmw:Config ovf:required="false" vmw:key="slotInfo.pciSlotNumber" vmw:value="160" />
+ </Item>
+ <Item>
+ <rasd:Address>1</rasd:Address>
+ <rasd:Description>IDE Controller</rasd:Description>
+ <rasd:ElementName>VirtualIDEController 1</rasd:ElementName>
+ <rasd:InstanceID>4</rasd:InstanceID>
+ <rasd:ResourceType>5</rasd:ResourceType>
+ </Item>
+ <Item>
+ <rasd:Address>0</rasd:Address>
+ <rasd:Description>IDE Controller</rasd:Description>
+ <rasd:ElementName>VirtualIDEController 0</rasd:ElementName>
+ <rasd:InstanceID>5</rasd:InstanceID>
+ <rasd:ResourceType>5</rasd:ResourceType>
+ </Item>
+ <Item ovf:required="false">
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:ElementName>VirtualVideoCard</rasd:ElementName>
+ <rasd:InstanceID>6</rasd:InstanceID>
+ <rasd:ResourceType>24</rasd:ResourceType>
+ <vmw:Config ovf:required="false" vmw:key="enable3DSupport" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="enableMPTSupport" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="use3dRenderer" vmw:value="automatic" />
+ <vmw:Config ovf:required="false" vmw:key="useAutoDetect" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="videoRamSizeInKB" vmw:value="8192" />
+ </Item>
+ <Item ovf:required="false">
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:ElementName>VirtualVMCIDevice</rasd:ElementName>
+ <rasd:InstanceID>7</rasd:InstanceID>
+ <rasd:ResourceSubType>vmware.vmci</rasd:ResourceSubType>
+ <rasd:ResourceType>1</rasd:ResourceType>
+ <vmw:Config ovf:required="false" vmw:key="allowUnrestrictedCommunication" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="slotInfo.pciSlotNumber" vmw:value="33" />
+ </Item>
+ <Item ovf:required="false">
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:ElementName>CD-ROM 1</rasd:ElementName>
+ <rasd:InstanceID>8</rasd:InstanceID>
+ <rasd:Parent>4</rasd:Parent>
+ <rasd:ResourceSubType>vmware.cdrom.iso</rasd:ResourceSubType>
+ <rasd:ResourceType>15</rasd:ResourceType>
+ </Item>
+ <Item>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:ElementName>Hard Disk 1</rasd:ElementName>
+ <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>
+ <rasd:InstanceID>9</rasd:InstanceID>
+ <rasd:Parent>3</rasd:Parent>
+ <rasd:ResourceType>17</rasd:ResourceType>
+ <vmw:Config ovf:required="false" vmw:key="backing.writeThrough" vmw:value="false" />
+ </Item>
+ <Item ovf:required="false">
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:Description>Floppy Drive</rasd:Description>
+ <rasd:ElementName>Floppy 1</rasd:ElementName>
+ <rasd:InstanceID>10</rasd:InstanceID>
+ <rasd:ResourceSubType>vmware.floppy.remotedevice</rasd:ResourceSubType>
+ <rasd:ResourceType>14</rasd:ResourceType>
+ </Item>
+ <Item>
+ <rasd:AddressOnParent>7</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
+ <rasd:Connection>VM Network</rasd:Connection>
+ <rasd:Description>E1000 ethernet adapter on "VM Network"</rasd:Description>
+ <rasd:ElementName>Ethernet 1</rasd:ElementName>
+ <rasd:InstanceID>11</rasd:InstanceID>
+ <rasd:ResourceSubType>E1000</rasd:ResourceSubType>
+ <rasd:ResourceType>10</rasd:ResourceType>
+ <vmw:Config ovf:required="false" vmw:key="slotInfo.pciSlotNumber" vmw:value="32" />
+ <vmw:Config ovf:required="false" vmw:key="wakeOnLanEnabled" vmw:value="true" />
+ </Item>
+ <vmw:Config ovf:required="false" vmw:key="cpuHotAddEnabled" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="cpuHotRemoveEnabled" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="firmware" vmw:value="bios" />
+ <vmw:Config ovf:required="false" vmw:key="virtualICH7MPresent" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="virtualSMCPresent" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="memoryHotAddEnabled" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="nestedHVEnabled" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="powerOpInfo.powerOffType" vmw:value="soft" />
+ <vmw:Config ovf:required="false" vmw:key="powerOpInfo.resetType" vmw:value="soft" />
+ <vmw:Config ovf:required="false" vmw:key="powerOpInfo.standbyAction" vmw:value="checkpoint" />
+ <vmw:Config ovf:required="false" vmw:key="powerOpInfo.suspendType" vmw:value="hard" />
+ <vmw:Config ovf:required="false" vmw:key="tools.afterPowerOn" vmw:value="true" />
+ <vmw:Config ovf:required="false" vmw:key="tools.afterResume" vmw:value="true" />
+ <vmw:Config ovf:required="false" vmw:key="tools.beforeGuestShutdown" vmw:value="true" />
+ <vmw:Config ovf:required="false" vmw:key="tools.beforeGuestStandby" vmw:value="true" />
+ <vmw:Config ovf:required="false" vmw:key="tools.syncTimeWithHost" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="tools.toolsUpgradePolicy" vmw:value="manual" />
+ </VirtualHardwareSection>
+ </VirtualSystem>
+</Envelope>
diff --git a/v2v/test-v2v-i-ova.sh b/v2v/test-v2v-i-ova.sh
new file mode 100755
index 0000000..018d03b
--- /dev/null
+++ b/v2v/test-v2v-i-ova.sh
@@ -0,0 +1,73 @@
+#!/bin/bash -
+# libguestfs virt-v2v test script
+# Copyright (C) 2014 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.
+
+# Test -i ova option.
+
+unset CDPATH
+export LANG=C
+set -e
+
+if [ -n "$SKIP_TEST_V2V_I_OVA_SH" ]; then
+ echo "$0: test skipped because environment variable is set"
+ exit 77
+fi
+
+if [ "$(../fish/guestfish get-backend)" = "uml" ]; then
+ echo "$0: test skipped because UML backend does not support network"
+ exit 77
+fi
+
+f=../tests/guests/windows.img
+if ! test -f $f || ! test -s $f; then
+ echo "$0: test skipped because phony Windows image was not created"
+ exit 77
+fi
+
+d=test-v2v-i-ova.d
+rm -rf $d
+mkdir $d
+
+vmdk=test-ova.vmdk
+ovf=test-v2v-i-ova.ovf
+mf=test-ova.mf
+ova=test-ova.ova
+xml=TestOva.xml
+raw=TestOva-sda
+
+qemu-img convert $f -O vmdk $d/$vmdk
+cp $ovf $d/$ovf
+sha1=`sha1sum $d/$ovf | awk '{print $1}'`
+echo "SHA1($ovf)= $sha1" > $d/$mf
+sha1=`sha1sum $d/$vmdk | awk '{print $1}'`
+echo "SHA1($vmdk)= $sha1" >> $d/$mf
+
+pushd .
+cd $d
+tar -cf $ova $ovf $mf $vmdk
+rm -rf $ovf $mf $vmdk
+popd
+
+$VG ./virt-v2v --debug-gc \
+ -i ova $d/$ova \
+ -o local -of raw -os $d
+
+# Test the libvirt XML metadata and a disk was created.
+test -f $d/$raw
+test -f $d/$xml
+
+rm -rf $d
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index cb7fec8..3c07841 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -32,8 +32,8 @@ libguestfs E<ge> 1.28.
┌────────────┐
-i disk ───────────┐ │ │ ┌───────▶ -o local
- │ │ virt-v2v │ │
- └──▶ │ conversion │ ──┘
+ └──▶ │ virt-v2v │ │
+ -i ova ──────────────▶ │ conversion │ ──┘
-i libvirt ───────────▶ │ server │ ────────▶ -o libvirt
(default) ┌──▶ │ │ ──┐ (default)
│ │ │ ─┐└──────▶ -o glance
@@ -52,6 +52,8 @@ option selects the precise libvirt source.
I<-i disk> is used for reading from local disk images (mainly for
testing).
+I<-i ova> is used for reading from libvirt ova source file.
+
I<-i libvirtxml> is used to read from libvirt XML files. This is the
method used by L<virt-p2v(1)> behind the scenes.
@@ -158,6 +160,14 @@ usually adequate but you can get finer control (eg. of memory and
vCPUs) by using I<-i libvirtxml> instead. Only guests that use a single
disk can be imported this way.
+=item B<-i ova>
+
+Set the input method to I<ova>.
+
+In this mode you can read a vmware ova file (tar format).
+virt-v2v tries to read the ova manifest file and check the ova files
+for validity (checksum) as well as analyzing the ovf file.
+
=item B<-i libvirt>
Set the input method to I<libvirt>. This is the default.
--
1.9.3
10 years, 1 month
[PATCH] v2v: adding input -i ova
by Shahar Havivi
Adding ability for v2v to get Libvirt ova file as an input.
Signed-off-by: Shahar Havivi <shaharh(a)redhat.com>
---
po/POTFILES-ml | 1 +
v2v/Makefile.am | 3 +
v2v/cmdline.ml | 12 ++-
v2v/input_ova.ml | 220 +++++++++++++++++++++++++++++++++++++++++++++++++
v2v/input_ova.mli | 22 +++++
v2v/test-v2v-i-ova.ovf | 147 +++++++++++++++++++++++++++++++++
v2v/test-v2v-i-ova.sh | 73 ++++++++++++++++
v2v/virt-v2v.pod | 14 +++-
8 files changed, 489 insertions(+), 3 deletions(-)
create mode 100644 v2v/input_ova.ml
create mode 100644 v2v/input_ova.mli
create mode 100644 v2v/test-v2v-i-ova.ovf
create mode 100755 v2v/test-v2v-i-ova.sh
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index 53a7bfb..4b33dd9 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -90,6 +90,7 @@ v2v/domainxml.ml
v2v/input_disk.ml
v2v/input_libvirt.ml
v2v/input_libvirtxml.ml
+v2v/input_ova.ml
v2v/lib_esx.ml
v2v/lib_linux.ml
v2v/modules_list.ml
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index b74325e..ae65046 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -38,6 +38,7 @@ SOURCES_MLI = \
lib_linux.mli \
modules_list.mli \
output_glance.mli \
+ input_ova.mli \
output_libvirt.mli \
output_local.mli \
output_RHEV.mli \
@@ -57,6 +58,7 @@ SOURCES_ML = \
input_disk.ml \
input_libvirtxml.ml \
input_libvirt.ml \
+ input_ova.ml \
convert_linux.ml \
convert_windows.ml \
output_glance.ml \
@@ -195,6 +197,7 @@ TESTS_ENVIRONMENT = $(top_builddir)/run --test
if ENABLE_APPLIANCE
TESTS = \
+ test-v2v-i-ova.sh \
test-v2v-i-disk.sh \
test-v2v-machine-readable.sh \
test-v2v-networks-and-bridges.sh \
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
index 6a72aeb..affe36f 100644
--- a/v2v/cmdline.ml
+++ b/v2v/cmdline.ml
@@ -54,6 +54,7 @@ let parse_cmdline () =
| "disk" | "local" -> input_mode := `Disk
| "libvirt" -> input_mode := `Libvirt
| "libvirtxml" -> input_mode := `LibvirtXML
+ | "ova" -> input_mode := `OVA
| s ->
error (f_"unknown -i option: %s") s
in
@@ -241,7 +242,16 @@ read the man page virt-v2v(1).
| [filename] -> filename
| _ ->
error (f_"expecting a libvirt XML file name on the command line") in
- Input_libvirtxml.input_libvirtxml verbose filename in
+ Input_libvirtxml.input_libvirtxml verbose filename
+
+ | `OVA ->
+ (* -i ova: Expecting an ova filename (tar file). *)
+ let filename =
+ match args with
+ | [filename] -> filename
+ | _ ->
+ error (f_"expecting an OVA file name on the command line") in
+ Input_ova.input_ova verbose filename in
(* Parse the output mode. *)
let output =
diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml
new file mode 100644
index 0000000..2737718
--- /dev/null
+++ b/v2v/input_ova.ml
@@ -0,0 +1,220 @@
+(* virt-v2v
+ * Copyright (C) 2009-2014 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.
+ *)
+
+open Printf
+
+open Common_gettext.Gettext
+open Common_utils
+
+open Types
+open Utils
+
+class input_ova verbose ova =
+ let tmpdir =
+ let base_dir = (new Guestfs.guestfs ())#get_cachedir () in
+ let t = Mkdtemp.temp_dir ~base_dir "ova." "" in
+ rmdir_on_exit t;
+ t in
+object
+ inherit input verbose
+
+ method as_options = "-i ova " ^ ova
+
+ method source () =
+
+ (* extract ova (tar) file *)
+ let cmd = sprintf "tar -xf %s -C %s" (quote ova) (quote tmpdir) in
+
+ if Sys.command cmd <> 0 then
+ error (f_"error running command: %s") cmd;
+
+ let files = Sys.readdir tmpdir in
+ let mf = ref "" in
+ let ovf = ref "" in
+ (* search for the ovf file *)
+ Array.iter (fun file ->
+ if Filename.check_suffix file ".ovf" then
+ ovf := file
+ else if Filename.check_suffix file ".mf" then
+ mf := file
+ ) files;
+
+ (* verify sha1 from manifest file *)
+ let mf = tmpdir // !mf in
+ let rex = Str.regexp "SHA1(\\(.*\\))= \\(.*?\\)\r\\?$" in
+ let lines = read_whole_file mf in
+ let lines = string_nsplit "\n" lines in
+ List.iter (
+ fun line ->
+ if Str.string_match rex line 0 then
+ let file = Str.matched_group 1 line in
+ let sha1 = Str.matched_group 2 line in
+ let cmd = sprintf "sha1sum %s" (quote (tmpdir // file)) in
+ let out = external_command ~prog cmd in
+ (match out with
+ | [] -> error (f_"no output from sha1sum command, see previous errors")
+ | [line] ->
+ let hash, _ = string_split " " line in
+ if hash <> sha1 then
+ error (f_"Checksum of %s does not match manifest sha1 %s") file sha1;
+ | _::_ -> error (f_"cannot parse output of sha1sum command")
+ );
+ ) lines;
+
+ (* parse the ovf file *)
+ let xml = read_whole_file (tmpdir // !ovf) in
+ let doc = Xml.parse_memory xml in
+ let xpathctx = Xml.xpath_new_context doc in
+ Xml.xpath_register_ns xpathctx "ovf" "http://schemas.dmtf.org/ovf/envelope/1";
+ Xml.xpath_register_ns xpathctx "rasd" "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationS...";
+ Xml.xpath_register_ns xpathctx "vssd" "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettin...";
+
+ let xpath_to_string expr default =
+ let obj = Xml.xpath_eval_expression xpathctx expr in
+ if Xml.xpathobj_nr_nodes obj < 1 then default
+ else (
+ let node = Xml.xpathobj_node doc obj 0 in
+ Xml.node_as_string node
+ )
+ and xpath_to_int expr default =
+ let obj = Xml.xpath_eval_expression xpathctx expr in
+ if Xml.xpathobj_nr_nodes obj < 1 then default
+ else (
+ let node = Xml.xpathobj_node doc obj 0 in
+ let str = Xml.node_as_string node in
+ try int_of_string str
+ with Failure "int_of_string" ->
+ error (f_"expecting XML expression to return an integer (expression: %s)")
+ expr
+ )
+ in
+
+ let disks = ref [] in
+ let removables = ref [] in
+
+ (* resources hard-disk, CD-ROMs and floppy *)
+ let add_resource id =
+ let expr = sprintf "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType/text()=%d]" id in
+ let obj = Xml.xpath_eval_expression xpathctx expr in
+ let nr_nodes = Xml.xpathobj_nr_nodes obj in
+ for i = 0 to nr_nodes-1 do
+ let n = Xml.xpathobj_node doc obj i in
+ Xml.xpathctx_set_current_context xpathctx n;
+ let address = xpath_to_int "rasd:AddressOnParent/text()" 0 in
+ let parent_id = xpath_to_int "rasd:Parent/text()" 0 in
+ (* prob the parent controller *)
+ let expr = sprintf "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:InstanceId/text()=%d]/rasd:ResourceType/text()" parent_id in
+ let controller = xpath_to_int expr 0 in
+ (* 6: iscsi controller, 5: ide. assueming scsi or ide *)
+ let target_dev =
+ match controller with
+ | 6 -> "sd"
+ | 0 | 5 | _ -> "hd" in
+ (*FIXME in floppy should be 'fd'??? *)
+
+ let target_dev = sprintf "%s%c" target_dev (Char.chr(48+address)) in
+
+ (* add disk(17)/removables to its collections *)
+ if id = 17 then (
+ Xml.xpathctx_set_current_context xpathctx n;
+ let file_id = xpath_to_string "rasd:HostResource/text()" "" in
+ let rex = Str.regexp "^ovf:/disk/\\(.*\\)" in
+ if Str.string_match rex file_id 0 then (
+ let file_id = Str.matched_group 1 file_id in
+ let expr = sprintf "/ovf:Envelope/ovf:DiskSection/ovf:Disk[@ovf:diskId='%s']/@ovf:fileRef" file_id in
+ let file_ref = xpath_to_string expr "" in
+ if file_ref == "" then error (f_"Error parsing disk fileRef");
+ let expr = sprintf "/ovf:Envelope/ovf:References/ovf:File[@ovf:id='%s']/@ovf:href" file_ref in
+ let file_name = xpath_to_string expr "" in
+ let disk = { s_qemu_uri=(tmpdir // file_name); s_format=Some "vmdk"; s_target_dev=Some target_dev } in
+ disks := disk :: !disks;
+ ) else
+ error (f_"could not parse disk rasd:HostResource from OVF document");
+ )
+ else (
+ (* 14: Floppy 15: CD 16: CDROM*)
+ let typ =
+ match id with
+ | 14 -> `Floppy
+ | 15 | 16 -> `CDROM
+ | _ -> assert false in
+ let disk = { s_removable_type = typ; s_removable_target_dev = Some target_dev } in
+ removables := disk :: !removables;
+ )
+ done;
+ in
+
+ (* search for vm name *)
+ let name = xpath_to_string "/ovf:Envelope/ovf:VirtualSystem/ovf:Name/text()" "" in
+ if name = "" then
+ error (f_"could not parse ovf:Name from OVF document");
+
+ (* search for memory *)
+ let memory = xpath_to_int "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType/text()=4]/rasd:VirtualQuantity/text()" (1024 * 1024) in
+ let memory = Int64.of_int (memory * 1024 * 1024) in
+
+ (* search for cpu *)
+ let cpu = xpath_to_int "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType/text()=3]/rasd:VirtualQuantity/text()" 1 in
+
+ (* search for floopy *)
+ add_resource 14;
+
+ (* search for cd *)
+ add_resource 15;
+
+ (* search for cdrom *)
+ add_resource 16;
+
+ (* search for hard-disk *)
+ add_resource 17;
+
+ (* serch for networks ResourceType: 10*)
+ let nics = ref [] in
+ let obj = Xml.xpath_eval_expression xpathctx "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType/text()=10]" in
+ let nr_nodes = Xml.xpathobj_nr_nodes obj in
+ for i = 0 to nr_nodes-1 do
+ let n = Xml.xpathobj_node doc obj i in
+ Xml.xpathctx_set_current_context xpathctx n;
+ let vnet = xpath_to_string "rasd:ElementName/text()" (sprintf"eth%d" i) in
+ let nic = {
+ s_mac = None;
+ s_vnet = vnet;
+ s_vnet_orig = vnet;
+ s_vnet_type = Network;
+ } in
+ nics := nic :: !nics
+ done;
+
+ let source = {
+ s_dom_type = "vmware";
+ s_name = name;
+ s_orig_name = name;
+ s_memory = memory;
+ s_vcpu = cpu;
+ s_arch = "x86_64"; (* XXX: no architucture in ovf, this entry will be overritten at os inspection via libguestfs *)
+ s_features = []; (* FIXME: *)
+ s_display = None; (* FIXME: *)
+ s_disks = !disks;
+ s_removables = !removables;
+ s_nics = !nics;
+ } in
+ source
+end
+
+let input_ova = new input_ova
+let () = Modules_list.register_input_module "ova"
diff --git a/v2v/input_ova.mli b/v2v/input_ova.mli
new file mode 100644
index 0000000..d4c347e
--- /dev/null
+++ b/v2v/input_ova.mli
@@ -0,0 +1,22 @@
+(* virt-v2v
+ * Copyright (C) 2009-2014 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.
+ *)
+
+(** [-i ova] source. *)
+
+val input_ova : bool -> string -> Types.input
+(** [input_ova filename] sets up an input from vmware ova file. *)
diff --git a/v2v/test-v2v-i-ova.ovf b/v2v/test-v2v-i-ova.ovf
new file mode 100644
index 0000000..a950645
--- /dev/null
+++ b/v2v/test-v2v-i-ova.ovf
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Envelope vmw:buildId="build-1623387" xmlns="http://schemas.dmtf.org/ovf/envelope/1" xmlns:cim="http://schemas.dmtf.org/wbem/wscim/1/common" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationS..." xmlns:vmw="http://www.vmware.com/schema/ovf" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettin..." xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <References>
+ <File ovf:href="test-ova.vmdk" ovf:id="file1" ovf:size="349405696" />
+ </References>
+ <DiskSection>
+ <Info>Virtual disk information</Info>
+ <Disk ovf:capacity="32" ovf:capacityAllocationUnits="byte * 2^30" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="1008926720" />
+ </DiskSection>
+ <NetworkSection>
+ <Info>The list of logical networks</Info>
+ <Network ovf:name="VM Network">
+ <Description>The VM Network network</Description>
+ </Network>
+ </NetworkSection>
+ <VirtualSystem ovf:id="TestOva">
+ <Info>A virtual machine</Info>
+ <Name>TestOva</Name>
+ <OperatingSystemSection ovf:id="74" vmw:osType="windows7_64Guest">
+ <Info>The kind of installed guest operating system</Info>
+ </OperatingSystemSection>
+ <VirtualHardwareSection>
+ <Info>Virtual hardware requirements</Info>
+ <System>
+ <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
+ <vssd:InstanceID>0</vssd:InstanceID>
+ <vssd:VirtualSystemIdentifier>TestOva</vssd:VirtualSystemIdentifier>
+ <vssd:VirtualSystemType>vmx-08</vssd:VirtualSystemType>
+ </System>
+ <Item>
+ <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>
+ <rasd:Description>Number of Virtual CPUs</rasd:Description>
+ <rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>
+ <rasd:InstanceID>1</rasd:InstanceID>
+ <rasd:ResourceType>3</rasd:ResourceType>
+ <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
+ </Item>
+ <Item>
+ <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>
+ <rasd:Description>Memory Size</rasd:Description>
+ <rasd:ElementName>2048MB of memory</rasd:ElementName>
+ <rasd:InstanceID>2</rasd:InstanceID>
+ <rasd:ResourceType>4</rasd:ResourceType>
+ <rasd:VirtualQuantity>2048</rasd:VirtualQuantity>
+ </Item>
+ <Item>
+ <rasd:Address>0</rasd:Address>
+ <rasd:Description>SCSI Controller</rasd:Description>
+ <rasd:ElementName>SCSI Controller 0</rasd:ElementName>
+ <rasd:InstanceID>3</rasd:InstanceID>
+ <rasd:ResourceSubType>lsilogicsas</rasd:ResourceSubType>
+ <rasd:ResourceType>6</rasd:ResourceType>
+ <vmw:Config ovf:required="false" vmw:key="slotInfo.pciSlotNumber" vmw:value="160" />
+ </Item>
+ <Item>
+ <rasd:Address>1</rasd:Address>
+ <rasd:Description>IDE Controller</rasd:Description>
+ <rasd:ElementName>VirtualIDEController 1</rasd:ElementName>
+ <rasd:InstanceID>4</rasd:InstanceID>
+ <rasd:ResourceType>5</rasd:ResourceType>
+ </Item>
+ <Item>
+ <rasd:Address>0</rasd:Address>
+ <rasd:Description>IDE Controller</rasd:Description>
+ <rasd:ElementName>VirtualIDEController 0</rasd:ElementName>
+ <rasd:InstanceID>5</rasd:InstanceID>
+ <rasd:ResourceType>5</rasd:ResourceType>
+ </Item>
+ <Item ovf:required="false">
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:ElementName>VirtualVideoCard</rasd:ElementName>
+ <rasd:InstanceID>6</rasd:InstanceID>
+ <rasd:ResourceType>24</rasd:ResourceType>
+ <vmw:Config ovf:required="false" vmw:key="enable3DSupport" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="enableMPTSupport" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="use3dRenderer" vmw:value="automatic" />
+ <vmw:Config ovf:required="false" vmw:key="useAutoDetect" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="videoRamSizeInKB" vmw:value="8192" />
+ </Item>
+ <Item ovf:required="false">
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:ElementName>VirtualVMCIDevice</rasd:ElementName>
+ <rasd:InstanceID>7</rasd:InstanceID>
+ <rasd:ResourceSubType>vmware.vmci</rasd:ResourceSubType>
+ <rasd:ResourceType>1</rasd:ResourceType>
+ <vmw:Config ovf:required="false" vmw:key="allowUnrestrictedCommunication" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="slotInfo.pciSlotNumber" vmw:value="33" />
+ </Item>
+ <Item ovf:required="false">
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:ElementName>CD-ROM 1</rasd:ElementName>
+ <rasd:InstanceID>8</rasd:InstanceID>
+ <rasd:Parent>4</rasd:Parent>
+ <rasd:ResourceSubType>vmware.cdrom.iso</rasd:ResourceSubType>
+ <rasd:ResourceType>15</rasd:ResourceType>
+ </Item>
+ <Item>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:ElementName>Hard Disk 1</rasd:ElementName>
+ <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>
+ <rasd:InstanceID>9</rasd:InstanceID>
+ <rasd:Parent>3</rasd:Parent>
+ <rasd:ResourceType>17</rasd:ResourceType>
+ <vmw:Config ovf:required="false" vmw:key="backing.writeThrough" vmw:value="false" />
+ </Item>
+ <Item ovf:required="false">
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:Description>Floppy Drive</rasd:Description>
+ <rasd:ElementName>Floppy 1</rasd:ElementName>
+ <rasd:InstanceID>10</rasd:InstanceID>
+ <rasd:ResourceSubType>vmware.floppy.remotedevice</rasd:ResourceSubType>
+ <rasd:ResourceType>14</rasd:ResourceType>
+ </Item>
+ <Item>
+ <rasd:AddressOnParent>7</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
+ <rasd:Connection>VM Network</rasd:Connection>
+ <rasd:Description>E1000 ethernet adapter on "VM Network"</rasd:Description>
+ <rasd:ElementName>Ethernet 1</rasd:ElementName>
+ <rasd:InstanceID>11</rasd:InstanceID>
+ <rasd:ResourceSubType>E1000</rasd:ResourceSubType>
+ <rasd:ResourceType>10</rasd:ResourceType>
+ <vmw:Config ovf:required="false" vmw:key="slotInfo.pciSlotNumber" vmw:value="32" />
+ <vmw:Config ovf:required="false" vmw:key="wakeOnLanEnabled" vmw:value="true" />
+ </Item>
+ <vmw:Config ovf:required="false" vmw:key="cpuHotAddEnabled" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="cpuHotRemoveEnabled" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="firmware" vmw:value="bios" />
+ <vmw:Config ovf:required="false" vmw:key="virtualICH7MPresent" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="virtualSMCPresent" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="memoryHotAddEnabled" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="nestedHVEnabled" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="powerOpInfo.powerOffType" vmw:value="soft" />
+ <vmw:Config ovf:required="false" vmw:key="powerOpInfo.resetType" vmw:value="soft" />
+ <vmw:Config ovf:required="false" vmw:key="powerOpInfo.standbyAction" vmw:value="checkpoint" />
+ <vmw:Config ovf:required="false" vmw:key="powerOpInfo.suspendType" vmw:value="hard" />
+ <vmw:Config ovf:required="false" vmw:key="tools.afterPowerOn" vmw:value="true" />
+ <vmw:Config ovf:required="false" vmw:key="tools.afterResume" vmw:value="true" />
+ <vmw:Config ovf:required="false" vmw:key="tools.beforeGuestShutdown" vmw:value="true" />
+ <vmw:Config ovf:required="false" vmw:key="tools.beforeGuestStandby" vmw:value="true" />
+ <vmw:Config ovf:required="false" vmw:key="tools.syncTimeWithHost" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="tools.toolsUpgradePolicy" vmw:value="manual" />
+ </VirtualHardwareSection>
+ </VirtualSystem>
+</Envelope>
diff --git a/v2v/test-v2v-i-ova.sh b/v2v/test-v2v-i-ova.sh
new file mode 100755
index 0000000..018d03b
--- /dev/null
+++ b/v2v/test-v2v-i-ova.sh
@@ -0,0 +1,73 @@
+#!/bin/bash -
+# libguestfs virt-v2v test script
+# Copyright (C) 2014 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.
+
+# Test -i ova option.
+
+unset CDPATH
+export LANG=C
+set -e
+
+if [ -n "$SKIP_TEST_V2V_I_OVA_SH" ]; then
+ echo "$0: test skipped because environment variable is set"
+ exit 77
+fi
+
+if [ "$(../fish/guestfish get-backend)" = "uml" ]; then
+ echo "$0: test skipped because UML backend does not support network"
+ exit 77
+fi
+
+f=../tests/guests/windows.img
+if ! test -f $f || ! test -s $f; then
+ echo "$0: test skipped because phony Windows image was not created"
+ exit 77
+fi
+
+d=test-v2v-i-ova.d
+rm -rf $d
+mkdir $d
+
+vmdk=test-ova.vmdk
+ovf=test-v2v-i-ova.ovf
+mf=test-ova.mf
+ova=test-ova.ova
+xml=TestOva.xml
+raw=TestOva-sda
+
+qemu-img convert $f -O vmdk $d/$vmdk
+cp $ovf $d/$ovf
+sha1=`sha1sum $d/$ovf | awk '{print $1}'`
+echo "SHA1($ovf)= $sha1" > $d/$mf
+sha1=`sha1sum $d/$vmdk | awk '{print $1}'`
+echo "SHA1($vmdk)= $sha1" >> $d/$mf
+
+pushd .
+cd $d
+tar -cf $ova $ovf $mf $vmdk
+rm -rf $ovf $mf $vmdk
+popd
+
+$VG ./virt-v2v --debug-gc \
+ -i ova $d/$ova \
+ -o local -of raw -os $d
+
+# Test the libvirt XML metadata and a disk was created.
+test -f $d/$raw
+test -f $d/$xml
+
+rm -rf $d
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index cb7fec8..3c07841 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -32,8 +32,8 @@ libguestfs E<ge> 1.28.
┌────────────┐
-i disk ───────────┐ │ │ ┌───────▶ -o local
- │ │ virt-v2v │ │
- └──▶ │ conversion │ ──┘
+ └──▶ │ virt-v2v │ │
+ -i ova ──────────────▶ │ conversion │ ──┘
-i libvirt ───────────▶ │ server │ ────────▶ -o libvirt
(default) ┌──▶ │ │ ──┐ (default)
│ │ │ ─┐└──────▶ -o glance
@@ -52,6 +52,8 @@ option selects the precise libvirt source.
I<-i disk> is used for reading from local disk images (mainly for
testing).
+I<-i ova> is used for reading from libvirt ova source file.
+
I<-i libvirtxml> is used to read from libvirt XML files. This is the
method used by L<virt-p2v(1)> behind the scenes.
@@ -158,6 +160,14 @@ usually adequate but you can get finer control (eg. of memory and
vCPUs) by using I<-i libvirtxml> instead. Only guests that use a single
disk can be imported this way.
+=item B<-i ova>
+
+Set the input method to I<ova>.
+
+In this mode you can read a vmware ova file (tar format).
+virt-v2v tries to read the ova manifest file and check the ova files
+for validity (checksum) as well as analyzing the ovf file.
+
=item B<-i libvirt>
Set the input method to I<libvirt>. This is the default.
--
1.9.3
10 years, 1 month
[PATCH] sysprep: user-account: remove the correct home
by Pino Toscano
Query using augeas for the home directory of an user, instead of
hardcoding /home/<username>.
---
sysprep/sysprep_operation_user_account.ml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/sysprep/sysprep_operation_user_account.ml b/sysprep/sysprep_operation_user_account.ml
index 3d88ffc..dc194f4 100644
--- a/sysprep/sysprep_operation_user_account.ml
+++ b/sysprep/sysprep_operation_user_account.ml
@@ -84,6 +84,8 @@ let user_account_perform ~verbose ~quiet g root side_effects =
String.sub userpath (i+1) (String.length userpath -i-1) in
if uid >= uid_min && uid <= uid_max
&& check_remove_user username then (
+ (* Get the home before removing the passwd entry. *)
+ let home_dir = g#aug_get (userpath ^ "/home") in
g#aug_rm userpath;
(* XXX Augeas doesn't yet have a lens for /etc/shadow, so the
* next line currently does nothing, but should start to
@@ -91,7 +93,7 @@ let user_account_perform ~verbose ~quiet g root side_effects =
*)
g#aug_rm (sprintf "/files/etc/shadow/%s" username);
g#aug_rm (sprintf "/files/etc/group/%s" username);
- g#rm_rf ("/home/" ^ username)
+ g#rm_rf home_dir
)
) users;
g#aug_save ();
--
1.9.3
10 years, 1 month
[PATCH] sysprep: user-account: select which users to remove or keep
by Pino Toscano
Enhance the user-account sysprep operation, so it is possible to select
which user accounts should be removed only (instead of all), or which to
eventually keep.
---
sysprep/sysprep_operation_user_account.ml | 73 ++++++++++++++++++++++++++++---
1 file changed, 67 insertions(+), 6 deletions(-)
diff --git a/sysprep/sysprep_operation_user_account.ml b/sysprep/sysprep_operation_user_account.ml
index fa93769..3d88ffc 100644
--- a/sysprep/sysprep_operation_user_account.ml
+++ b/sysprep/sysprep_operation_user_account.ml
@@ -1,5 +1,6 @@
(* virt-sysprep
* Copyright (C) 2012 FUJITSU LIMITED
+ * Copyright (C) 2014 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
@@ -25,6 +26,45 @@ open Common_gettext.Gettext
module G = Guestfs
+module StringSet = Set.Make (String)
+
+let users_included = ref StringSet.empty
+let users_excluded = ref StringSet.empty
+let set_users users =
+ let users = string_nsplit "," users in
+ List.iter (
+ fun user ->
+ let op =
+ if string_prefix user "-" then
+ `Exclude (String.sub user 1 (String.length user - 1))
+ else
+ `Include user in
+ match op with
+ | `Include "" | `Exclude "" ->
+ eprintf (f_"%s: --user-accounts: empty user name\n")
+ prog;
+ exit 1
+ | `Include n ->
+ users_included := StringSet.add n !users_included;
+ users_excluded := StringSet.remove n !users_excluded
+ | `Exclude n ->
+ users_included := StringSet.remove n !users_included;
+ users_excluded := StringSet.add n !users_excluded
+ ) users
+
+let check_remove_user user =
+ (* If an user is explicitly excluded, keep it. *)
+ if StringSet.mem user !users_excluded then
+ false
+ (* If the list of included users is empty (thus no users were explicitly
+ * included), or an user is explicitly included, remove it. *)
+ else if StringSet.is_empty !users_included
+ or StringSet.mem user !users_included then
+ true
+ (* Any other case, not a reason to remove it. *)
+ else
+ false
+
let user_account_perform ~verbose ~quiet g root side_effects =
let typ = g#inspect_get_type root in
if typ <> "windows" then (
@@ -39,11 +79,12 @@ let user_account_perform ~verbose ~quiet g root side_effects =
let uid = userpath ^ "/uid" in
let uid = g#aug_get uid in
let uid = int_of_string uid in
- if uid >= uid_min && uid <= uid_max then (
+ let username =
+ let i = String.rindex userpath '/' in
+ String.sub userpath (i+1) (String.length userpath -i-1) in
+ if uid >= uid_min && uid <= uid_max
+ && check_remove_user username then (
g#aug_rm userpath;
- let username =
- let i = String.rindex userpath '/' in
- String.sub userpath (i+1) (String.length userpath -i-1) in
(* XXX Augeas doesn't yet have a lens for /etc/shadow, so the
* next line currently does nothing, but should start to
* work in a future version.
@@ -62,12 +103,32 @@ let op = {
enabled_by_default = false;
heading = s_"Remove the user accounts in the guest";
pod_description = Some (s_"\
-Remove all the user accounts and their home directories.
-The \"root\" account is not removed.");
+By default remove all the user accounts and their home directories.
+The \"root\" account is not removed.
+
+See the I<--user-accounts> parameter for a way to specify
+how to remove only some users, or to not remove some others.");
pod_notes = Some (s_"\
Currently this does not remove the user accounts from
C</etc/shadow>. This is because there is no lens for
the shadow password file in Augeas.");
+ extra_args = [
+ { extra_argspec = "--user-accounts", Arg.String set_users, s_"users" ^ " " ^ s_"Users to remove/keep";
+ extra_pod_argval = Some "USERS";
+ extra_pod_description = s_"\
+The user accounts to be removed (or not) from the guest.
+The value of this option is a list of user names separated by comma,
+where specifying an user means it is going to be removed,
+while prepending C<-> in front of it name means it is not removed.
+For example:
+
+ --user-accounts bob,eve
+
+would only remove the user accounts C<bob> and C<eve>.
+
+This option can be specified multiple times."
+ };
+ ];
perform_on_filesystems = Some user_account_perform;
}
--
1.9.3
10 years, 1 month
[PATCH] appliance: exclude a lvm2 rule on Ubuntu (FHBZ#1111662).
by Pino Toscano
On Ubuntu, exclude the Ubuntu-only 85-lvm2.rules since it causes the
automatic activation of volume groups on addition or change. This
interferes with libguestfs, as vgs which are disables suddently get
enabled.
---
appliance/excludefiles.in | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/appliance/excludefiles.in b/appliance/excludefiles.in
index 70762ae..9a48db7 100644
--- a/appliance/excludefiles.in
+++ b/appliance/excludefiles.in
@@ -45,3 +45,10 @@ dnl For Debian:
-/usr/share/doc-base/*
-/usr/share/bug/*
-/etc/initramfs-tools/*
+
+dnl For Ubuntu:
+ifelse(UBUNTU,1,
+dnl This lvm2 rule automatically re-enables vgs when they are added
+dnl or changed
+-/lib/udev/rules.d/85-lvm2.rules
+)
--
1.9.3
10 years, 1 month
[PATCH] fish: edit: write to the real file name
by Pino Toscano
When saving, resolve the path of the file being edited and use that as
real target to write to. Otherwise, if the file name is a symlink then
it will be replaced by a regular file with the new content, leaving the
old file untouched.
Extend test-edit.sh to check for this situation.
---
fish/file-edit.c | 15 ++++++++++++++-
fish/test-edit.sh | 12 +++++++++++-
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/fish/file-edit.c b/fish/file-edit.c
index e6d25f5..dd2272b 100644
--- a/fish/file-edit.c
+++ b/fish/file-edit.c
@@ -216,11 +216,24 @@ do_download (guestfs_h *g, const char *filename, char **tempfile)
}
static int
-do_upload (guestfs_h *g, const char *filename, const char *tempfile,
+do_upload (guestfs_h *g, const char *fn, const char *tempfile,
const char *backup_extension)
{
+ CLEANUP_FREE char *filename = NULL;
CLEANUP_FREE char *newname = NULL;
+ /* Resolve the file name and write to the actual target, since
+ * that is the file it was opened earlier; otherwise, if it is
+ * a symlink it will be overwritten by a regular file with the
+ * new content.
+ *
+ * Theoretically realpath should work, but just check again
+ * to be safe.
+ */
+ filename = guestfs_realpath (g, fn);
+ if (filename == NULL)
+ return -1;
+
/* Upload to a new file in the same directory, so if it fails we
* don't end up with a partially written file. Give the new file
* a completely random name so we have only a tiny chance of
diff --git a/fish/test-edit.sh b/fish/test-edit.sh
index 34bfc9d..9d7ab9d 100755
--- a/fish/test-edit.sh
+++ b/fish/test-edit.sh
@@ -43,6 +43,12 @@ cat /file.txt
stat /file.txt | grep mode:
stat /file.txt | grep uid:
stat /file.txt | grep gid:
+echo ==========
+write /file-2.txt "symlink test\n"
+ln-s /file-2.txt /symlink-2.txt
+edit /symlink-2.txt
+is-symlink /symlink-2.txt
+cat /symlink-2.txt
EOF
)
@@ -51,7 +57,11 @@ second line of text
mode: 33152
uid: 10
-gid: 11" ]; then
+gid: 11
+==========
+true
+symlink test
+second line of text" ]; then
echo "$0: error: output of guestfish after edit command did not match expected output"
echo "$output"
exit 1
--
1.9.3
10 years, 1 month
[PATCH 1/2] fish: edit: factor out download and reupload phases
by Pino Toscano
Share some code between edit_file_editor and edit_file_perl; mostly code
motion, with no actual behaviour change.
---
fish/file-edit.c | 143 +++++++++++++++++++++++--------------------------------
1 file changed, 60 insertions(+), 83 deletions(-)
diff --git a/fish/file-edit.c b/fish/file-edit.c
index ff36ac2..74cb89b 100644
--- a/fish/file-edit.c
+++ b/fish/file-edit.c
@@ -35,6 +35,9 @@
#include "guestfs-internal-frontend.h"
+static int do_download (guestfs_h *g, const char *filename, char **tempfile);
+static int do_upload (guestfs_h *g, const char *filename, const char *tempfile,
+ const char *backup_extension);
static char *generate_random_name (const char *filename);
static char *generate_backup_name (const char *filename,
const char *backup_extension);
@@ -43,38 +46,15 @@ int
edit_file_editor (guestfs_h *g, const char *filename, const char *editor,
const char *backup_extension, int verbose)
{
- CLEANUP_FREE char *tmpdir = guestfs_get_tmpdir (g);
CLEANUP_UNLINK_FREE char *tmpfilename = NULL;
- char buf[256];
- CLEANUP_FREE char *newname = NULL;
CLEANUP_FREE char *cmd = NULL;
struct stat oldstat, newstat;
- int r, fd;
+ int r;
struct utimbuf times;
/* Download the file and write it to a temporary. */
- if (asprintf (&tmpfilename, "%s/libguestfsXXXXXX", tmpdir) == -1) {
- perror ("asprintf");
- return -1;
- }
-
- fd = mkstemp (tmpfilename);
- if (fd == -1) {
- perror ("mkstemp");
- return -1;
- }
-
- snprintf (buf, sizeof buf, "/dev/fd/%d", fd);
-
- if (guestfs_download (g, filename, buf) == -1) {
- close (fd);
+ if (do_download (g, filename, &tmpfilename) == -1)
return -1;
- }
-
- if (close (fd) == -1) {
- perror (tmpfilename);
- return -1;
- }
/* Set the time back a few seconds on the original file. This is so
* that if the user is very fast at editing, or if EDITOR is an
@@ -125,38 +105,7 @@ edit_file_editor (guestfs_h *g, const char *filename, const char *editor,
oldstat.st_size == newstat.st_size)
return 1;
- /* Upload to a new file in the same directory, so if it fails we
- * don't end up with a partially written file. Give the new file
- * a completely random name so we have only a tiny chance of
- * overwriting some existing file.
- */
- newname = generate_random_name (filename);
- if (!newname)
- return -1;
-
- /* Write new content. */
- if (guestfs_upload (g, tmpfilename, newname) == -1)
- return -1;
-
- /* Set the permissions, UID, GID and SELinux context of the new
- * file to match the old file (RHBZ#788641).
- */
- if (guestfs_copy_attributes (g, filename, newname,
- GUESTFS_COPY_ATTRIBUTES_ALL, 1, -1) == -1)
- return -1;
-
- /* Backup or overwrite the file. */
- if (backup_extension) {
- CLEANUP_FREE char *backupname = NULL;
-
- backupname = generate_backup_name (filename, backup_extension);
- if (backupname == NULL)
- return -1;
-
- if (guestfs_mv (g, filename, backupname) == -1)
- return -1;
- }
- if (guestfs_mv (g, newname, filename) == -1)
+ if (do_upload (g, filename, tmpfilename, backup_extension) == -1)
return -1;
return 0;
@@ -166,37 +115,14 @@ int
edit_file_perl (guestfs_h *g, const char *filename, const char *perl_expr,
const char *backup_extension, int verbose)
{
- CLEANUP_FREE char *tmpdir = guestfs_get_tmpdir (g);
CLEANUP_UNLINK_FREE char *tmpfilename = NULL;
- char buf[256];
- CLEANUP_FREE char *newname = NULL;
CLEANUP_FREE char *cmd = NULL;
CLEANUP_FREE char *outfile = NULL;
- int r, fd;
+ int r;
/* Download the file and write it to a temporary. */
- if (asprintf (&tmpfilename, "%s/libguestfsXXXXXX", tmpdir) == -1) {
- perror ("asprintf");
+ if (do_download (g, filename, &tmpfilename) == -1)
return -1;
- }
-
- fd = mkstemp (tmpfilename);
- if (fd == -1) {
- perror ("mkstemp");
- return -1;
- }
-
- snprintf (buf, sizeof buf, "/dev/fd/%d", fd);
-
- if (guestfs_download (g, filename, buf) == -1) {
- close (fd);
- return -1;
- }
-
- if (close (fd) == -1) {
- perror (tmpfilename);
- return -1;
- }
if (asprintf (&outfile, "%s.out", tmpfilename) == -1) {
perror ("asprintf");
@@ -238,6 +164,57 @@ edit_file_perl (guestfs_h *g, const char *filename, const char *perl_expr,
return -1;
}
+ if (do_upload (g, filename, tmpfilename, backup_extension) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int
+do_download (guestfs_h *g, const char *filename, char **tempfile)
+{
+ CLEANUP_FREE char *tmpdir = guestfs_get_tmpdir (g);
+ CLEANUP_UNLINK_FREE char *tmpfilename = NULL;
+ char buf[256];
+ int fd;
+
+ /* Download the file and write it to a temporary. */
+ if (asprintf (&tmpfilename, "%s/libguestfsXXXXXX", tmpdir) == -1) {
+ perror ("asprintf");
+ return -1;
+ }
+
+ fd = mkstemp (tmpfilename);
+ if (fd == -1) {
+ perror ("mkstemp");
+ return -1;
+ }
+
+ snprintf (buf, sizeof buf, "/dev/fd/%d", fd);
+
+ if (guestfs_download (g, filename, buf) == -1) {
+ close (fd);
+ return -1;
+ }
+
+ if (close (fd) == -1) {
+ perror (tmpfilename);
+ return -1;
+ }
+
+ /* Hand over the temporary file. */
+ *tempfile = tmpfilename;
+ tmpfilename = NULL;
+
+ return 0;
+}
+
+static int
+do_upload (guestfs_h *g, const char *filename, const char *tempfile,
+ const char *backup_extension)
+{
+ CLEANUP_FREE char *newname = NULL;
+
/* Upload to a new file in the same directory, so if it fails we
* don't end up with a partially written file. Give the new file
* a completely random name so we have only a tiny chance of
@@ -248,7 +225,7 @@ edit_file_perl (guestfs_h *g, const char *filename, const char *perl_expr,
return -1;
/* Write new content. */
- if (guestfs_upload (g, tmpfilename, newname) == -1)
+ if (guestfs_upload (g, tempfile, newname) == -1)
return -1;
/* Set the permissions, UID, GID and SELinux context of the new
--
1.9.3
10 years, 1 month