[PATCH] daemon: lvm: Change the separator character to ':'.
by Richard W.M. Jones
The separator character (currently comma) was picked arbitrarily to
allow us to parse the output of commands like 'lvs' for APIs such as
'lvs-full'. Unfortunately the choice of comma conflicts with the 'lvs
-o modules' column, since the list of modules is separated by commas,
breaking our parser.
Change the separator to another arbitrary character (colon) which
hopefully is not used by any column.
---
generator/daemon.ml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/generator/daemon.ml b/generator/daemon.ml
index a950c17..13ef350 100644
--- a/generator/daemon.ml
+++ b/generator/daemon.ml
@@ -561,7 +561,7 @@ cleanup_free_mountable (mountable_t *mountable)
pr " fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
pr " return -1;\n";
pr " }\n";
- pr " p = strchrnul (tok, ',');\n";
+ pr " p = strchrnul (tok, ':');\n";
pr " if (*p) next = p+1; else next = NULL;\n";
pr " *p = '\\0';\n";
(match coltype with
@@ -631,7 +631,7 @@ cleanup_free_mountable (mountable_t *mountable)
pr " r = command (&out, &err,\n";
pr " \"lvm\", \"%ss\",\n" typ;
pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
- pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
+ pr " \"--nosuffix\", \"--separator\", \":\", \"--units\", \"b\", NULL);\n";
pr " if (r == -1) {\n";
pr " reply_with_error (\"%%s\", err);\n";
pr " free (out);\n";
--
2.5.0
9 years, 1 month
[PATCH] OCaml tools: use open_guestfs everywhere
by Pino Toscano
Instead of creating Guestfs handles and manually apply common options
(e.g. debug and trace), use the open_guestfs in Common_utils.
This also applies the common options to handles which didn't set them
before, so we can inspect also their messages if needed.
---
builder/builder.ml | 8 ++------
customize/customize_main.ml | 4 +---
dib/dib.ml | 4 +---
get-kernel/get_kernel.ml | 4 +---
resize/resize.ml | 10 +++-------
sparsify/cmdline.ml | 2 +-
sparsify/copying.ml | 16 +++++-----------
sparsify/in_place.ml | 4 +---
sysprep/main.ml | 4 +---
v2v/v2v.ml | 6 +++---
10 files changed, 19 insertions(+), 43 deletions(-)
diff --git a/builder/builder.ml b/builder/builder.ml
index feb6e0d..2c51550 100644
--- a/builder/builder.ml
+++ b/builder/builder.ml
@@ -570,9 +570,7 @@ let main () =
(human_size osize);
let preallocation = if oformat = "qcow2" then Some "metadata" else None in
let () =
- let g = new G.guestfs () in
- if trace () then g#set_trace true;
- if verbose () then g#set_verbose true;
+ let g = open_guestfs () in
g#disk_create ?preallocation ofile oformat osize in
let cmd =
sprintf "virt-resize%s%s%s --output-format %s%s%s --unknown-filesystems error %s %s"
@@ -626,9 +624,7 @@ let main () =
(* Now mount the output disk so we can make changes. *)
message (f_"Opening the new disk");
let g =
- let g = new G.guestfs () in
- if trace () then g#set_trace true;
- if verbose () then g#set_verbose true;
+ let g = open_guestfs () in
(match memsize with None -> () | Some memsize -> g#set_memsize memsize);
(match smp with None -> () | Some smp -> g#set_smp smp);
diff --git a/customize/customize_main.ml b/customize/customize_main.ml
index 49d510c..e161e82 100644
--- a/customize/customize_main.ml
+++ b/customize/customize_main.ml
@@ -165,9 +165,7 @@ read the man page virt-customize(1).
(* Connect to libguestfs. *)
let g =
- let g = new G.guestfs () in
- if trace () then g#set_trace true;
- if verbose () then g#set_verbose true;
+ let g = open_guestfs () in
(match memsize with None -> () | Some memsize -> g#set_memsize memsize);
(match smp with None -> () | Some smp -> g#set_smp smp);
diff --git a/dib/dib.ml b/dib/dib.ml
index caf13f2..1ae8876 100644
--- a/dib/dib.ml
+++ b/dib/dib.ml
@@ -626,9 +626,7 @@ let main () =
let is_ramdisk_build = is_ramdisk || StringSet.mem "ironic-agent" all_elements in
let g, tmpdisk, tmpdiskfmt, drive_partition =
- let g = new G.guestfs () in
- if verbose () then g#set_verbose true;
- if trace () then g#set_trace true;
+ let g = open_guestfs () in
(match memsize with None -> () | Some memsize -> g#set_memsize memsize);
(match smp with None -> () | Some smp -> g#set_smp smp);
diff --git a/get-kernel/get_kernel.ml b/get-kernel/get_kernel.ml
index 2bea559..59bd9d6 100644
--- a/get-kernel/get_kernel.ml
+++ b/get-kernel/get_kernel.ml
@@ -182,9 +182,7 @@ let main () =
let add, output, unversioned, prefix = parse_cmdline () in
(* Connect to libguestfs. *)
- let g = new G.guestfs () in
- if trace () then g#set_trace true;
- if verbose () then g#set_verbose true;
+ let g = open_guestfs () in
add g;
g#launch ();
diff --git a/resize/resize.ml b/resize/resize.ml
index af7b37f..b2802c7 100644
--- a/resize/resize.ml
+++ b/resize/resize.ml
@@ -284,7 +284,7 @@ read the man page virt-resize(1).
printf "alignment\n";
printf "align-first\n";
printf "infile-uri\n";
- let g = new G.guestfs () in
+ let g = open_guestfs () in
g#add_drive "/dev/null";
g#launch ();
if g#feature_available [| "ntfsprogs"; "ntfs3g" |] then
@@ -329,9 +329,7 @@ read the man page virt-resize(1).
(* Add in and out disks to the handle and launch. *)
let connect_both_disks () =
- let g = new G.guestfs () in
- if trace () then g#set_trace true;
- if verbose () then g#set_verbose true;
+ let g = open_guestfs () in
let _, { URI.path = path; protocol = protocol;
server = server; username = username;
password = password } = infile in
@@ -1295,9 +1293,7 @@ read the man page virt-resize(1).
g#shutdown ();
g#close ();
- let g = new G.guestfs () in
- if trace () then g#set_trace true;
- if verbose () then g#set_verbose true;
+ let g = open_guestfs () in
(* The output disk is being created, so use cache=unsafe here. *)
g#add_drive ?format:output_format ~readonly:false ~cachemode:"unsafe"
outfile;
diff --git a/sparsify/cmdline.ml b/sparsify/cmdline.ml
index 17b5542..868456f 100644
--- a/sparsify/cmdline.ml
+++ b/sparsify/cmdline.ml
@@ -107,7 +107,7 @@ read the man page virt-sparsify(1).
printf "check-tmpdir\n";
printf "in-place\n";
printf "tmp-option\n";
- let g = new Guestfs.guestfs () in
+ let g = open_guestfs () in
g#add_drive "/dev/null";
g#launch ();
if g#feature_available [| "ntfsprogs"; "ntfs3g" |] then
diff --git a/sparsify/copying.ml b/sparsify/copying.ml
index ef196f6..bef0664 100644
--- a/sparsify/copying.ml
+++ b/sparsify/copying.ml
@@ -60,7 +60,7 @@ let run indisk outdisk check_tmpdir compress convert
| Some fmt -> fmt (* user specified input format, use that *)
| None ->
(* Don't know, so we must autodetect. *)
- match (new G.guestfs ())#disk_format indisk with
+ match (open_guestfs ())#disk_format indisk with
| "unknown" ->
error (f_"cannot detect input disk format; use the --format parameter")
| fmt -> fmt in
@@ -79,9 +79,7 @@ let run indisk outdisk check_tmpdir compress convert
let file = String.sub file 9 (String.length file - 9) in
if not (Sys.file_exists file) then
error (f_"--tmp prebuilt:file: %s: file does not exist") file;
- let g = new G.guestfs () in
- if trace () then g#set_trace true;
- if verbose () then g#set_verbose true;
+ let g = open_guestfs () in
if g#disk_format file <> "qcow2" then
error (f_"--tmp prebuilt:file: %s: file format is not qcow2") file;
if not (g#disk_has_backing_file file) then
@@ -97,7 +95,7 @@ let run indisk outdisk check_tmpdir compress convert
| Prebuilt_file _ -> ()
| Directory tmpdir ->
(* Get virtual size of the input disk. *)
- let virtual_size = (new G.guestfs ())#disk_virtual_size indisk in
+ let virtual_size = (open_guestfs ())#disk_virtual_size indisk in
if verbose () then
printf "input disk virtual size is %Ld bytes (%s)\n%!"
virtual_size (human_size virtual_size);
@@ -153,9 +151,7 @@ You can ignore this warning or change it to a hard failure using the
(* Create 'tmp' with the indisk as the backing file. *)
let create tmp =
- let g = new G.guestfs () in
- if trace () then g#set_trace true;
- if verbose () then g#set_verbose true;
+ let g = open_guestfs () in
g#disk_create
~backingfile:indisk ?backingformat:format ~compat:"1.1"
tmp "qcow2" Int64.minus_one
@@ -180,9 +176,7 @@ You can ignore this warning or change it to a hard failure using the
(* Connect to libguestfs. *)
let g =
- let g = new G.guestfs () in
- if trace () then g#set_trace true;
- if verbose () then g#set_verbose true;
+ let g = open_guestfs () in
(* Note that the temporary overlay disk is always qcow2 format. *)
g#add_drive ~format:"qcow2" ~readonly:false ~cachemode:"unsafe" overlaydisk;
diff --git a/sparsify/in_place.ml b/sparsify/in_place.ml
index 3a2b32c..6a42a11 100644
--- a/sparsify/in_place.ml
+++ b/sparsify/in_place.ml
@@ -31,9 +31,7 @@ module G = Guestfs
let rec run disk format ignores machine_readable zeroes =
(* Connect to libguestfs. *)
- let g = new G.guestfs () in
- if trace () then g#set_trace true;
- if verbose () then g#set_verbose true;
+ let g = open_guestfs () in
(* Capture ^C and clean up gracefully. *)
let quit = ref false in
diff --git a/sysprep/main.ml b/sysprep/main.ml
index 411c595..12d4b02 100644
--- a/sysprep/main.ml
+++ b/sysprep/main.ml
@@ -211,9 +211,7 @@ read the man page virt-sysprep(1).
message (f_"Examining the guest ...");
(* Connect to libguestfs. *)
- let g = new G.guestfs () in
- if trace () then g#set_trace true;
- if verbose () then g#set_verbose true;
+ let g = open_guestfs () in
add g dryrun;
g#launch ();
diff --git a/v2v/v2v.ml b/v2v/v2v.ml
index dabec7f..3610446 100644
--- a/v2v/v2v.ml
+++ b/v2v/v2v.ml
@@ -236,12 +236,12 @@ and create_overlays src_disks =
error (f_"qemu-img command failed, see earlier errors");
(* Sanity check created overlay (see below). *)
- if not ((new G.guestfs ())#disk_has_backing_file overlay_file) then
+ if not ((open_guestfs ())#disk_has_backing_file overlay_file) then
error (f_"internal error: qemu-img did not create overlay with backing file");
let sd = "sd" ^ drive_name i in
- let vsize = (new G.guestfs ())#disk_virtual_size overlay_file in
+ let vsize = (open_guestfs ())#disk_virtual_size overlay_file in
{ ov_overlay_file = overlay_file; ov_sd = sd;
ov_virtual_size = vsize; ov_source = source }
@@ -780,7 +780,7 @@ and copy_targets targets input output output_alloc =
* backing file. Just sanity check this here.
*)
let overlay_file = t.target_overlay.ov_overlay_file in
- if not ((new G.guestfs ())#disk_has_backing_file overlay_file) then
+ if not ((open_guestfs ())#disk_has_backing_file overlay_file) then
error (f_"internal error: qemu corrupted the overlay file");
(* Give the input module a chance to adjust the parameters
--
2.1.0
9 years, 1 month
Mount multiple logical disks (Windows guest)
by 1 1
Hi, everyone! I faced one problem: I want to mount 2 logical disks (C and D) of my Windows 7 at the same time using libguestfs (to find file on both this disks), but I couldn't find any references in your manual. Can you help me?
Detailed:
Host system: Centos 7.1
libguestfs 1.28.1
9 years, 1 month
Hierarchical local mount
by Maxim Perevedentsev
Hello everyone!
I have to implement the functionality of mounting all VM disks/partitions.
E.g. if a VM has 2 disks of 2 partitions each (I get it from
virt-filesystems), I want to get the following structure on host node
after mount:
mnt/
------hdd0/
-------------volume1/
-------------volume2/
------hdd1/
-------------volume1/
-------------volume2/
I'd like to use guestmount due to syntax simplicity, but I found out
that it's impossible to call e.g.
guestmount -a disk.qcow2 -m /dev/sda1:/hdd0/volume1 -m
/dev/sda2:/hdd0/volume2 mnt/
So I came to only two possible options:
1)
mkdir -p mnt/hdd0/volume1
guestmount -a disk.qcow2 -m /dev/sda1 mnt/hdd0/volume1
....
(Is it safe to use the same disk from multiple guestmounts?)
2)
guestfish -a disk.qcow2 "
run :
mkmountpoint /hdd0 :
mkmountpoint /hdd0/volume1 :
... :
mount /dev/sda1 /hdd0/volume1 :
... :
mount-local mnt/ :
mount-local-run"
kill -TERM `pidof guestfish`
guestunmount mnt/
Is any of these options safe enough/preferred? Or, maybe, other options?
I'd like to avoid guestfs API, threading and so on, and confine myself
to command-line.
Thanks in advance!
--
Your sincerely,
Maxim Perevedentsev
9 years, 1 month
[PATCH] v2v: Add --compressed option to produce compressed qcow2 files (RHBZ#1279273).
by Richard W.M. Jones
---
v2v/cmdline.ml | 5 ++++-
v2v/v2v.ml | 21 ++++++++++++++-------
v2v/virt-v2v.pod | 6 ++++++
3 files changed, 24 insertions(+), 8 deletions(-)
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
index d4bddce..f6e75ce 100644
--- a/v2v/cmdline.ml
+++ b/v2v/cmdline.ml
@@ -27,6 +27,7 @@ open Types
open Utils
let parse_cmdline () =
+ let compressed = ref false in
let debug_overlays = ref false in
let do_copy = ref true in
let machine_readable = ref false in
@@ -147,6 +148,7 @@ let parse_cmdline () =
let argspec = [
"-b", Arg.String add_bridge, "in:out " ^ s_"Map bridge 'in' to 'out'";
"--bridge", Arg.String add_bridge, "in:out " ^ ditto;
+ "--compressed", Arg.Set compressed, " " ^ s_"Compress output file";
"--dcpath", Arg.String (set_string_option_once "--dcpath" dcpath),
"path " ^ s_"Override dcPath (for vCenter)";
"--dcPath", Arg.String (set_string_option_once "--dcPath" dcpath),
@@ -220,6 +222,7 @@ read the man page virt-v2v(1).
(* Dereference the arguments. *)
let args = List.rev !args in
+ let compressed = !compressed in
let dcpath = !dcpath in
let debug_overlays = !debug_overlays in
let do_copy = !do_copy in
@@ -414,6 +417,6 @@ read the man page virt-v2v(1).
Output_vdsm.output_vdsm os vdsm_params vmtype output_alloc in
input, output,
- debug_overlays, do_copy, in_place, network_map, no_trim,
+ compressed, debug_overlays, do_copy, in_place, network_map, no_trim,
output_alloc, output_format, output_name,
print_source, root_choice
diff --git a/v2v/v2v.ml b/v2v/v2v.ml
index dabec7f..f1ebb45 100644
--- a/v2v/v2v.ml
+++ b/v2v/v2v.ml
@@ -50,7 +50,7 @@ let () = Random.self_init ()
let rec main () =
(* Handle the command line. *)
let input, output,
- debug_overlays, do_copy, in_place, network_map, no_trim,
+ compressed, debug_overlays, do_copy, in_place, network_map, no_trim,
output_alloc, output_format, output_name, print_source, root_choice =
Cmdline.parse_cmdline () in
@@ -65,7 +65,8 @@ let rec main () =
let conversion_mode =
if not in_place then (
let overlays = create_overlays source.s_disks in
- let targets = init_targets overlays source output output_format in
+ let targets =
+ init_targets overlays source output output_format compressed in
Copying (overlays, targets)
)
else In_place in
@@ -132,7 +133,7 @@ let rec main () =
let targets =
if not do_copy then targets
- else copy_targets targets input output output_alloc in
+ else copy_targets targets input output output_alloc compressed in
(* Create output metadata. *)
message (f_"Creating output metadata");
@@ -247,7 +248,7 @@ and create_overlays src_disks =
ov_virtual_size = vsize; ov_source = source }
) src_disks
-and init_targets overlays source output output_format =
+and init_targets overlays source output output_format compressed =
(* Work out where we will write the final output. Do this early
* just so we can display errors to the user before doing too much
* work.
@@ -274,6 +275,10 @@ and init_targets overlays source output output_format =
if format <> "raw" && format <> "qcow2" then
error (f_"output format should be 'raw' or 'qcow2'.\n\nUse the '-of <format>' option to select a different output format for the converted guest.\n\nOther output formats are not supported at the moment, although might be considered in future.");
+ (* Only allow compressed with qcow2. *)
+ if compressed && format <> "qcow2" then
+ error (f_"the --compressed flag is only allowed when the output format is qcow2 (-of qcow2)");
+
(* output#prepare_targets will fill in the target_file field.
* estimate_target_size will fill in the target_estimated_size field.
* actual_target_size will fill in the target_actual_size field.
@@ -757,7 +762,7 @@ and get_target_firmware inspect guestcaps source output =
and delete_target_on_exit = ref true
-and copy_targets targets input output output_alloc =
+and copy_targets targets input output output_alloc compressed =
(* Copy the source to the output. *)
at_exit (fun () ->
if !delete_target_on_exit then (
@@ -813,9 +818,11 @@ and copy_targets targets input output output_alloc =
?preallocation ?compat;
let cmd =
- sprintf "qemu-img convert%s -n -f qcow2 -O %s %s %s"
+ sprintf "qemu-img convert%s -n -f qcow2 -O %s%s %s %s"
(if not (quiet ()) then " -p" else "")
- (quote t.target_format) (quote overlay_file)
+ (quote t.target_format)
+ (if compressed then " -c" else "")
+ (quote overlay_file)
(quote t.target_file) in
if verbose () then printf "%s\n%!" cmd;
let start_time = gettimeofday () in
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index 4370963..2e83168 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -255,6 +255,12 @@ Display help.
See I<--network> below.
+=item B<--compressed>
+
+Write a compressed output file. This is only allowed if the output
+format is qcow2 (see I<-of> below), and is equivalent to the I<-c>
+option of L<qemu-img(1)>.
+
=item B<--dcpath> Folder/Datacenter
B<NB:> You don't need to use this parameter if you have
--
2.5.0
9 years, 1 month
[PATCH 1/2] customize: check for file existence with --edit (RHBZ#1275806)
by Pino Toscano
Check that a path provided to --edit exists already; while the is_file
call later will fail for non-existing files, with an explicit check a
better error message can be provided.
---
customize/customize_run.ml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/customize/customize_run.ml b/customize/customize_run.ml
index ff7bd0d..054ee53 100644
--- a/customize/customize_run.ml
+++ b/customize/customize_run.ml
@@ -198,6 +198,9 @@ exec >>%s 2>&1
| `Edit (path, expr) ->
message (f_"Editing: %s") path;
+ if not (g#exists path) then
+ error (f_"%s does not exist in the guest") path;
+
if not (g#is_file path) then
error (f_"%s is not a regular file in the guest") path;
--
2.1.0
9 years, 1 month
[PATCH 1/2] lib: enable the libvirt code consistently everywhere
by Pino Toscano
With commit bc2b41778405cc6a376a670703ce63e3678bf1fb
HAVE_LIBVIRT_BACKEND is defined based on the libvirt version (using its
version macro), although libvirt.h is included only after that check:
because of this, variables in the guestfs_h struct after the
HAVE_LIBVIRT_BACKEND block would be used wrongly if libvirt.h was not
included before guestfs-internal.h, like in the recently added
available.c (all the other places using libvirt features in the handle
already happened to do so).
Considering guestfs-internal.h already includes libvirt.h, move its
inclusion up, right before the libvirt version check.
---
src/guestfs-internal.h | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index bc03ccc..a9f2f0d 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -38,12 +38,11 @@
MIN_LIBVIRT_MINOR * 1000 + \
MIN_LIBVIRT_MICRO)
-#if defined(HAVE_LIBVIRT) && LIBVIR_VERSION_NUMBER >= MIN_LIBVIRT_VERSION
-#define HAVE_LIBVIRT_BACKEND
-#endif
-
#ifdef HAVE_LIBVIRT
#include <libvirt/libvirt.h>
+#if LIBVIR_VERSION_NUMBER >= MIN_LIBVIRT_VERSION
+#define HAVE_LIBVIRT_BACKEND
+#endif
#endif
#include "hash.h"
--
2.1.0
9 years, 1 month
[PATCH 1/2] actions: turn available & feature_available as non-daemon
by Pino Toscano
Rename the current available and feature_available into internal daemon
functions, and provide non-daemon functions wrapping them at library
side. This will make it possible to e.g. add caching for them.
Should be only refactoring, no actual behaviour change.
---
daemon/available.c | 4 +-
generator/actions.ml | 192 ++++++++++++++++++++++++++++-----------------------
po/POTFILES | 1 +
src/MAX_PROC_NR | 2 +-
src/Makefile.am | 1 +
src/available.c | 34 +++++++++
6 files changed, 143 insertions(+), 91 deletions(-)
create mode 100644 src/available.c
diff --git a/daemon/available.c b/daemon/available.c
index 54c6b9b..6409b90 100644
--- a/daemon/available.c
+++ b/daemon/available.c
@@ -67,13 +67,13 @@ available (char *const *groups, int error_on_unavailable)
}
int
-do_feature_available (char *const *groups)
+do_internal_feature_available (char *const *groups)
{
return available (groups, 0);
}
int
-do_available (char *const *groups)
+do_internal_available (char *const *groups)
{
if (available (groups, 1) == -1)
return -1;
diff --git a/generator/actions.ml b/generator/actions.ml
index 7ecd384..6348c88 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -3412,6 +3412,92 @@ C<guestfs_get_identifier>." };
longdesc = "\
Get the handle identifier. See C<guestfs_set_identifier>." };
+ { defaults with
+ name = "available"; added = (1, 0, 80);
+ style = RErr, [StringList "groups"], [];
+ tests = [
+ InitNone, Always, TestRun [["available"; ""]], []
+ ];
+ shortdesc = "test availability of some parts of the API";
+ longdesc = "\
+This command is used to check the availability of some
+groups of functionality in the appliance, which not all builds of
+the libguestfs appliance will be able to provide.
+
+The libguestfs groups, and the functions that those
+groups correspond to, are listed in L<guestfs(3)/AVAILABILITY>.
+You can also fetch this list at runtime by calling
+C<guestfs_available_all_groups>.
+
+The argument C<groups> is a list of group names, eg:
+C<[\"inotify\", \"augeas\"]> would check for the availability of
+the Linux inotify functions and Augeas (configuration file
+editing) functions.
+
+The command returns no error if I<all> requested groups are available.
+
+It fails with an error if one or more of the requested
+groups is unavailable in the appliance.
+
+If an unknown group name is included in the
+list of groups then an error is always returned.
+
+I<Notes:>
+
+=over 4
+
+=item *
+
+C<guestfs_feature_available> is the same as this call, but
+with a slightly simpler to use API: that call returns a boolean
+true/false instead of throwing an error.
+
+=item *
+
+You must call C<guestfs_launch> before calling this function.
+
+The reason is because we don't know what groups are
+supported by the appliance/daemon until it is running and can
+be queried.
+
+=item *
+
+If a group of functions is available, this does not necessarily
+mean that they will work. You still have to check for errors
+when calling individual API functions even if they are
+available.
+
+=item *
+
+It is usually the job of distro packagers to build
+complete functionality into the libguestfs appliance.
+Upstream libguestfs, if built from source with all
+requirements satisfied, will support everything.
+
+=item *
+
+This call was added in version C<1.0.80>. In previous
+versions of libguestfs all you could do would be to speculatively
+execute a command to find out if the daemon implemented it.
+See also C<guestfs_version>.
+
+=back
+
+See also C<guestfs_filesystem_available>." };
+
+ { defaults with
+ name = "feature_available"; added = (1, 21, 26);
+ style = RBool "isavailable", [StringList "groups"], [];
+ tests = [
+ InitNone, Always, TestResultTrue [["feature_available"; ""]], []
+ ];
+ shortdesc = "test availability of some parts of the API";
+ longdesc = "\
+This is the same as C<guestfs_available>, but unlike that
+call it returns a simple true/false boolean result, instead
+of throwing an exception if a feature is not found. For
+other documentation see C<guestfs_available>." };
+
]
(* daemon_functions are any functions which cause some action
@@ -8031,80 +8117,6 @@ To create a file with a pattern of repeating bytes
use C<guestfs_fill_pattern>." };
{ defaults with
- name = "available"; added = (1, 0, 80);
- style = RErr, [StringList "groups"], [];
- proc_nr = Some 216;
- tests = [
- InitNone, Always, TestRun [["available"; ""]], []
- ];
- shortdesc = "test availability of some parts of the API";
- longdesc = "\
-This command is used to check the availability of some
-groups of functionality in the appliance, which not all builds of
-the libguestfs appliance will be able to provide.
-
-The libguestfs groups, and the functions that those
-groups correspond to, are listed in L<guestfs(3)/AVAILABILITY>.
-You can also fetch this list at runtime by calling
-C<guestfs_available_all_groups>.
-
-The argument C<groups> is a list of group names, eg:
-C<[\"inotify\", \"augeas\"]> would check for the availability of
-the Linux inotify functions and Augeas (configuration file
-editing) functions.
-
-The command returns no error if I<all> requested groups are available.
-
-It fails with an error if one or more of the requested
-groups is unavailable in the appliance.
-
-If an unknown group name is included in the
-list of groups then an error is always returned.
-
-I<Notes:>
-
-=over 4
-
-=item *
-
-C<guestfs_feature_available> is the same as this call, but
-with a slightly simpler to use API: that call returns a boolean
-true/false instead of throwing an error.
-
-=item *
-
-You must call C<guestfs_launch> before calling this function.
-
-The reason is because we don't know what groups are
-supported by the appliance/daemon until it is running and can
-be queried.
-
-=item *
-
-If a group of functions is available, this does not necessarily
-mean that they will work. You still have to check for errors
-when calling individual API functions even if they are
-available.
-
-=item *
-
-It is usually the job of distro packagers to build
-complete functionality into the libguestfs appliance.
-Upstream libguestfs, if built from source with all
-requirements satisfied, will support everything.
-
-=item *
-
-This call was added in version C<1.0.80>. In previous
-versions of libguestfs all you could do would be to speculatively
-execute a command to find out if the daemon implemented it.
-See also C<guestfs_version>.
-
-=back
-
-See also C<guestfs_filesystem_available>." };
-
- { defaults with
name = "dd"; added = (1, 0, 80);
style = RErr, [Dev_or_Path "src"; Dev_or_Path "dest"], [];
proc_nr = Some 217;
@@ -11763,20 +11775,6 @@ This is only used to debug RHBZ#914931. Note that this
deliberately crashes guestfsd." };
{ defaults with
- name = "feature_available"; added = (1, 21, 26);
- style = RBool "isavailable", [StringList "groups"], [];
- proc_nr = Some 398;
- tests = [
- InitNone, Always, TestResultTrue [["feature_available"; ""]], []
- ];
- shortdesc = "test availability of some parts of the API";
- longdesc = "\
-This is the same as C<guestfs_available>, but unlike that
-call it returns a simple true/false boolean result, instead
-of throwing an exception if a feature is not found. For
-other documentation see C<guestfs_available>." };
-
- { defaults with
name = "syslinux"; added = (1, 21, 27);
style = RErr, [Device "device"], [OString "directory"];
proc_nr = Some 399;
@@ -12780,6 +12778,24 @@ this will fail and set errno as ENOTSUP.
See also L<ntfsresize(8)>, L<resize2fs(8)>, L<btrfs(8)>, L<xfs_info(8)>." };
+ { defaults with
+ name = "internal_available"; added = (1, 31, 25);
+ style = RErr, [StringList "groups"], [];
+ proc_nr = Some 458;
+ visibility = VInternal;
+ shortdesc = "test availability of some parts of the API";
+ longdesc = "\
+This is the internal call which implements C<guestfs_available>." };
+
+ { defaults with
+ name = "internal_feature_available"; added = (1, 31, 25);
+ style = RBool "isavailable", [StringList "groups"], [];
+ proc_nr = Some 459;
+ visibility = VInternal;
+ shortdesc = "test availability of some parts of the API";
+ longdesc = "\
+This is the internal call which implements C<guestfs_feature_available>." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/po/POTFILES b/po/POTFILES
index 32f88a1..d87d668 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -300,6 +300,7 @@ src/actions-support.c
src/actions-variants.c
src/alloc.c
src/appliance.c
+src/available.c
src/bindtests.c
src/canonical-name.c
src/cleanup.c
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index de2a00c..658bd78 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-457
+459
diff --git a/src/Makefile.am b/src/Makefile.am
index 4515c4d..25c6fa3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -83,6 +83,7 @@ libguestfs_la_SOURCES = \
actions-variants.c \
alloc.c \
appliance.c \
+ available.c \
bindtests.c \
canonical-name.c \
command.c \
diff --git a/src/available.c b/src/available.c
new file mode 100644
index 0000000..6738449
--- /dev/null
+++ b/src/available.c
@@ -0,0 +1,34 @@
+/* libguestfs
+ * Copyright (C) 2015 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "guestfs.h"
+#include "guestfs-internal-actions.h"
+
+int
+guestfs_impl_available (guestfs_h *g, char *const *groups)
+{
+ return guestfs_internal_available (g, groups);
+}
+
+int
+guestfs_impl_feature_available (guestfs_h *g, char *const *groups)
+{
+ return guestfs_internal_feature_available (g, groups);
+}
--
2.1.0
9 years, 1 month
mkfs.ext2 succeeds despite nbd write errors?
by Jason Pepas
Hi,
So I've been hacking together an nbdkit plugin (similar to the "file"
plugin, but it splits the file up into chunks):
https://github.com/pepaslabs/nbdkit-chunks-plugin
I got it to the point of being a working prototype. Then I threw it
onto a raspberry pi, which it turns out only has a 50/50 shot of
fallocate() working correctly.
I'm checking the return code of fallocate(), and my chunks_pwrite()
returns -1 if it fails. No problems there.
When I run mkfs.ext2 /dev/nbd0 on the client, I see this on the nbd-server:
nbdkit: chunks[1]: error: Unable to fallocate
'/home/cell/nbds/default/chunks/00000000000000030723'
nbdkit: chunks[1]: error: Unable to fallocate
'/home/cell/nbds/default/chunks/00000000000000030724'
nbdkit: chunks[1]: error: Unable to fallocate
'/home/cell/nbds/default/chunks/00000000000000030725'
nbdkit: chunks[1]: error: Unable to fallocate
'/home/cell/nbds/default/chunks/00000000000000030726'
nbdkit: chunks[1]: error: Unable to fallocate
'/home/cell/nbds/default/chunks/00000000000000030727'
nbdkit: chunks[1]: error: Unable to fallocate
'/home/cell/nbds/default/chunks/00000000000000030728'
nbdkit: chunks[1]: error: Unable to fallocate
'/home/cell/nbds/default/chunks/00000000000000031232'
Indeed, there is definitely a problem with fallocate, as some of the
chunks are the correct size (256k), and some are zero length:
cell@pi1$ pwd
/home/cell/nbds/default/chunks
cell@pi1$ ls -l | tail
-rw------- 1 cell cell 262144 Nov 7 06:01 00000000000000032256
-rw------- 1 cell cell 262144 Nov 7 06:01 00000000000000032257
-rw------- 1 cell cell 262144 Nov 7 06:01 00000000000000032258
-rw------- 1 cell cell 262144 Nov 7 06:01 00000000000000032259
-rw------- 1 cell cell 262144 Nov 7 06:01 00000000000000032260
-rw------- 1 cell cell 262144 Nov 7 06:01 00000000000000032261
-rw------- 1 cell cell 262144 Nov 7 06:01 00000000000000032262
-rw------- 1 cell cell 262144 Nov 7 06:01 00000000000000032263
-rw------- 1 cell cell 0 Nov 7 06:01 00000000000000032264
-rw------- 1 cell cell 0 Nov 7 06:01 00000000000000032767
But that's my concern. The problem is that, alarmingly, mkfs.ext2
isn't phased by this at all:
root@debian:~# nbd-client pi1 10809 /dev/nbd0
Negotiation: ..size = 8192MB
bs=1024, sz=8589934592 bytes
root@debian:~# mkfs.ext2 /dev/nbd0
mke2fs 1.42.12 (29-Aug-2014)
Creating filesystem with 2097152 4k blocks and 524288 inodes
Filesystem UUID: 2230269c-6d2a-4927-93df-d9dd9f4fa40c
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632
Allocating group tables: done
Writing inode tables: done
Writing superblocks and filesystem accounting information: done
root@debian:~#
However, the nbd-client's dmesg is chock full of errors:
[ 9832.409219] block nbd0: Other side returned error (22)
[ 9832.457401] block nbd0: Other side returned error (22)
[ 9832.503100] block nbd0: Other side returned error (22)
[ 9832.542457] block nbd0: Other side returned error (22)
[ 9832.590394] block nbd0: Other side returned error (22)
[ 9832.642393] block nbd0: Other side returned error (22)
[ 9832.681455] block nbd0: Other side returned error (22)
[ 9832.721355] block nbd0: Other side returned error (22)
[ 9832.722676] quiet_error: 15129 callbacks suppressed
[ 9832.722679] Buffer I/O error on device nbd0, logical block 6293248
[ 9832.724274] lost page write due to I/O error on nbd0
[ 9832.724282] Buffer I/O error on device nbd0, logical block 6293249
[ 9832.725110] lost page write due to I/O error on nbd0
[ 9832.725110] Buffer I/O error on device nbd0, logical block 6293250
[ 9832.725110] lost page write due to I/O error on nbd0
[ 9832.725110] Buffer I/O error on device nbd0, logical block 6293251
[ 9832.725110] lost page write due to I/O error on nbd0
[ 9832.725110] Buffer I/O error on device nbd0, logical block 6293252
[ 9832.725110] lost page write due to I/O error on nbd0
[ 9832.725110] Buffer I/O error on device nbd0, logical block 6293253
[ 9832.725110] lost page write due to I/O error on nbd0
[ 9832.725110] Buffer I/O error on device nbd0, logical block 6293254
[ 9832.725110] lost page write due to I/O error on nbd0
[ 9832.725110] Buffer I/O error on device nbd0, logical block 6293255
[ 9832.725110] lost page write due to I/O error on nbd0
[ 9832.725110] Buffer I/O error on device nbd0, logical block 6293256
[ 9832.725110] lost page write due to I/O error on nbd0
[ 9832.725110] Buffer I/O error on device nbd0, logical block 6293257
[ 9832.725110] lost page write due to I/O error on nbd0
[ 9832.743111] block nbd0: Other side returned error (22)
[ 9832.744420] blk_update_request: 125 callbacks suppressed
[ 9832.744422] end_request: I/O error, dev nbd0, sector 12587008
[ 9832.758203] block nbd0: Other side returned error (22)
[ 9832.759513] end_request: I/O error, dev nbd0, sector 12845056
[ 9832.777635] block nbd0: Other side returned error (22)
[ 9832.779511] end_request: I/O error, dev nbd0, sector 12849160
[ 9832.805950] block nbd0: Other side returned error (22)
[ 9832.810278] end_request: I/O error, dev nbd0, sector 12849416
[ 9832.846880] block nbd0: Other side returned error (22)
So, my question / concern is, how is it that the nbd-client's kernel
is correctly detecting massive I/O errors, but apparently not sending
them through to mkfs.ext2?
Or perhaps mkfs.ext2 doesn't check for I/O errors? That's a bit hard
to believe...
Anyway, I'm sure someone on this list has run into similar issues, so
I thought I'd reach out before I go too far down a rabbit hole.
Thanks,
Jason Pepas
9 years, 1 month