[PATCHv2] New API: part_expand_gpt.
by Maxim Perevedentsev
This action moves second(backup) GPT header to the end of the disk.
It is usable in in-place image expanding, since free space after
second GPT header is unusable. To use additional space, we have
to move second header. This is what sgdisk -e does.
However, sgdisk -e may perform additional actions if the partition
table has unexpected params (e.g. if we call sgdisk -e /dev/sda1,
it may fix partition table thus destroying the filesystem).
To prevent such cases, we do a dry-run at first and fail if
additional actions are scheduled.
---
daemon/parted.c | 34 ++++++++++++++++++++
generator/actions.ml | 14 +++++++++
src/MAX_PROC_NR | 2 +-
tests/daemon/Makefile.am | 3 +-
tests/daemon/test-expand-gpt.pl | 69 +++++++++++++++++++++++++++++++++++++++++
5 files changed, 120 insertions(+), 2 deletions(-)
create mode 100755 tests/daemon/test-expand-gpt.pl
diff --git a/daemon/parted.c b/daemon/parted.c
index 22cd92b..00ae424 100644
--- a/daemon/parted.c
+++ b/daemon/parted.c
@@ -1003,3 +1003,37 @@ do_part_set_disk_guid_random (const char *device)
return 0;
}
+
+int
+do_part_expand_gpt(const char *device)
+{
+ CLEANUP_FREE char *err = NULL;
+
+ /* If something is broken, sgdisk may try to correct it.
+ * (e.g. recreate partition table and so on).
+ * We do not want such behavior, so dry-run at first.*/
+ int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
+ str_sgdisk, "--pretend", "-e", device, NULL);
+
+ if (r == -1) {
+ reply_with_error ("%s --pretend -e %s: %s", str_sgdisk, device, err);
+ return -1;
+ }
+ if (err && strlen(err) != 0) {
+ /* Unexpected actions. */
+ reply_with_error ("%s --pretend -e %s: %s", str_sgdisk, device, err);
+ return -1;
+ }
+ free(err);
+
+ /* Now we can do a real run. */
+ r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
+ str_sgdisk, "-e", device, NULL);
+
+ if (r == -1) {
+ reply_with_error ("%s -e %s: %s", str_sgdisk, device, err);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index d345175..75d3fc5 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12845,6 +12845,20 @@ Set the disk identifier (GUID) of a GPT-partitioned C<device> to
a randomly generated value.
Return an error if the partition table of C<device> isn't GPT." };
+ { defaults with
+ name = "part_expand_gpt"; added = (1, 33, 2);
+ style = RErr, [Device "device"], [];
+ proc_nr = Some 462;
+ optional = Some "gdisk";
+ shortdesc = "move backup GPT header to the end of the disk";
+ longdesc = "\
+Move backup GPT data structures to the end of the disk.
+This is useful in case of in-place image expand
+since disk space after backup GPT header is not usable.
+This is equivalent to C<sgdisk -e>.
+
+See also L<sgdisk(8)>." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 408b885..bf7aeeb 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-461
+462
diff --git a/tests/daemon/Makefile.am b/tests/daemon/Makefile.am
index bb380c5..329b00c 100644
--- a/tests/daemon/Makefile.am
+++ b/tests/daemon/Makefile.am
@@ -25,7 +25,8 @@ check_DATA = captive-daemon.pm
TESTS = \
test-daemon-start.pl \
- test-btrfs.pl
+ test-btrfs.pl \
+ test-expand-gpt.pl
TESTS_ENVIRONMENT = $(top_builddir)/run --test $(VG)
diff --git a/tests/daemon/test-expand-gpt.pl b/tests/daemon/test-expand-gpt.pl
new file mode 100755
index 0000000..637b90e
--- /dev/null
+++ b/tests/daemon/test-expand-gpt.pl
@@ -0,0 +1,69 @@
+#!/usr/bin/env perl
+# Copyright (C) 2015 Maxim Perevedentsev mperevedentsev(a)virtuozzo.com
+#
+# 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.
+
+use strict;
+use warnings;
+
+use Sys::Guestfs;
+
+sub tests {
+ my $g = Sys::Guestfs->new ();
+
+ foreach ("gpt", "mbr") {
+ $g->disk_create ("disk_$_.img", "qcow2", 50 * 1024 * 1024);
+ $g->add_drive ("disk_$_.img");
+ }
+
+ $g->launch ();
+
+ $g->part_disk ("/dev/sda", "gpt");
+ $g->part_disk ("/dev/sdb", "mbr");
+
+ $g->close ();
+
+ die if system ("qemu-img resize disk_gpt.img 100M &>/dev/null");
+
+ $g = Sys::Guestfs->new ();
+
+ foreach ("gpt", "mbr") {
+ $g->add_drive ("disk_$_.img");
+ }
+
+ $g->launch ();
+ die if $g->part_expand_gpt ("/dev/sda");
+
+ my $output = $g->debug ("sh", ["sgdisk", "-p", "/dev/sda"]);
+ die if $output eq "";
+ $output =~ s/\n/ /g;
+ $output =~ s/.*last usable sector is (\d+).*/$1/g;
+
+ my $end_sectors = 100 * 1024 * 2 - $output;
+ die unless $end_sectors <= 34;
+
+ # Negative tests.
+ eval { $g->part_expand_gpt ("/dev/sdb") };
+ die unless $@;
+ eval { $g->part_expand_gpt ("/dev/sda1") };
+ die unless $@;
+}
+
+eval { tests() };
+system ("rm -f disk_*.img");
+if ($@) {
+ die;
+}
+exit 0
--
1.8.3.1
8 years, 10 months
[PATCH] convert_windows: uninstall Parallels Tools on first boot
by Roman Kagan
If present, Parallels Tools may stand in the way of proper running the
windows guests in non-Parallels hypervisors, so we're better off
uninstalling them on the first boot into the new environment.
With this patch, the uninstall records for Parallels Tools are looked up
in the registry and, if found, corresponding firstboot actions are
registered, taking special care that those actions are run fully
unattended.
Signed-off-by: Roman Kagan <rkagan(a)virtuozzo.com>
---
v2v/convert_windows.ml | 73 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 72 insertions(+), 1 deletion(-)
diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml
index a08555f..3ab58c2 100644
--- a/v2v/convert_windows.ml
+++ b/v2v/convert_windows.ml
@@ -163,12 +163,66 @@ let convert ~keep_serial_console (g : G.guestfs) inspect source =
Not_found -> None
) in
+ (* Locate and retrieve all uninstallation commands for Parallels Tools *)
+ let prltools_uninsts =
+ let uninsts = ref [] in
+
+ Windows.with_hive g software_hive_filename ~write:false
+ (fun root ->
+ try
+ let path = ["Microsoft"; "Windows"; "CurrentVersion"; "Uninstall"] in
+ let node =
+ match Windows.get_node g root path with
+ | None -> raise Not_found
+ | Some node -> node in
+ let uninstnodes = g#hivex_node_children node in
+
+ Array.iter (
+ fun { G.hivex_node_h = uninstnode } ->
+ try
+ let valueh = g#hivex_node_get_value uninstnode "DisplayName" in
+ if valueh = 0L then
+ raise Not_found;
+
+ let dispname = g#hivex_value_utf8 valueh in
+ if not (Str.string_match (Str.regexp ".*Parallels Tools.*")
+ dispname 0) then
+ raise Not_found;
+
+ let uninstval = "UninstallString" in
+ let valueh = g#hivex_node_get_value uninstnode uninstval in
+ if valueh = 0L then (
+ let name = g#hivex_node_name uninstnode in
+ warning (f_"cannot uninstall Parallels Tools: registry key 'HKLM\\SOFTWARE\\%s\\%s' with DisplayName '%s' doesn't contain value '%s'")
+ (String.concat "\\" path) name dispname uninstval;
+ raise Not_found
+ );
+
+ let uninst = (g#hivex_value_utf8 valueh) ^
+ " /quiet /norestart /l*v+ \"%~dpn0.log\"" ^
+ " REBOOT=ReallySuppress REMOVE=ALL" ^
+ (* without these custom Parallels-specific MSI properties the
+ * uninstaller still shows a no-way-out reboot dialog *)
+ " PREVENT_REBOOT=Yes LAUNCHED_BY_SETUP_EXE=Yes" in
+
+ uninsts := uninst :: !uninsts
+ with
+ Not_found -> ()
+ ) uninstnodes
+ with
+ Not_found -> ()
+ );
+
+ !uninsts
+ in
+
(*----------------------------------------------------------------------*)
(* Perform the conversion of the Windows guest. *)
let rec configure_firstboot () =
configure_rhev_apt ();
- unconfigure_xenpv ()
+ unconfigure_xenpv ();
+ unconfigure_prltools ()
and configure_rhev_apt () =
(* Configure RHEV-APT (the RHEV guest agent). However if it doesn't
@@ -203,6 +257,23 @@ echo uninstalling Xen PV driver
" uninst in
Firstboot.add_firstboot_script g inspect.i_root
"uninstall Xen PV" fb_script
+
+ and unconfigure_prltools () =
+ List.iter (
+ fun uninst ->
+ let fb_script = "\
+@echo off
+
+echo uninstalling Parallels guest tools
+" ^ uninst ^
+(* ERROR_SUCCESS_REBOOT_REQUIRED == 3010 is OK too *)
+"
+if errorlevel 3010 exit /b 0
+" in
+
+ Firstboot.add_firstboot_script g inspect.i_root
+ "uninstall Parallels tools" fb_script
+ ) prltools_uninsts
in
let rec update_system_hive root =
--
2.5.0
8 years, 10 months
[PATCH libguestfs v3] lib: Handle slow USB devices more gracefully.
by Richard W.M. Jones
Libvirt has a fixed 15 second timeout for qemu to exit. If qemu is
writing to a slow USB key, it can hang (in D state) for much longer
than this - many minutes usually.
The solution is to check specifically for the libvirt EBUSY error when
this happens, and retry the virDomainDestroyFlags operation
(indefinitely).
See also the description here:
https://www.redhat.com/archives/libvir-list/2016-January/msg00767.html
Similar to the following OpenStack Nova commit:
http://git.openstack.org/cgit/openstack/nova/commit/?id=3907867
Thanks: Kashyap Chamarthy and Daniel Berrange.
---
src/launch-libvirt.c | 45 +++++++++++++++++++++++++++++++++++----------
1 file changed, 35 insertions(+), 10 deletions(-)
diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c
index 8215e02..90b6c49 100644
--- a/src/launch-libvirt.c
+++ b/src/launch-libvirt.c
@@ -25,6 +25,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <grp.h>
+#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
@@ -2015,6 +2016,8 @@ ignore_errors (void *ignore, virErrorPtr ignore2)
/* empty */
}
+static int destroy_domain (guestfs_h *g, virDomainPtr dom, int check_for_errors);
+
static int
shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors)
{
@@ -2023,23 +2026,14 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors)
virDomainPtr dom = data->dom;
size_t i;
int ret = 0;
- int flags;
/* Note that we can be called back very early in launch (specifically
* from launch_libvirt itself), when conn and dom might be NULL.
*/
-
if (dom != NULL) {
- flags = check_for_errors ? VIR_DOMAIN_DESTROY_GRACEFUL : 0;
- debug (g, "calling virDomainDestroy \"%s\" flags=%s",
- data->name, check_for_errors ? "VIR_DOMAIN_DESTROY_GRACEFUL" : "0");
- if (virDomainDestroyFlags (dom, flags) == -1) {
- libvirt_error (g, _("could not destroy libvirt domain"));
- ret = -1;
- }
+ ret = destroy_domain (g, dom, check_for_errors);
virDomainFree (dom);
}
-
if (conn != NULL)
virConnectClose (conn);
@@ -2068,6 +2062,37 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors)
return ret;
}
+/* Wrapper around virDomainDestroy which handles errors and retries.. */
+static int
+destroy_domain (guestfs_h *g, virDomainPtr dom, int check_for_errors)
+{
+ const int flags = check_for_errors ? VIR_DOMAIN_DESTROY_GRACEFUL : 0;
+ virErrorPtr err;
+
+ again:
+ debug (g, "calling virDomainDestroy flags=%s",
+ check_for_errors ? "VIR_DOMAIN_DESTROY_GRACEFUL" : "0");
+ if (virDomainDestroyFlags (dom, flags) == -1) {
+ err = virGetLastError ();
+
+ /* Second chance if we're just waiting for qemu to shut down. See:
+ * https://www.redhat.com/archives/libvir-list/2016-January/msg00767.html
+ */
+ if ((flags & VIR_DOMAIN_DESTROY_GRACEFUL) &&
+ err && err->code == VIR_ERR_SYSTEM_ERROR && err->int1 == EBUSY)
+ goto again;
+
+ /* "Domain not found" is not treated as an error. */
+ if (err && err->code == VIR_ERR_NO_DOMAIN)
+ return 0;
+
+ libvirt_error (g, _("could not destroy libvirt domain"));
+ return -1;
+ }
+
+ return 0;
+}
+
/* Wrapper around error() which produces better errors for
* libvirt functions.
*/
--
2.5.0
8 years, 10 months
[PATCHv2] New API: part_expand_gpt.
by Maxim Perevedentsev
This action moves second(backup) GPT header to the end of the disk.
It is usable in in-place image expanding, since free space after
second GPT header is unusable. To use additional space, we have
to move second header. This is what sgdisk -e does.
However, sgdisk -e may perform additional actions if the partition
table has unexpected params (e.g. if we call sgdisk -e /dev/sda1,
it may fix partition table thus destroying the filesystem).
To prevent such cases, we do a dry-run at first and fail if
additional actions are scheduled.
---
daemon/parted.c | 33 ++++++++++++++++++++
generator/actions.ml | 14 +++++++++
src/MAX_PROC_NR | 2 +-
tests/daemon/Makefile.am | 3 +-
tests/daemon/test-expand-gpt.pl | 69 +++++++++++++++++++++++++++++++++++++++++
5 files changed, 119 insertions(+), 2 deletions(-)
create mode 100755 tests/daemon/test-expand-gpt.pl
diff --git a/daemon/parted.c b/daemon/parted.c
index df6b7e7..033c136 100644
--- a/daemon/parted.c
+++ b/daemon/parted.c
@@ -928,3 +928,36 @@ do_part_get_mbr_part_type (const char *device, int partnum)
reply_with_error ("strdup failed");
return NULL;
}
+
+int
+do_part_expand_gpt(const char *device)
+{
+ CLEANUP_FREE char *err = NULL;
+
+ /* If something is broken, sgdisk may try to correct it.
+ * (e.g. recreate partition table and so on).
+ * We do not want such behavior, so dry-run at first.*/
+ int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
+ str_sgdisk, "--pretend", "-e", device, NULL);
+
+ if (r == -1) {
+ reply_with_error ("%s --pretend -e %s: %s", str_sgdisk, device, err);
+ return -1;
+ }
+ if (err && strlen(err) != 0) {
+ /* Unexpected actions. */
+ reply_with_error ("%s --pretend -e %s: %s", str_sgdisk, device, err);
+ return -1;
+ }
+
+ /* Now we can do a real run. */
+ r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
+ str_sgdisk, "-e", device, NULL);
+
+ if (r == -1) {
+ reply_with_error ("%s -e %s: %s", str_sgdisk, device, err);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index 7ab8ee4..3a14683 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12787,6 +12787,20 @@ See also L<ntfsresize(8)>, L<resize2fs(8)>, L<btrfs(8)>, L<xfs_info(8)>." };
longdesc = "\
This is the internal call which implements C<guestfs_feature_available>." };
+ { defaults with
+ name = "part_expand_gpt"; added = (1, 31, 29);
+ style = RErr, [Device "device"], [];
+ proc_nr = Some 459;
+ optional = Some "gdisk";
+ shortdesc = "move backup GPT header to the end of the disk";
+ longdesc = "\
+Move backup GPT data structures to the end of the disk.
+This is useful in case of in-place image expand
+since disk space after backup GPT header is not usable.
+This is equivalent to C<sgdisk -e>.
+
+See also L<sgdisk(8)>." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index c92ddb6..658bd78 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-458
+459
diff --git a/tests/daemon/Makefile.am b/tests/daemon/Makefile.am
index bb380c5..329b00c 100644
--- a/tests/daemon/Makefile.am
+++ b/tests/daemon/Makefile.am
@@ -25,7 +25,8 @@ check_DATA = captive-daemon.pm
TESTS = \
test-daemon-start.pl \
- test-btrfs.pl
+ test-btrfs.pl \
+ test-expand-gpt.pl
TESTS_ENVIRONMENT = $(top_builddir)/run --test $(VG)
diff --git a/tests/daemon/test-expand-gpt.pl b/tests/daemon/test-expand-gpt.pl
new file mode 100755
index 0000000..637b90e
--- /dev/null
+++ b/tests/daemon/test-expand-gpt.pl
@@ -0,0 +1,69 @@
+#!/usr/bin/env perl
+# Copyright (C) 2015 Maxim Perevedentsev mperevedentsev(a)virtuozzo.com
+#
+# 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.
+
+use strict;
+use warnings;
+
+use Sys::Guestfs;
+
+sub tests {
+ my $g = Sys::Guestfs->new ();
+
+ foreach ("gpt", "mbr") {
+ $g->disk_create ("disk_$_.img", "qcow2", 50 * 1024 * 1024);
+ $g->add_drive ("disk_$_.img");
+ }
+
+ $g->launch ();
+
+ $g->part_disk ("/dev/sda", "gpt");
+ $g->part_disk ("/dev/sdb", "mbr");
+
+ $g->close ();
+
+ die if system ("qemu-img resize disk_gpt.img 100M &>/dev/null");
+
+ $g = Sys::Guestfs->new ();
+
+ foreach ("gpt", "mbr") {
+ $g->add_drive ("disk_$_.img");
+ }
+
+ $g->launch ();
+ die if $g->part_expand_gpt ("/dev/sda");
+
+ my $output = $g->debug ("sh", ["sgdisk", "-p", "/dev/sda"]);
+ die if $output eq "";
+ $output =~ s/\n/ /g;
+ $output =~ s/.*last usable sector is (\d+).*/$1/g;
+
+ my $end_sectors = 100 * 1024 * 2 - $output;
+ die unless $end_sectors <= 34;
+
+ # Negative tests.
+ eval { $g->part_expand_gpt ("/dev/sdb") };
+ die unless $@;
+ eval { $g->part_expand_gpt ("/dev/sda1") };
+ die unless $@;
+}
+
+eval { tests() };
+system ("rm -f disk_*.img");
+if ($@) {
+ die;
+}
+exit 0
--
1.8.3.1
8 years, 10 months
[PATCHv2 0/3] Get/set disk GPT GUID API and support in virt-resize.
by Maxim Perevedentsev
Some OSes (e.g. Windows Server 2012 R2) fail to boot after virt-resize
due to changed disk guid. To fix it, we add new APIs:
part_get_disk_guid
part_set_disk_guid
part_set_disk_guid_random
We also preserve disk GUID in virt-resize.
Maxim Perevedentsev (3):
New API: part_get_disk_guid and part_set_disk_guid.
New API: part_set_disk_guid_random.
resize: preserve GPT disk GUID.
daemon/parted.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++
generator/actions.ml | 52 ++++++++++++++++++++++++++++++++++++
resize/resize.ml | 12 ++++++++-
src/MAX_PROC_NR | 2 +-
4 files changed, 139 insertions(+), 2 deletions(-)
--
1.8.3.1
8 years, 10 months
[PATCH v2] resize, builder: fsync the output file before closing the libvirt connection.
by Richard W.M. Jones
Libvirt has a fixed 15 second timeout for qemu to exit. If qemu is
writing to a slow USB key, it can hang (in D state) for much longer
than this - many minutes usually.
To work around this, fsync the output file before closing the libvirt
connection so that qemu shouldn't have anything (much) to write. We
have to do this in a few places in the code.
This is a hack - it would be better to find a way to fix this in
libvirt.
See also the description here:
https://www.redhat.com/archives/libvir-list/2016-January/msg00767.html
---
builder/builder.ml | 8 +++++++-
resize/resize.ml | 10 ++++++++++
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/builder/builder.ml b/builder/builder.ml
index 1f9a472..093982d 100644
--- a/builder/builder.ml
+++ b/builder/builder.ml
@@ -722,7 +722,13 @@ let main () =
(* Unmount everything and we're done! *)
message (f_"Finishing off");
- g#umount_all ();
+ if cmdline.sync then (
+ (* Work around libvirt 15 second timeout waiting for qemu
+ https://www.redhat.com/archives/libvir-list/2016-January/msg00767.html *)
+ g#sync ();
+ Fsync.file output_filename
+ );
+
g#shutdown ();
g#close ();
diff --git a/resize/resize.ml b/resize/resize.ml
index d6dd9a5..84e38be 100644
--- a/resize/resize.ml
+++ b/resize/resize.ml
@@ -1283,6 +1283,11 @@ read the man page virt-resize(1).
let g =
if to_be_expanded then (
+ (* Work around libvirt 15 second timeout waiting for qemu
+ https://www.redhat.com/archives/libvir-list/2016-January/msg00767.html *)
+ g#sync ();
+ Fsync.file outfile;
+
g#shutdown ();
g#close ();
@@ -1354,6 +1359,11 @@ read the man page virt-resize(1).
) lvs
);
+ (* Work around libvirt 15 second timeout waiting for qemu
+ https://www.redhat.com/archives/libvir-list/2016-January/msg00767.html *)
+ g#sync ();
+ Fsync.file outfile;
+
(* Finished. Unmount disks and exit. *)
g#shutdown ();
g#close ();
--
2.5.0
8 years, 10 months
[PATCH] daemon: resolve paths for ll and llz
by Pino Toscano
Resolve in the guest the given path, so absolute symlinks can be listed
using appliance tools without resolution errors.
Also remove the note about the possibility to escape the sysroot using
ll and llz, since realpath won't return paths outside sysroot.
Fixes part of RHBZ#1293276.
---
daemon/ls.c | 28 ++++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/daemon/ls.c b/daemon/ls.c
index d3689cd..0e2f110 100644
--- a/daemon/ls.c
+++ b/daemon/ls.c
@@ -95,21 +95,24 @@ do_ls0 (const char *path)
return 0;
}
-/* Because we can't chroot and run the ls command (since 'ls' won't
- * necessarily exist in the chroot), this command can be used to escape
- * from the sysroot (eg. 'll /..'). This command is not meant for
- * serious use anyway, just for quick interactive sessions.
- */
-
char *
do_ll (const char *path)
{
int r;
char *out;
CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *rpath = NULL;
CLEANUP_FREE char *spath = NULL;
- spath = sysroot_path (path);
+ CHROOT_IN;
+ rpath = realpath (path, NULL);
+ CHROOT_OUT;
+ if (rpath == NULL) {
+ reply_with_perror ("%s", path);
+ return NULL;
+ }
+
+ spath = sysroot_path (rpath);
if (!spath) {
reply_with_perror ("malloc");
return NULL;
@@ -131,9 +134,18 @@ do_llz (const char *path)
int r;
char *out;
CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *rpath = NULL;
CLEANUP_FREE char *spath = NULL;
- spath = sysroot_path (path);
+ CHROOT_IN;
+ rpath = realpath (path, NULL);
+ CHROOT_OUT;
+ if (rpath == NULL) {
+ reply_with_perror ("%s", path);
+ return NULL;
+ }
+
+ spath = sysroot_path (rpath);
if (!spath) {
reply_with_perror ("malloc");
return NULL;
--
2.5.0
8 years, 10 months
[PATCH] New API: part_get_disk_guid and part_set_disk_guid.
by Maxim Perevedentsev
Some OSes (e.g. Windows Server 2012 R2) fail to boot if the disk
GPT GUID has changed. To preserve disk GUID e.g. during virt-resize,
we need a way to get/set disk GUIDs.
---
daemon/parted.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++
generator/actions.ml | 37 ++++++++++++++++++++++++++++++++
src/MAX_PROC_NR | 2 +-
3 files changed, 98 insertions(+), 1 deletion(-)
diff --git a/daemon/parted.c b/daemon/parted.c
index b073bd8..40f9676 100644
--- a/daemon/parted.c
+++ b/daemon/parted.c
@@ -928,3 +928,63 @@ do_part_get_mbr_part_type (const char *device, int partnum)
reply_with_error ("strdup failed");
return NULL;
}
+
+char *
+do_part_get_disk_guid (const char *device)
+{
+ const char *pattern = "Disk identifier (GUID):";
+ size_t i;
+
+ CLEANUP_FREE char *err = NULL;
+ int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
+ str_sgdisk, device, "-p", NULL);
+ if (r == -1) {
+ reply_with_error ("%s %s -p: %s", str_sgdisk, device, err);
+ return NULL;
+ }
+
+ CLEANUP_FREE_STRING_LIST char **lines = split_lines (err);
+ if (lines == NULL) {
+ reply_with_error ("'%s %s -p' returned no output",
+ str_sgdisk, device);
+ return NULL;
+ }
+
+ for (i = 0; lines[i] != NULL; ++i) {
+ if (STRPREFIX (lines[i], pattern)) {
+ char *value = lines[i] + strlen (pattern);
+
+ /* Skip any leading whitespace */
+ value += strspn (value, " \t");
+
+ /* Extract the actual information from the field. */
+ char *ret = extract_uuid (value);
+ if (ret == NULL) {
+ /* The extraction function already sends the error. */
+ return NULL;
+ }
+
+ return ret;
+ }
+ }
+
+ /* If we got here it means we didn't find the field */
+ reply_with_error ("sgdisk output did not contain disk GUID. "
+ "See LIBGUESTFS_DEBUG output for more details");
+ return NULL;
+}
+
+int
+do_part_set_disk_guid (const char *device, const char *guid)
+{
+ CLEANUP_FREE char *err = NULL;
+ int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
+ str_sgdisk, device, "-U", guid, NULL);
+
+ if (r == -1) {
+ reply_with_error ("%s %s -U %s: %s", str_sgdisk, device, guid, err);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index 7f8e80b..62c4839 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12793,6 +12793,43 @@ See also L<ntfsresize(8)>, L<resize2fs(8)>, L<btrfs(8)>, L<xfs_info(8)>." };
longdesc = "\
This is the internal call which implements C<guestfs_feature_available>." };
+ { defaults with
+ name = "part_set_disk_guid"; added = (1, 33, 2);
+ style = RErr, [Device "device"; GUID "guid"], [];
+ proc_nr = Some 459;
+ optional = Some "gdisk";
+ tests = [
+ InitGPT, Always, TestLastFail (
+ [["part_set_disk_guid"; "/dev/sda"; "f"]]), [];
+ InitGPT, Always, TestResultString (
+ [["part_set_disk_guid"; "/dev/sda";
+ "01234567-89AB-CDEF-0123-456789ABCDEF"];
+ ["part_get_disk_guid"; "/dev/sda"]],
+ "01234567-89AB-CDEF-0123-456789ABCDEF"), [];
+ ];
+ shortdesc = "set the GUID of a GPT-partitioned disk";
+ longdesc = "\
+Set the disk identifier (GUID) of a GPT-partitioned C<device> to C<guid>.
+Return an error if the partition table of C<device> isn't GPT,
+or if C<guid> is not a valid GUID." };
+
+ { defaults with
+ name = "part_get_disk_guid"; added = (1, 33, 2);
+ style = RString "guid", [Device "device"], [];
+ proc_nr = Some 460;
+ optional = Some "gdisk";
+ tests = [
+ InitGPT, Always, TestResultString (
+ [["part_set_disk_guid"; "/dev/sda";
+ "01234567-89AB-CDEF-0123-456789ABCDEF"];
+ ["part_get_disk_guid"; "/dev/sda"]],
+ "01234567-89AB-CDEF-0123-456789ABCDEF"), [];
+ ];
+ shortdesc = "get the GUID of a GPT-partitioned disk";
+ longdesc = "\
+Return the disk identifier (GUID) of a GPT-partitioned C<device>.
+Behaviour is undefined for other partition types." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index c92ddb6..ccbd68f 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-458
+460
--
1.8.3.1
8 years, 10 months
[PATCH] Add -f option to resize2fs -P in vfs_minimum_size.
by Maxim Perevedentsev
Sometimes the user wants to know minimum size
for dirty (e.g. mounted) filesystems. In this case,
resize2fs -P will require calling e2fsck -f, while
"in general, it is not safe to run e2fsck on mounted filesystems".
Since resize2fs -P does not modify filesystem, we force it
to display (probably approximate) minimum size.
---
daemon/ext2.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/daemon/ext2.c b/daemon/ext2.c
index 898d066..9ba4f09 100644
--- a/daemon/ext2.c
+++ b/daemon/ext2.c
@@ -317,7 +317,7 @@ ext_minimum_size (const char *device)
long block_size;
const char *pattern = "Estimated minimum size of the filesystem: ";
- r = command (&out, &err, str_resize2fs, "-P", device, NULL);
+ r = command (&out, &err, str_resize2fs, "-P", "-f", device, NULL);
if (r == -1) {
reply_with_error ("%s", err);
return -1;
--
1.8.3.1
8 years, 10 months
[PATCH] resize: fsync the output file before closing the libvirt connection.
by Richard W.M. Jones
Libvirt has a fixed 15 second timeout for qemu to exit. If qemu is
writing to a slow USB key, it can hang (in D state) for much longer
than this - many minutes usually.
To work around this, fsync the output file before closing the libvirt
connection so that qemu shouldn't have anything (much) to write. We
have to do this in two places in the code since we can reopen the
connection (if using --expand for example).
See also the description here:
https://www.redhat.com/archives/libvir-list/2016-January/msg00767.html
---
resize/resize.ml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/resize/resize.ml b/resize/resize.ml
index d6dd9a5..5e9f108 100644
--- a/resize/resize.ml
+++ b/resize/resize.ml
@@ -1283,6 +1283,9 @@ read the man page virt-resize(1).
let g =
if to_be_expanded then (
+ g#sync ();
+ Fsync.file outfile;
+
g#shutdown ();
g#close ();
@@ -1354,6 +1357,9 @@ read the man page virt-resize(1).
) lvs
);
+ g#sync ();
+ Fsync.file outfile;
+
(* Finished. Unmount disks and exit. *)
g#shutdown ();
g#close ();
--
2.5.0
8 years, 10 months